blob: 72437a6173f6001dfb8e2f66652295c5139f2cdb [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 Cercueil3e94a5b2014-03-04 13:00:41 +010092static ssize_t network_read_dev_attr(const struct iio_device *dev,
93 const char *attr, char *dst, size_t len)
94{
95 int fd = dev->ctx->pdata->fd;
96 long read_len;
97 ssize_t ret;
98 char buf[1024];
99
100 DEBUG("Writing READ command\n");
101 snprintf(buf, sizeof(buf), "READ %s %s\r\n", dev->id, attr);
102 ret = write_all(buf, strlen(buf), fd);
103 if (ret < 0) {
104 strerror_r(-ret, buf, sizeof(buf));
105 ERROR("Unable to send READ command: %s\n", buf);
106 return ret;
107 }
108
109 DEBUG("Reading READ response\n");
110 ret = read_integer(fd, &read_len);
111 if (ret < 0) {
112 strerror_r(-ret, buf, sizeof(buf));
113 ERROR("Unable to read response to READ: %s\n", buf);
114 return ret;
115 }
116
117 if (read_len < 0) {
118 strerror_r(-read_len, buf, sizeof(buf));
119 ERROR("Server returned an error: %s\n", buf);
120 return read_len;
121 }
122
123 if (read_len > len) {
124 ERROR("Value returned by server is too large\n");
125 return -EIO;
126 }
127
128 ret = read_all(dst, read_len, fd);
129 if (ret < 0) {
130 strerror_r(-ret, buf, sizeof(buf));
131 ERROR("Unable to read response to READ: %s\n", buf);
132 return ret;
133 }
134
135 dst[read_len] = '\0';
136 return read_len + 1;
137}
138
139static ssize_t network_write_dev_attr(const struct iio_device *dev,
140 const char *attr, const char *src)
141{
142 int fd = dev->ctx->pdata->fd;
143 long resp;
144 ssize_t ret;
145 char buf[1024];
146
147 DEBUG("Writing WRITE command\n");
148 snprintf(buf, sizeof(buf), "READ %s %s %s\r\n", dev->id, attr, src);
149 ret = write_all(buf, strlen(buf), fd);
150 if (ret < 0) {
151 strerror_r(-ret, buf, sizeof(buf));
152 ERROR("Unable to send READ command: %s\n", buf);
153 return ret;
154 }
155
156 DEBUG("Reading WRITE response\n");
157 ret = read_integer(fd, &resp);
158 if (ret < 0) {
159 strerror_r(-ret, buf, sizeof(buf));
160 ERROR("Unable to read response to WRITE: %s\n", buf);
161 return ret;
162 }
163
164 if (resp < 0) {
165 strerror_r(-ret, buf, sizeof(buf));
166 ERROR("Server returned an error: %s\n", buf);
167 }
168
169 return resp;
170}
171
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100172static void network_shutdown(struct iio_context *ctx)
173{
174 struct iio_context_pdata *pdata = ctx->pdata;
175
176 write_all("\r\nEXIT\r\n", sizeof("\r\nEXIT\r\n") - 1, pdata->fd);
177 close(pdata->fd);
178 free(pdata);
179}
180
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100181static struct iio_backend_ops network_ops = {
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100182 .read_device_attr = network_read_dev_attr,
183 .write_device_attr = network_write_dev_attr,
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100184 .shutdown = network_shutdown,
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100185};
186
187static struct iio_context * get_context(int fd)
188{
189 struct iio_context *ctx;
Paul Cercueile60c3ed2014-03-04 11:23:56 +0100190 long xml_len;
191 char *xml;
192 ssize_t ret;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100193
194 DEBUG("Writing PRINT command\n");
Paul Cercueile60c3ed2014-03-04 11:23:56 +0100195 ret = write_all("PRINT\r\n", sizeof("PRINT\r\n") - 1, fd);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100196 if (ret < 0) {
Paul Cercueil497020d2014-03-04 12:17:55 +0100197 char buf[1024];
198 strerror_r(-ret, buf, sizeof(buf));
199 ERROR("Unable to send PRINT command: %s\n", buf);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100200 return NULL;
201 }
202
203 DEBUG("Reading response...\n");
Paul Cercueile60c3ed2014-03-04 11:23:56 +0100204 ret = read_integer(fd, &xml_len);
205 if (ret < 0) {
206 char buf[1024];
207 strerror_r(-ret, buf, sizeof(buf));
208 ERROR("Unable to read response to PRINT: %s\n", buf);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100209 return NULL;
210 }
211
Paul Cercueile60c3ed2014-03-04 11:23:56 +0100212 if (xml_len < 0) {
213 char buf[1024];
214 strerror_r(-xml_len, buf, sizeof(buf));
215 ERROR("Server returned an error: %s\n", buf);
216 return NULL;
217 }
218
219 DEBUG("Server returned a XML string of length %li\n", xml_len);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100220
221 xml = malloc(xml_len);
222 if (!xml) {
223 ERROR("Unable to allocate data\n");
224 return NULL;
225 }
226
227 DEBUG("Reading XML string...\n");
228 read_all(xml, xml_len, fd);
229
230 DEBUG("Creating context from XML...\n");
231 ctx = iio_create_xml_context_mem(xml, xml_len);
232 free(xml);
233 return ctx;
234}
235
236struct iio_context * iio_create_network_context(const char *host)
237{
238 struct hostent *ent;
239 struct sockaddr_in serv;
240 struct iio_context *ctx;
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100241 struct iio_context_pdata *pdata;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100242 int fd;
243
244 memset(&serv, 0, sizeof(serv));
245 serv.sin_family = AF_INET;
246 serv.sin_port = htons(IIOD_PORT);
247
248 /* gethostbyname is not reentrant, and gethostbyname_r
249 * is a GNU extension. So we use a mutex to prevent races */
250 pthread_mutex_lock(&hostname_lock);
251 ent = gethostbyname(host);
252 if (!ent) {
253 ERROR("Unable to create network context: %s\n",
254 strerror(h_errno));
255 pthread_mutex_unlock(&hostname_lock);
256 return NULL;
257 } else if (!ent->h_addr_list[0]) {
258 ERROR("Unable to find an IP for host %s\n", host);
259 pthread_mutex_unlock(&hostname_lock);
260 return NULL;
261 } else {
262 memcpy(&serv.sin_addr.s_addr,
263 ent->h_addr_list[0], ent->h_length);
264 pthread_mutex_unlock(&hostname_lock);
265 }
266
267 fd = socket(AF_INET, SOCK_STREAM, 0);
268 if (fd < 0) {
269 ERROR("Unable to open socket\n");
270 return NULL;
271 }
272
273 if (connect(fd, (struct sockaddr *) &serv, sizeof(serv)) < 0) {
274 ERROR("Unable to connect\n");
275 goto err_close_socket;
276 }
277
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100278 pdata = calloc(1, sizeof(*pdata));
279 if (!pdata) {
280 ERROR("Unable to allocate memory\n");
281 goto err_close_socket;
282 }
283
284 pdata->fd = fd;
285
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100286 DEBUG("Creating context...\n");
287 ctx = get_context(fd);
288 if (!ctx)
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100289 goto err_free_pdata;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100290
291 /* Override the name and low-level functions of the XML context
292 * with those corresponding to the network context */
293 ctx->name = "network";
294 ctx->ops = &network_ops;
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100295 ctx->pdata = pdata;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100296
297 return ctx;
298
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100299err_free_pdata:
300 free(pdata);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100301err_close_socket:
302 close(fd);
303 return NULL;
304}