blob: 006d5346efec4919506268739bec5f21fa49d5b7 [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
Paul Cercueilc7bad0f2014-03-03 17:06:48 +010019#include "iio-private.h"
20
Paul Cercueil9aabe892014-09-02 12:33:46 +020021#ifndef HAVE_PTHREAD
22#define HAVE_PTHREAD 1
23#endif
24
Paul Cercueilc7bad0f2014-03-03 17:06:48 +010025#include <errno.h>
Paul Cercueila7d445b2014-11-11 16:00:15 +010026#include <fcntl.h>
Paul Cercueile60c3ed2014-03-04 11:23:56 +010027#include <stdbool.h>
Paul Cercueilc7bad0f2014-03-03 17:06:48 +010028#include <string.h>
29#include <sys/types.h>
Paul Cercueilab114932014-05-19 13:03:17 +020030#include <time.h>
Paul Cercueil1fef1a52014-04-07 16:31:15 +020031
32#ifdef _WIN32
Paul Cercueil06c479d2015-01-08 16:14:57 +010033/* Override the default version of Windows supported by MinGW.
34 * This is required to use the function inet_ntop. */
35#undef _WIN32_WINNT
36#define _WIN32_WINNT 0x0600
37
Paul Cercueil1fef1a52014-04-07 16:31:15 +020038#include <winsock2.h>
39#include <ws2tcpip.h>
40#define close(s) closesocket(s)
41
42/* winsock2.h defines ERROR, we don't want that */
43#undef ERROR
44
45#else /* _WIN32 */
Paul Cercueil06c479d2015-01-08 16:14:57 +010046#include <arpa/inet.h>
Paul Cercueil1fef1a52014-04-07 16:31:15 +020047#include <netdb.h>
Paul Cercueil0c3ce452015-02-05 16:37:42 +010048#include <netinet/in.h>
Paul Cercueil0b584e12015-01-28 11:47:03 +010049#include <netinet/tcp.h>
Paul Cercueiled15e492015-01-12 15:52:28 +010050#include <net/if.h>
Paul Cercueil83628b32014-11-24 11:26:21 +010051#include <sys/select.h>
Paul Cercueilc7bad0f2014-03-03 17:06:48 +010052#include <sys/socket.h>
53#include <unistd.h>
Paul Cercueil1fef1a52014-04-07 16:31:15 +020054#endif /* _WIN32 */
55
Paul Cercueil257e6ca2014-12-09 17:32:47 +010056#if HAVE_PTHREAD
57#include <pthread.h>
58#endif
59
Paul Cercueilab114932014-05-19 13:03:17 +020060#ifdef HAVE_AVAHI
61#include <avahi-client/client.h>
62#include <avahi-common/error.h>
63#include <avahi-client/lookup.h>
64#include <avahi-common/simple-watch.h>
65#endif
66
Paul Cercueil1fef1a52014-04-07 16:31:15 +020067#include "debug.h"
Paul Cercueilc7bad0f2014-03-03 17:06:48 +010068
Paul Cercueil8a266f12014-06-10 16:06:31 +020069#define DEFAULT_TIMEOUT_MS 5000
70
Paul Cercueil2e38bbe2014-03-19 15:27:15 +010071#define _STRINGIFY(x) #x
72#define STRINGIFY(x) _STRINGIFY(x)
73
Paul Cercueilc7bad0f2014-03-03 17:06:48 +010074#define IIOD_PORT 30431
Paul Cercueil2e38bbe2014-03-19 15:27:15 +010075#define IIOD_PORT_STR STRINGIFY(IIOD_PORT)
Paul Cercueilc7bad0f2014-03-03 17:06:48 +010076
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +010077struct iio_context_pdata {
78 int fd;
Paul Cercueil2dd2c132015-02-24 10:41:01 +010079 struct addrinfo *addrinfo;
Paul Cercueil05e26262014-05-09 11:32:43 +020080#if HAVE_PTHREAD
Paul Cercueil1494b862014-05-05 12:49:07 +020081 pthread_mutex_t lock;
Paul Cercueil05e26262014-05-09 11:32:43 +020082#endif
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +010083};
84
Paul Cercueilab114932014-05-19 13:03:17 +020085#ifdef HAVE_AVAHI
86struct avahi_discovery_data {
87 AvahiSimplePoll *poll;
88 AvahiAddress *address;
89 uint16_t *port;
90 bool found, resolved;
91};
92
93static void __avahi_resolver_cb(AvahiServiceResolver *resolver,
94 __notused AvahiIfIndex iface, __notused AvahiProtocol proto,
95 __notused AvahiResolverEvent event, __notused const char *name,
96 __notused const char *type, __notused const char *domain,
97 __notused const char *host_name, const AvahiAddress *address,
98 uint16_t port, __notused AvahiStringList *txt,
99 __notused AvahiLookupResultFlags flags, void *d)
100{
101 struct avahi_discovery_data *ddata = (struct avahi_discovery_data *) d;
102
103 memcpy(ddata->address, address, sizeof(*address));
104 *ddata->port = port;
105 ddata->resolved = true;
106 avahi_service_resolver_free(resolver);
107}
108
109static void __avahi_browser_cb(AvahiServiceBrowser *browser,
110 AvahiIfIndex iface, AvahiProtocol proto,
111 AvahiBrowserEvent event, const char *name,
112 const char *type, const char *domain,
113 __notused AvahiLookupResultFlags flags, void *d)
114{
115 struct avahi_discovery_data *ddata = (struct avahi_discovery_data *) d;
116 struct AvahiClient *client = avahi_service_browser_get_client(browser);
117
118 switch (event) {
119 default:
120 case AVAHI_BROWSER_NEW:
121 ddata->found = !!avahi_service_resolver_new(client, iface,
122 proto, name, type, domain,
123 AVAHI_PROTO_UNSPEC, 0,
124 __avahi_resolver_cb, d);
125 break;
126 case AVAHI_BROWSER_ALL_FOR_NOW:
127 if (ddata->found) {
128 while (!ddata->resolved) {
129 struct timespec ts;
130 ts.tv_sec = 0;
131 ts.tv_nsec = 4000000;
132 nanosleep(&ts, NULL);
133 }
134 }
135 case AVAHI_BROWSER_FAILURE: /* fall-through */
136 avahi_simple_poll_quit(ddata->poll);
137 case AVAHI_BROWSER_CACHE_EXHAUSTED: /* fall-through */
138 break;
139 }
140}
141
142static int discover_host(AvahiAddress *addr, uint16_t *port)
143{
144 struct avahi_discovery_data ddata;
145 int ret = 0;
146 AvahiClient *client;
147 AvahiServiceBrowser *browser;
148 AvahiSimplePoll *poll = avahi_simple_poll_new();
149 if (!poll)
150 return -ENOMEM;
151
152 client = avahi_client_new(avahi_simple_poll_get(poll),
153 0, NULL, NULL, &ret);
154 if (!client) {
155 ERROR("Unable to start ZeroConf client :%s\n",
156 avahi_strerror(ret));
157 goto err_free_poll;
158 }
159
160 memset(&ddata, 0, sizeof(ddata));
161 ddata.poll = poll;
162 ddata.address = addr;
163 ddata.port = port;
164
165 browser = avahi_service_browser_new(client,
166 AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
167 "_iio._tcp", NULL, 0, __avahi_browser_cb, &ddata);
168 if (!browser) {
169 ret = avahi_client_errno(client);
170 ERROR("Unable to create ZeroConf browser: %s\n",
171 avahi_strerror(ret));
172 goto err_free_client;
173 }
174
175 DEBUG("Trying to discover host\n");
176 avahi_simple_poll_loop(poll);
177
178 if (!ddata.found)
179 ret = ENXIO;
180
181 avahi_service_browser_free(browser);
182err_free_client:
183 avahi_client_free(client);
184err_free_poll:
185 avahi_simple_poll_free(poll);
186 return -ret; /* we want a negative error code */
187}
188#endif /* HAVE_AVAHI */
189
Paul Cercueil05e26262014-05-09 11:32:43 +0200190static void network_lock(struct iio_context_pdata *pdata)
191{
192#if HAVE_PTHREAD
193 pthread_mutex_lock(&pdata->lock);
194#endif
195}
196
197static void network_unlock(struct iio_context_pdata *pdata)
198{
199#if HAVE_PTHREAD
200 pthread_mutex_unlock(&pdata->lock);
201#endif
202}
203
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100204static ssize_t write_all(const void *src, size_t len, int fd)
205{
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200206 uintptr_t ptr = (uintptr_t) src;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100207 while (len) {
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200208 ssize_t ret = send(fd, (const void *) ptr, len, 0);
Lars-Peter Clausencb7b8bf2014-12-05 16:08:52 +0100209 if (ret < 0) {
210 if (errno == EINTR) {
211 continue;
212 }
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100213 return -errno;
Lars-Peter Clausencb7b8bf2014-12-05 16:08:52 +0100214 }
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100215 ptr += ret;
216 len -= ret;
217 }
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200218 return ptr - (uintptr_t) src;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100219}
220
221static ssize_t read_all(void *dst, size_t len, int fd)
222{
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200223 uintptr_t ptr = (uintptr_t) dst;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100224 while (len) {
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200225 ssize_t ret = recv(fd, (void *) ptr, len, 0);
Lars-Peter Clausencb7b8bf2014-12-05 16:08:52 +0100226 if (ret < 0) {
227 if (errno == EINTR)
228 continue;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100229 return -errno;
Lars-Peter Clausencb7b8bf2014-12-05 16:08:52 +0100230 }
Paul Cercueil43eb7e82014-11-13 12:46:59 +0100231 if (ret == 0)
232 return -EPIPE;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100233 ptr += ret;
234 len -= ret;
235 }
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200236 return ptr - (uintptr_t) dst;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100237}
238
Paul Cercueile60c3ed2014-03-04 11:23:56 +0100239static int read_integer(int fd, long *val)
240{
241 unsigned int i;
242 char buf[1024], *ptr;
243 ssize_t ret;
244 bool found = false;
245
246 for (i = 0; i < sizeof(buf) - 1; i++) {
247 ret = read_all(buf + i, 1, fd);
248 if (ret < 0)
249 return (int) ret;
250
Paul Cercueil6691a3f2014-05-02 12:32:01 +0200251 /* Skip the eventual first few carriage returns.
252 * Also stop when a dot is found (for parsing floats) */
253 if (buf[i] != '\n' && buf[i] != '.')
Paul Cercueile60c3ed2014-03-04 11:23:56 +0100254 found = true;
255 else if (found)
256 break;
257 }
258
259 buf[i] = '\0';
260 ret = (ssize_t) strtol(buf, &ptr, 10);
261 if (ptr == buf)
262 return -EINVAL;
263 *val = (long) ret;
264 return 0;
265}
266
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100267static ssize_t write_command(const char *cmd, int fd)
268{
269 ssize_t ret;
270
271 DEBUG("Writing command: %s\n", cmd);
272 ret = write_all(cmd, strlen(cmd), fd);
273 if (ret < 0) {
274 char buf[1024];
275 strerror_r(-ret, buf, sizeof(buf));
276 ERROR("Unable to send command: %s\n", buf);
277 }
278 return ret;
279}
280
281static long exec_command(const char *cmd, int fd)
282{
283 long resp;
284 ssize_t ret = write_command(cmd, fd);
285 if (ret < 0)
286 return (long) ret;
287
288 DEBUG("Reading response\n");
289 ret = read_integer(fd, &resp);
290 if (ret < 0) {
291 char buf[1024];
292 strerror_r(-ret, buf, sizeof(buf));
293 ERROR("Unable to read response: %s\n", buf);
294 return (long) ret;
295 }
296
Paul Cercueilc7fe2ea2014-03-28 11:38:45 +0100297#if LOG_LEVEL >= DEBUG_L
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100298 if (resp < 0) {
299 char buf[1024];
300 strerror_r(-resp, buf, sizeof(buf));
Paul Cercueilc7fe2ea2014-03-28 11:38:45 +0100301 DEBUG("Server returned an error: %s\n", buf);
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100302 }
Paul Cercueilc7fe2ea2014-03-28 11:38:45 +0100303#endif
304
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100305 return resp;
306}
307
Paul Cercueil4970ac32015-02-24 10:59:00 +0100308#ifndef _WIN32
309static int set_blocking_mode(int fd, bool blocking)
310{
311 int ret = fcntl(fd, F_GETFL, 0);
312 if (ret < 0)
313 return -errno;
314
315 if (blocking)
316 ret &= ~O_NONBLOCK;
317 else
318 ret |= O_NONBLOCK;
319
320 ret = fcntl(fd, F_SETFL, ret);
321 return ret < 0 ? -errno : 0;
322}
323
324/* The purpose of this function is to provide a version of connect()
325 * that does not ignore timeouts... */
326static int do_connect(int fd, const struct sockaddr *addr,
327 socklen_t addrlen, struct timeval *timeout)
328{
329 int ret, error;
330 socklen_t len;
331 fd_set set;
332
333 FD_ZERO(&set);
334 FD_SET(fd, &set);
335
336 ret = set_blocking_mode(fd, false);
337 if (ret < 0)
338 return ret;
339
340 ret = connect(fd, addr, addrlen);
341 if (ret < 0 && errno != EINPROGRESS) {
342 ret = -errno;
343 goto end;
344 }
345
346 ret = select(fd + 1, &set, &set, NULL, timeout);
347 if (ret < 0) {
348 ret = -errno;
349 goto end;
350 }
351 if (ret == 0) {
352 ret = -ETIMEDOUT;
353 goto end;
354 }
355
356 /* Verify that we don't have an error */
357 len = sizeof(error);
358 ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len);
359 if(ret < 0) {
360 ret = -errno;
361 goto end;
362 }
363 if (error) {
364 ret = -error;
365 goto end;
366 }
367
368end:
369 /* Restore blocking mode */
370 set_blocking_mode(fd, true);
371 return ret;
372}
373
374static int set_socket_timeout(int fd, unsigned int timeout)
375{
376 struct timeval tv;
377
378 tv.tv_sec = timeout / 1000;
379 tv.tv_usec = (timeout % 1000) * 1000;
380 if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0 ||
381 setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO,
382 &tv, sizeof(tv)) < 0)
383 return -errno;
384 else
385 return 0;
386}
387#else
388static int set_socket_timeout(int fd, unsigned int timeout)
389{
390 if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO,
391 (const char *) &timeout, sizeof(timeout)) < 0 ||
392 setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO,
393 (const char *) &timeout, sizeof(timeout)) < 0)
394 return -errno;
395 else
396 return 0;
397}
398#endif /* !_WIN32 */
399
400static int create_socket(const struct addrinfo *addrinfo)
401{
402 struct timeval timeout;
403 int ret, fd, yes = 1;
404
405 fd = socket(addrinfo->ai_family, addrinfo->ai_socktype, 0);
406 if (fd < 0) {
407 ERROR("Unable to open socket\n");
408 return fd;
409 }
410
411 timeout.tv_sec = DEFAULT_TIMEOUT_MS / 1000;
412 timeout.tv_usec = (DEFAULT_TIMEOUT_MS % 1000) * 1000;
413
414#ifndef _WIN32
415 ret = do_connect(fd, addrinfo->ai_addr, addrinfo->ai_addrlen, &timeout);
416#else
417 ret = connect(fd, addrinfo->ai_addr, addrinfo->ai_addrlen);
418#endif
419 if (ret < 0) {
420 ERROR("Unable to connect\n");
421 close(fd);
422 return ret;
423 }
424
425 set_socket_timeout(fd, DEFAULT_TIMEOUT_MS);
426 setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
427 (const char *) &yes, sizeof(yes));
428 return fd;
429}
430
Paul Cercueil71694c72014-05-22 14:02:13 +0200431static int network_open(const struct iio_device *dev, size_t samples_count,
432 uint32_t *mask, size_t nb, bool cyclic)
Paul Cercueilba059762014-03-14 11:02:02 +0100433{
434 char buf[1024], *ptr;
435 unsigned int i;
Paul Cercueil44ae11c2014-03-17 09:56:29 +0100436 int ret;
Paul Cercueilba059762014-03-14 11:02:02 +0100437
Paul Cercueilff778232014-03-24 14:23:08 +0100438 if (nb != dev->words)
Paul Cercueilba059762014-03-14 11:02:02 +0100439 return -EINVAL;
440
Paul Cercueil3c407f82014-04-02 14:11:59 +0200441 snprintf(buf, sizeof(buf), "OPEN %s %lu ",
442 dev->id, (unsigned long) samples_count);
Paul Cercueilba059762014-03-14 11:02:02 +0100443 ptr = buf + strlen(buf);
444
445 for (i = nb; i > 0; i--) {
Paul Cercueil8c29e412014-04-07 09:46:45 +0200446 snprintf(ptr, (ptr - buf) + i * 8, "%08x", mask[i - 1]);
Paul Cercueilba059762014-03-14 11:02:02 +0100447 ptr += 8;
448 }
Paul Cercueil71694c72014-05-22 14:02:13 +0200449
450 strcpy(ptr, cyclic ? " CYCLIC\r\n" : "\r\n");
Paul Cercueilba059762014-03-14 11:02:02 +0100451
Paul Cercueil05e26262014-05-09 11:32:43 +0200452 network_lock(dev->ctx->pdata);
Paul Cercueil44ae11c2014-03-17 09:56:29 +0100453 ret = (int) exec_command(buf, dev->ctx->pdata->fd);
Paul Cercueil05e26262014-05-09 11:32:43 +0200454 network_unlock(dev->ctx->pdata);
Paul Cercueil1494b862014-05-05 12:49:07 +0200455
Paul Cercueil44ae11c2014-03-17 09:56:29 +0100456 if (ret < 0) {
Paul Cercueil44ae11c2014-03-17 09:56:29 +0100457 return ret;
458 } else {
Paul Cercueilff778232014-03-24 14:23:08 +0100459 memcpy(dev->mask, mask, nb * sizeof(*mask));
Paul Cercueil44ae11c2014-03-17 09:56:29 +0100460 return 0;
461 }
Paul Cercueilba059762014-03-14 11:02:02 +0100462}
463
464static int network_close(const struct iio_device *dev)
465{
Paul Cercueil1494b862014-05-05 12:49:07 +0200466 int ret;
Paul Cercueilba059762014-03-14 11:02:02 +0100467 char buf[1024];
468 snprintf(buf, sizeof(buf), "CLOSE %s\r\n", dev->id);
Paul Cercueil1494b862014-05-05 12:49:07 +0200469
Paul Cercueil05e26262014-05-09 11:32:43 +0200470 network_lock(dev->ctx->pdata);
Paul Cercueil1494b862014-05-05 12:49:07 +0200471 ret = (int) exec_command(buf, dev->ctx->pdata->fd);
Paul Cercueil05e26262014-05-09 11:32:43 +0200472 network_unlock(dev->ctx->pdata);
Paul Cercueil1494b862014-05-05 12:49:07 +0200473
474 return ret;
Paul Cercueilba059762014-03-14 11:02:02 +0100475}
476
Paul Cercueil45c575d2014-03-20 15:14:01 +0100477static ssize_t network_read(const struct iio_device *dev, void *dst, size_t len,
478 uint32_t *mask, size_t words)
Paul Cercueilf9286452014-03-18 14:32:17 +0100479{
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200480 uintptr_t ptr = (uintptr_t) dst;
Paul Cercueil05e26262014-05-09 11:32:43 +0200481 struct iio_context_pdata *pdata = dev->ctx->pdata;
482 int fd = pdata->fd;
Paul Cercueil45c575d2014-03-20 15:14:01 +0100483 ssize_t ret, read = 0;
Paul Cercueil9945bc82014-03-05 14:07:29 +0100484 char buf[1024];
Paul Cercueil45c575d2014-03-20 15:14:01 +0100485 bool read_mask = true;
Paul Cercueil9945bc82014-03-05 14:07:29 +0100486
Paul Cercueil45c575d2014-03-20 15:14:01 +0100487 if (!len || words != (dev->nb_channels + 31) / 32)
Paul Cercueil9945bc82014-03-05 14:07:29 +0100488 return -EINVAL;
489
Paul Cercueila78b6eb2014-03-17 17:28:07 +0100490 snprintf(buf, sizeof(buf), "READBUF %s %lu\r\n",
491 dev->id, (unsigned long) len);
Paul Cercueil1494b862014-05-05 12:49:07 +0200492
Paul Cercueil05e26262014-05-09 11:32:43 +0200493 network_lock(pdata);
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100494 ret = write_command(buf, fd);
Paul Cercueil1494b862014-05-05 12:49:07 +0200495 if (ret < 0) {
Paul Cercueil05e26262014-05-09 11:32:43 +0200496 network_unlock(pdata);
Paul Cercueil9945bc82014-03-05 14:07:29 +0100497 return ret;
Paul Cercueil1494b862014-05-05 12:49:07 +0200498 }
Paul Cercueil9945bc82014-03-05 14:07:29 +0100499
500 do {
Paul Cercueil5cab3ae2014-03-14 11:23:56 +0100501 unsigned int i;
Paul Cercueil9945bc82014-03-05 14:07:29 +0100502 long read_len;
503
504 DEBUG("Reading READ response\n");
505 ret = read_integer(fd, &read_len);
506 if (ret < 0) {
507 strerror_r(-ret, buf, sizeof(buf));
508 ERROR("Unable to read response to READ: %s\n", buf);
Paul Cercueil05e26262014-05-09 11:32:43 +0200509 network_unlock(pdata);
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200510 return read ? read : ret;
Paul Cercueil9945bc82014-03-05 14:07:29 +0100511 }
512
513 if (read_len < 0) {
514 strerror_r(-read_len, buf, sizeof(buf));
515 ERROR("Server returned an error: %s\n", buf);
Paul Cercueil05e26262014-05-09 11:32:43 +0200516 network_unlock(pdata);
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200517 return read ? read : read_len;
Paul Cercueila78b6eb2014-03-17 17:28:07 +0100518 } else if (read_len == 0) {
519 break;
Paul Cercueil9945bc82014-03-05 14:07:29 +0100520 }
521
522 DEBUG("Bytes to read: %li\n", read_len);
523
Paul Cercueil43c1e6c2014-03-20 14:26:20 +0100524 if (read_mask) {
525 DEBUG("Reading mask\n");
526 buf[8] = '\0';
Paul Cercueil45c575d2014-03-20 15:14:01 +0100527 for (i = words; i > 0; i--) {
Paul Cercueil43c1e6c2014-03-20 14:26:20 +0100528 ret = read_all(buf, 8, fd);
529 if (ret < 0)
530 break;
531 sscanf(buf, "%08x", &mask[i - 1]);
532 DEBUG("mask[%i] = 0x%x\n", i - 1, mask[i - 1]);
Paul Cercueil43c1e6c2014-03-20 14:26:20 +0100533 }
534 read_mask = false;
Paul Cercueil5cab3ae2014-03-14 11:23:56 +0100535 }
536
537 if (ret > 0) {
538 char c;
Lars-Peter Clausencb7b8bf2014-12-05 16:08:52 +0100539 ret = read_all(&c, 1, fd);
Paul Cercueil5cab3ae2014-03-14 11:23:56 +0100540 if (ret > 0 && c != '\n')
541 ret = -EIO;
542 }
543
544 if (ret < 0) {
545 strerror_r(-ret, buf, sizeof(buf));
546 ERROR("Unable to read mask: %s\n", buf);
Paul Cercueil05e26262014-05-09 11:32:43 +0200547 network_unlock(pdata);
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200548 return read ? read : ret;
Paul Cercueil5cab3ae2014-03-14 11:23:56 +0100549 }
550
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200551 ret = read_all((void *) ptr, read_len, fd);
Paul Cercueil9945bc82014-03-05 14:07:29 +0100552 if (ret < 0) {
553 strerror_r(-ret, buf, sizeof(buf));
554 ERROR("Unable to read response to READ: %s\n", buf);
Paul Cercueil05e26262014-05-09 11:32:43 +0200555 network_unlock(pdata);
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200556 return read ? read : ret;
Paul Cercueil9945bc82014-03-05 14:07:29 +0100557 }
558
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200559 ptr += ret;
Paul Cercueilf9286452014-03-18 14:32:17 +0100560 read += ret;
Paul Cercueil9945bc82014-03-05 14:07:29 +0100561 len -= read_len;
562 } while (len);
563
Paul Cercueil05e26262014-05-09 11:32:43 +0200564 network_unlock(pdata);
Paul Cercueil9945bc82014-03-05 14:07:29 +0100565 return read;
566}
567
Paul Cercueild93215d2014-05-19 16:36:06 +0200568static ssize_t do_write(struct iio_context_pdata *pdata, bool attr,
Paul Cercueilcecda352014-05-06 18:14:29 +0200569 const char *command, const void *src, size_t len)
Paul Cercueil2725f702014-05-02 11:02:16 +0200570{
Paul Cercueilcecda352014-05-06 18:14:29 +0200571 int fd = pdata->fd;
Paul Cercueil2725f702014-05-02 11:02:16 +0200572 ssize_t ret;
Paul Cercueil2725f702014-05-02 11:02:16 +0200573 long resp;
574
Paul Cercueil05e26262014-05-09 11:32:43 +0200575 network_lock(pdata);
Paul Cercueild93215d2014-05-19 16:36:06 +0200576 if (attr)
577 ret = (ssize_t) write_command(command, fd);
578 else
579 ret = (ssize_t) exec_command(command, fd);
Paul Cercueil2725f702014-05-02 11:02:16 +0200580 if (ret < 0)
Paul Cercueil1494b862014-05-05 12:49:07 +0200581 goto err_unlock;
Paul Cercueil2725f702014-05-02 11:02:16 +0200582
583 ret = write_all(src, len, fd);
584 if (ret < 0)
Paul Cercueil1494b862014-05-05 12:49:07 +0200585 goto err_unlock;
Paul Cercueil2725f702014-05-02 11:02:16 +0200586
587 ret = read_integer(fd, &resp);
Paul Cercueil05e26262014-05-09 11:32:43 +0200588 network_unlock(pdata);
Paul Cercueil1494b862014-05-05 12:49:07 +0200589
Paul Cercueil2725f702014-05-02 11:02:16 +0200590 if (ret < 0)
591 return ret;
592 return (ssize_t) resp;
Paul Cercueil1494b862014-05-05 12:49:07 +0200593
594err_unlock:
Paul Cercueil05e26262014-05-09 11:32:43 +0200595 network_unlock(pdata);
Paul Cercueil1494b862014-05-05 12:49:07 +0200596 return ret;
Paul Cercueil2725f702014-05-02 11:02:16 +0200597}
598
Paul Cercueilcecda352014-05-06 18:14:29 +0200599static ssize_t network_write(const struct iio_device *dev,
600 const void *src, size_t len)
601{
602 char buf[1024];
603 snprintf(buf, sizeof(buf), "WRITEBUF %s %lu\r\n",
604 dev->id, (unsigned long) len);
Paul Cercueild93215d2014-05-19 16:36:06 +0200605 return do_write(dev->ctx->pdata, false, buf, src, len);
Paul Cercueilcecda352014-05-06 18:14:29 +0200606}
607
Paul Cercueil1494b862014-05-05 12:49:07 +0200608static ssize_t network_read_attr_helper(const struct iio_device *dev,
Paul Cercueil0cc0e162014-05-07 12:51:22 +0200609 const struct iio_channel *chn, const char *attr, char *dst,
Paul Cercueil1494b862014-05-05 12:49:07 +0200610 size_t len, bool is_debug)
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100611{
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100612 long read_len;
613 ssize_t ret;
614 char buf[1024];
Paul Cercueil05e26262014-05-09 11:32:43 +0200615 struct iio_context_pdata *pdata = dev->ctx->pdata;
616 int fd = pdata->fd;
Paul Cercueil1494b862014-05-05 12:49:07 +0200617 const char *id = dev->id;
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100618
Paul Cercueil99cf3d42014-03-06 12:35:26 +0100619 if (chn)
Paul Cercueil0cc0e162014-05-07 12:51:22 +0200620 snprintf(buf, sizeof(buf), "READ %s %s %s %s\r\n", id,
621 chn->is_output ? "OUTPUT" : "INPUT",
Paul Cercueil2a3e43d2014-05-21 16:58:45 +0200622 chn->id, attr ? attr : "");
Paul Cercueilc6f03612014-04-14 16:41:31 +0200623 else if (is_debug)
Paul Cercueil2a3e43d2014-05-21 16:58:45 +0200624 snprintf(buf, sizeof(buf), "READ %s DEBUG %s\r\n",
625 id, attr ? attr : "");
Paul Cercueil99cf3d42014-03-06 12:35:26 +0100626 else
Paul Cercueil2a3e43d2014-05-21 16:58:45 +0200627 snprintf(buf, sizeof(buf), "READ %s %s\r\n",
628 id, attr ? attr : "");
Paul Cercueil1494b862014-05-05 12:49:07 +0200629
Paul Cercueil05e26262014-05-09 11:32:43 +0200630 network_lock(pdata);
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100631 read_len = exec_command(buf, fd);
Paul Cercueil1494b862014-05-05 12:49:07 +0200632 if (read_len < 0) {
Paul Cercueil05e26262014-05-09 11:32:43 +0200633 network_unlock(pdata);
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100634 return (ssize_t) read_len;
Paul Cercueil1494b862014-05-05 12:49:07 +0200635 }
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100636
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200637 if ((unsigned long) read_len > len) {
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100638 ERROR("Value returned by server is too large\n");
Paul Cercueil05e26262014-05-09 11:32:43 +0200639 network_unlock(pdata);
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100640 return -EIO;
641 }
642
643 ret = read_all(dst, read_len, fd);
Paul Cercueil05e26262014-05-09 11:32:43 +0200644 network_unlock(pdata);
Paul Cercueil1494b862014-05-05 12:49:07 +0200645
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100646 if (ret < 0) {
647 strerror_r(-ret, buf, sizeof(buf));
648 ERROR("Unable to read response to READ: %s\n", buf);
649 return ret;
650 }
651
Paul Cercueil7d95fd72014-05-22 14:26:44 +0200652 return read_len;
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100653}
654
Paul Cercueil1494b862014-05-05 12:49:07 +0200655static ssize_t network_write_attr_helper(const struct iio_device *dev,
Paul Cercueil0cc0e162014-05-07 12:51:22 +0200656 const struct iio_channel *chn, const char *attr,
657 const char *src, size_t len, bool is_debug)
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100658{
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100659 char buf[1024];
Paul Cercueil1494b862014-05-05 12:49:07 +0200660 const char *id = dev->id;
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100661
Paul Cercueil07897d32014-03-06 12:46:08 +0100662 if (chn)
Paul Cercueil0cc0e162014-05-07 12:51:22 +0200663 snprintf(buf, sizeof(buf), "WRITE %s %s %s %s %lu\r\n",
664 id, chn->is_output ? "OUTPUT" : "INPUT",
Paul Cercueil8747efe2014-05-22 11:12:12 +0200665 chn->id, attr ? attr : "", (unsigned long) len);
Paul Cercueilc6f03612014-04-14 16:41:31 +0200666 else if (is_debug)
Paul Cercueil8747efe2014-05-22 11:12:12 +0200667 snprintf(buf, sizeof(buf), "WRITE %s DEBUG %s %lu\r\n",
668 id, attr ? attr : "", (unsigned long) len);
Paul Cercueil07897d32014-03-06 12:46:08 +0100669 else
Paul Cercueilcecda352014-05-06 18:14:29 +0200670 snprintf(buf, sizeof(buf), "WRITE %s %s %lu\r\n",
Paul Cercueil8747efe2014-05-22 11:12:12 +0200671 id, attr ? attr : "", (unsigned long) len);
Paul Cercueild93215d2014-05-19 16:36:06 +0200672 return do_write(dev->ctx->pdata, true, buf, src, len);
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100673}
674
Paul Cercueil99cf3d42014-03-06 12:35:26 +0100675static ssize_t network_read_dev_attr(const struct iio_device *dev,
Paul Cercueil50c762a2014-04-14 15:55:43 +0200676 const char *attr, char *dst, size_t len, bool is_debug)
Paul Cercueil99cf3d42014-03-06 12:35:26 +0100677{
Paul Cercueil5b577762014-06-03 15:31:42 +0200678 if (attr && ((is_debug && !iio_device_find_debug_attr(dev, attr)) ||
679 (!is_debug && !iio_device_find_attr(dev, attr))))
680 return -ENOENT;
681
Paul Cercueil1494b862014-05-05 12:49:07 +0200682 return network_read_attr_helper(dev, NULL, attr, dst, len, is_debug);
Paul Cercueil99cf3d42014-03-06 12:35:26 +0100683}
684
Paul Cercueil07897d32014-03-06 12:46:08 +0100685static ssize_t network_write_dev_attr(const struct iio_device *dev,
Paul Cercueilcecda352014-05-06 18:14:29 +0200686 const char *attr, const char *src, size_t len, bool is_debug)
Paul Cercueil07897d32014-03-06 12:46:08 +0100687{
Paul Cercueil5b577762014-06-03 15:31:42 +0200688 if (attr && ((is_debug && !iio_device_find_debug_attr(dev, attr)) ||
689 (!is_debug && !iio_device_find_attr(dev, attr))))
690 return -ENOENT;
691
Paul Cercueilcecda352014-05-06 18:14:29 +0200692 return network_write_attr_helper(dev, NULL, attr, src, len, is_debug);
Paul Cercueil07897d32014-03-06 12:46:08 +0100693}
694
Paul Cercueil99cf3d42014-03-06 12:35:26 +0100695static ssize_t network_read_chn_attr(const struct iio_channel *chn,
696 const char *attr, char *dst, size_t len)
697{
Paul Cercueil5b577762014-06-03 15:31:42 +0200698 if (attr && !iio_channel_find_attr(chn, attr))
699 return -ENOENT;
700
Paul Cercueil0cc0e162014-05-07 12:51:22 +0200701 return network_read_attr_helper(chn->dev, chn, attr, dst, len, false);
Paul Cercueil99cf3d42014-03-06 12:35:26 +0100702}
703
Paul Cercueil07897d32014-03-06 12:46:08 +0100704static ssize_t network_write_chn_attr(const struct iio_channel *chn,
Paul Cercueilcecda352014-05-06 18:14:29 +0200705 const char *attr, const char *src, size_t len)
Paul Cercueil07897d32014-03-06 12:46:08 +0100706{
Paul Cercueil5b577762014-06-03 15:31:42 +0200707 if (attr && !iio_channel_find_attr(chn, attr))
708 return -ENOENT;
709
Paul Cercueil0cc0e162014-05-07 12:51:22 +0200710 return network_write_attr_helper(chn->dev, chn, attr, src, len, false);
Paul Cercueil07897d32014-03-06 12:46:08 +0100711}
712
Paul Cercueildcab40c2014-03-11 10:59:14 +0100713static int network_get_trigger(const struct iio_device *dev,
714 const struct iio_device **trigger)
715{
716 struct iio_context_pdata *pdata = dev->ctx->pdata;
717 unsigned int i;
718 char buf[1024];
719 ssize_t ret;
720 long resp;
721
722 snprintf(buf, sizeof(buf), "GETTRIG %s\r\n", dev->id);
Paul Cercueil1494b862014-05-05 12:49:07 +0200723
Paul Cercueil05e26262014-05-09 11:32:43 +0200724 network_lock(dev->ctx->pdata);
Paul Cercueildcab40c2014-03-11 10:59:14 +0100725 resp = exec_command(buf, pdata->fd);
726 if (resp < 0) {
Paul Cercueil05e26262014-05-09 11:32:43 +0200727 network_unlock(pdata);
Paul Cercueildcab40c2014-03-11 10:59:14 +0100728 return (int) resp;
729 } else if (resp == 0) {
730 *trigger = NULL;
Paul Cercueil05e26262014-05-09 11:32:43 +0200731 network_unlock(pdata);
Paul Cercueildcab40c2014-03-11 10:59:14 +0100732 return 0;
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200733 } else if ((unsigned long) resp > sizeof(buf)) {
Paul Cercueildcab40c2014-03-11 10:59:14 +0100734 ERROR("Value returned by server is too large\n");
Paul Cercueil05e26262014-05-09 11:32:43 +0200735 network_unlock(pdata);
Paul Cercueildcab40c2014-03-11 10:59:14 +0100736 return -EIO;
737 }
738
739 ret = read_all(buf, resp, pdata->fd);
Paul Cercueil05e26262014-05-09 11:32:43 +0200740 network_unlock(pdata);
Paul Cercueil1494b862014-05-05 12:49:07 +0200741
Paul Cercueildcab40c2014-03-11 10:59:14 +0100742 if (ret < 0) {
743 strerror_r(-ret, buf, sizeof(buf));
744 ERROR("Unable to read response to GETTRIG: %s\n", buf);
745 return ret;
746 }
747
Lars-Peter Clausenb5cdc102014-08-21 14:45:52 +0200748 if (buf[0] == '\0') {
749 *trigger = NULL;
750 return 0;
751 }
752
Paul Cercueildcab40c2014-03-11 10:59:14 +0100753 for (i = 0; i < dev->ctx->nb_devices; i++) {
754 struct iio_device *cur = dev->ctx->devices[i];
755 if (iio_device_is_trigger(cur) &&
756 !strncmp(cur->name, buf, resp)) {
757 *trigger = cur;
758 return 0;
759 }
760 }
761
762 return -ENXIO;
763}
764
765static int network_set_trigger(const struct iio_device *dev,
766 const struct iio_device *trigger)
767{
Paul Cercueil1494b862014-05-05 12:49:07 +0200768 int ret;
Paul Cercueildcab40c2014-03-11 10:59:14 +0100769 char buf[1024];
770 if (trigger)
771 snprintf(buf, sizeof(buf), "SETTRIG %s %s\r\n",
772 dev->id, trigger->id);
773 else
774 snprintf(buf, sizeof(buf), "SETTRIG %s\r\n", dev->id);
Paul Cercueil1494b862014-05-05 12:49:07 +0200775
Paul Cercueil05e26262014-05-09 11:32:43 +0200776 network_lock(dev->ctx->pdata);
Paul Cercueil1494b862014-05-05 12:49:07 +0200777 ret = (int) exec_command(buf, dev->ctx->pdata->fd);
Paul Cercueil05e26262014-05-09 11:32:43 +0200778 network_unlock(dev->ctx->pdata);
Paul Cercueil1494b862014-05-05 12:49:07 +0200779 return ret;
Paul Cercueildcab40c2014-03-11 10:59:14 +0100780}
781
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100782static void network_shutdown(struct iio_context *ctx)
783{
784 struct iio_context_pdata *pdata = ctx->pdata;
Paul Cercueil44ae11c2014-03-17 09:56:29 +0100785 unsigned int i;
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100786
Paul Cercueil05e26262014-05-09 11:32:43 +0200787 network_lock(pdata);
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100788 write_command("\r\nEXIT\r\n", pdata->fd);
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100789 close(pdata->fd);
Paul Cercueil05e26262014-05-09 11:32:43 +0200790 network_unlock(pdata);
Paul Cercueil1494b862014-05-05 12:49:07 +0200791
Paul Cercueil05e26262014-05-09 11:32:43 +0200792#if HAVE_PTHREAD
Paul Cercueil1494b862014-05-05 12:49:07 +0200793 /* XXX(pcercuei): is this safe? */
794 pthread_mutex_destroy(&pdata->lock);
Paul Cercueil05e26262014-05-09 11:32:43 +0200795#endif
Paul Cercueil2dd2c132015-02-24 10:41:01 +0100796 freeaddrinfo(pdata->addrinfo);
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100797 free(pdata);
Paul Cercueil44ae11c2014-03-17 09:56:29 +0100798
799 for (i = 0; i < ctx->nb_devices; i++) {
800 struct iio_device *dev = ctx->devices[i];
801 if (dev->pdata)
802 free(dev->pdata);
803 }
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100804}
805
Paul Cercueil6691a3f2014-05-02 12:32:01 +0200806static int network_get_version(const struct iio_context *ctx,
Paul Cercueil9de9e9d2014-05-20 13:18:19 +0200807 unsigned int *major, unsigned int *minor, char git_tag[8])
Paul Cercueil6691a3f2014-05-02 12:32:01 +0200808{
809 struct iio_context_pdata *pdata = ctx->pdata;
810 long maj, min;
811 int ret;
Paul Cercueil6691a3f2014-05-02 12:32:01 +0200812
Paul Cercueil05e26262014-05-09 11:32:43 +0200813 network_lock(pdata);
Paul Cercueil1494b862014-05-05 12:49:07 +0200814 ret = (int) write_command("VERSION\r\n", pdata->fd);
815 if (ret < 0)
816 goto err_unlock;
817
818 ret = read_integer(pdata->fd, &maj);
819 if (!ret)
820 ret = read_integer(pdata->fd, &min);
821 if (!ret) {
Paul Cercueil9de9e9d2014-05-20 13:18:19 +0200822 char tag[8];
823 tag[7] = '\0';
824
825 ret = read_all(tag, sizeof(tag) - 1, pdata->fd);
826 if (ret < 0)
827 goto err_unlock;
828
Paul Cercueild15d9952014-05-20 11:40:08 +0200829 if (major)
830 *major = (unsigned int) maj;
831 if (minor)
832 *minor = (unsigned int) min;
Paul Cercueil9de9e9d2014-05-20 13:18:19 +0200833 if (git_tag)
834 strncpy(git_tag, tag, 8);
Paul Cercueil1494b862014-05-05 12:49:07 +0200835 }
836
Paul Cercueil8e8f8992014-06-12 16:58:12 +0200837 ret = 0;
Paul Cercueil1494b862014-05-05 12:49:07 +0200838err_unlock:
Paul Cercueil05e26262014-05-09 11:32:43 +0200839 network_unlock(pdata);
Paul Cercueil1494b862014-05-05 12:49:07 +0200840 return ret;
Paul Cercueil6691a3f2014-05-02 12:32:01 +0200841}
842
Paul Cercueil8a266f12014-06-10 16:06:31 +0200843static unsigned int calculate_remote_timeout(unsigned int timeout)
844{
845 /* XXX(pcercuei): We currently hardcode timeout / 2 for the backend used
846 * by the remote. Is there something better to do here? */
847 return timeout / 2;
848}
849
Paul Cercueilbca3dbc2014-06-11 12:00:21 +0200850static int set_remote_timeout(struct iio_context *ctx, unsigned int timeout)
851{
852 char buf[1024];
853 int ret;
854
855 snprintf(buf, sizeof(buf), "TIMEOUT %u\r\n", timeout);
856 network_lock(ctx->pdata);
857 ret = (int) exec_command(buf, ctx->pdata->fd);
858 network_unlock(ctx->pdata);
859 return ret;
860}
861
862static int network_set_timeout(struct iio_context *ctx, unsigned int timeout)
863{
864 int ret = set_socket_timeout(ctx->pdata->fd, timeout);
865 if (!ret) {
866 timeout = calculate_remote_timeout(timeout);
867 ret = set_remote_timeout(ctx, timeout);
868 }
869 if (ret < 0) {
870 char buf[1024];
871 strerror_r(-ret, buf, sizeof(buf));
Paul Cercueil8a266f12014-06-10 16:06:31 +0200872 WARNING("Unable to set R/W timeout: %s\n", buf);
873 } else {
Paul Cercueil8a266f12014-06-10 16:06:31 +0200874 ctx->rw_timeout_ms = timeout;
875 }
876 return ret;
877}
878
Paul Cercueil12d41832014-10-28 14:35:53 +0100879static struct iio_context * network_clone(const struct iio_context *ctx)
880{
Paul Cercueild3d56ee2015-01-08 16:36:31 +0100881 return iio_create_network_context(ctx->description);
Paul Cercueil12d41832014-10-28 14:35:53 +0100882}
883
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100884static struct iio_backend_ops network_ops = {
Paul Cercueil12d41832014-10-28 14:35:53 +0100885 .clone = network_clone,
Paul Cercueilba059762014-03-14 11:02:02 +0100886 .open = network_open,
887 .close = network_close,
Paul Cercueil9945bc82014-03-05 14:07:29 +0100888 .read = network_read,
Paul Cercueil2725f702014-05-02 11:02:16 +0200889 .write = network_write,
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100890 .read_device_attr = network_read_dev_attr,
891 .write_device_attr = network_write_dev_attr,
Paul Cercueil99cf3d42014-03-06 12:35:26 +0100892 .read_channel_attr = network_read_chn_attr,
Paul Cercueil07897d32014-03-06 12:46:08 +0100893 .write_channel_attr = network_write_chn_attr,
Paul Cercueildcab40c2014-03-11 10:59:14 +0100894 .get_trigger = network_get_trigger,
895 .set_trigger = network_set_trigger,
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100896 .shutdown = network_shutdown,
Paul Cercueil6691a3f2014-05-02 12:32:01 +0200897 .get_version = network_get_version,
Paul Cercueil8a266f12014-06-10 16:06:31 +0200898 .set_timeout = network_set_timeout,
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100899};
900
901static struct iio_context * get_context(int fd)
902{
903 struct iio_context *ctx;
Paul Cercueile60c3ed2014-03-04 11:23:56 +0100904 char *xml;
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100905 long xml_len = exec_command("PRINT\r\n", fd);
906 if (xml_len < 0)
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100907 return NULL;
Paul Cercueile60c3ed2014-03-04 11:23:56 +0100908
909 DEBUG("Server returned a XML string of length %li\n", xml_len);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100910 xml = malloc(xml_len);
911 if (!xml) {
912 ERROR("Unable to allocate data\n");
913 return NULL;
914 }
915
916 DEBUG("Reading XML string...\n");
917 read_all(xml, xml_len, fd);
918
919 DEBUG("Creating context from XML...\n");
920 ctx = iio_create_xml_context_mem(xml, xml_len);
Paul Cercueilc1ed8482014-06-11 16:29:43 +0200921
922 if (ctx)
923 ctx->xml = xml;
924 else
925 free(xml);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100926 return ctx;
927}
928
Paul Cercueil63e52182014-12-11 12:52:48 +0100929struct iio_context * network_create_context(const char *host)
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100930{
Paul Cercueil2e38bbe2014-03-19 15:27:15 +0100931 struct addrinfo hints, *res;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100932 struct iio_context *ctx;
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100933 struct iio_context_pdata *pdata;
Paul Cercueil06c479d2015-01-08 16:14:57 +0100934 unsigned int i, len;
Paul Cercueil4970ac32015-02-24 10:59:00 +0100935 int fd, ret;
Paul Cercueil1fef1a52014-04-07 16:31:15 +0200936#ifdef _WIN32
937 WSADATA wsaData;
938
939 ret = WSAStartup(MAKEWORD(2, 0), &wsaData);
940 if (ret < 0) {
941 ERROR("WSAStartup failed with error %i\n", ret);
942 return NULL;
943 }
944#endif
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100945
Paul Cercueil2e38bbe2014-03-19 15:27:15 +0100946 memset(&hints, 0, sizeof(hints));
947 hints.ai_family = AF_UNSPEC;
948 hints.ai_socktype = SOCK_STREAM;
Paul Cercueilab114932014-05-19 13:03:17 +0200949
950#ifdef HAVE_AVAHI
951 if (!host) {
952 char addr_str[AVAHI_ADDRESS_STR_MAX];
953 char port_str[6];
954 AvahiAddress address;
Paul Cercueil0f729d32014-06-05 17:38:54 +0200955 uint16_t port = IIOD_PORT;
Paul Cercueilab114932014-05-19 13:03:17 +0200956
957 memset(&address, 0, sizeof(address));
958
959 ret = discover_host(&address, &port);
960 if (ret < 0) {
961 ERROR("Unable to find host: %s\n", strerror(-ret));
962 return NULL;
963 }
964
965 avahi_address_snprint(addr_str, sizeof(addr_str), &address);
966 snprintf(port_str, sizeof(port_str), "%hu", port);
967 ret = getaddrinfo(addr_str, port_str, &hints, &res);
968 } else
969#endif
970 {
971 ret = getaddrinfo(host, IIOD_PORT_STR, &hints, &res);
972 }
973
Paul Cercueil2e38bbe2014-03-19 15:27:15 +0100974 if (ret) {
Paul Cercueilab114932014-05-19 13:03:17 +0200975 ERROR("Unable to find host: %s\n", gai_strerror(ret));
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100976 return NULL;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100977 }
978
Paul Cercueil4970ac32015-02-24 10:59:00 +0100979 fd = create_socket(res);
980 if (fd < 0)
Paul Cercueil2dd2c132015-02-24 10:41:01 +0100981 goto err_free_addrinfo;
Paul Cercueilbca3dbc2014-06-11 12:00:21 +0200982
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100983 pdata = calloc(1, sizeof(*pdata));
984 if (!pdata) {
985 ERROR("Unable to allocate memory\n");
986 goto err_close_socket;
987 }
988
989 pdata->fd = fd;
Paul Cercueil2dd2c132015-02-24 10:41:01 +0100990 pdata->addrinfo = res;
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100991
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100992 DEBUG("Creating context...\n");
993 ctx = get_context(fd);
994 if (!ctx)
Paul Cercueild3d56ee2015-01-08 16:36:31 +0100995 goto err_free_pdata;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100996
Paul Cercueil2057fd32014-10-28 14:44:19 +0100997 /* Override the name and low-level functions of the XML context
998 * with those corresponding to the network context */
999 ctx->name = "network";
1000 ctx->ops = &network_ops;
1001 ctx->pdata = pdata;
1002
Paul Cercueil06c479d2015-01-08 16:14:57 +01001003#ifdef HAVE_IPV6
Paul Cercueiled15e492015-01-12 15:52:28 +01001004 len = INET6_ADDRSTRLEN + IF_NAMESIZE + 2;
Paul Cercueil06c479d2015-01-08 16:14:57 +01001005#else
1006 len = INET_ADDRSTRLEN + 1;
1007#endif
1008 ctx->description = malloc(len);
1009 if (!ctx->description) {
1010 ERROR("Unable to allocate memory\n");
1011 goto err_network_shutdown;
1012 }
1013
1014 ctx->description[0] = '\0';
1015
1016#ifdef HAVE_IPV6
1017 if (res->ai_family == AF_INET6) {
1018 struct sockaddr_in6 *in = (struct sockaddr_in6 *) res->ai_addr;
Paul Cercueiled15e492015-01-12 15:52:28 +01001019 char *ptr;
Paul Cercueil06c479d2015-01-08 16:14:57 +01001020 inet_ntop(AF_INET6, &in->sin6_addr,
1021 ctx->description, INET6_ADDRSTRLEN);
Paul Cercueiled15e492015-01-12 15:52:28 +01001022
1023 ptr = if_indextoname(in->sin6_scope_id, ctx->description +
1024 strlen(ctx->description) + 1);
1025 if (!ptr) {
1026 ERROR("Unable to lookup interface of IPv6 address\n");
1027 goto err_network_shutdown;
1028 }
1029
1030 *(ptr - 1) = '%';
Paul Cercueil06c479d2015-01-08 16:14:57 +01001031 }
1032#endif
1033 if (res->ai_family == AF_INET) {
1034 struct sockaddr_in *in = (struct sockaddr_in *) res->ai_addr;
1035 inet_ntop(AF_INET, &in->sin_addr,
1036 ctx->description, INET_ADDRSTRLEN);
1037 }
1038
Paul Cercueil44ae11c2014-03-17 09:56:29 +01001039 for (i = 0; i < ctx->nb_devices; i++) {
1040 struct iio_device *dev = ctx->devices[i];
Paul Cercueilff778232014-03-24 14:23:08 +01001041 uint32_t *mask = NULL;
1042
1043 dev->words = (dev->nb_channels + 31) / 32;
1044 if (dev->words) {
1045 mask = calloc(dev->words, sizeof(*mask));
Paul Cercueil2057fd32014-10-28 14:44:19 +01001046 if (!mask) {
1047 ERROR("Unable to allocate memory\n");
Paul Cercueilff778232014-03-24 14:23:08 +01001048 goto err_network_shutdown;
Paul Cercueil2057fd32014-10-28 14:44:19 +01001049 }
Paul Cercueilff778232014-03-24 14:23:08 +01001050 }
1051
1052 dev->mask = mask;
Paul Cercueil44ae11c2014-03-17 09:56:29 +01001053 }
1054
Paul Cercueilc1ed8482014-06-11 16:29:43 +02001055 iio_context_init(ctx);
Paul Cercueil4c6729d2014-04-04 17:24:41 +02001056
Paul Cercueil05e26262014-05-09 11:32:43 +02001057#if HAVE_PTHREAD
Paul Cercueil1494b862014-05-05 12:49:07 +02001058 ret = pthread_mutex_init(&pdata->lock, NULL);
1059 if (ret < 0) {
1060 char buf[1024];
1061 strerror_r(-ret, buf, sizeof(buf));
1062 ERROR("Unable to initialize mutex: %s\n", buf);
1063 goto err_network_shutdown;
1064 }
Paul Cercueil05e26262014-05-09 11:32:43 +02001065#endif
Paul Cercueil1494b862014-05-05 12:49:07 +02001066
Paul Cercueilbca3dbc2014-06-11 12:00:21 +02001067 set_remote_timeout(ctx, calculate_remote_timeout(DEFAULT_TIMEOUT_MS));
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001068 return ctx;
1069
Paul Cercueil44ae11c2014-03-17 09:56:29 +01001070err_network_shutdown:
Paul Cercueil44ae11c2014-03-17 09:56:29 +01001071 iio_context_destroy(ctx);
Paul Cercueil2057fd32014-10-28 14:44:19 +01001072 return NULL;
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +01001073err_free_pdata:
1074 free(pdata);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001075err_close_socket:
1076 close(fd);
Paul Cercueil2dd2c132015-02-24 10:41:01 +01001077err_free_addrinfo:
1078 freeaddrinfo(res);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001079 return NULL;
1080}