blob: 62fbac2caac9efdd6f2a201a1d0d3ad98b28594f [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 Cercueilbb76bf92014-03-11 10:20:18 +010092static ssize_t write_command(const char *cmd, int fd)
93{
94 ssize_t ret;
95
96 DEBUG("Writing command: %s\n", cmd);
97 ret = write_all(cmd, strlen(cmd), fd);
98 if (ret < 0) {
99 char buf[1024];
100 strerror_r(-ret, buf, sizeof(buf));
101 ERROR("Unable to send command: %s\n", buf);
102 }
103 return ret;
104}
105
106static long exec_command(const char *cmd, int fd)
107{
108 long resp;
109 ssize_t ret = write_command(cmd, fd);
110 if (ret < 0)
111 return (long) ret;
112
113 DEBUG("Reading response\n");
114 ret = read_integer(fd, &resp);
115 if (ret < 0) {
116 char buf[1024];
117 strerror_r(-ret, buf, sizeof(buf));
118 ERROR("Unable to read response: %s\n", buf);
119 return (long) ret;
120 }
121
122 if (resp < 0) {
123 char buf[1024];
124 strerror_r(-resp, buf, sizeof(buf));
125 ERROR("Server returned an error: %s\n", buf);
126 }
127 return resp;
128}
129
Paul Cercueil9945bc82014-03-05 14:07:29 +0100130static ssize_t network_read(const struct iio_device *dev, void *dst, size_t len)
131{
132 int fd = dev->ctx->pdata->fd;
133 ssize_t ret, read = 0;
134 char buf[1024];
135
136 if (!len)
137 return -EINVAL;
138
Paul Cercueil9945bc82014-03-05 14:07:29 +0100139 snprintf(buf, sizeof(buf), "READBUF %s %lu %u\r\n", dev->id,
140 (unsigned long) len, 1);
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100141 ret = write_command(buf, fd);
142 if (ret < 0)
Paul Cercueil9945bc82014-03-05 14:07:29 +0100143 return ret;
Paul Cercueil9945bc82014-03-05 14:07:29 +0100144
145 do {
146 long read_len;
147
148 DEBUG("Reading READ response\n");
149 ret = read_integer(fd, &read_len);
150 if (ret < 0) {
151 strerror_r(-ret, buf, sizeof(buf));
152 ERROR("Unable to read response to READ: %s\n", buf);
153 return read ?: ret;
154 }
155
156 if (read_len < 0) {
157 strerror_r(-read_len, buf, sizeof(buf));
158 ERROR("Server returned an error: %s\n", buf);
159 return read ?: read_len;
160 }
161
162 DEBUG("Bytes to read: %li\n", read_len);
163
164 ret = read_all(dst, read_len, fd);
165 if (ret < 0) {
166 strerror_r(-ret, buf, sizeof(buf));
167 ERROR("Unable to read response to READ: %s\n", buf);
168 return read ?: ret;
169 }
170
171 dst += read_len;
172 read += read_len;
173 len -= read_len;
174 } while (len);
175
176 return read;
177}
178
Paul Cercueil99cf3d42014-03-06 12:35:26 +0100179static ssize_t network_read_attr_helper(int fd, const char *id,
180 const char *chn, const char *attr, char *dst, size_t len)
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100181{
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100182 long read_len;
183 ssize_t ret;
184 char buf[1024];
185
Paul Cercueil99cf3d42014-03-06 12:35:26 +0100186 if (chn)
187 snprintf(buf, sizeof(buf), "READ %s %s %s\r\n", id, chn, attr);
188 else
189 snprintf(buf, sizeof(buf), "READ %s %s\r\n", id, attr);
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100190 read_len = exec_command(buf, fd);
191 if (read_len < 0)
192 return (ssize_t) read_len;
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100193
194 if (read_len > len) {
195 ERROR("Value returned by server is too large\n");
196 return -EIO;
197 }
198
199 ret = read_all(dst, read_len, fd);
200 if (ret < 0) {
201 strerror_r(-ret, buf, sizeof(buf));
202 ERROR("Unable to read response to READ: %s\n", buf);
203 return ret;
204 }
205
206 dst[read_len] = '\0';
207 return read_len + 1;
208}
209
Paul Cercueil07897d32014-03-06 12:46:08 +0100210static ssize_t network_write_attr_helper(int fd, const char *id,
211 const char *chn, const char *attr, const char *src)
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100212{
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100213 char buf[1024];
214
Paul Cercueil07897d32014-03-06 12:46:08 +0100215 if (chn)
216 snprintf(buf, sizeof(buf), "WRITE %s %s %s %s\r\n",
217 id, chn, attr, src);
218 else
219 snprintf(buf, sizeof(buf), "WRITE %s %s %s\r\n", id, attr, src);
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100220 return (ssize_t) exec_command(buf, fd);
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100221}
222
Paul Cercueil99cf3d42014-03-06 12:35:26 +0100223static ssize_t network_read_dev_attr(const struct iio_device *dev,
224 const char *attr, char *dst, size_t len)
225{
226 return network_read_attr_helper(dev->ctx->pdata->fd, dev->id,
227 NULL, attr, dst, len);
228}
229
Paul Cercueil07897d32014-03-06 12:46:08 +0100230static ssize_t network_write_dev_attr(const struct iio_device *dev,
231 const char *attr, const char *src)
232{
233 return network_write_attr_helper(dev->ctx->pdata->fd, dev->id,
234 NULL, attr, src);
235}
236
Paul Cercueil99cf3d42014-03-06 12:35:26 +0100237static ssize_t network_read_chn_attr(const struct iio_channel *chn,
238 const char *attr, char *dst, size_t len)
239{
240 return network_read_attr_helper(chn->dev->ctx->pdata->fd, chn->dev->id,
241 chn->id, attr, dst, len);
242}
243
Paul Cercueil07897d32014-03-06 12:46:08 +0100244static ssize_t network_write_chn_attr(const struct iio_channel *chn,
245 const char *attr, const char *src)
246{
247 return network_write_attr_helper(chn->dev->ctx->pdata->fd, chn->dev->id,
248 chn->id, attr, src);
249}
250
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100251static void network_shutdown(struct iio_context *ctx)
252{
253 struct iio_context_pdata *pdata = ctx->pdata;
254
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100255 write_command("\r\nEXIT\r\n", pdata->fd);
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100256 close(pdata->fd);
257 free(pdata);
258}
259
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100260static struct iio_backend_ops network_ops = {
Paul Cercueil9945bc82014-03-05 14:07:29 +0100261 .read = network_read,
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100262 .read_device_attr = network_read_dev_attr,
263 .write_device_attr = network_write_dev_attr,
Paul Cercueil99cf3d42014-03-06 12:35:26 +0100264 .read_channel_attr = network_read_chn_attr,
Paul Cercueil07897d32014-03-06 12:46:08 +0100265 .write_channel_attr = network_write_chn_attr,
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100266 .shutdown = network_shutdown,
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100267};
268
269static struct iio_context * get_context(int fd)
270{
271 struct iio_context *ctx;
Paul Cercueile60c3ed2014-03-04 11:23:56 +0100272 char *xml;
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100273 long xml_len = exec_command("PRINT\r\n", fd);
274 if (xml_len < 0)
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100275 return NULL;
Paul Cercueile60c3ed2014-03-04 11:23:56 +0100276
277 DEBUG("Server returned a XML string of length %li\n", xml_len);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100278 xml = malloc(xml_len);
279 if (!xml) {
280 ERROR("Unable to allocate data\n");
281 return NULL;
282 }
283
284 DEBUG("Reading XML string...\n");
285 read_all(xml, xml_len, fd);
286
287 DEBUG("Creating context from XML...\n");
288 ctx = iio_create_xml_context_mem(xml, xml_len);
289 free(xml);
290 return ctx;
291}
292
293struct iio_context * iio_create_network_context(const char *host)
294{
295 struct hostent *ent;
296 struct sockaddr_in serv;
297 struct iio_context *ctx;
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100298 struct iio_context_pdata *pdata;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100299 int fd;
300
301 memset(&serv, 0, sizeof(serv));
302 serv.sin_family = AF_INET;
303 serv.sin_port = htons(IIOD_PORT);
304
305 /* gethostbyname is not reentrant, and gethostbyname_r
306 * is a GNU extension. So we use a mutex to prevent races */
307 pthread_mutex_lock(&hostname_lock);
308 ent = gethostbyname(host);
309 if (!ent) {
310 ERROR("Unable to create network context: %s\n",
311 strerror(h_errno));
312 pthread_mutex_unlock(&hostname_lock);
313 return NULL;
314 } else if (!ent->h_addr_list[0]) {
315 ERROR("Unable to find an IP for host %s\n", host);
316 pthread_mutex_unlock(&hostname_lock);
317 return NULL;
318 } else {
319 memcpy(&serv.sin_addr.s_addr,
320 ent->h_addr_list[0], ent->h_length);
321 pthread_mutex_unlock(&hostname_lock);
322 }
323
324 fd = socket(AF_INET, SOCK_STREAM, 0);
325 if (fd < 0) {
326 ERROR("Unable to open socket\n");
327 return NULL;
328 }
329
330 if (connect(fd, (struct sockaddr *) &serv, sizeof(serv)) < 0) {
331 ERROR("Unable to connect\n");
332 goto err_close_socket;
333 }
334
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100335 pdata = calloc(1, sizeof(*pdata));
336 if (!pdata) {
337 ERROR("Unable to allocate memory\n");
338 goto err_close_socket;
339 }
340
341 pdata->fd = fd;
342
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100343 DEBUG("Creating context...\n");
344 ctx = get_context(fd);
345 if (!ctx)
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100346 goto err_free_pdata;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100347
348 /* Override the name and low-level functions of the XML context
349 * with those corresponding to the network context */
350 ctx->name = "network";
351 ctx->ops = &network_ops;
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100352 ctx->pdata = pdata;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100353
354 return ctx;
355
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100356err_free_pdata:
357 free(pdata);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100358err_close_socket:
359 close(fd);
360 return NULL;
361}