blob: 6d918aa1ddca00ec1ac2c6e01e1d29ae382d3714 [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 Cercueil9945bc82014-03-05 14:07:29 +010092static ssize_t network_read(const struct iio_device *dev, void *dst, size_t len)
93{
94 int fd = dev->ctx->pdata->fd;
95 ssize_t ret, read = 0;
96 char buf[1024];
97
98 if (!len)
99 return -EINVAL;
100
101 DEBUG("Writing READBUF command\n");
102 snprintf(buf, sizeof(buf), "READBUF %s %lu %u\r\n", dev->id,
103 (unsigned long) len, 1);
104 ret = write_all(buf, strlen(buf), fd);
105 if (ret < 0) {
106 strerror_r(-ret, buf, sizeof(buf));
107 ERROR("Unable to send READBUF command: %s\n", buf);
108 return ret;
109 }
110
111 do {
112 long read_len;
113
114 DEBUG("Reading READ response\n");
115 ret = read_integer(fd, &read_len);
116 if (ret < 0) {
117 strerror_r(-ret, buf, sizeof(buf));
118 ERROR("Unable to read response to READ: %s\n", buf);
119 return read ?: ret;
120 }
121
122 if (read_len < 0) {
123 strerror_r(-read_len, buf, sizeof(buf));
124 ERROR("Server returned an error: %s\n", buf);
125 return read ?: read_len;
126 }
127
128 DEBUG("Bytes to read: %li\n", read_len);
129
130 ret = read_all(dst, read_len, fd);
131 if (ret < 0) {
132 strerror_r(-ret, buf, sizeof(buf));
133 ERROR("Unable to read response to READ: %s\n", buf);
134 return read ?: ret;
135 }
136
137 dst += read_len;
138 read += read_len;
139 len -= read_len;
140 } while (len);
141
142 return read;
143}
144
Paul Cercueil99cf3d42014-03-06 12:35:26 +0100145static ssize_t network_read_attr_helper(int fd, const char *id,
146 const char *chn, const char *attr, char *dst, size_t len)
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100147{
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100148 long read_len;
149 ssize_t ret;
150 char buf[1024];
151
152 DEBUG("Writing READ command\n");
Paul Cercueil99cf3d42014-03-06 12:35:26 +0100153 if (chn)
154 snprintf(buf, sizeof(buf), "READ %s %s %s\r\n", id, chn, attr);
155 else
156 snprintf(buf, sizeof(buf), "READ %s %s\r\n", id, attr);
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100157 ret = write_all(buf, strlen(buf), fd);
158 if (ret < 0) {
159 strerror_r(-ret, buf, sizeof(buf));
160 ERROR("Unable to send READ command: %s\n", buf);
161 return ret;
162 }
163
164 DEBUG("Reading READ response\n");
165 ret = read_integer(fd, &read_len);
166 if (ret < 0) {
167 strerror_r(-ret, buf, sizeof(buf));
168 ERROR("Unable to read response to READ: %s\n", buf);
169 return ret;
170 }
171
172 if (read_len < 0) {
173 strerror_r(-read_len, buf, sizeof(buf));
174 ERROR("Server returned an error: %s\n", buf);
175 return read_len;
176 }
177
178 if (read_len > len) {
179 ERROR("Value returned by server is too large\n");
180 return -EIO;
181 }
182
183 ret = read_all(dst, read_len, fd);
184 if (ret < 0) {
185 strerror_r(-ret, buf, sizeof(buf));
186 ERROR("Unable to read response to READ: %s\n", buf);
187 return ret;
188 }
189
190 dst[read_len] = '\0';
191 return read_len + 1;
192}
193
Paul Cercueil07897d32014-03-06 12:46:08 +0100194static ssize_t network_write_attr_helper(int fd, const char *id,
195 const char *chn, const char *attr, const char *src)
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100196{
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100197 long resp;
198 ssize_t ret;
199 char buf[1024];
200
201 DEBUG("Writing WRITE command\n");
Paul Cercueil07897d32014-03-06 12:46:08 +0100202 if (chn)
203 snprintf(buf, sizeof(buf), "WRITE %s %s %s %s\r\n",
204 id, chn, attr, src);
205 else
206 snprintf(buf, sizeof(buf), "WRITE %s %s %s\r\n", id, attr, src);
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100207 ret = write_all(buf, strlen(buf), fd);
208 if (ret < 0) {
209 strerror_r(-ret, buf, sizeof(buf));
Paul Cercueil1818e4f2014-03-06 12:43:20 +0100210 ERROR("Unable to send WRITE command: %s\n", buf);
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100211 return ret;
212 }
213
214 DEBUG("Reading WRITE response\n");
215 ret = read_integer(fd, &resp);
216 if (ret < 0) {
217 strerror_r(-ret, buf, sizeof(buf));
218 ERROR("Unable to read response to WRITE: %s\n", buf);
219 return ret;
220 }
221
222 if (resp < 0) {
223 strerror_r(-ret, buf, sizeof(buf));
224 ERROR("Server returned an error: %s\n", buf);
225 }
226
227 return resp;
228}
229
Paul Cercueil99cf3d42014-03-06 12:35:26 +0100230static ssize_t network_read_dev_attr(const struct iio_device *dev,
231 const char *attr, char *dst, size_t len)
232{
233 return network_read_attr_helper(dev->ctx->pdata->fd, dev->id,
234 NULL, attr, dst, len);
235}
236
Paul Cercueil07897d32014-03-06 12:46:08 +0100237static ssize_t network_write_dev_attr(const struct iio_device *dev,
238 const char *attr, const char *src)
239{
240 return network_write_attr_helper(dev->ctx->pdata->fd, dev->id,
241 NULL, attr, src);
242}
243
Paul Cercueil99cf3d42014-03-06 12:35:26 +0100244static ssize_t network_read_chn_attr(const struct iio_channel *chn,
245 const char *attr, char *dst, size_t len)
246{
247 return network_read_attr_helper(chn->dev->ctx->pdata->fd, chn->dev->id,
248 chn->id, attr, dst, len);
249}
250
Paul Cercueil07897d32014-03-06 12:46:08 +0100251static ssize_t network_write_chn_attr(const struct iio_channel *chn,
252 const char *attr, const char *src)
253{
254 return network_write_attr_helper(chn->dev->ctx->pdata->fd, chn->dev->id,
255 chn->id, attr, src);
256}
257
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100258static void network_shutdown(struct iio_context *ctx)
259{
260 struct iio_context_pdata *pdata = ctx->pdata;
261
262 write_all("\r\nEXIT\r\n", sizeof("\r\nEXIT\r\n") - 1, pdata->fd);
263 close(pdata->fd);
264 free(pdata);
265}
266
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100267static struct iio_backend_ops network_ops = {
Paul Cercueil9945bc82014-03-05 14:07:29 +0100268 .read = network_read,
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100269 .read_device_attr = network_read_dev_attr,
270 .write_device_attr = network_write_dev_attr,
Paul Cercueil99cf3d42014-03-06 12:35:26 +0100271 .read_channel_attr = network_read_chn_attr,
Paul Cercueil07897d32014-03-06 12:46:08 +0100272 .write_channel_attr = network_write_chn_attr,
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100273 .shutdown = network_shutdown,
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100274};
275
276static struct iio_context * get_context(int fd)
277{
278 struct iio_context *ctx;
Paul Cercueile60c3ed2014-03-04 11:23:56 +0100279 long xml_len;
280 char *xml;
281 ssize_t ret;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100282
283 DEBUG("Writing PRINT command\n");
Paul Cercueile60c3ed2014-03-04 11:23:56 +0100284 ret = write_all("PRINT\r\n", sizeof("PRINT\r\n") - 1, fd);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100285 if (ret < 0) {
Paul Cercueil497020d2014-03-04 12:17:55 +0100286 char buf[1024];
287 strerror_r(-ret, buf, sizeof(buf));
288 ERROR("Unable to send PRINT command: %s\n", buf);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100289 return NULL;
290 }
291
292 DEBUG("Reading response...\n");
Paul Cercueile60c3ed2014-03-04 11:23:56 +0100293 ret = read_integer(fd, &xml_len);
294 if (ret < 0) {
295 char buf[1024];
296 strerror_r(-ret, buf, sizeof(buf));
297 ERROR("Unable to read response to PRINT: %s\n", buf);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100298 return NULL;
299 }
300
Paul Cercueile60c3ed2014-03-04 11:23:56 +0100301 if (xml_len < 0) {
302 char buf[1024];
303 strerror_r(-xml_len, buf, sizeof(buf));
304 ERROR("Server returned an error: %s\n", buf);
305 return NULL;
306 }
307
308 DEBUG("Server returned a XML string of length %li\n", xml_len);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100309
310 xml = malloc(xml_len);
311 if (!xml) {
312 ERROR("Unable to allocate data\n");
313 return NULL;
314 }
315
316 DEBUG("Reading XML string...\n");
317 read_all(xml, xml_len, fd);
318
319 DEBUG("Creating context from XML...\n");
320 ctx = iio_create_xml_context_mem(xml, xml_len);
321 free(xml);
322 return ctx;
323}
324
325struct iio_context * iio_create_network_context(const char *host)
326{
327 struct hostent *ent;
328 struct sockaddr_in serv;
329 struct iio_context *ctx;
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100330 struct iio_context_pdata *pdata;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100331 int fd;
332
333 memset(&serv, 0, sizeof(serv));
334 serv.sin_family = AF_INET;
335 serv.sin_port = htons(IIOD_PORT);
336
337 /* gethostbyname is not reentrant, and gethostbyname_r
338 * is a GNU extension. So we use a mutex to prevent races */
339 pthread_mutex_lock(&hostname_lock);
340 ent = gethostbyname(host);
341 if (!ent) {
342 ERROR("Unable to create network context: %s\n",
343 strerror(h_errno));
344 pthread_mutex_unlock(&hostname_lock);
345 return NULL;
346 } else if (!ent->h_addr_list[0]) {
347 ERROR("Unable to find an IP for host %s\n", host);
348 pthread_mutex_unlock(&hostname_lock);
349 return NULL;
350 } else {
351 memcpy(&serv.sin_addr.s_addr,
352 ent->h_addr_list[0], ent->h_length);
353 pthread_mutex_unlock(&hostname_lock);
354 }
355
356 fd = socket(AF_INET, SOCK_STREAM, 0);
357 if (fd < 0) {
358 ERROR("Unable to open socket\n");
359 return NULL;
360 }
361
362 if (connect(fd, (struct sockaddr *) &serv, sizeof(serv)) < 0) {
363 ERROR("Unable to connect\n");
364 goto err_close_socket;
365 }
366
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100367 pdata = calloc(1, sizeof(*pdata));
368 if (!pdata) {
369 ERROR("Unable to allocate memory\n");
370 goto err_close_socket;
371 }
372
373 pdata->fd = fd;
374
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100375 DEBUG("Creating context...\n");
376 ctx = get_context(fd);
377 if (!ctx)
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100378 goto err_free_pdata;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100379
380 /* Override the name and low-level functions of the XML context
381 * with those corresponding to the network context */
382 ctx->name = "network";
383 ctx->ops = &network_ops;
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100384 ctx->pdata = pdata;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100385
386 return ctx;
387
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100388err_free_pdata:
389 free(pdata);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100390err_close_socket:
391 close(fd);
392 return NULL;
393}