blob: abd4ff907b26c12da1b7ce2d5ffb67ba8897c4d5 [file] [log] [blame]
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001/*
2 * libiio - Library for interfacing industrial I/O (IIO) devices
3 *
Paul Cercueil135b3612015-06-30 14:10:14 +02004 * Copyright (C) 2014-2015 Analog Devices, Inc.
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01005 * 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 Cercueil2814ed12016-08-25 17:08:18 +020019#include "iio-config.h"
Paul Cercueilc7bad0f2014-03-03 17:06:48 +010020#include "iio-private.h"
Paul Cercueil388dcd62015-11-27 15:15:48 +010021#include "iio-lock.h"
Paul Cercueil157d43c2015-11-30 15:05:06 +010022#include "iiod-client.h"
Paul Cercueil9aabe892014-09-02 12:33:46 +020023
Paul Cercueilc7bad0f2014-03-03 17:06:48 +010024#include <errno.h>
Paul Cercueila7d445b2014-11-11 16:00:15 +010025#include <fcntl.h>
Paul Cercueile60c3ed2014-03-04 11:23:56 +010026#include <stdbool.h>
Paul Cercueilc7bad0f2014-03-03 17:06:48 +010027#include <string.h>
28#include <sys/types.h>
Paul Cercueilab114932014-05-19 13:03:17 +020029#include <time.h>
Paul Cercueil1fef1a52014-04-07 16:31:15 +020030
31#ifdef _WIN32
32#include <winsock2.h>
33#include <ws2tcpip.h>
34#define close(s) closesocket(s)
35
36/* winsock2.h defines ERROR, we don't want that */
37#undef ERROR
38
39#else /* _WIN32 */
Paul Cercueil06c479d2015-01-08 16:14:57 +010040#include <arpa/inet.h>
Paul Cercueil1fef1a52014-04-07 16:31:15 +020041#include <netdb.h>
Paul Cercueil0c3ce452015-02-05 16:37:42 +010042#include <netinet/in.h>
Paul Cercueil0b584e12015-01-28 11:47:03 +010043#include <netinet/tcp.h>
Paul Cercueiled15e492015-01-12 15:52:28 +010044#include <net/if.h>
Paul Cercueil09a43482015-03-04 15:50:27 +010045#include <sys/mman.h>
Lars-Peter Clausen14a1f642018-01-23 18:15:45 +010046#include <poll.h>
Paul Cercueilc7bad0f2014-03-03 17:06:48 +010047#include <sys/socket.h>
48#include <unistd.h>
Paul Cercueil1fef1a52014-04-07 16:31:15 +020049#endif /* _WIN32 */
50
Paul Cercueilab114932014-05-19 13:03:17 +020051#ifdef HAVE_AVAHI
52#include <avahi-client/client.h>
53#include <avahi-common/error.h>
54#include <avahi-client/lookup.h>
55#include <avahi-common/simple-watch.h>
56#endif
57
Paul Cercueil1fef1a52014-04-07 16:31:15 +020058#include "debug.h"
Paul Cercueilc7bad0f2014-03-03 17:06:48 +010059
Paul Cercueil8a266f12014-06-10 16:06:31 +020060#define DEFAULT_TIMEOUT_MS 5000
61
Paul Cercueil2e38bbe2014-03-19 15:27:15 +010062#define _STRINGIFY(x) #x
63#define STRINGIFY(x) _STRINGIFY(x)
64
Paul Cercueilc7bad0f2014-03-03 17:06:48 +010065#define IIOD_PORT 30431
Paul Cercueil2e38bbe2014-03-19 15:27:15 +010066#define IIOD_PORT_STR STRINGIFY(IIOD_PORT)
Paul Cercueilc7bad0f2014-03-03 17:06:48 +010067
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +020068struct iio_network_io_context {
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +010069 int fd;
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +020070
71 /* Only buffer IO contexts can be cancelled. */
72 bool cancellable;
73 bool cancelled;
74#if defined(_WIN32)
75 WSAEVENT events[2];
76#elif defined(WITH_NETWORK_EVENTFD)
77 int cancel_fd[1]; /* eventfd */
78#else
79 int cancel_fd[2]; /* pipe */
80#endif
Paul Cercueil6a0eb582016-08-30 10:54:22 +020081 unsigned int timeout_ms;
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +020082};
83
84struct iio_context_pdata {
85 struct iio_network_io_context io_ctx;
Paul Cercueil2dd2c132015-02-24 10:41:01 +010086 struct addrinfo *addrinfo;
Paul Cercueil388dcd62015-11-27 15:15:48 +010087 struct iio_mutex *lock;
Paul Cercueil157d43c2015-11-30 15:05:06 +010088 struct iiod_client *iiod_client;
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +010089};
90
Paul Cercueil439e1a22015-02-24 13:50:51 +010091struct iio_device_pdata {
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +020092 struct iio_network_io_context io_ctx;
Paul Cercueil90189672015-03-16 11:41:53 +010093#ifdef WITH_NETWORK_GET_BUFFER
Paul Cercueil09a43482015-03-04 15:50:27 +010094 int memfd;
Paul Cercueile6e5a092015-03-04 16:33:26 +010095 void *mmap_addr;
Paul Cercueil09a43482015-03-04 15:50:27 +010096 size_t mmap_len;
Paul Cercueile6e5a092015-03-04 16:33:26 +010097#endif
Paul Cercueil09a43482015-03-04 15:50:27 +010098 bool wait_for_err_code, is_cyclic, is_tx;
Paul Cercueil388dcd62015-11-27 15:15:48 +010099 struct iio_mutex *lock;
Paul Cercueil439e1a22015-02-24 13:50:51 +0100100};
101
Lars-Peter Clausendd04e6a2016-02-10 14:56:36 +0100102#ifdef _WIN32
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200103
Lars-Peter Clausenac256dd2017-03-07 13:06:15 +0100104static int set_blocking_mode(int s, bool blocking)
105{
Lars-Peter Clausencd3c49f2017-03-30 15:04:19 +0200106 unsigned long nonblock;
Lars-Peter Clausenac256dd2017-03-07 13:06:15 +0100107 int ret;
108
109 nonblock = blocking ? 0 : 1;
110
111 ret = ioctlsocket(s, FIONBIO, &nonblock);
112 if (ret == SOCKET_ERROR) {
113 ret = -WSAGetLastError();
114 return ret;
115 }
116
117 return 0;
118}
119
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200120static int setup_cancel(struct iio_network_io_context *io_ctx)
121{
122 io_ctx->events[0] = WSACreateEvent();
123 if (io_ctx->events[0] == WSA_INVALID_EVENT)
124 return -ENOMEM; /* Pretty much the only error that can happen */
125
126 io_ctx->events[1] = WSACreateEvent();
127 if (io_ctx->events[1] == WSA_INVALID_EVENT) {
128 WSACloseEvent(io_ctx->events[0]);
129 return -ENOMEM;
130 }
131
132 return 0;
133}
134
135static void cleanup_cancel(struct iio_network_io_context *io_ctx)
136{
137 WSACloseEvent(io_ctx->events[0]);
138 WSACloseEvent(io_ctx->events[1]);
139}
140
141static void do_cancel(struct iio_network_io_context *io_ctx)
142{
143 WSASetEvent(io_ctx->events[1]);
144}
145
146static int wait_cancellable(struct iio_network_io_context *io_ctx, bool read)
147{
148 long wsa_events = FD_CLOSE;
149 DWORD ret;
150
151 if (!io_ctx->cancellable)
152 return 0;
153
154 if (read)
155 wsa_events |= FD_READ;
156 else
157 wsa_events |= FD_WRITE;
158
159 WSAEventSelect(io_ctx->fd, NULL, 0);
160 WSAResetEvent(io_ctx->events[0]);
161 WSAEventSelect(io_ctx->fd, io_ctx->events[0], wsa_events);
162
163 ret = WSAWaitForMultipleEvents(2, io_ctx->events, FALSE,
164 WSA_INFINITE, FALSE);
165
166 if (ret == WSA_WAIT_EVENT_0 + 1)
167 return -EBADF;
168
169 return 0;
170}
171
Lars-Peter Clausendd04e6a2016-02-10 14:56:36 +0100172static int network_get_error(void)
173{
174 return -WSAGetLastError();
175}
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200176
177static bool network_should_retry(int err)
178{
Paul Cercueil63a48ed2016-09-01 12:27:46 +0200179 return err == -WSAEWOULDBLOCK || err == -WSAETIMEDOUT;
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200180}
181
Paul Cercueilb419f1e2016-08-31 16:59:57 +0200182static bool network_is_interrupted(int err)
183{
184 return false;
185}
186
Lars-Peter Clausenac256dd2017-03-07 13:06:15 +0100187static bool network_connect_in_progress(int err)
188{
189 return err == -WSAEWOULDBLOCK;
190}
191
192#define NETWORK_ERR_TIMEOUT WSAETIMEDOUT
193
Lars-Peter Clausendd04e6a2016-02-10 14:56:36 +0100194#else
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200195
Paul Cercueil7a683272016-08-24 14:50:20 +0200196static int set_blocking_mode(int fd, bool blocking)
197{
198 int ret = fcntl(fd, F_GETFL, 0);
199 if (ret < 0)
200 return -errno;
201
202 if (blocking)
203 ret &= ~O_NONBLOCK;
204 else
205 ret |= O_NONBLOCK;
206
207 ret = fcntl(fd, F_SETFL, ret);
208 return ret < 0 ? -errno : 0;
209}
210
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200211#include <poll.h>
212
213#if defined(WITH_NETWORK_EVENTFD)
214
215#include <sys/eventfd.h>
216
217static int create_cancel_fd(struct iio_network_io_context *io_ctx)
218{
219 io_ctx->cancel_fd[0] = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
220 if (io_ctx->cancel_fd[0] < 0)
221 return -errno;
222 return 0;
223}
224
225static void cleanup_cancel(struct iio_network_io_context *io_ctx)
226{
227 close(io_ctx->cancel_fd[0]);
228}
229
230#define CANCEL_WR_FD 0
231
232#else
233
234static int create_cancel_fd(struct iio_network_io_context *io_ctx)
235{
236 int ret;
237
238#ifdef HAS_PIPE2
239 ret = pipe2(io_ctx->cancel_fd, O_CLOEXEC | O_NONBLOCK);
240 if (ret < 0 && errno != ENOSYS) /* If ENOSYS try pipe() */
241 return -errno;
242#endif
243 ret = pipe(io_ctx->cancel_fd);
244 if (ret < 0)
245 return -errno;
246 ret = set_blocking_mode(io_ctx->cancel_fd[0], false);
247 if (ret < 0)
248 goto err_close;
249 ret = set_blocking_mode(io_ctx->cancel_fd[1], false);
250 if (ret < 0)
251 goto err_close;
252
253 return 0;
254err_close:
255 close(io_ctx->cancel_fd[0]);
256 close(io_ctx->cancel_fd[1]);
257 return ret;
258}
259
260static void cleanup_cancel(struct iio_network_io_context *io_ctx)
261{
262 close(io_ctx->cancel_fd[0]);
263 close(io_ctx->cancel_fd[1]);
264}
265
266#define CANCEL_WR_FD 1
267
268#endif
269
270static int setup_cancel(struct iio_network_io_context *io_ctx)
271{
272 int ret;
273
274 ret = set_blocking_mode(io_ctx->fd, false);
275 if (ret)
276 return ret;
277
278 return create_cancel_fd(io_ctx);
279}
280
281static void do_cancel(struct iio_network_io_context *io_ctx)
282{
283 uint64_t event = 1;
284 int ret;
285
286 ret = write(io_ctx->cancel_fd[CANCEL_WR_FD], &event, sizeof(event));
287 if (ret == -1) {
288 /* If this happens something went very seriously wrong */
289 char err_str[1024];
290 iio_strerror(errno, err_str, sizeof(err_str));
291 ERROR("Unable to signal cancellation event: %s\n", err_str);
292 }
293}
294
295static int wait_cancellable(struct iio_network_io_context *io_ctx, bool read)
296{
297 struct pollfd pfd[2];
298 int ret;
299
300 if (!io_ctx->cancellable)
301 return 0;
302
303 memset(pfd, 0, sizeof(pfd));
304
305 pfd[0].fd = io_ctx->fd;
306 if (read)
307 pfd[0].events = POLLIN;
308 else
309 pfd[0].events = POLLOUT;
310 pfd[1].fd = io_ctx->cancel_fd[0];
311 pfd[1].events = POLLIN;
312
313 do {
Paul Cercueil6a0eb582016-08-30 10:54:22 +0200314 int timeout_ms;
315
316 if (io_ctx->timeout_ms > 0)
317 timeout_ms = (int) io_ctx->timeout_ms;
318 else
319 timeout_ms = -1;
320
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200321 do {
Paul Cercueil6a0eb582016-08-30 10:54:22 +0200322 ret = poll(pfd, 2, timeout_ms);
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200323 } while (ret == -1 && errno == EINTR);
324
325 if (ret == -1)
326 return -errno;
Paul Cercueil6a0eb582016-08-30 10:54:22 +0200327 if (!ret)
Paul Cercueile8e7aca2016-08-31 16:15:13 +0200328 return -EPIPE;
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200329
330 if (pfd[1].revents & POLLIN)
331 return -EBADF;
332 } while (!(pfd[0].revents & (pfd[0].events | POLLERR | POLLHUP)));
333
334 return 0;
335}
336
Lars-Peter Clausendd04e6a2016-02-10 14:56:36 +0100337static int network_get_error(void)
338{
339 return -errno;
340}
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200341
342static bool network_should_retry(int err)
343{
Paul Cercueilb419f1e2016-08-31 16:59:57 +0200344 return err == -EAGAIN;
345}
346
347static bool network_is_interrupted(int err)
348{
349 return err == -EINTR;
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200350}
351
Lars-Peter Clausenac256dd2017-03-07 13:06:15 +0100352static bool network_connect_in_progress(int err)
353{
354 return err == -EINPROGRESS;
355}
356
357#define NETWORK_ERR_TIMEOUT ETIMEDOUT
358
Lars-Peter Clausendd04e6a2016-02-10 14:56:36 +0100359#endif
360
Paul Cercueilab114932014-05-19 13:03:17 +0200361#ifdef HAVE_AVAHI
362struct avahi_discovery_data {
363 AvahiSimplePoll *poll;
364 AvahiAddress *address;
365 uint16_t *port;
366 bool found, resolved;
367};
368
369static void __avahi_resolver_cb(AvahiServiceResolver *resolver,
370 __notused AvahiIfIndex iface, __notused AvahiProtocol proto,
371 __notused AvahiResolverEvent event, __notused const char *name,
372 __notused const char *type, __notused const char *domain,
373 __notused const char *host_name, const AvahiAddress *address,
374 uint16_t port, __notused AvahiStringList *txt,
375 __notused AvahiLookupResultFlags flags, void *d)
376{
377 struct avahi_discovery_data *ddata = (struct avahi_discovery_data *) d;
378
379 memcpy(ddata->address, address, sizeof(*address));
380 *ddata->port = port;
381 ddata->resolved = true;
382 avahi_service_resolver_free(resolver);
383}
384
385static void __avahi_browser_cb(AvahiServiceBrowser *browser,
386 AvahiIfIndex iface, AvahiProtocol proto,
387 AvahiBrowserEvent event, const char *name,
388 const char *type, const char *domain,
389 __notused AvahiLookupResultFlags flags, void *d)
390{
391 struct avahi_discovery_data *ddata = (struct avahi_discovery_data *) d;
392 struct AvahiClient *client = avahi_service_browser_get_client(browser);
393
394 switch (event) {
395 default:
396 case AVAHI_BROWSER_NEW:
397 ddata->found = !!avahi_service_resolver_new(client, iface,
398 proto, name, type, domain,
399 AVAHI_PROTO_UNSPEC, 0,
400 __avahi_resolver_cb, d);
401 break;
402 case AVAHI_BROWSER_ALL_FOR_NOW:
403 if (ddata->found) {
404 while (!ddata->resolved) {
405 struct timespec ts;
406 ts.tv_sec = 0;
407 ts.tv_nsec = 4000000;
408 nanosleep(&ts, NULL);
409 }
410 }
Lars-Peter Clausen4d847cb2017-12-18 10:39:13 +0100411 /* fall-through */
412 case AVAHI_BROWSER_FAILURE:
Paul Cercueilab114932014-05-19 13:03:17 +0200413 avahi_simple_poll_quit(ddata->poll);
Lars-Peter Clausen4d847cb2017-12-18 10:39:13 +0100414 /* fall-through */
415 case AVAHI_BROWSER_CACHE_EXHAUSTED:
Paul Cercueilab114932014-05-19 13:03:17 +0200416 break;
417 }
418}
419
420static int discover_host(AvahiAddress *addr, uint16_t *port)
421{
422 struct avahi_discovery_data ddata;
423 int ret = 0;
424 AvahiClient *client;
425 AvahiServiceBrowser *browser;
426 AvahiSimplePoll *poll = avahi_simple_poll_new();
427 if (!poll)
428 return -ENOMEM;
429
430 client = avahi_client_new(avahi_simple_poll_get(poll),
431 0, NULL, NULL, &ret);
432 if (!client) {
433 ERROR("Unable to start ZeroConf client :%s\n",
434 avahi_strerror(ret));
435 goto err_free_poll;
436 }
437
438 memset(&ddata, 0, sizeof(ddata));
439 ddata.poll = poll;
440 ddata.address = addr;
441 ddata.port = port;
442
443 browser = avahi_service_browser_new(client,
444 AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
445 "_iio._tcp", NULL, 0, __avahi_browser_cb, &ddata);
446 if (!browser) {
447 ret = avahi_client_errno(client);
448 ERROR("Unable to create ZeroConf browser: %s\n",
449 avahi_strerror(ret));
450 goto err_free_client;
451 }
452
453 DEBUG("Trying to discover host\n");
454 avahi_simple_poll_loop(poll);
455
456 if (!ddata.found)
457 ret = ENXIO;
458
459 avahi_service_browser_free(browser);
460err_free_client:
461 avahi_client_free(client);
462err_free_poll:
463 avahi_simple_poll_free(poll);
464 return -ret; /* we want a negative error code */
465}
466#endif /* HAVE_AVAHI */
467
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200468static ssize_t network_recv(struct iio_network_io_context *io_ctx,
469 void *data, size_t len, int flags)
Lars-Peter Clausen6a6c8662016-02-12 15:35:52 +0100470{
471 ssize_t ret;
472 int err;
473
474 while (1) {
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200475 ret = wait_cancellable(io_ctx, true);
476 if (ret < 0)
477 return ret;
478
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200479 ret = recv(io_ctx->fd, data, (int) len, flags);
Lars-Peter Clausen6a6c8662016-02-12 15:35:52 +0100480 if (ret == 0)
481 return -EPIPE;
482 else if (ret > 0)
483 break;
484
485 err = network_get_error();
Paul Cercueilb419f1e2016-08-31 16:59:57 +0200486 if (network_should_retry(err)) {
487 if (io_ctx->cancellable)
488 continue;
489 else
490 return -EPIPE;
491 } else if (!network_is_interrupted(err)) {
Lars-Peter Clausen6a6c8662016-02-12 15:35:52 +0100492 return (ssize_t) err;
Paul Cercueilb419f1e2016-08-31 16:59:57 +0200493 }
Lars-Peter Clausen6a6c8662016-02-12 15:35:52 +0100494 }
495 return ret;
496}
497
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200498static ssize_t network_send(struct iio_network_io_context *io_ctx,
499 const void *data, size_t len, int flags)
Lars-Peter Clausen6a6c8662016-02-12 15:35:52 +0100500{
501 ssize_t ret;
502 int err;
503
504 while (1) {
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200505 ret = wait_cancellable(io_ctx, false);
506 if (ret < 0)
507 return ret;
508
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200509 ret = send(io_ctx->fd, data, (int) len, flags);
Lars-Peter Clausen6a6c8662016-02-12 15:35:52 +0100510 if (ret == 0)
511 return -EPIPE;
512 else if (ret > 0)
513 break;
514
515 err = network_get_error();
Paul Cercueilb419f1e2016-08-31 16:59:57 +0200516 if (network_should_retry(err)) {
517 if (io_ctx->cancellable)
518 continue;
519 else
520 return -EPIPE;
521 } else if (!network_is_interrupted(err)) {
Lars-Peter Clausen6a6c8662016-02-12 15:35:52 +0100522 return (ssize_t) err;
Paul Cercueilb419f1e2016-08-31 16:59:57 +0200523 }
Lars-Peter Clausen6a6c8662016-02-12 15:35:52 +0100524 }
525
526 return ret;
527}
528
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200529static ssize_t write_all(struct iio_network_io_context *io_ctx,
530 const void *src, size_t len)
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100531{
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200532 uintptr_t ptr = (uintptr_t) src;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100533 while (len) {
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200534 ssize_t ret = network_send(io_ctx, (const void *) ptr, len, 0);
Lars-Peter Clausen27a53e42016-04-13 17:08:07 +0200535 if (ret < 0)
536 return ret;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100537 ptr += ret;
538 len -= ret;
539 }
Paul Cercueil4012cff2015-05-11 10:47:40 +0200540 return (ssize_t)(ptr - (uintptr_t) src);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100541}
542
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200543static ssize_t write_command(struct iio_network_io_context *io_ctx,
544 const char *cmd)
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100545{
546 ssize_t ret;
547
548 DEBUG("Writing command: %s\n", cmd);
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200549 ret = write_all(io_ctx, cmd, strlen(cmd));
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100550 if (ret < 0) {
551 char buf[1024];
Paul Cercueil53fc4852015-05-22 10:57:53 +0200552 iio_strerror(-ret, buf, sizeof(buf));
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100553 ERROR("Unable to send command: %s\n", buf);
554 }
555 return ret;
556}
557
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200558static void network_cancel(const struct iio_device *dev)
559{
560 struct iio_device_pdata *ppdata = dev->pdata;
561
562 do_cancel(&ppdata->io_ctx);
563
564 ppdata->io_ctx.cancelled = true;
565}
566
Paul Cercueil4970ac32015-02-24 10:59:00 +0100567#ifndef _WIN32
Lars-Peter Clausena2cbc812016-02-11 14:49:27 +0100568
569/* Use it if available */
Paul Cercueild454e012016-06-28 15:19:19 +0200570#ifndef SOCK_CLOEXEC
571#define SOCK_CLOEXEC 0
Lars-Peter Clausena2cbc812016-02-11 14:49:27 +0100572#endif
573
Lars-Peter Clausenac256dd2017-03-07 13:06:15 +0100574static int do_create_socket(const struct addrinfo *addrinfo)
Paul Cercueil4970ac32015-02-24 10:59:00 +0100575{
Lars-Peter Clausen1ca01b72016-02-10 15:10:09 +0100576 int fd;
577
Lars-Peter Clausena2cbc812016-02-11 14:49:27 +0100578 fd = socket(addrinfo->ai_family, addrinfo->ai_socktype | SOCK_CLOEXEC, 0);
Lars-Peter Clausen1ca01b72016-02-10 15:10:09 +0100579 if (fd < 0)
580 return -errno;
Paul Cercueil4970ac32015-02-24 10:59:00 +0100581
Lars-Peter Clausenebbd9072016-02-11 15:15:08 +0100582 return fd;
Paul Cercueil4970ac32015-02-24 10:59:00 +0100583}
584
585static int set_socket_timeout(int fd, unsigned int timeout)
586{
587 struct timeval tv;
588
589 tv.tv_sec = timeout / 1000;
590 tv.tv_usec = (timeout % 1000) * 1000;
591 if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0 ||
592 setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO,
593 &tv, sizeof(tv)) < 0)
594 return -errno;
595 else
596 return 0;
597}
598#else
Lars-Peter Clausen1ca01b72016-02-10 15:10:09 +0100599
Lars-Peter Clausena2cbc812016-02-11 14:49:27 +0100600/* Use it if available */
601#ifndef WSA_FLAG_NO_HANDLE_INHERIT
602#define WSA_FLAG_NO_HANDLE_INHERIT 0
603#endif
604
Lars-Peter Clausenac256dd2017-03-07 13:06:15 +0100605static int do_create_socket(const struct addrinfo *addrinfo)
Lars-Peter Clausen1ca01b72016-02-10 15:10:09 +0100606{
Lars-Peter Clausen1ca01b72016-02-10 15:10:09 +0100607 SOCKET s;
608
Paul Cercueilba16cea2016-04-18 12:14:58 +0200609 s = WSASocketW(addrinfo->ai_family, addrinfo->ai_socktype, 0, NULL, 0,
Paul Cercueil9dc0a622016-09-01 12:28:30 +0200610 WSA_FLAG_NO_HANDLE_INHERIT | WSA_FLAG_OVERLAPPED);
Lars-Peter Clausen1ca01b72016-02-10 15:10:09 +0100611 if (s == INVALID_SOCKET)
612 return -WSAGetLastError();
613
Lars-Peter Clausen1ca01b72016-02-10 15:10:09 +0100614 return (int) s;
615}
616
Paul Cercueil4970ac32015-02-24 10:59:00 +0100617static int set_socket_timeout(int fd, unsigned int timeout)
618{
619 if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO,
620 (const char *) &timeout, sizeof(timeout)) < 0 ||
621 setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO,
622 (const char *) &timeout, sizeof(timeout)) < 0)
Paul Cercueil135b3612015-06-30 14:10:14 +0200623 return -WSAGetLastError();
Paul Cercueil4970ac32015-02-24 10:59:00 +0100624 else
625 return 0;
626}
627#endif /* !_WIN32 */
628
Lars-Peter Clausenac256dd2017-03-07 13:06:15 +0100629/* The purpose of this function is to provide a version of connect()
630 * that does not ignore timeouts... */
631static int do_connect(int fd, const struct addrinfo *addrinfo,
632 unsigned int timeout)
Paul Cercueil4970ac32015-02-24 10:59:00 +0100633{
Lars-Peter Clausenac256dd2017-03-07 13:06:15 +0100634 int ret, error;
635 socklen_t len;
Lars-Peter Clausen14a1f642018-01-23 18:15:45 +0100636#ifdef _WIN32
637 struct timeval tv;
638 struct timeval *ptv;
Lars-Peter Clausenac256dd2017-03-07 13:06:15 +0100639 fd_set set;
Lars-Peter Clausen14a1f642018-01-23 18:15:45 +0100640#else
641 struct pollfd pfd;
642#endif
Lars-Peter Clausenac256dd2017-03-07 13:06:15 +0100643
644 ret = set_blocking_mode(fd, false);
645 if (ret < 0)
646 return ret;
647
648 ret = connect(fd, addrinfo->ai_addr, (int) addrinfo->ai_addrlen);
649 if (ret < 0) {
650 ret = network_get_error();
651 if (!network_connect_in_progress(ret))
652 return ret;
653 }
654
Lars-Peter Clausen14a1f642018-01-23 18:15:45 +0100655#ifdef _WIN32
Lars-Peter Clausenac256dd2017-03-07 13:06:15 +0100656 FD_ZERO(&set);
657 FD_SET(fd, &set);
Paul Cercueil4970ac32015-02-24 10:59:00 +0100658
Lars-Peter Clausen828b5482017-03-07 13:50:53 +0100659 if (timeout != 0) {
660 tv.tv_sec = timeout / 1000;
661 tv.tv_usec = (timeout % 1000) * 1000;
662 ptv = &tv;
663 } else {
664 ptv = NULL;
665 }
Paul Cercueil4970ac32015-02-24 10:59:00 +0100666
Lars-Peter Clausenac256dd2017-03-07 13:06:15 +0100667 ret = select(fd + 1, NULL, &set, &set, ptv);
Lars-Peter Clausen14a1f642018-01-23 18:15:45 +0100668#else
669 pfd.fd = fd;
670 pfd.events = POLLOUT | POLLERR;
671 pfd.revents = 0;
672
673 do {
674 ret = poll(&pfd, 1, timeout);
675 } while (ret == -1 && errno == EINTR);
676#endif
677
Lars-Peter Clausenac256dd2017-03-07 13:06:15 +0100678 if (ret < 0)
679 return network_get_error();
680
681 if (ret == 0)
682 return -NETWORK_ERR_TIMEOUT;
683
684 /* Verify that we don't have an error */
685 len = sizeof(error);
686 ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, (char *)&error, &len);
687 if(ret < 0)
688 return network_get_error();
689
690 if (error)
691 return -error;
692
693 ret = set_blocking_mode(fd, true);
694 if (ret < 0)
695 return ret;
696
697 return 0;
698}
699
700static int create_socket(const struct addrinfo *addrinfo, unsigned int timeout)
701{
702 int ret, fd, yes = 1;
703
704 fd = do_create_socket(addrinfo);
Lars-Peter Clausen1ca01b72016-02-10 15:10:09 +0100705 if (fd < 0)
706 return fd;
Paul Cercueil4970ac32015-02-24 10:59:00 +0100707
Lars-Peter Clausenac256dd2017-03-07 13:06:15 +0100708 ret = do_connect(fd, addrinfo, timeout);
709 if (ret < 0) {
710 close(fd);
711 return ret;
712 }
713
Lars-Peter Clausen6f127f02017-03-09 15:20:04 +0100714 set_socket_timeout(fd, timeout);
Paul Cercueil32dce822016-12-12 14:51:59 +0100715 if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
Paul Cercueilaf3370e2017-02-01 12:14:12 +0100716 (const char *) &yes, sizeof(yes)) < 0) {
717 ret = -errno;
718 close(fd);
719 return ret;
720 }
Paul Cercueil32dce822016-12-12 14:51:59 +0100721
Paul Cercueil4970ac32015-02-24 10:59:00 +0100722 return fd;
723}
724
Paul Cercueil92f15c22015-04-20 11:36:51 +0200725static int network_open(const struct iio_device *dev,
726 size_t samples_count, bool cyclic)
Paul Cercueilba059762014-03-14 11:02:02 +0100727{
Paul Cercueil439e1a22015-02-24 13:50:51 +0100728 struct iio_context_pdata *pdata = dev->ctx->pdata;
Paul Cercueil80dc1082015-12-01 18:20:31 +0100729 struct iio_device_pdata *ppdata = dev->pdata;
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200730 int ret = -EBUSY;
Paul Cercueilba059762014-03-14 11:02:02 +0100731
Paul Cercueil80dc1082015-12-01 18:20:31 +0100732 iio_mutex_lock(ppdata->lock);
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200733 if (ppdata->io_ctx.fd >= 0)
Paul Cercueil80dc1082015-12-01 18:20:31 +0100734 goto out_mutex_unlock;
Paul Cercueil439e1a22015-02-24 13:50:51 +0100735
Lars-Peter Clausen6f127f02017-03-09 15:20:04 +0100736 ret = create_socket(pdata->addrinfo, DEFAULT_TIMEOUT_MS);
Paul Cercueil80dc1082015-12-01 18:20:31 +0100737 if (ret < 0)
738 goto out_mutex_unlock;
Paul Cercueilba059762014-03-14 11:02:02 +0100739
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200740 ppdata->io_ctx.fd = ret;
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200741 ppdata->io_ctx.cancelled = false;
Lars-Peter Clausen6f127f02017-03-09 15:20:04 +0100742 ppdata->io_ctx.timeout_ms = DEFAULT_TIMEOUT_MS;
743
744 ret = iiod_client_open_unlocked(pdata->iiod_client,
745 &ppdata->io_ctx, dev, samples_count, cyclic);
746 if (ret < 0)
747 goto err_close_socket;
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200748
749 ret = setup_cancel(&ppdata->io_ctx);
750 if (ret < 0)
751 goto err_close_socket;
Paul Cercueilba059762014-03-14 11:02:02 +0100752
Lars-Peter Clausen6f127f02017-03-09 15:20:04 +0100753 set_socket_timeout(ppdata->io_ctx.fd, pdata->io_ctx.timeout_ms);
Paul Cercueil439e1a22015-02-24 13:50:51 +0100754
Lars-Peter Clausen6f127f02017-03-09 15:20:04 +0100755 ppdata->io_ctx.timeout_ms = pdata->io_ctx.timeout_ms;
756 ppdata->io_ctx.cancellable = true;
Paul Cercueil80dc1082015-12-01 18:20:31 +0100757 ppdata->is_tx = iio_device_is_tx(dev);
758 ppdata->is_cyclic = cyclic;
Paul Cercueil80dc1082015-12-01 18:20:31 +0100759 ppdata->wait_for_err_code = false;
Paul Cercueild957b982015-08-05 14:39:01 +0200760#ifdef WITH_NETWORK_GET_BUFFER
Paul Cercueil80dc1082015-12-01 18:20:31 +0100761 ppdata->mmap_len = samples_count * iio_device_get_sample_size(dev);
Paul Cercueild957b982015-08-05 14:39:01 +0200762#endif
Paul Cercueil80dc1082015-12-01 18:20:31 +0100763
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200764 iio_mutex_unlock(ppdata->lock);
765
766 return 0;
767
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200768err_close_socket:
769 close(ppdata->io_ctx.fd);
770 ppdata->io_ctx.fd = -1;
Paul Cercueil80dc1082015-12-01 18:20:31 +0100771out_mutex_unlock:
772 iio_mutex_unlock(ppdata->lock);
773 return ret;
Paul Cercueilba059762014-03-14 11:02:02 +0100774}
775
Lars-Peter Clausen90e75a92016-02-22 11:34:34 +0100776static int network_close(const struct iio_device *dev)
777{
778 struct iio_device_pdata *pdata = dev->pdata;
779 int ret = -EBADF;
780
781 iio_mutex_lock(pdata->lock);
782
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200783 if (pdata->io_ctx.fd >= 0) {
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200784 if (!pdata->io_ctx.cancelled) {
785 ret = iiod_client_close_unlocked(
786 dev->ctx->pdata->iiod_client,
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +0200787 &pdata->io_ctx, dev);
Lars-Peter Clausen90e75a92016-02-22 11:34:34 +0100788
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200789 write_command(&pdata->io_ctx, "\r\nEXIT\r\n");
790 } else {
791 ret = 0;
792 }
Lars-Peter Clausen90e75a92016-02-22 11:34:34 +0100793
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200794 cleanup_cancel(&pdata->io_ctx);
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200795 close(pdata->io_ctx.fd);
796 pdata->io_ctx.fd = -1;
Lars-Peter Clausen90e75a92016-02-22 11:34:34 +0100797 }
798
799#ifdef WITH_NETWORK_GET_BUFFER
800 if (pdata->memfd >= 0)
801 close(pdata->memfd);
802 pdata->memfd = -1;
803
804 if (pdata->mmap_addr) {
805 munmap(pdata->mmap_addr, pdata->mmap_len);
806 pdata->mmap_addr = NULL;
807 }
808#endif
809
810 iio_mutex_unlock(pdata->lock);
811 return ret;
812}
813
814static ssize_t network_read(const struct iio_device *dev, void *dst, size_t len,
815 uint32_t *mask, size_t words)
816{
817 struct iio_device_pdata *pdata = dev->pdata;
818 ssize_t ret;
819
820 iio_mutex_lock(pdata->lock);
821 ret = iiod_client_read_unlocked(dev->ctx->pdata->iiod_client,
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +0200822 &pdata->io_ctx, dev, dst, len, mask, words);
Lars-Peter Clausen90e75a92016-02-22 11:34:34 +0100823 iio_mutex_unlock(pdata->lock);
824
825 return ret;
826}
827
828static ssize_t network_write(const struct iio_device *dev,
829 const void *src, size_t len)
830{
831 struct iio_device_pdata *pdata = dev->pdata;
832 ssize_t ret;
833
834 iio_mutex_lock(pdata->lock);
835 ret = iiod_client_write_unlocked(dev->ctx->pdata->iiod_client,
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +0200836 &pdata->io_ctx, dev, src, len);
Lars-Peter Clausen90e75a92016-02-22 11:34:34 +0100837 iio_mutex_unlock(pdata->lock);
838
839 return ret;
840}
841
842#ifdef WITH_NETWORK_GET_BUFFER
843
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200844static ssize_t read_all(struct iio_network_io_context *io_ctx,
845 void *dst, size_t len)
Lars-Peter Clausen90e75a92016-02-22 11:34:34 +0100846{
847 uintptr_t ptr = (uintptr_t) dst;
848 while (len) {
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200849 ssize_t ret = network_recv(io_ctx, (void *) ptr, len, 0);
Lars-Peter Clausen90e75a92016-02-22 11:34:34 +0100850 if (ret < 0)
851 return ret;
852 ptr += ret;
853 len -= ret;
854 }
855 return (ssize_t)(ptr - (uintptr_t) dst);
856}
857
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200858static int read_integer(struct iio_network_io_context *io_ctx, long *val)
Lars-Peter Clausen90e75a92016-02-22 11:34:34 +0100859{
860 unsigned int i;
861 char buf[1024], *ptr;
862 ssize_t ret;
863 bool found = false;
864
865 for (i = 0; i < sizeof(buf) - 1; i++) {
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200866 ret = read_all(io_ctx, buf + i, 1);
Lars-Peter Clausen90e75a92016-02-22 11:34:34 +0100867 if (ret < 0)
868 return (int) ret;
869
870 /* Skip the eventual first few carriage returns.
871 * Also stop when a dot is found (for parsing floats) */
872 if (buf[i] != '\n' && buf[i] != '.')
873 found = true;
874 else if (found)
875 break;
876 }
877
878 buf[i] = '\0';
879 ret = (ssize_t) strtol(buf, &ptr, 10);
880 if (ptr == buf)
881 return -EINVAL;
882 *val = (long) ret;
883 return 0;
884}
885
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200886static ssize_t network_read_mask(struct iio_network_io_context *io_ctx,
887 uint32_t *mask, size_t words)
Lars-Peter Clausen90e75a92016-02-22 11:34:34 +0100888{
889 long read_len;
890 ssize_t ret;
891
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200892 ret = read_integer(io_ctx, &read_len);
Lars-Peter Clausen90e75a92016-02-22 11:34:34 +0100893 if (ret < 0)
894 return ret;
895
896 if (read_len > 0 && mask) {
897 size_t i;
898 char buf[9];
899
900 buf[8] = '\0';
901 DEBUG("Reading mask\n");
902
903 for (i = words; i > 0; i--) {
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200904 ret = read_all(io_ctx, buf, 8);
Lars-Peter Clausen90e75a92016-02-22 11:34:34 +0100905 if (ret < 0)
906 return ret;
907
908 sscanf(buf, "%08x", &mask[i - 1]);
Paul Cercueilb133a0c2016-04-18 11:57:50 +0200909 DEBUG("mask[%lu] = 0x%x\n",
910 (unsigned long)(i - 1), mask[i - 1]);
Lars-Peter Clausen90e75a92016-02-22 11:34:34 +0100911 }
912 }
913
914 if (read_len > 0) {
915 char c;
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200916 ssize_t nb = read_all(io_ctx, &c, 1);
Lars-Peter Clausen90e75a92016-02-22 11:34:34 +0100917 if (nb > 0 && c != '\n')
918 read_len = -EIO;
919 }
920
921 return (ssize_t) read_len;
922}
923
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200924static ssize_t read_error_code(struct iio_network_io_context *io_ctx)
Paul Cercueil8f7f6c42015-02-24 15:00:35 +0100925{
926 /*
927 * The server returns two integer codes.
928 * The first one is returned right after the WRITEBUF command is issued,
929 * and corresponds to the error code returned when the server attempted
930 * to open the device.
931 * If zero, a second error code is returned, that corresponds (if positive)
932 * to the number of bytes written.
933 *
934 * To speed up things, we delay error reporting. We just send out the
935 * data without reading the error code that the server gives us, because
936 * the answer will take too much time. If an error occured, it will be
937 * reported by the next call to iio_buffer_push().
938 */
939
940 unsigned int i;
941 long resp = 0;
942
943 for (i = 0; i < 2; i++) {
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200944 ssize_t ret = read_integer(io_ctx, &resp);
Paul Cercueil8f7f6c42015-02-24 15:00:35 +0100945 if (ret < 0)
946 return ret;
947 if (resp < 0)
948 return (ssize_t) resp;
949 }
950
Paul Cercueil7d7e5d32015-03-05 10:51:41 +0100951 return (ssize_t) resp;
Paul Cercueil8f7f6c42015-02-24 15:00:35 +0100952}
953
Paul Cercueil3c0da372015-03-05 11:36:39 +0100954static ssize_t write_rwbuf_command(const struct iio_device *dev,
Lars-Peter Clausen2e380822016-02-11 20:36:13 +0100955 const char *cmd)
Paul Cercueil3c0da372015-03-05 11:36:39 +0100956{
957 struct iio_device_pdata *pdata = dev->pdata;
Paul Cercueil3c0da372015-03-05 11:36:39 +0100958
959 if (pdata->wait_for_err_code) {
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200960 ssize_t ret = read_error_code(&pdata->io_ctx);
Paul Cercueil3c0da372015-03-05 11:36:39 +0100961
962 pdata->wait_for_err_code = false;
963 if (ret < 0)
964 return ret;
965 }
966
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200967 return write_command(&pdata->io_ctx, cmd);
Paul Cercueil3c0da372015-03-05 11:36:39 +0100968}
969
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200970static ssize_t network_do_splice(struct iio_device_pdata *pdata, size_t len,
971 bool read)
Paul Cercueil09a43482015-03-04 15:50:27 +0100972{
973 int pipefd[2];
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200974 int fd_in, fd_out;
Lars-Peter Clausenf83877e2016-10-26 18:20:06 +0200975 ssize_t ret, read_len = len, write_len = 0;
Paul Cercueil09a43482015-03-04 15:50:27 +0100976
Lars-Peter Clausena2cbc812016-02-11 14:49:27 +0100977 ret = (ssize_t) pipe2(pipefd, O_CLOEXEC);
Paul Cercueil09a43482015-03-04 15:50:27 +0100978 if (ret < 0)
979 return -errno;
980
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200981 if (read) {
982 fd_in = pdata->io_ctx.fd;
983 fd_out = pdata->memfd;
984 } else {
985 fd_in = pdata->memfd;
986 fd_out = pdata->io_ctx.fd;
987 }
988
Paul Cercueil09a43482015-03-04 15:50:27 +0100989 do {
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200990 ret = wait_cancellable(&pdata->io_ctx, read);
991 if (ret < 0)
992 goto err_close_pipe;
993
Lars-Peter Clausenf83877e2016-10-26 18:20:06 +0200994 if (read_len) {
995 /*
996 * SPLICE_F_NONBLOCK is just here to avoid a deadlock when
997 * splicing from a socket. As the socket is not in
998 * non-blocking mode, it should never return -EAGAIN.
999 * TODO(pcercuei): Find why it locks...
1000 * */
1001 ret = splice(fd_in, NULL, pipefd[1], NULL, read_len,
1002 SPLICE_F_MOVE | SPLICE_F_NONBLOCK);
1003 if (!ret)
1004 ret = -EIO;
1005 if (ret < 0 && errno != EAGAIN) {
1006 ret = -errno;
1007 goto err_close_pipe;
1008 } else if (ret > 0) {
1009 write_len += ret;
1010 read_len -= ret;
1011 }
Lars-Peter Clausen7247b922016-10-26 18:34:23 +02001012 }
Paul Cercueil09a43482015-03-04 15:50:27 +01001013
Lars-Peter Clausenf83877e2016-10-26 18:20:06 +02001014 if (write_len) {
1015 ret = splice(pipefd[0], NULL, fd_out, NULL, write_len,
1016 SPLICE_F_MOVE | SPLICE_F_NONBLOCK);
1017 if (!ret)
1018 ret = -EIO;
1019 if (ret < 0 && errno != EAGAIN) {
1020 ret = -errno;
1021 goto err_close_pipe;
1022 } else if (ret > 0) {
1023 write_len -= ret;
1024 }
Lars-Peter Clausen7247b922016-10-26 18:34:23 +02001025 }
Paul Cercueil09a43482015-03-04 15:50:27 +01001026
Lars-Peter Clausenf83877e2016-10-26 18:20:06 +02001027 } while (write_len || read_len);
Paul Cercueil09a43482015-03-04 15:50:27 +01001028
1029err_close_pipe:
1030 close(pipefd[0]);
1031 close(pipefd[1]);
Lars-Peter Clausenf83877e2016-10-26 18:20:06 +02001032 return ret < 0 ? ret : len;
Paul Cercueil09a43482015-03-04 15:50:27 +01001033}
1034
1035static ssize_t network_get_buffer(const struct iio_device *dev,
Paul Cercueil76ca8842015-03-05 11:16:16 +01001036 void **addr_ptr, size_t bytes_used,
1037 uint32_t *mask, size_t words)
Paul Cercueil09a43482015-03-04 15:50:27 +01001038{
1039 struct iio_device_pdata *pdata = dev->pdata;
Paul Cercueil04065c22015-03-05 14:08:16 +01001040 ssize_t ret, read = 0;
Paul Cercueilca9d3382015-05-04 14:30:09 +02001041 int memfd;
Paul Cercueil09a43482015-03-04 15:50:27 +01001042
Paul Cercueil04065c22015-03-05 14:08:16 +01001043 if (pdata->is_cyclic)
Paul Cercueil09a43482015-03-04 15:50:27 +01001044 return -ENOSYS;
Paul Cercueilca9d3382015-05-04 14:30:09 +02001045
1046 /* We check early that the temporary file can be created, so that we can
1047 * return -ENOSYS in case it fails, which will indicate that the
1048 * high-speed interface is not available.
1049 *
1050 * O_TMPFILE -> Linux 3.11.
1051 * TODO: use memfd_create (Linux 3.17) */
Lars-Peter Clausena2cbc812016-02-11 14:49:27 +01001052 memfd = open(P_tmpdir, O_RDWR | O_TMPFILE | O_EXCL | O_CLOEXEC, S_IRWXU);
Paul Cercueilca9d3382015-05-04 14:30:09 +02001053 if (memfd < 0)
1054 return -ENOSYS;
1055
1056 if (!addr_ptr || words != (dev->nb_channels + 31) / 32) {
1057 close(memfd);
Paul Cercueil09a43482015-03-04 15:50:27 +01001058 return -EINVAL;
Paul Cercueilca9d3382015-05-04 14:30:09 +02001059 }
Paul Cercueil09a43482015-03-04 15:50:27 +01001060
Paul Cercueile6e5a092015-03-04 16:33:26 +01001061 if (pdata->mmap_addr)
1062 munmap(pdata->mmap_addr, pdata->mmap_len);
Paul Cercueil09a43482015-03-04 15:50:27 +01001063
Paul Cercueile6e5a092015-03-04 16:33:26 +01001064 if (pdata->mmap_addr && pdata->is_tx) {
Paul Cercueil09a43482015-03-04 15:50:27 +01001065 char buf[1024];
Paul Cercueil9c9a5562017-01-24 10:48:31 +01001066
1067 iio_snprintf(buf, sizeof(buf), "WRITEBUF %s %lu\r\n",
Paul Cercueild957b982015-08-05 14:39:01 +02001068 dev->id, (unsigned long) bytes_used);
Paul Cercueil09a43482015-03-04 15:50:27 +01001069
Paul Cercueil388dcd62015-11-27 15:15:48 +01001070 iio_mutex_lock(pdata->lock);
Paul Cercueil09a43482015-03-04 15:50:27 +01001071
Lars-Peter Clausen78067fc2016-02-11 12:48:01 +01001072 ret = write_rwbuf_command(dev, buf);
Paul Cercueil09a43482015-03-04 15:50:27 +01001073 if (ret < 0)
Paul Cercueilca9d3382015-05-04 14:30:09 +02001074 goto err_close_memfd;
Paul Cercueil09a43482015-03-04 15:50:27 +01001075
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +02001076 ret = network_do_splice(pdata, bytes_used, false);
Paul Cercueil09a43482015-03-04 15:50:27 +01001077 if (ret < 0)
Paul Cercueilca9d3382015-05-04 14:30:09 +02001078 goto err_close_memfd;
Paul Cercueil09a43482015-03-04 15:50:27 +01001079
1080 pdata->wait_for_err_code = true;
Paul Cercueil388dcd62015-11-27 15:15:48 +01001081 iio_mutex_unlock(pdata->lock);
Paul Cercueil09a43482015-03-04 15:50:27 +01001082 }
1083
1084 if (pdata->memfd >= 0)
1085 close(pdata->memfd);
1086
Paul Cercueilca9d3382015-05-04 14:30:09 +02001087 pdata->memfd = memfd;
Paul Cercueil09a43482015-03-04 15:50:27 +01001088
Paul Cercueilef32d582015-03-05 11:18:35 +01001089 ret = (ssize_t) ftruncate(pdata->memfd, pdata->mmap_len);
1090 if (ret < 0) {
1091 ret = -errno;
1092 ERROR("Unable to truncate temp file: %zi\n", -ret);
1093 return ret;
1094 }
Paul Cercueil09a43482015-03-04 15:50:27 +01001095
Paul Cercueil04065c22015-03-05 14:08:16 +01001096 if (!pdata->is_tx) {
1097 char buf[1024];
1098 size_t len = pdata->mmap_len;
1099
Paul Cercueil9c9a5562017-01-24 10:48:31 +01001100 iio_snprintf(buf, sizeof(buf), "READBUF %s %lu\r\n",
Paul Cercueil04065c22015-03-05 14:08:16 +01001101 dev->id, (unsigned long) len);
1102
Paul Cercueil388dcd62015-11-27 15:15:48 +01001103 iio_mutex_lock(pdata->lock);
Lars-Peter Clausen78067fc2016-02-11 12:48:01 +01001104 ret = write_rwbuf_command(dev, buf);
Paul Cercueil04065c22015-03-05 14:08:16 +01001105 if (ret < 0)
1106 goto err_unlock;
1107
1108 do {
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +02001109 ret = network_read_mask(&pdata->io_ctx, mask, words);
Paul Cercueil04065c22015-03-05 14:08:16 +01001110 if (!ret)
1111 break;
1112 if (ret < 0)
1113 goto err_unlock;
1114
1115 mask = NULL; /* We read the mask only once */
1116
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +02001117 ret = network_do_splice(pdata, ret, true);
Paul Cercueil04065c22015-03-05 14:08:16 +01001118 if (ret < 0)
1119 goto err_unlock;
1120
1121 read += ret;
1122 len -= ret;
1123 } while (len);
1124
Paul Cercueil388dcd62015-11-27 15:15:48 +01001125 iio_mutex_unlock(pdata->lock);
Paul Cercueil04065c22015-03-05 14:08:16 +01001126 }
Paul Cercueil09a43482015-03-04 15:50:27 +01001127
Paul Cercueile6e5a092015-03-04 16:33:26 +01001128 pdata->mmap_addr = mmap(NULL, pdata->mmap_len,
Paul Cercueil09a43482015-03-04 15:50:27 +01001129 PROT_READ | PROT_WRITE, MAP_SHARED, pdata->memfd, 0);
Paul Cercueile6e5a092015-03-04 16:33:26 +01001130 if (pdata->mmap_addr == MAP_FAILED) {
1131 pdata->mmap_addr = NULL;
Paul Cercueil09a43482015-03-04 15:50:27 +01001132 ret = -errno;
Paul Cercueil7d7e5d32015-03-05 10:51:41 +01001133 ERROR("Unable to mmap: %zi\n", -ret);
Paul Cercueil09a43482015-03-04 15:50:27 +01001134 return ret;
1135 }
1136
Paul Cercueile6e5a092015-03-04 16:33:26 +01001137 *addr_ptr = pdata->mmap_addr;
Paul Cercueil7c3f5d22016-02-18 11:49:04 +01001138 return read ? read : (ssize_t) bytes_used;
Paul Cercueil09a43482015-03-04 15:50:27 +01001139
Paul Cercueilca9d3382015-05-04 14:30:09 +02001140err_close_memfd:
1141 close(memfd);
Paul Cercueil09a43482015-03-04 15:50:27 +01001142err_unlock:
Paul Cercueil388dcd62015-11-27 15:15:48 +01001143 iio_mutex_unlock(pdata->lock);
Paul Cercueil09a43482015-03-04 15:50:27 +01001144 return ret;
1145}
1146#endif
1147
Paul Cercueil99cf3d42014-03-06 12:35:26 +01001148static ssize_t network_read_dev_attr(const struct iio_device *dev,
Matt Fornero81f04a52017-11-30 14:36:37 -05001149 const char *attr, char *dst, size_t len, enum iio_attr_type type)
Paul Cercueil99cf3d42014-03-06 12:35:26 +01001150{
Paul Cercueil2e28d502015-11-30 18:46:49 +01001151 struct iio_context_pdata *pdata = dev->ctx->pdata;
Paul Cercueil5b577762014-06-03 15:31:42 +02001152
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +02001153 return iiod_client_read_attr(pdata->iiod_client,
Matt Fornero81f04a52017-11-30 14:36:37 -05001154 &pdata->io_ctx, dev, NULL, attr, dst, len, type);
Paul Cercueil99cf3d42014-03-06 12:35:26 +01001155}
1156
Paul Cercueil07897d32014-03-06 12:46:08 +01001157static ssize_t network_write_dev_attr(const struct iio_device *dev,
Matt Fornero81f04a52017-11-30 14:36:37 -05001158 const char *attr, const char *src, size_t len, enum iio_attr_type type)
Paul Cercueil07897d32014-03-06 12:46:08 +01001159{
Paul Cercueil2e28d502015-11-30 18:46:49 +01001160 struct iio_context_pdata *pdata = dev->ctx->pdata;
Paul Cercueil5b577762014-06-03 15:31:42 +02001161
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +02001162 return iiod_client_write_attr(pdata->iiod_client,
Matt Fornero81f04a52017-11-30 14:36:37 -05001163 &pdata->io_ctx, dev, NULL, attr, src, len, type);
Paul Cercueil07897d32014-03-06 12:46:08 +01001164}
1165
Paul Cercueil99cf3d42014-03-06 12:35:26 +01001166static ssize_t network_read_chn_attr(const struct iio_channel *chn,
1167 const char *attr, char *dst, size_t len)
1168{
Paul Cercueil2e28d502015-11-30 18:46:49 +01001169 struct iio_context_pdata *pdata = chn->dev->ctx->pdata;
Paul Cercueil5b577762014-06-03 15:31:42 +02001170
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +02001171 return iiod_client_read_attr(pdata->iiod_client,
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +02001172 &pdata->io_ctx, chn->dev, chn, attr, dst, len, false);
Paul Cercueil99cf3d42014-03-06 12:35:26 +01001173}
1174
Paul Cercueil07897d32014-03-06 12:46:08 +01001175static ssize_t network_write_chn_attr(const struct iio_channel *chn,
Paul Cercueilcecda352014-05-06 18:14:29 +02001176 const char *attr, const char *src, size_t len)
Paul Cercueil07897d32014-03-06 12:46:08 +01001177{
Paul Cercueil2e28d502015-11-30 18:46:49 +01001178 struct iio_context_pdata *pdata = chn->dev->ctx->pdata;
Paul Cercueil5b577762014-06-03 15:31:42 +02001179
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +02001180 return iiod_client_write_attr(pdata->iiod_client,
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +02001181 &pdata->io_ctx, chn->dev, chn, attr, src, len, false);
Paul Cercueil07897d32014-03-06 12:46:08 +01001182}
1183
Paul Cercueildcab40c2014-03-11 10:59:14 +01001184static int network_get_trigger(const struct iio_device *dev,
1185 const struct iio_device **trigger)
1186{
1187 struct iio_context_pdata *pdata = dev->ctx->pdata;
Paul Cercueildcab40c2014-03-11 10:59:14 +01001188
Paul Cercueilcae6c2a2015-11-30 16:37:19 +01001189 return iiod_client_get_trigger(pdata->iiod_client,
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +02001190 &pdata->io_ctx, dev, trigger);
Paul Cercueildcab40c2014-03-11 10:59:14 +01001191}
1192
1193static int network_set_trigger(const struct iio_device *dev,
1194 const struct iio_device *trigger)
1195{
Paul Cercueila7b2aae2015-12-04 16:02:00 +01001196 struct iio_context_pdata *pdata = dev->ctx->pdata;
Paul Cercueil1494b862014-05-05 12:49:07 +02001197
Paul Cercueilcae6c2a2015-11-30 16:37:19 +01001198 return iiod_client_set_trigger(pdata->iiod_client,
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +02001199 &pdata->io_ctx, dev, trigger);
Paul Cercueildcab40c2014-03-11 10:59:14 +01001200}
1201
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +01001202static void network_shutdown(struct iio_context *ctx)
1203{
1204 struct iio_context_pdata *pdata = ctx->pdata;
Paul Cercueil44ae11c2014-03-17 09:56:29 +01001205 unsigned int i;
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +01001206
Paul Cercueil388dcd62015-11-27 15:15:48 +01001207 iio_mutex_lock(pdata->lock);
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +02001208 write_command(&pdata->io_ctx, "\r\nEXIT\r\n");
1209 close(pdata->io_ctx.fd);
Paul Cercueil388dcd62015-11-27 15:15:48 +01001210 iio_mutex_unlock(pdata->lock);
Paul Cercueil1494b862014-05-05 12:49:07 +02001211
Paul Cercueil439e1a22015-02-24 13:50:51 +01001212 for (i = 0; i < ctx->nb_devices; i++) {
1213 struct iio_device *dev = ctx->devices[i];
Paul Cercueilc5b00752015-02-24 14:29:53 +01001214 struct iio_device_pdata *dpdata = dev->pdata;
Paul Cercueil439e1a22015-02-24 13:50:51 +01001215
Paul Cercueilc5b00752015-02-24 14:29:53 +01001216 if (dpdata) {
Paul Cercueilaa0db142015-03-04 16:25:24 +01001217 network_close(dev);
Paul Cercueil388dcd62015-11-27 15:15:48 +01001218 iio_mutex_destroy(dpdata->lock);
Paul Cercueilc5b00752015-02-24 14:29:53 +01001219 free(dpdata);
Paul Cercueil439e1a22015-02-24 13:50:51 +01001220 }
1221 }
1222
Paul Cercueil157d43c2015-11-30 15:05:06 +01001223 iiod_client_destroy(pdata->iiod_client);
Paul Cercueil388dcd62015-11-27 15:15:48 +01001224 iio_mutex_destroy(pdata->lock);
Paul Cercueil2dd2c132015-02-24 10:41:01 +01001225 freeaddrinfo(pdata->addrinfo);
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +01001226 free(pdata);
1227}
1228
Paul Cercueil6691a3f2014-05-02 12:32:01 +02001229static int network_get_version(const struct iio_context *ctx,
Paul Cercueil9de9e9d2014-05-20 13:18:19 +02001230 unsigned int *major, unsigned int *minor, char git_tag[8])
Paul Cercueil6691a3f2014-05-02 12:32:01 +02001231{
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +02001232 return iiod_client_get_version(ctx->pdata->iiod_client,
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +02001233 &ctx->pdata->io_ctx, major, minor, git_tag);
Paul Cercueil6691a3f2014-05-02 12:32:01 +02001234}
1235
Paul Cercueil8a266f12014-06-10 16:06:31 +02001236static unsigned int calculate_remote_timeout(unsigned int timeout)
1237{
1238 /* XXX(pcercuei): We currently hardcode timeout / 2 for the backend used
1239 * by the remote. Is there something better to do here? */
1240 return timeout / 2;
1241}
1242
Paul Cercueilbca3dbc2014-06-11 12:00:21 +02001243static int network_set_timeout(struct iio_context *ctx, unsigned int timeout)
1244{
Paul Cercueilf996ae12015-12-03 12:29:13 +01001245 struct iio_context_pdata *pdata = ctx->pdata;
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +02001246 int ret, fd = pdata->io_ctx.fd;
Paul Cercueilf996ae12015-12-03 12:29:13 +01001247
1248 ret = set_socket_timeout(fd, timeout);
Paul Cercueilbca3dbc2014-06-11 12:00:21 +02001249 if (!ret) {
Paul Cercueil6a0eb582016-08-30 10:54:22 +02001250 unsigned int remote_timeout = calculate_remote_timeout(timeout);
1251
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +02001252 ret = iiod_client_set_timeout(pdata->iiod_client,
Paul Cercueil6a0eb582016-08-30 10:54:22 +02001253 &pdata->io_ctx, remote_timeout);
1254 if (!ret)
1255 pdata->io_ctx.timeout_ms = timeout;
Paul Cercueilbca3dbc2014-06-11 12:00:21 +02001256 }
1257 if (ret < 0) {
1258 char buf[1024];
Paul Cercueil53fc4852015-05-22 10:57:53 +02001259 iio_strerror(-ret, buf, sizeof(buf));
Paul Cercueil8a266f12014-06-10 16:06:31 +02001260 WARNING("Unable to set R/W timeout: %s\n", buf);
Paul Cercueil8a266f12014-06-10 16:06:31 +02001261 }
1262 return ret;
1263}
1264
Paul Cercueil61157f92015-11-19 17:48:22 +01001265static int network_set_kernel_buffers_count(const struct iio_device *dev,
1266 unsigned int nb_blocks)
1267{
Paul Cercueila9810a82015-11-30 16:55:07 +01001268 struct iio_context_pdata *pdata = dev->ctx->pdata;
Paul Cercueil61157f92015-11-19 17:48:22 +01001269
Paul Cercueila9810a82015-11-30 16:55:07 +01001270 return iiod_client_set_kernel_buffers_count(pdata->iiod_client,
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +02001271 &pdata->io_ctx, dev, nb_blocks);
Paul Cercueil61157f92015-11-19 17:48:22 +01001272}
1273
Paul Cercueil12d41832014-10-28 14:35:53 +01001274static struct iio_context * network_clone(const struct iio_context *ctx)
1275{
Paul Cercueilf2cc5112017-02-08 12:18:22 +01001276 const char *addr = iio_context_get_attr_value(ctx, "ip,ip-addr");
Paul Cercueil7ef45ce2015-03-16 14:36:16 +01001277
Paul Cercueilf2cc5112017-02-08 12:18:22 +01001278 return iio_create_network_context(addr);
Paul Cercueil12d41832014-10-28 14:35:53 +01001279}
1280
Lars-Peter Clausen09a59d72016-02-03 15:27:04 +01001281static const struct iio_backend_ops network_ops = {
Paul Cercueil12d41832014-10-28 14:35:53 +01001282 .clone = network_clone,
Paul Cercueilba059762014-03-14 11:02:02 +01001283 .open = network_open,
1284 .close = network_close,
Paul Cercueil9945bc82014-03-05 14:07:29 +01001285 .read = network_read,
Paul Cercueil2725f702014-05-02 11:02:16 +02001286 .write = network_write,
Paul Cercueil90189672015-03-16 11:41:53 +01001287#ifdef WITH_NETWORK_GET_BUFFER
Paul Cercueil09a43482015-03-04 15:50:27 +01001288 .get_buffer = network_get_buffer,
1289#endif
Paul Cercueil3e94a5b2014-03-04 13:00:41 +01001290 .read_device_attr = network_read_dev_attr,
1291 .write_device_attr = network_write_dev_attr,
Paul Cercueil99cf3d42014-03-06 12:35:26 +01001292 .read_channel_attr = network_read_chn_attr,
Paul Cercueil07897d32014-03-06 12:46:08 +01001293 .write_channel_attr = network_write_chn_attr,
Paul Cercueildcab40c2014-03-11 10:59:14 +01001294 .get_trigger = network_get_trigger,
1295 .set_trigger = network_set_trigger,
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +01001296 .shutdown = network_shutdown,
Paul Cercueil6691a3f2014-05-02 12:32:01 +02001297 .get_version = network_get_version,
Paul Cercueil8a266f12014-06-10 16:06:31 +02001298 .set_timeout = network_set_timeout,
Paul Cercueil61157f92015-11-19 17:48:22 +01001299 .set_kernel_buffers_count = network_set_kernel_buffers_count,
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +02001300
1301 .cancel = network_cancel,
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001302};
1303
Paul Cercueil157d43c2015-11-30 15:05:06 +01001304static ssize_t network_write_data(struct iio_context_pdata *pdata,
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +02001305 void *io_data, const char *src, size_t len)
Paul Cercueil157d43c2015-11-30 15:05:06 +01001306{
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +02001307 struct iio_network_io_context *io_ctx = io_data;
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +02001308
1309 return network_send(io_ctx, src, len, 0);
Paul Cercueil157d43c2015-11-30 15:05:06 +01001310}
1311
1312static ssize_t network_read_data(struct iio_context_pdata *pdata,
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +02001313 void *io_data, char *dst, size_t len)
Paul Cercueil157d43c2015-11-30 15:05:06 +01001314{
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +02001315 struct iio_network_io_context *io_ctx = io_data;
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +02001316
1317 return network_recv(io_ctx, dst, len, 0);
Paul Cercueil157d43c2015-11-30 15:05:06 +01001318}
1319
1320static ssize_t network_read_line(struct iio_context_pdata *pdata,
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +02001321 void *io_data, char *dst, size_t len)
Paul Cercueil157d43c2015-11-30 15:05:06 +01001322{
Paul Cercueil1cb01fe2016-11-16 16:34:00 +01001323 bool found = false;
Paul Cercueil157d43c2015-11-30 15:05:06 +01001324 size_t i;
Paul Cercueilce02dc92016-01-07 11:46:38 +01001325#ifdef __linux__
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +02001326 struct iio_network_io_context *io_ctx = io_data;
Paul Cercueilce02dc92016-01-07 11:46:38 +01001327 ssize_t ret;
Paul Cercueil1cb01fe2016-11-16 16:34:00 +01001328 size_t bytes_read = 0;
Paul Cercueilce02dc92016-01-07 11:46:38 +01001329
Paul Cercueil1cb01fe2016-11-16 16:34:00 +01001330 do {
1331 size_t to_trunc;
Paul Cercueilce02dc92016-01-07 11:46:38 +01001332
Paul Cercueil1cb01fe2016-11-16 16:34:00 +01001333 ret = network_recv(io_ctx, dst, len, MSG_PEEK);
1334 if (ret < 0)
1335 return ret;
Paul Cercueilce02dc92016-01-07 11:46:38 +01001336
Paul Cercueil1cb01fe2016-11-16 16:34:00 +01001337 /* Lookup for the trailing \n */
1338 for (i = 0; i < (size_t) ret && dst[i] != '\n'; i++);
1339 found = i < (size_t) ret;
1340
1341 len -= ret;
1342 dst += ret;
Paul Cercueil1cb01fe2016-11-16 16:34:00 +01001343
1344 if (found)
1345 to_trunc = i + 1;
1346 else
1347 to_trunc = (size_t) ret;
1348
1349 /* Advance the read offset to the byte following the \n if
1350 * found, or after the last charater read otherwise */
1351 ret = network_recv(io_ctx, NULL, to_trunc, MSG_TRUNC);
1352 if (ret < 0)
1353 return ret;
1354
1355 bytes_read += to_trunc;
1356 } while (!found && len);
1357
1358 if (!found)
Paul Cercueilce02dc92016-01-07 11:46:38 +01001359 return -EIO;
Paul Cercueil1cb01fe2016-11-16 16:34:00 +01001360 else
1361 return bytes_read;
Paul Cercueilce02dc92016-01-07 11:46:38 +01001362#else
Paul Cercueil157d43c2015-11-30 15:05:06 +01001363 for (i = 0; i < len - 1; i++) {
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +02001364 ssize_t ret = network_read_data(pdata, io_data, dst + i, 1);
Paul Cercueil157d43c2015-11-30 15:05:06 +01001365
1366 if (ret < 0)
1367 return ret;
1368
1369 if (dst[i] != '\n')
1370 found = true;
1371 else if (found)
1372 break;
1373 }
1374
Paul Cercueil209def82016-04-08 14:47:59 +02001375 if (!found || i == len - 1)
1376 return -EIO;
1377
1378 return (ssize_t) i + 1;
Paul Cercueilce02dc92016-01-07 11:46:38 +01001379#endif
Paul Cercueil157d43c2015-11-30 15:05:06 +01001380}
1381
Lars-Peter Clausen09a59d72016-02-03 15:27:04 +01001382static const struct iiod_client_ops network_iiod_client_ops = {
Paul Cercueil157d43c2015-11-30 15:05:06 +01001383 .write = network_write_data,
1384 .read = network_read_data,
1385 .read_line = network_read_line,
1386};
1387
Paul Cercueil63e52182014-12-11 12:52:48 +01001388struct iio_context * network_create_context(const char *host)
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001389{
Paul Cercueil2e38bbe2014-03-19 15:27:15 +01001390 struct addrinfo hints, *res;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001391 struct iio_context *ctx;
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +01001392 struct iio_context_pdata *pdata;
Paul Cercueil0e3c04d2015-05-13 17:37:11 +02001393 size_t i, len;
Paul Cercueil4970ac32015-02-24 10:59:00 +01001394 int fd, ret;
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001395 char *description;
Paul Cercueil1fef1a52014-04-07 16:31:15 +02001396#ifdef _WIN32
1397 WSADATA wsaData;
1398
1399 ret = WSAStartup(MAKEWORD(2, 0), &wsaData);
1400 if (ret < 0) {
1401 ERROR("WSAStartup failed with error %i\n", ret);
Paul Cercueilcc575532015-03-16 17:15:24 +01001402 errno = -ret;
Paul Cercueil1fef1a52014-04-07 16:31:15 +02001403 return NULL;
1404 }
1405#endif
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001406
Paul Cercueil2e38bbe2014-03-19 15:27:15 +01001407 memset(&hints, 0, sizeof(hints));
1408 hints.ai_family = AF_UNSPEC;
1409 hints.ai_socktype = SOCK_STREAM;
Paul Cercueilab114932014-05-19 13:03:17 +02001410
1411#ifdef HAVE_AVAHI
1412 if (!host) {
1413 char addr_str[AVAHI_ADDRESS_STR_MAX];
1414 char port_str[6];
1415 AvahiAddress address;
Paul Cercueil0f729d32014-06-05 17:38:54 +02001416 uint16_t port = IIOD_PORT;
Paul Cercueilab114932014-05-19 13:03:17 +02001417
1418 memset(&address, 0, sizeof(address));
1419
1420 ret = discover_host(&address, &port);
1421 if (ret < 0) {
Lars-Peter Clausen3417a1a2016-04-18 14:29:02 +02001422 char buf[1024];
1423 iio_strerror(-ret, buf, sizeof(buf));
1424 DEBUG("Unable to find host: %s\n", buf);
Paul Cercueilcc575532015-03-16 17:15:24 +01001425 errno = -ret;
Paul Cercueilab114932014-05-19 13:03:17 +02001426 return NULL;
1427 }
1428
1429 avahi_address_snprint(addr_str, sizeof(addr_str), &address);
Paul Cercueil9c9a5562017-01-24 10:48:31 +01001430 iio_snprintf(port_str, sizeof(port_str), "%hu", port);
Paul Cercueilab114932014-05-19 13:03:17 +02001431 ret = getaddrinfo(addr_str, port_str, &hints, &res);
1432 } else
1433#endif
1434 {
1435 ret = getaddrinfo(host, IIOD_PORT_STR, &hints, &res);
1436 }
1437
Paul Cercueil2e38bbe2014-03-19 15:27:15 +01001438 if (ret) {
Paul Cercueilab114932014-05-19 13:03:17 +02001439 ERROR("Unable to find host: %s\n", gai_strerror(ret));
Paul Cercueild9eb4cb2015-03-23 14:30:20 +01001440#ifndef _WIN32
Paul Cercueilcc575532015-03-16 17:15:24 +01001441 if (ret != EAI_SYSTEM)
Paul Cercueil7cc85112016-11-15 14:59:40 +01001442 errno = -ret;
Paul Cercueild9eb4cb2015-03-23 14:30:20 +01001443#endif
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001444 return NULL;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001445 }
1446
Paul Cercueil6a0eb582016-08-30 10:54:22 +02001447 fd = create_socket(res, DEFAULT_TIMEOUT_MS);
Paul Cercueilcc575532015-03-16 17:15:24 +01001448 if (fd < 0) {
Paul Cercueilc3fe6042016-11-16 17:38:56 +01001449 errno = -fd;
Paul Cercueil2dd2c132015-02-24 10:41:01 +01001450 goto err_free_addrinfo;
Paul Cercueilcc575532015-03-16 17:15:24 +01001451 }
Paul Cercueilbca3dbc2014-06-11 12:00:21 +02001452
Lars-Peter Clausend1be8382016-02-24 11:13:45 +01001453 pdata = zalloc(sizeof(*pdata));
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +01001454 if (!pdata) {
Paul Cercueilcc575532015-03-16 17:15:24 +01001455 errno = ENOMEM;
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +01001456 goto err_close_socket;
1457 }
1458
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +02001459 pdata->io_ctx.fd = fd;
Paul Cercueil2dd2c132015-02-24 10:41:01 +01001460 pdata->addrinfo = res;
Paul Cercueil6a0eb582016-08-30 10:54:22 +02001461 pdata->io_ctx.timeout_ms = DEFAULT_TIMEOUT_MS;
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +01001462
Paul Cercueil157d43c2015-11-30 15:05:06 +01001463 pdata->lock = iio_mutex_create();
1464 if (!pdata->lock) {
1465 errno = ENOMEM;
1466 goto err_free_pdata;
1467 }
1468
1469 pdata->iiod_client = iiod_client_new(pdata, pdata->lock,
1470 &network_iiod_client_ops);
1471 if (!pdata->iiod_client)
1472 goto err_destroy_mutex;
1473
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001474 DEBUG("Creating context...\n");
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +02001475 ctx = iiod_client_create_context(pdata->iiod_client, &pdata->io_ctx);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001476 if (!ctx)
Paul Cercueil157d43c2015-11-30 15:05:06 +01001477 goto err_destroy_iiod_client;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001478
Paul Cercueil2057fd32014-10-28 14:44:19 +01001479 /* Override the name and low-level functions of the XML context
1480 * with those corresponding to the network context */
1481 ctx->name = "network";
1482 ctx->ops = &network_ops;
1483 ctx->pdata = pdata;
1484
Paul Cercueil06c479d2015-01-08 16:14:57 +01001485#ifdef HAVE_IPV6
Paul Cercueiled15e492015-01-12 15:52:28 +01001486 len = INET6_ADDRSTRLEN + IF_NAMESIZE + 2;
Paul Cercueil06c479d2015-01-08 16:14:57 +01001487#else
1488 len = INET_ADDRSTRLEN + 1;
1489#endif
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001490
1491 description = malloc(len);
1492 if (!description) {
Paul Cercueilcc575532015-03-16 17:15:24 +01001493 ret = -ENOMEM;
Paul Cercueil06c479d2015-01-08 16:14:57 +01001494 goto err_network_shutdown;
1495 }
1496
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001497 description[0] = '\0';
Paul Cercueil06c479d2015-01-08 16:14:57 +01001498
1499#ifdef HAVE_IPV6
1500 if (res->ai_family == AF_INET6) {
1501 struct sockaddr_in6 *in = (struct sockaddr_in6 *) res->ai_addr;
Paul Cercueiled15e492015-01-12 15:52:28 +01001502 char *ptr;
Paul Cercueil06c479d2015-01-08 16:14:57 +01001503 inet_ntop(AF_INET6, &in->sin6_addr,
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001504 description, INET6_ADDRSTRLEN);
Paul Cercueiled15e492015-01-12 15:52:28 +01001505
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001506 ptr = if_indextoname(in->sin6_scope_id, description +
1507 strlen(description) + 1);
Paul Cercueiled15e492015-01-12 15:52:28 +01001508 if (!ptr) {
Paul Cercueilcc575532015-03-16 17:15:24 +01001509 ret = -errno;
Paul Cercueiled15e492015-01-12 15:52:28 +01001510 ERROR("Unable to lookup interface of IPv6 address\n");
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001511 goto err_free_description;
Paul Cercueiled15e492015-01-12 15:52:28 +01001512 }
1513
1514 *(ptr - 1) = '%';
Paul Cercueil06c479d2015-01-08 16:14:57 +01001515 }
1516#endif
1517 if (res->ai_family == AF_INET) {
1518 struct sockaddr_in *in = (struct sockaddr_in *) res->ai_addr;
Paul Cercueile7a31692015-07-15 10:52:47 +02001519#if (!_WIN32 || _WIN32_WINNT >= 0x600)
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001520 inet_ntop(AF_INET, &in->sin_addr, description, INET_ADDRSTRLEN);
Paul Cercueile7a31692015-07-15 10:52:47 +02001521#else
1522 char *tmp = inet_ntoa(in->sin_addr);
1523 strncpy(description, tmp, len);
1524#endif
Paul Cercueil06c479d2015-01-08 16:14:57 +01001525 }
1526
Paul Cercueil554ef262017-02-08 12:16:57 +01001527 ret = iio_context_add_attr(ctx, "ip,ip-addr", description);
1528 if (ret < 0)
1529 goto err_free_description;
1530
Paul Cercueil44ae11c2014-03-17 09:56:29 +01001531 for (i = 0; i < ctx->nb_devices; i++) {
1532 struct iio_device *dev = ctx->devices[i];
Paul Cercueilff778232014-03-24 14:23:08 +01001533
Lars-Peter Clausend1be8382016-02-24 11:13:45 +01001534 dev->pdata = zalloc(sizeof(*dev->pdata));
Paul Cercueil439e1a22015-02-24 13:50:51 +01001535 if (!dev->pdata) {
Paul Cercueilcc575532015-03-16 17:15:24 +01001536 ret = -ENOMEM;
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001537 goto err_free_description;
Paul Cercueil439e1a22015-02-24 13:50:51 +01001538 }
1539
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +02001540 dev->pdata->io_ctx.fd = -1;
Paul Cercueil6a0eb582016-08-30 10:54:22 +02001541 dev->pdata->io_ctx.timeout_ms = DEFAULT_TIMEOUT_MS;
Paul Cercueil90189672015-03-16 11:41:53 +01001542#ifdef WITH_NETWORK_GET_BUFFER
Paul Cercueil09a43482015-03-04 15:50:27 +01001543 dev->pdata->memfd = -1;
Paul Cercueile6e5a092015-03-04 16:33:26 +01001544#endif
Paul Cercueilc5b00752015-02-24 14:29:53 +01001545
Paul Cercueil388dcd62015-11-27 15:15:48 +01001546 dev->pdata->lock = iio_mutex_create();
1547 if (!dev->pdata->lock) {
1548 ret = -ENOMEM;
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001549 goto err_free_description;
Paul Cercueil388dcd62015-11-27 15:15:48 +01001550 }
Paul Cercueil44ae11c2014-03-17 09:56:29 +01001551 }
1552
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001553 if (ctx->description) {
Paul Cercueil0e3c04d2015-05-13 17:37:11 +02001554 size_t desc_len = strlen(description);
1555 size_t new_size = desc_len + strlen(ctx->description) + 2;
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001556 char *ptr, *new_description = realloc(description, new_size);
Paul Cercueilcc575532015-03-16 17:15:24 +01001557 if (!new_description) {
1558 ret = -ENOMEM;
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001559 goto err_free_description;
Paul Cercueilcc575532015-03-16 17:15:24 +01001560 }
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001561
1562 ptr = strrchr(new_description, '\0');
Paul Cercueil9c9a5562017-01-24 10:48:31 +01001563 iio_snprintf(ptr, new_size - desc_len, " %s", ctx->description);
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001564 free(ctx->description);
1565
1566 ctx->description = new_description;
1567 } else {
1568 ctx->description = description;
1569 }
1570
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +02001571 iiod_client_set_timeout(pdata->iiod_client, &pdata->io_ctx,
Paul Cercueilf996ae12015-12-03 12:29:13 +01001572 calculate_remote_timeout(DEFAULT_TIMEOUT_MS));
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001573 return ctx;
1574
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001575err_free_description:
1576 free(description);
Paul Cercueil44ae11c2014-03-17 09:56:29 +01001577err_network_shutdown:
Paul Cercueil44ae11c2014-03-17 09:56:29 +01001578 iio_context_destroy(ctx);
Paul Cercueilcc575532015-03-16 17:15:24 +01001579 errno = -ret;
Paul Cercueil2057fd32014-10-28 14:44:19 +01001580 return NULL;
Paul Cercueil157d43c2015-11-30 15:05:06 +01001581
1582err_destroy_iiod_client:
1583 iiod_client_destroy(pdata->iiod_client);
1584err_destroy_mutex:
1585 iio_mutex_destroy(pdata->lock);
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +01001586err_free_pdata:
1587 free(pdata);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001588err_close_socket:
1589 close(fd);
Paul Cercueil2dd2c132015-02-24 10:41:01 +01001590err_free_addrinfo:
1591 freeaddrinfo(res);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001592 return NULL;
1593}