blob: e1a2a84f9c7756bc19097a6b9aeda500824a56c3 [file] [log] [blame]
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001/*
2 * libiio - Library for interfacing industrial I/O (IIO) devices
3 *
4 * Copyright (C) 2014 Analog Devices, Inc.
5 * Author: Paul Cercueil <paul.cercueil@analog.com>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * */
18
19#include "debug.h"
20#include "iio-private.h"
21
22#include <errno.h>
23#include <netdb.h>
24#include <pthread.h>
Paul Cercueile60c3ed2014-03-04 11:23:56 +010025#include <stdbool.h>
Paul Cercueilc7bad0f2014-03-03 17:06:48 +010026#include <string.h>
27#include <sys/types.h>
28#include <sys/socket.h>
29#include <unistd.h>
30
31#define IIOD_PORT 30431
32
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +010033struct iio_context_pdata {
34 int fd;
35};
36
Paul Cercueilc7bad0f2014-03-03 17:06:48 +010037static pthread_mutex_t hostname_lock = PTHREAD_MUTEX_INITIALIZER;
38
39static ssize_t write_all(const void *src, size_t len, int fd)
40{
41 const void *ptr = src;
42 while (len) {
43 ssize_t ret = send(fd, ptr, len, 0);
44 if (ret < 0)
45 return -errno;
46 ptr += ret;
47 len -= ret;
48 }
49 return ptr - src;
50}
51
52static ssize_t read_all(void *dst, size_t len, int fd)
53{
54 void *ptr = dst;
55 while (len) {
56 ssize_t ret = recv(fd, ptr, len, 0);
57 if (ret < 0)
58 return -errno;
59 ptr += ret;
60 len -= ret;
61 }
62 return ptr - dst;
63}
64
Paul Cercueile60c3ed2014-03-04 11:23:56 +010065static int read_integer(int fd, long *val)
66{
67 unsigned int i;
68 char buf[1024], *ptr;
69 ssize_t ret;
70 bool found = false;
71
72 for (i = 0; i < sizeof(buf) - 1; i++) {
73 ret = read_all(buf + i, 1, fd);
74 if (ret < 0)
75 return (int) ret;
76
77 /* Skip the eventual first few carriage returns */
78 if (buf[i] != '\n')
79 found = true;
80 else if (found)
81 break;
82 }
83
84 buf[i] = '\0';
85 ret = (ssize_t) strtol(buf, &ptr, 10);
86 if (ptr == buf)
87 return -EINVAL;
88 *val = (long) ret;
89 return 0;
90}
91
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +010092static void network_shutdown(struct iio_context *ctx)
93{
94 struct iio_context_pdata *pdata = ctx->pdata;
95
96 write_all("\r\nEXIT\r\n", sizeof("\r\nEXIT\r\n") - 1, pdata->fd);
97 close(pdata->fd);
98 free(pdata);
99}
100
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100101static struct iio_backend_ops network_ops = {
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100102 .shutdown = network_shutdown,
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100103};
104
105static struct iio_context * get_context(int fd)
106{
107 struct iio_context *ctx;
Paul Cercueile60c3ed2014-03-04 11:23:56 +0100108 long xml_len;
109 char *xml;
110 ssize_t ret;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100111
112 DEBUG("Writing PRINT command\n");
Paul Cercueile60c3ed2014-03-04 11:23:56 +0100113 ret = write_all("PRINT\r\n", sizeof("PRINT\r\n") - 1, fd);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100114 if (ret < 0) {
Paul Cercueil497020d2014-03-04 12:17:55 +0100115 char buf[1024];
116 strerror_r(-ret, buf, sizeof(buf));
117 ERROR("Unable to send PRINT command: %s\n", buf);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100118 return NULL;
119 }
120
121 DEBUG("Reading response...\n");
Paul Cercueile60c3ed2014-03-04 11:23:56 +0100122 ret = read_integer(fd, &xml_len);
123 if (ret < 0) {
124 char buf[1024];
125 strerror_r(-ret, buf, sizeof(buf));
126 ERROR("Unable to read response to PRINT: %s\n", buf);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100127 return NULL;
128 }
129
Paul Cercueile60c3ed2014-03-04 11:23:56 +0100130 if (xml_len < 0) {
131 char buf[1024];
132 strerror_r(-xml_len, buf, sizeof(buf));
133 ERROR("Server returned an error: %s\n", buf);
134 return NULL;
135 }
136
137 DEBUG("Server returned a XML string of length %li\n", xml_len);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100138
139 xml = malloc(xml_len);
140 if (!xml) {
141 ERROR("Unable to allocate data\n");
142 return NULL;
143 }
144
145 DEBUG("Reading XML string...\n");
146 read_all(xml, xml_len, fd);
147
148 DEBUG("Creating context from XML...\n");
149 ctx = iio_create_xml_context_mem(xml, xml_len);
150 free(xml);
151 return ctx;
152}
153
154struct iio_context * iio_create_network_context(const char *host)
155{
156 struct hostent *ent;
157 struct sockaddr_in serv;
158 struct iio_context *ctx;
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100159 struct iio_context_pdata *pdata;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100160 int fd;
161
162 memset(&serv, 0, sizeof(serv));
163 serv.sin_family = AF_INET;
164 serv.sin_port = htons(IIOD_PORT);
165
166 /* gethostbyname is not reentrant, and gethostbyname_r
167 * is a GNU extension. So we use a mutex to prevent races */
168 pthread_mutex_lock(&hostname_lock);
169 ent = gethostbyname(host);
170 if (!ent) {
171 ERROR("Unable to create network context: %s\n",
172 strerror(h_errno));
173 pthread_mutex_unlock(&hostname_lock);
174 return NULL;
175 } else if (!ent->h_addr_list[0]) {
176 ERROR("Unable to find an IP for host %s\n", host);
177 pthread_mutex_unlock(&hostname_lock);
178 return NULL;
179 } else {
180 memcpy(&serv.sin_addr.s_addr,
181 ent->h_addr_list[0], ent->h_length);
182 pthread_mutex_unlock(&hostname_lock);
183 }
184
185 fd = socket(AF_INET, SOCK_STREAM, 0);
186 if (fd < 0) {
187 ERROR("Unable to open socket\n");
188 return NULL;
189 }
190
191 if (connect(fd, (struct sockaddr *) &serv, sizeof(serv)) < 0) {
192 ERROR("Unable to connect\n");
193 goto err_close_socket;
194 }
195
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100196 pdata = calloc(1, sizeof(*pdata));
197 if (!pdata) {
198 ERROR("Unable to allocate memory\n");
199 goto err_close_socket;
200 }
201
202 pdata->fd = fd;
203
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100204 DEBUG("Creating context...\n");
205 ctx = get_context(fd);
206 if (!ctx)
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100207 goto err_free_pdata;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100208
209 /* Override the name and low-level functions of the XML context
210 * with those corresponding to the network context */
211 ctx->name = "network";
212 ctx->ops = &network_ops;
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100213 ctx->pdata = pdata;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100214
215 return ctx;
216
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100217err_free_pdata:
218 free(pdata);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100219err_close_socket:
220 close(fd);
221 return NULL;
222}