blob: bf0992a3eafc6d32665366e97b57a7f3c7355d29 [file] [log] [blame]
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001/*
2 * libiio - Library for interfacing industrial I/O (IIO) devices
3 *
Robin Getzaf161e02020-02-12 10:54:06 -05004 * Copyright (C) 2014-2020 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;
JaredD8cecbe52018-03-10 21:16:51 -080089 bool msg_trunc_supported;
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +010090};
91
Paul Cercueil439e1a22015-02-24 13:50:51 +010092struct iio_device_pdata {
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +020093 struct iio_network_io_context io_ctx;
Paul Cercueil90189672015-03-16 11:41:53 +010094#ifdef WITH_NETWORK_GET_BUFFER
Paul Cercueil09a43482015-03-04 15:50:27 +010095 int memfd;
Paul Cercueile6e5a092015-03-04 16:33:26 +010096 void *mmap_addr;
Paul Cercueil09a43482015-03-04 15:50:27 +010097 size_t mmap_len;
Paul Cercueile6e5a092015-03-04 16:33:26 +010098#endif
Paul Cercueil09a43482015-03-04 15:50:27 +010099 bool wait_for_err_code, is_cyclic, is_tx;
Paul Cercueil388dcd62015-11-27 15:15:48 +0100100 struct iio_mutex *lock;
Paul Cercueil439e1a22015-02-24 13:50:51 +0100101};
102
Lars-Peter Clausendd04e6a2016-02-10 14:56:36 +0100103#ifdef _WIN32
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200104
Lars-Peter Clausenac256dd2017-03-07 13:06:15 +0100105static int set_blocking_mode(int s, bool blocking)
106{
Lars-Peter Clausencd3c49f2017-03-30 15:04:19 +0200107 unsigned long nonblock;
Lars-Peter Clausenac256dd2017-03-07 13:06:15 +0100108 int ret;
109
110 nonblock = blocking ? 0 : 1;
111
112 ret = ioctlsocket(s, FIONBIO, &nonblock);
113 if (ret == SOCKET_ERROR) {
114 ret = -WSAGetLastError();
115 return ret;
116 }
117
118 return 0;
119}
120
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200121static int setup_cancel(struct iio_network_io_context *io_ctx)
122{
123 io_ctx->events[0] = WSACreateEvent();
124 if (io_ctx->events[0] == WSA_INVALID_EVENT)
125 return -ENOMEM; /* Pretty much the only error that can happen */
126
127 io_ctx->events[1] = WSACreateEvent();
128 if (io_ctx->events[1] == WSA_INVALID_EVENT) {
129 WSACloseEvent(io_ctx->events[0]);
130 return -ENOMEM;
131 }
132
133 return 0;
134}
135
136static void cleanup_cancel(struct iio_network_io_context *io_ctx)
137{
138 WSACloseEvent(io_ctx->events[0]);
139 WSACloseEvent(io_ctx->events[1]);
140}
141
142static void do_cancel(struct iio_network_io_context *io_ctx)
143{
144 WSASetEvent(io_ctx->events[1]);
145}
146
147static int wait_cancellable(struct iio_network_io_context *io_ctx, bool read)
148{
149 long wsa_events = FD_CLOSE;
150 DWORD ret;
151
152 if (!io_ctx->cancellable)
153 return 0;
154
155 if (read)
156 wsa_events |= FD_READ;
157 else
158 wsa_events |= FD_WRITE;
159
160 WSAEventSelect(io_ctx->fd, NULL, 0);
161 WSAResetEvent(io_ctx->events[0]);
162 WSAEventSelect(io_ctx->fd, io_ctx->events[0], wsa_events);
163
164 ret = WSAWaitForMultipleEvents(2, io_ctx->events, FALSE,
165 WSA_INFINITE, FALSE);
166
167 if (ret == WSA_WAIT_EVENT_0 + 1)
168 return -EBADF;
169
170 return 0;
171}
172
Lars-Peter Clausendd04e6a2016-02-10 14:56:36 +0100173static int network_get_error(void)
174{
175 return -WSAGetLastError();
176}
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200177
178static bool network_should_retry(int err)
179{
Paul Cercueil63a48ed2016-09-01 12:27:46 +0200180 return err == -WSAEWOULDBLOCK || err == -WSAETIMEDOUT;
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200181}
182
Paul Cercueilb419f1e2016-08-31 16:59:57 +0200183static bool network_is_interrupted(int err)
184{
185 return false;
186}
187
Lars-Peter Clausenac256dd2017-03-07 13:06:15 +0100188static bool network_connect_in_progress(int err)
189{
190 return err == -WSAEWOULDBLOCK;
191}
192
193#define NETWORK_ERR_TIMEOUT WSAETIMEDOUT
194
Lars-Peter Clausendd04e6a2016-02-10 14:56:36 +0100195#else
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200196
Paul Cercueil7a683272016-08-24 14:50:20 +0200197static int set_blocking_mode(int fd, bool blocking)
198{
199 int ret = fcntl(fd, F_GETFL, 0);
200 if (ret < 0)
201 return -errno;
202
203 if (blocking)
204 ret &= ~O_NONBLOCK;
205 else
206 ret |= O_NONBLOCK;
207
208 ret = fcntl(fd, F_SETFL, ret);
209 return ret < 0 ? -errno : 0;
210}
211
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200212#include <poll.h>
213
214#if defined(WITH_NETWORK_EVENTFD)
215
216#include <sys/eventfd.h>
217
218static int create_cancel_fd(struct iio_network_io_context *io_ctx)
219{
220 io_ctx->cancel_fd[0] = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
221 if (io_ctx->cancel_fd[0] < 0)
222 return -errno;
223 return 0;
224}
225
226static void cleanup_cancel(struct iio_network_io_context *io_ctx)
227{
228 close(io_ctx->cancel_fd[0]);
229}
230
231#define CANCEL_WR_FD 0
232
233#else
234
235static int create_cancel_fd(struct iio_network_io_context *io_ctx)
236{
237 int ret;
238
239#ifdef HAS_PIPE2
240 ret = pipe2(io_ctx->cancel_fd, O_CLOEXEC | O_NONBLOCK);
241 if (ret < 0 && errno != ENOSYS) /* If ENOSYS try pipe() */
242 return -errno;
243#endif
244 ret = pipe(io_ctx->cancel_fd);
245 if (ret < 0)
246 return -errno;
247 ret = set_blocking_mode(io_ctx->cancel_fd[0], false);
248 if (ret < 0)
249 goto err_close;
250 ret = set_blocking_mode(io_ctx->cancel_fd[1], false);
251 if (ret < 0)
252 goto err_close;
253
254 return 0;
255err_close:
256 close(io_ctx->cancel_fd[0]);
257 close(io_ctx->cancel_fd[1]);
258 return ret;
259}
260
261static void cleanup_cancel(struct iio_network_io_context *io_ctx)
262{
263 close(io_ctx->cancel_fd[0]);
264 close(io_ctx->cancel_fd[1]);
265}
266
267#define CANCEL_WR_FD 1
268
269#endif
270
271static int setup_cancel(struct iio_network_io_context *io_ctx)
272{
273 int ret;
274
275 ret = set_blocking_mode(io_ctx->fd, false);
276 if (ret)
277 return ret;
278
279 return create_cancel_fd(io_ctx);
280}
281
282static void do_cancel(struct iio_network_io_context *io_ctx)
283{
284 uint64_t event = 1;
285 int ret;
286
287 ret = write(io_ctx->cancel_fd[CANCEL_WR_FD], &event, sizeof(event));
288 if (ret == -1) {
289 /* If this happens something went very seriously wrong */
290 char err_str[1024];
291 iio_strerror(errno, err_str, sizeof(err_str));
292 ERROR("Unable to signal cancellation event: %s\n", err_str);
293 }
294}
295
296static int wait_cancellable(struct iio_network_io_context *io_ctx, bool read)
297{
298 struct pollfd pfd[2];
299 int ret;
300
301 if (!io_ctx->cancellable)
302 return 0;
303
304 memset(pfd, 0, sizeof(pfd));
305
306 pfd[0].fd = io_ctx->fd;
307 if (read)
308 pfd[0].events = POLLIN;
309 else
310 pfd[0].events = POLLOUT;
311 pfd[1].fd = io_ctx->cancel_fd[0];
312 pfd[1].events = POLLIN;
313
314 do {
Paul Cercueil6a0eb582016-08-30 10:54:22 +0200315 int timeout_ms;
316
317 if (io_ctx->timeout_ms > 0)
318 timeout_ms = (int) io_ctx->timeout_ms;
319 else
320 timeout_ms = -1;
321
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200322 do {
Paul Cercueil6a0eb582016-08-30 10:54:22 +0200323 ret = poll(pfd, 2, timeout_ms);
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200324 } while (ret == -1 && errno == EINTR);
325
326 if (ret == -1)
327 return -errno;
Paul Cercueil6a0eb582016-08-30 10:54:22 +0200328 if (!ret)
Paul Cercueile8e7aca2016-08-31 16:15:13 +0200329 return -EPIPE;
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200330
331 if (pfd[1].revents & POLLIN)
332 return -EBADF;
333 } while (!(pfd[0].revents & (pfd[0].events | POLLERR | POLLHUP)));
334
335 return 0;
336}
337
Lars-Peter Clausendd04e6a2016-02-10 14:56:36 +0100338static int network_get_error(void)
339{
340 return -errno;
341}
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200342
343static bool network_should_retry(int err)
344{
Paul Cercueilb419f1e2016-08-31 16:59:57 +0200345 return err == -EAGAIN;
346}
347
348static bool network_is_interrupted(int err)
349{
350 return err == -EINTR;
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200351}
352
Lars-Peter Clausenac256dd2017-03-07 13:06:15 +0100353static bool network_connect_in_progress(int err)
354{
355 return err == -EINPROGRESS;
356}
357
358#define NETWORK_ERR_TIMEOUT ETIMEDOUT
359
Lars-Peter Clausendd04e6a2016-02-10 14:56:36 +0100360#endif
361
Paul Cercueilab114932014-05-19 13:03:17 +0200362#ifdef HAVE_AVAHI
363struct avahi_discovery_data {
364 AvahiSimplePoll *poll;
365 AvahiAddress *address;
366 uint16_t *port;
367 bool found, resolved;
368};
369
370static void __avahi_resolver_cb(AvahiServiceResolver *resolver,
371 __notused AvahiIfIndex iface, __notused AvahiProtocol proto,
372 __notused AvahiResolverEvent event, __notused const char *name,
373 __notused const char *type, __notused const char *domain,
374 __notused const char *host_name, const AvahiAddress *address,
375 uint16_t port, __notused AvahiStringList *txt,
376 __notused AvahiLookupResultFlags flags, void *d)
377{
378 struct avahi_discovery_data *ddata = (struct avahi_discovery_data *) d;
379
380 memcpy(ddata->address, address, sizeof(*address));
381 *ddata->port = port;
382 ddata->resolved = true;
383 avahi_service_resolver_free(resolver);
384}
385
386static void __avahi_browser_cb(AvahiServiceBrowser *browser,
387 AvahiIfIndex iface, AvahiProtocol proto,
388 AvahiBrowserEvent event, const char *name,
389 const char *type, const char *domain,
390 __notused AvahiLookupResultFlags flags, void *d)
391{
392 struct avahi_discovery_data *ddata = (struct avahi_discovery_data *) d;
393 struct AvahiClient *client = avahi_service_browser_get_client(browser);
394
395 switch (event) {
396 default:
397 case AVAHI_BROWSER_NEW:
398 ddata->found = !!avahi_service_resolver_new(client, iface,
399 proto, name, type, domain,
400 AVAHI_PROTO_UNSPEC, 0,
401 __avahi_resolver_cb, d);
402 break;
403 case AVAHI_BROWSER_ALL_FOR_NOW:
404 if (ddata->found) {
405 while (!ddata->resolved) {
406 struct timespec ts;
407 ts.tv_sec = 0;
408 ts.tv_nsec = 4000000;
409 nanosleep(&ts, NULL);
410 }
411 }
Lars-Peter Clausen4d847cb2017-12-18 10:39:13 +0100412 /* fall-through */
413 case AVAHI_BROWSER_FAILURE:
Paul Cercueilab114932014-05-19 13:03:17 +0200414 avahi_simple_poll_quit(ddata->poll);
Lars-Peter Clausen4d847cb2017-12-18 10:39:13 +0100415 /* fall-through */
416 case AVAHI_BROWSER_CACHE_EXHAUSTED:
Paul Cercueilab114932014-05-19 13:03:17 +0200417 break;
418 }
419}
420
421static int discover_host(AvahiAddress *addr, uint16_t *port)
422{
423 struct avahi_discovery_data ddata;
424 int ret = 0;
425 AvahiClient *client;
426 AvahiServiceBrowser *browser;
427 AvahiSimplePoll *poll = avahi_simple_poll_new();
428 if (!poll)
429 return -ENOMEM;
430
431 client = avahi_client_new(avahi_simple_poll_get(poll),
432 0, NULL, NULL, &ret);
433 if (!client) {
434 ERROR("Unable to start ZeroConf client :%s\n",
435 avahi_strerror(ret));
436 goto err_free_poll;
437 }
438
439 memset(&ddata, 0, sizeof(ddata));
440 ddata.poll = poll;
441 ddata.address = addr;
442 ddata.port = port;
443
444 browser = avahi_service_browser_new(client,
445 AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
446 "_iio._tcp", NULL, 0, __avahi_browser_cb, &ddata);
447 if (!browser) {
448 ret = avahi_client_errno(client);
449 ERROR("Unable to create ZeroConf browser: %s\n",
450 avahi_strerror(ret));
451 goto err_free_client;
452 }
453
454 DEBUG("Trying to discover host\n");
455 avahi_simple_poll_loop(poll);
456
457 if (!ddata.found)
458 ret = ENXIO;
459
460 avahi_service_browser_free(browser);
461err_free_client:
462 avahi_client_free(client);
463err_free_poll:
464 avahi_simple_poll_free(poll);
465 return -ret; /* we want a negative error code */
466}
467#endif /* HAVE_AVAHI */
468
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200469static ssize_t network_recv(struct iio_network_io_context *io_ctx,
470 void *data, size_t len, int flags)
Lars-Peter Clausen6a6c8662016-02-12 15:35:52 +0100471{
472 ssize_t ret;
473 int err;
474
475 while (1) {
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200476 ret = wait_cancellable(io_ctx, true);
477 if (ret < 0)
478 return ret;
479
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200480 ret = recv(io_ctx->fd, data, (int) len, flags);
Lars-Peter Clausen6a6c8662016-02-12 15:35:52 +0100481 if (ret == 0)
482 return -EPIPE;
483 else if (ret > 0)
484 break;
485
486 err = network_get_error();
Paul Cercueilb419f1e2016-08-31 16:59:57 +0200487 if (network_should_retry(err)) {
488 if (io_ctx->cancellable)
489 continue;
490 else
491 return -EPIPE;
492 } else if (!network_is_interrupted(err)) {
Lars-Peter Clausen6a6c8662016-02-12 15:35:52 +0100493 return (ssize_t) err;
Paul Cercueilb419f1e2016-08-31 16:59:57 +0200494 }
Lars-Peter Clausen6a6c8662016-02-12 15:35:52 +0100495 }
496 return ret;
497}
498
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200499static ssize_t network_send(struct iio_network_io_context *io_ctx,
500 const void *data, size_t len, int flags)
Lars-Peter Clausen6a6c8662016-02-12 15:35:52 +0100501{
502 ssize_t ret;
503 int err;
504
505 while (1) {
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200506 ret = wait_cancellable(io_ctx, false);
507 if (ret < 0)
508 return ret;
509
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200510 ret = send(io_ctx->fd, data, (int) len, flags);
Lars-Peter Clausen6a6c8662016-02-12 15:35:52 +0100511 if (ret == 0)
512 return -EPIPE;
513 else if (ret > 0)
514 break;
515
516 err = network_get_error();
Paul Cercueilb419f1e2016-08-31 16:59:57 +0200517 if (network_should_retry(err)) {
518 if (io_ctx->cancellable)
519 continue;
520 else
521 return -EPIPE;
522 } else if (!network_is_interrupted(err)) {
Lars-Peter Clausen6a6c8662016-02-12 15:35:52 +0100523 return (ssize_t) err;
Paul Cercueilb419f1e2016-08-31 16:59:57 +0200524 }
Lars-Peter Clausen6a6c8662016-02-12 15:35:52 +0100525 }
526
527 return ret;
528}
529
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200530static ssize_t write_all(struct iio_network_io_context *io_ctx,
531 const void *src, size_t len)
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100532{
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200533 uintptr_t ptr = (uintptr_t) src;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100534 while (len) {
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200535 ssize_t ret = network_send(io_ctx, (const void *) ptr, len, 0);
Lars-Peter Clausen27a53e42016-04-13 17:08:07 +0200536 if (ret < 0)
537 return ret;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100538 ptr += ret;
539 len -= ret;
540 }
Paul Cercueil4012cff2015-05-11 10:47:40 +0200541 return (ssize_t)(ptr - (uintptr_t) src);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100542}
543
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200544static ssize_t write_command(struct iio_network_io_context *io_ctx,
545 const char *cmd)
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100546{
547 ssize_t ret;
548
549 DEBUG("Writing command: %s\n", cmd);
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200550 ret = write_all(io_ctx, cmd, strlen(cmd));
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100551 if (ret < 0) {
552 char buf[1024];
Paul Cercueil53fc4852015-05-22 10:57:53 +0200553 iio_strerror(-ret, buf, sizeof(buf));
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100554 ERROR("Unable to send command: %s\n", buf);
555 }
556 return ret;
557}
558
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200559static void network_cancel(const struct iio_device *dev)
560{
561 struct iio_device_pdata *ppdata = dev->pdata;
562
563 do_cancel(&ppdata->io_ctx);
564
565 ppdata->io_ctx.cancelled = true;
566}
567
Paul Cercueil4970ac32015-02-24 10:59:00 +0100568#ifndef _WIN32
Lars-Peter Clausena2cbc812016-02-11 14:49:27 +0100569
570/* Use it if available */
Paul Cercueild454e012016-06-28 15:19:19 +0200571#ifndef SOCK_CLOEXEC
572#define SOCK_CLOEXEC 0
Lars-Peter Clausena2cbc812016-02-11 14:49:27 +0100573#endif
574
Lars-Peter Clausenac256dd2017-03-07 13:06:15 +0100575static int do_create_socket(const struct addrinfo *addrinfo)
Paul Cercueil4970ac32015-02-24 10:59:00 +0100576{
Lars-Peter Clausen1ca01b72016-02-10 15:10:09 +0100577 int fd;
578
Lars-Peter Clausena2cbc812016-02-11 14:49:27 +0100579 fd = socket(addrinfo->ai_family, addrinfo->ai_socktype | SOCK_CLOEXEC, 0);
Lars-Peter Clausen1ca01b72016-02-10 15:10:09 +0100580 if (fd < 0)
581 return -errno;
Paul Cercueil4970ac32015-02-24 10:59:00 +0100582
Lars-Peter Clausenebbd9072016-02-11 15:15:08 +0100583 return fd;
Paul Cercueil4970ac32015-02-24 10:59:00 +0100584}
585
586static int set_socket_timeout(int fd, unsigned int timeout)
587{
588 struct timeval tv;
589
590 tv.tv_sec = timeout / 1000;
591 tv.tv_usec = (timeout % 1000) * 1000;
592 if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0 ||
593 setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO,
594 &tv, sizeof(tv)) < 0)
595 return -errno;
596 else
597 return 0;
598}
599#else
Lars-Peter Clausen1ca01b72016-02-10 15:10:09 +0100600
Lars-Peter Clausena2cbc812016-02-11 14:49:27 +0100601/* Use it if available */
602#ifndef WSA_FLAG_NO_HANDLE_INHERIT
603#define WSA_FLAG_NO_HANDLE_INHERIT 0
604#endif
605
Lars-Peter Clausenac256dd2017-03-07 13:06:15 +0100606static int do_create_socket(const struct addrinfo *addrinfo)
Lars-Peter Clausen1ca01b72016-02-10 15:10:09 +0100607{
Lars-Peter Clausen1ca01b72016-02-10 15:10:09 +0100608 SOCKET s;
609
Paul Cercueilba16cea2016-04-18 12:14:58 +0200610 s = WSASocketW(addrinfo->ai_family, addrinfo->ai_socktype, 0, NULL, 0,
Paul Cercueil9dc0a622016-09-01 12:28:30 +0200611 WSA_FLAG_NO_HANDLE_INHERIT | WSA_FLAG_OVERLAPPED);
Lars-Peter Clausen1ca01b72016-02-10 15:10:09 +0100612 if (s == INVALID_SOCKET)
613 return -WSAGetLastError();
614
Lars-Peter Clausen1ca01b72016-02-10 15:10:09 +0100615 return (int) s;
616}
617
Paul Cercueil4970ac32015-02-24 10:59:00 +0100618static int set_socket_timeout(int fd, unsigned int timeout)
619{
620 if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO,
621 (const char *) &timeout, sizeof(timeout)) < 0 ||
622 setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO,
623 (const char *) &timeout, sizeof(timeout)) < 0)
Paul Cercueil135b3612015-06-30 14:10:14 +0200624 return -WSAGetLastError();
Paul Cercueil4970ac32015-02-24 10:59:00 +0100625 else
626 return 0;
627}
628#endif /* !_WIN32 */
629
Lars-Peter Clausenac256dd2017-03-07 13:06:15 +0100630/* The purpose of this function is to provide a version of connect()
631 * that does not ignore timeouts... */
632static int do_connect(int fd, const struct addrinfo *addrinfo,
633 unsigned int timeout)
Paul Cercueil4970ac32015-02-24 10:59:00 +0100634{
Lars-Peter Clausenac256dd2017-03-07 13:06:15 +0100635 int ret, error;
636 socklen_t len;
Lars-Peter Clausen14a1f642018-01-23 18:15:45 +0100637#ifdef _WIN32
638 struct timeval tv;
639 struct timeval *ptv;
Lars-Peter Clausenac256dd2017-03-07 13:06:15 +0100640 fd_set set;
Lars-Peter Clausen14a1f642018-01-23 18:15:45 +0100641#else
642 struct pollfd pfd;
643#endif
Lars-Peter Clausenac256dd2017-03-07 13:06:15 +0100644
645 ret = set_blocking_mode(fd, false);
646 if (ret < 0)
647 return ret;
648
649 ret = connect(fd, addrinfo->ai_addr, (int) addrinfo->ai_addrlen);
650 if (ret < 0) {
651 ret = network_get_error();
652 if (!network_connect_in_progress(ret))
653 return ret;
654 }
655
Lars-Peter Clausen14a1f642018-01-23 18:15:45 +0100656#ifdef _WIN32
Lars-Peter Clausenac256dd2017-03-07 13:06:15 +0100657 FD_ZERO(&set);
658 FD_SET(fd, &set);
Paul Cercueil4970ac32015-02-24 10:59:00 +0100659
Lars-Peter Clausen828b5482017-03-07 13:50:53 +0100660 if (timeout != 0) {
661 tv.tv_sec = timeout / 1000;
662 tv.tv_usec = (timeout % 1000) * 1000;
663 ptv = &tv;
664 } else {
665 ptv = NULL;
666 }
Paul Cercueil4970ac32015-02-24 10:59:00 +0100667
Lars-Peter Clausenac256dd2017-03-07 13:06:15 +0100668 ret = select(fd + 1, NULL, &set, &set, ptv);
Lars-Peter Clausen14a1f642018-01-23 18:15:45 +0100669#else
670 pfd.fd = fd;
671 pfd.events = POLLOUT | POLLERR;
672 pfd.revents = 0;
673
674 do {
675 ret = poll(&pfd, 1, timeout);
676 } while (ret == -1 && errno == EINTR);
677#endif
678
Lars-Peter Clausenac256dd2017-03-07 13:06:15 +0100679 if (ret < 0)
680 return network_get_error();
681
682 if (ret == 0)
683 return -NETWORK_ERR_TIMEOUT;
684
685 /* Verify that we don't have an error */
686 len = sizeof(error);
687 ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, (char *)&error, &len);
688 if(ret < 0)
689 return network_get_error();
690
691 if (error)
692 return -error;
693
694 ret = set_blocking_mode(fd, true);
695 if (ret < 0)
696 return ret;
697
698 return 0;
699}
700
701static int create_socket(const struct addrinfo *addrinfo, unsigned int timeout)
702{
703 int ret, fd, yes = 1;
704
705 fd = do_create_socket(addrinfo);
Lars-Peter Clausen1ca01b72016-02-10 15:10:09 +0100706 if (fd < 0)
707 return fd;
Paul Cercueil4970ac32015-02-24 10:59:00 +0100708
Lars-Peter Clausenac256dd2017-03-07 13:06:15 +0100709 ret = do_connect(fd, addrinfo, timeout);
710 if (ret < 0) {
711 close(fd);
712 return ret;
713 }
714
Lars-Peter Clausen6f127f02017-03-09 15:20:04 +0100715 set_socket_timeout(fd, timeout);
Paul Cercueil32dce822016-12-12 14:51:59 +0100716 if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
Paul Cercueilaf3370e2017-02-01 12:14:12 +0100717 (const char *) &yes, sizeof(yes)) < 0) {
718 ret = -errno;
719 close(fd);
720 return ret;
721 }
Paul Cercueil32dce822016-12-12 14:51:59 +0100722
Paul Cercueil4970ac32015-02-24 10:59:00 +0100723 return fd;
724}
725
Paul Cercueil92f15c22015-04-20 11:36:51 +0200726static int network_open(const struct iio_device *dev,
727 size_t samples_count, bool cyclic)
Paul Cercueilba059762014-03-14 11:02:02 +0100728{
Paul Cercueil439e1a22015-02-24 13:50:51 +0100729 struct iio_context_pdata *pdata = dev->ctx->pdata;
Paul Cercueil80dc1082015-12-01 18:20:31 +0100730 struct iio_device_pdata *ppdata = dev->pdata;
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200731 int ret = -EBUSY;
Paul Cercueilba059762014-03-14 11:02:02 +0100732
Paul Cercueil80dc1082015-12-01 18:20:31 +0100733 iio_mutex_lock(ppdata->lock);
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200734 if (ppdata->io_ctx.fd >= 0)
Paul Cercueil80dc1082015-12-01 18:20:31 +0100735 goto out_mutex_unlock;
Paul Cercueil439e1a22015-02-24 13:50:51 +0100736
Lars-Peter Clausen6f127f02017-03-09 15:20:04 +0100737 ret = create_socket(pdata->addrinfo, DEFAULT_TIMEOUT_MS);
Robin Getzaf161e02020-02-12 10:54:06 -0500738 if (ret < 0) {
739 ERROR("Create socket: %d\n", ret);
Paul Cercueil80dc1082015-12-01 18:20:31 +0100740 goto out_mutex_unlock;
Robin Getzaf161e02020-02-12 10:54:06 -0500741 }
Paul Cercueilba059762014-03-14 11:02:02 +0100742
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200743 ppdata->io_ctx.fd = ret;
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200744 ppdata->io_ctx.cancelled = false;
Lars-Peter Clausen8ddf6372018-01-29 15:29:54 +0100745 ppdata->io_ctx.cancellable = false;
Lars-Peter Clausen6f127f02017-03-09 15:20:04 +0100746 ppdata->io_ctx.timeout_ms = DEFAULT_TIMEOUT_MS;
747
Harvey Yangbc3f48e2019-10-22 11:17:28 +0800748 ret = iiod_client_register_client_id(dev->ctx->pdata->iiod_client,
749 &ppdata->io_ctx, dev->ctx->client_id);
750 if (ret < 0)
751 printf ("Failed to register client id: %i\n", ret);
752
Lars-Peter Clausen6f127f02017-03-09 15:20:04 +0100753 ret = iiod_client_open_unlocked(pdata->iiod_client,
754 &ppdata->io_ctx, dev, samples_count, cyclic);
Robin Getzaf161e02020-02-12 10:54:06 -0500755 if (ret < 0) {
Dan Nechitaa6e4fcf2020-02-14 10:38:09 +0200756 ERROR("Open unlocked: %d\n", ret);
Lars-Peter Clausen6f127f02017-03-09 15:20:04 +0100757 goto err_close_socket;
Robin Getzaf161e02020-02-12 10:54:06 -0500758 }
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200759
760 ret = setup_cancel(&ppdata->io_ctx);
761 if (ret < 0)
762 goto err_close_socket;
Paul Cercueilba059762014-03-14 11:02:02 +0100763
Lars-Peter Clausen6f127f02017-03-09 15:20:04 +0100764 set_socket_timeout(ppdata->io_ctx.fd, pdata->io_ctx.timeout_ms);
Paul Cercueil439e1a22015-02-24 13:50:51 +0100765
Lars-Peter Clausen6f127f02017-03-09 15:20:04 +0100766 ppdata->io_ctx.timeout_ms = pdata->io_ctx.timeout_ms;
767 ppdata->io_ctx.cancellable = true;
Paul Cercueil80dc1082015-12-01 18:20:31 +0100768 ppdata->is_tx = iio_device_is_tx(dev);
769 ppdata->is_cyclic = cyclic;
Paul Cercueil80dc1082015-12-01 18:20:31 +0100770 ppdata->wait_for_err_code = false;
Paul Cercueild957b982015-08-05 14:39:01 +0200771#ifdef WITH_NETWORK_GET_BUFFER
Paul Cercueil80dc1082015-12-01 18:20:31 +0100772 ppdata->mmap_len = samples_count * iio_device_get_sample_size(dev);
Paul Cercueild957b982015-08-05 14:39:01 +0200773#endif
Paul Cercueil80dc1082015-12-01 18:20:31 +0100774
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200775 iio_mutex_unlock(ppdata->lock);
776
777 return 0;
778
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200779err_close_socket:
780 close(ppdata->io_ctx.fd);
781 ppdata->io_ctx.fd = -1;
Paul Cercueil80dc1082015-12-01 18:20:31 +0100782out_mutex_unlock:
783 iio_mutex_unlock(ppdata->lock);
784 return ret;
Paul Cercueilba059762014-03-14 11:02:02 +0100785}
786
Lars-Peter Clausen90e75a92016-02-22 11:34:34 +0100787static int network_close(const struct iio_device *dev)
788{
789 struct iio_device_pdata *pdata = dev->pdata;
790 int ret = -EBADF;
791
792 iio_mutex_lock(pdata->lock);
793
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200794 if (pdata->io_ctx.fd >= 0) {
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200795 if (!pdata->io_ctx.cancelled) {
796 ret = iiod_client_close_unlocked(
797 dev->ctx->pdata->iiod_client,
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +0200798 &pdata->io_ctx, dev);
Lars-Peter Clausen90e75a92016-02-22 11:34:34 +0100799
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200800 write_command(&pdata->io_ctx, "\r\nEXIT\r\n");
801 } else {
802 ret = 0;
803 }
Lars-Peter Clausen90e75a92016-02-22 11:34:34 +0100804
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200805 cleanup_cancel(&pdata->io_ctx);
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200806 close(pdata->io_ctx.fd);
807 pdata->io_ctx.fd = -1;
Lars-Peter Clausen90e75a92016-02-22 11:34:34 +0100808 }
809
810#ifdef WITH_NETWORK_GET_BUFFER
811 if (pdata->memfd >= 0)
812 close(pdata->memfd);
813 pdata->memfd = -1;
814
815 if (pdata->mmap_addr) {
816 munmap(pdata->mmap_addr, pdata->mmap_len);
817 pdata->mmap_addr = NULL;
818 }
819#endif
820
821 iio_mutex_unlock(pdata->lock);
822 return ret;
823}
824
825static ssize_t network_read(const struct iio_device *dev, void *dst, size_t len,
826 uint32_t *mask, size_t words)
827{
828 struct iio_device_pdata *pdata = dev->pdata;
829 ssize_t ret;
830
831 iio_mutex_lock(pdata->lock);
832 ret = iiod_client_read_unlocked(dev->ctx->pdata->iiod_client,
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +0200833 &pdata->io_ctx, dev, dst, len, mask, words);
Lars-Peter Clausen90e75a92016-02-22 11:34:34 +0100834 iio_mutex_unlock(pdata->lock);
835
836 return ret;
837}
838
839static ssize_t network_write(const struct iio_device *dev,
840 const void *src, size_t len)
841{
842 struct iio_device_pdata *pdata = dev->pdata;
843 ssize_t ret;
844
845 iio_mutex_lock(pdata->lock);
846 ret = iiod_client_write_unlocked(dev->ctx->pdata->iiod_client,
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +0200847 &pdata->io_ctx, dev, src, len);
Lars-Peter Clausen90e75a92016-02-22 11:34:34 +0100848 iio_mutex_unlock(pdata->lock);
849
850 return ret;
851}
852
853#ifdef WITH_NETWORK_GET_BUFFER
854
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200855static ssize_t read_all(struct iio_network_io_context *io_ctx,
856 void *dst, size_t len)
Lars-Peter Clausen90e75a92016-02-22 11:34:34 +0100857{
858 uintptr_t ptr = (uintptr_t) dst;
859 while (len) {
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200860 ssize_t ret = network_recv(io_ctx, (void *) ptr, len, 0);
Robin Getzaf161e02020-02-12 10:54:06 -0500861 if (ret < 0) {
862 ERROR("NETWORK RECV: %zu\n", ret);
Lars-Peter Clausen90e75a92016-02-22 11:34:34 +0100863 return ret;
Robin Getzaf161e02020-02-12 10:54:06 -0500864 }
Lars-Peter Clausen90e75a92016-02-22 11:34:34 +0100865 ptr += ret;
866 len -= ret;
867 }
868 return (ssize_t)(ptr - (uintptr_t) dst);
869}
870
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200871static int read_integer(struct iio_network_io_context *io_ctx, long *val)
Lars-Peter Clausen90e75a92016-02-22 11:34:34 +0100872{
873 unsigned int i;
874 char buf[1024], *ptr;
875 ssize_t ret;
876 bool found = false;
877
878 for (i = 0; i < sizeof(buf) - 1; i++) {
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200879 ret = read_all(io_ctx, buf + i, 1);
Lars-Peter Clausen90e75a92016-02-22 11:34:34 +0100880 if (ret < 0)
881 return (int) ret;
882
883 /* Skip the eventual first few carriage returns.
884 * Also stop when a dot is found (for parsing floats) */
885 if (buf[i] != '\n' && buf[i] != '.')
886 found = true;
887 else if (found)
888 break;
889 }
890
891 buf[i] = '\0';
892 ret = (ssize_t) strtol(buf, &ptr, 10);
893 if (ptr == buf)
894 return -EINVAL;
895 *val = (long) ret;
896 return 0;
897}
898
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200899static ssize_t network_read_mask(struct iio_network_io_context *io_ctx,
900 uint32_t *mask, size_t words)
Lars-Peter Clausen90e75a92016-02-22 11:34:34 +0100901{
902 long read_len;
903 ssize_t ret;
904
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200905 ret = read_integer(io_ctx, &read_len);
Robin Getzaf161e02020-02-12 10:54:06 -0500906 if (ret < 0) {
907 ERROR("READ INTEGER: %zu\n", ret);
Lars-Peter Clausen90e75a92016-02-22 11:34:34 +0100908 return ret;
Robin Getzaf161e02020-02-12 10:54:06 -0500909 }
Lars-Peter Clausen90e75a92016-02-22 11:34:34 +0100910
911 if (read_len > 0 && mask) {
912 size_t i;
913 char buf[9];
914
915 buf[8] = '\0';
916 DEBUG("Reading mask\n");
917
918 for (i = words; i > 0; i--) {
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200919 ret = read_all(io_ctx, buf, 8);
Lars-Peter Clausen90e75a92016-02-22 11:34:34 +0100920 if (ret < 0)
921 return ret;
922
923 sscanf(buf, "%08x", &mask[i - 1]);
Paul Cercueilb133a0c2016-04-18 11:57:50 +0200924 DEBUG("mask[%lu] = 0x%x\n",
925 (unsigned long)(i - 1), mask[i - 1]);
Lars-Peter Clausen90e75a92016-02-22 11:34:34 +0100926 }
927 }
928
929 if (read_len > 0) {
930 char c;
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200931 ssize_t nb = read_all(io_ctx, &c, 1);
Lars-Peter Clausen90e75a92016-02-22 11:34:34 +0100932 if (nb > 0 && c != '\n')
933 read_len = -EIO;
934 }
935
936 return (ssize_t) read_len;
937}
938
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200939static ssize_t read_error_code(struct iio_network_io_context *io_ctx)
Paul Cercueil8f7f6c42015-02-24 15:00:35 +0100940{
941 /*
942 * The server returns two integer codes.
943 * The first one is returned right after the WRITEBUF command is issued,
944 * and corresponds to the error code returned when the server attempted
945 * to open the device.
946 * If zero, a second error code is returned, that corresponds (if positive)
947 * to the number of bytes written.
948 *
949 * To speed up things, we delay error reporting. We just send out the
950 * data without reading the error code that the server gives us, because
951 * the answer will take too much time. If an error occured, it will be
952 * reported by the next call to iio_buffer_push().
953 */
954
955 unsigned int i;
956 long resp = 0;
957
958 for (i = 0; i < 2; i++) {
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200959 ssize_t ret = read_integer(io_ctx, &resp);
Paul Cercueil8f7f6c42015-02-24 15:00:35 +0100960 if (ret < 0)
961 return ret;
962 if (resp < 0)
963 return (ssize_t) resp;
964 }
965
Paul Cercueil7d7e5d32015-03-05 10:51:41 +0100966 return (ssize_t) resp;
Paul Cercueil8f7f6c42015-02-24 15:00:35 +0100967}
968
Paul Cercueil3c0da372015-03-05 11:36:39 +0100969static ssize_t write_rwbuf_command(const struct iio_device *dev,
Lars-Peter Clausen2e380822016-02-11 20:36:13 +0100970 const char *cmd)
Paul Cercueil3c0da372015-03-05 11:36:39 +0100971{
972 struct iio_device_pdata *pdata = dev->pdata;
Paul Cercueil3c0da372015-03-05 11:36:39 +0100973
974 if (pdata->wait_for_err_code) {
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200975 ssize_t ret = read_error_code(&pdata->io_ctx);
Paul Cercueil3c0da372015-03-05 11:36:39 +0100976
977 pdata->wait_for_err_code = false;
978 if (ret < 0)
979 return ret;
980 }
981
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200982 return write_command(&pdata->io_ctx, cmd);
Paul Cercueil3c0da372015-03-05 11:36:39 +0100983}
984
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200985static ssize_t network_do_splice(struct iio_device_pdata *pdata, size_t len,
986 bool read)
Paul Cercueil09a43482015-03-04 15:50:27 +0100987{
988 int pipefd[2];
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200989 int fd_in, fd_out;
Lars-Peter Clausenf83877e2016-10-26 18:20:06 +0200990 ssize_t ret, read_len = len, write_len = 0;
Paul Cercueil09a43482015-03-04 15:50:27 +0100991
Lars-Peter Clausena2cbc812016-02-11 14:49:27 +0100992 ret = (ssize_t) pipe2(pipefd, O_CLOEXEC);
Paul Cercueil09a43482015-03-04 15:50:27 +0100993 if (ret < 0)
994 return -errno;
995
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200996 if (read) {
997 fd_in = pdata->io_ctx.fd;
998 fd_out = pdata->memfd;
999 } else {
1000 fd_in = pdata->memfd;
1001 fd_out = pdata->io_ctx.fd;
1002 }
1003
Paul Cercueil09a43482015-03-04 15:50:27 +01001004 do {
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +02001005 ret = wait_cancellable(&pdata->io_ctx, read);
1006 if (ret < 0)
1007 goto err_close_pipe;
1008
Lars-Peter Clausenf83877e2016-10-26 18:20:06 +02001009 if (read_len) {
1010 /*
1011 * SPLICE_F_NONBLOCK is just here to avoid a deadlock when
1012 * splicing from a socket. As the socket is not in
1013 * non-blocking mode, it should never return -EAGAIN.
1014 * TODO(pcercuei): Find why it locks...
1015 * */
1016 ret = splice(fd_in, NULL, pipefd[1], NULL, read_len,
1017 SPLICE_F_MOVE | SPLICE_F_NONBLOCK);
1018 if (!ret)
1019 ret = -EIO;
1020 if (ret < 0 && errno != EAGAIN) {
1021 ret = -errno;
1022 goto err_close_pipe;
1023 } else if (ret > 0) {
1024 write_len += ret;
1025 read_len -= ret;
1026 }
Lars-Peter Clausen7247b922016-10-26 18:34:23 +02001027 }
Paul Cercueil09a43482015-03-04 15:50:27 +01001028
Lars-Peter Clausenf83877e2016-10-26 18:20:06 +02001029 if (write_len) {
1030 ret = splice(pipefd[0], NULL, fd_out, NULL, write_len,
1031 SPLICE_F_MOVE | SPLICE_F_NONBLOCK);
1032 if (!ret)
1033 ret = -EIO;
1034 if (ret < 0 && errno != EAGAIN) {
1035 ret = -errno;
1036 goto err_close_pipe;
1037 } else if (ret > 0) {
1038 write_len -= ret;
1039 }
Lars-Peter Clausen7247b922016-10-26 18:34:23 +02001040 }
Paul Cercueil09a43482015-03-04 15:50:27 +01001041
Lars-Peter Clausenf83877e2016-10-26 18:20:06 +02001042 } while (write_len || read_len);
Paul Cercueil09a43482015-03-04 15:50:27 +01001043
1044err_close_pipe:
1045 close(pipefd[0]);
1046 close(pipefd[1]);
Lars-Peter Clausenf83877e2016-10-26 18:20:06 +02001047 return ret < 0 ? ret : len;
Paul Cercueil09a43482015-03-04 15:50:27 +01001048}
1049
1050static ssize_t network_get_buffer(const struct iio_device *dev,
Paul Cercueil76ca8842015-03-05 11:16:16 +01001051 void **addr_ptr, size_t bytes_used,
1052 uint32_t *mask, size_t words)
Paul Cercueil09a43482015-03-04 15:50:27 +01001053{
1054 struct iio_device_pdata *pdata = dev->pdata;
Paul Cercueil04065c22015-03-05 14:08:16 +01001055 ssize_t ret, read = 0;
Paul Cercueilca9d3382015-05-04 14:30:09 +02001056 int memfd;
Paul Cercueil09a43482015-03-04 15:50:27 +01001057
Paul Cercueil04065c22015-03-05 14:08:16 +01001058 if (pdata->is_cyclic)
Paul Cercueil09a43482015-03-04 15:50:27 +01001059 return -ENOSYS;
Paul Cercueilca9d3382015-05-04 14:30:09 +02001060
1061 /* We check early that the temporary file can be created, so that we can
1062 * return -ENOSYS in case it fails, which will indicate that the
1063 * high-speed interface is not available.
1064 *
1065 * O_TMPFILE -> Linux 3.11.
1066 * TODO: use memfd_create (Linux 3.17) */
Lars-Peter Clausena2cbc812016-02-11 14:49:27 +01001067 memfd = open(P_tmpdir, O_RDWR | O_TMPFILE | O_EXCL | O_CLOEXEC, S_IRWXU);
Paul Cercueilca9d3382015-05-04 14:30:09 +02001068 if (memfd < 0)
1069 return -ENOSYS;
1070
1071 if (!addr_ptr || words != (dev->nb_channels + 31) / 32) {
1072 close(memfd);
Paul Cercueil09a43482015-03-04 15:50:27 +01001073 return -EINVAL;
Paul Cercueilca9d3382015-05-04 14:30:09 +02001074 }
Paul Cercueil09a43482015-03-04 15:50:27 +01001075
Paul Cercueile6e5a092015-03-04 16:33:26 +01001076 if (pdata->mmap_addr)
1077 munmap(pdata->mmap_addr, pdata->mmap_len);
Paul Cercueil09a43482015-03-04 15:50:27 +01001078
Paul Cercueile6e5a092015-03-04 16:33:26 +01001079 if (pdata->mmap_addr && pdata->is_tx) {
Paul Cercueil09a43482015-03-04 15:50:27 +01001080 char buf[1024];
Paul Cercueil9c9a5562017-01-24 10:48:31 +01001081
1082 iio_snprintf(buf, sizeof(buf), "WRITEBUF %s %lu\r\n",
Paul Cercueild957b982015-08-05 14:39:01 +02001083 dev->id, (unsigned long) bytes_used);
Paul Cercueil09a43482015-03-04 15:50:27 +01001084
Paul Cercueil388dcd62015-11-27 15:15:48 +01001085 iio_mutex_lock(pdata->lock);
Paul Cercueil09a43482015-03-04 15:50:27 +01001086
Lars-Peter Clausen78067fc2016-02-11 12:48:01 +01001087 ret = write_rwbuf_command(dev, buf);
Paul Cercueil09a43482015-03-04 15:50:27 +01001088 if (ret < 0)
Paul Cercueilca9d3382015-05-04 14:30:09 +02001089 goto err_close_memfd;
Paul Cercueil09a43482015-03-04 15:50:27 +01001090
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +02001091 ret = network_do_splice(pdata, bytes_used, false);
Paul Cercueil09a43482015-03-04 15:50:27 +01001092 if (ret < 0)
Paul Cercueilca9d3382015-05-04 14:30:09 +02001093 goto err_close_memfd;
Paul Cercueil09a43482015-03-04 15:50:27 +01001094
1095 pdata->wait_for_err_code = true;
Paul Cercueil388dcd62015-11-27 15:15:48 +01001096 iio_mutex_unlock(pdata->lock);
Paul Cercueil09a43482015-03-04 15:50:27 +01001097 }
1098
1099 if (pdata->memfd >= 0)
1100 close(pdata->memfd);
1101
Paul Cercueilca9d3382015-05-04 14:30:09 +02001102 pdata->memfd = memfd;
Paul Cercueil09a43482015-03-04 15:50:27 +01001103
Paul Cercueilef32d582015-03-05 11:18:35 +01001104 ret = (ssize_t) ftruncate(pdata->memfd, pdata->mmap_len);
1105 if (ret < 0) {
1106 ret = -errno;
1107 ERROR("Unable to truncate temp file: %zi\n", -ret);
1108 return ret;
1109 }
Paul Cercueil09a43482015-03-04 15:50:27 +01001110
Paul Cercueil04065c22015-03-05 14:08:16 +01001111 if (!pdata->is_tx) {
1112 char buf[1024];
1113 size_t len = pdata->mmap_len;
1114
Paul Cercueil9c9a5562017-01-24 10:48:31 +01001115 iio_snprintf(buf, sizeof(buf), "READBUF %s %lu\r\n",
Paul Cercueil04065c22015-03-05 14:08:16 +01001116 dev->id, (unsigned long) len);
1117
Paul Cercueil388dcd62015-11-27 15:15:48 +01001118 iio_mutex_lock(pdata->lock);
Lars-Peter Clausen78067fc2016-02-11 12:48:01 +01001119 ret = write_rwbuf_command(dev, buf);
Paul Cercueil04065c22015-03-05 14:08:16 +01001120 if (ret < 0)
1121 goto err_unlock;
1122
1123 do {
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +02001124 ret = network_read_mask(&pdata->io_ctx, mask, words);
Paul Cercueil04065c22015-03-05 14:08:16 +01001125 if (!ret)
1126 break;
1127 if (ret < 0)
1128 goto err_unlock;
1129
1130 mask = NULL; /* We read the mask only once */
1131
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +02001132 ret = network_do_splice(pdata, ret, true);
Paul Cercueil04065c22015-03-05 14:08:16 +01001133 if (ret < 0)
1134 goto err_unlock;
1135
1136 read += ret;
1137 len -= ret;
1138 } while (len);
1139
Paul Cercueil388dcd62015-11-27 15:15:48 +01001140 iio_mutex_unlock(pdata->lock);
Paul Cercueil04065c22015-03-05 14:08:16 +01001141 }
Paul Cercueil09a43482015-03-04 15:50:27 +01001142
Paul Cercueile6e5a092015-03-04 16:33:26 +01001143 pdata->mmap_addr = mmap(NULL, pdata->mmap_len,
Paul Cercueil09a43482015-03-04 15:50:27 +01001144 PROT_READ | PROT_WRITE, MAP_SHARED, pdata->memfd, 0);
Paul Cercueile6e5a092015-03-04 16:33:26 +01001145 if (pdata->mmap_addr == MAP_FAILED) {
1146 pdata->mmap_addr = NULL;
Paul Cercueil09a43482015-03-04 15:50:27 +01001147 ret = -errno;
Paul Cercueil7d7e5d32015-03-05 10:51:41 +01001148 ERROR("Unable to mmap: %zi\n", -ret);
Paul Cercueil09a43482015-03-04 15:50:27 +01001149 return ret;
1150 }
1151
Paul Cercueile6e5a092015-03-04 16:33:26 +01001152 *addr_ptr = pdata->mmap_addr;
Paul Cercueil7c3f5d22016-02-18 11:49:04 +01001153 return read ? read : (ssize_t) bytes_used;
Paul Cercueil09a43482015-03-04 15:50:27 +01001154
Paul Cercueilca9d3382015-05-04 14:30:09 +02001155err_close_memfd:
1156 close(memfd);
Paul Cercueil09a43482015-03-04 15:50:27 +01001157err_unlock:
Paul Cercueil388dcd62015-11-27 15:15:48 +01001158 iio_mutex_unlock(pdata->lock);
Paul Cercueil09a43482015-03-04 15:50:27 +01001159 return ret;
1160}
1161#endif
1162
Paul Cercueil99cf3d42014-03-06 12:35:26 +01001163static ssize_t network_read_dev_attr(const struct iio_device *dev,
Matt Fornero81f04a52017-11-30 14:36:37 -05001164 const char *attr, char *dst, size_t len, enum iio_attr_type type)
Paul Cercueil99cf3d42014-03-06 12:35:26 +01001165{
Paul Cercueil2e28d502015-11-30 18:46:49 +01001166 struct iio_context_pdata *pdata = dev->ctx->pdata;
Paul Cercueil5b577762014-06-03 15:31:42 +02001167
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +02001168 return iiod_client_read_attr(pdata->iiod_client,
Matt Fornero81f04a52017-11-30 14:36:37 -05001169 &pdata->io_ctx, dev, NULL, attr, dst, len, type);
Paul Cercueil99cf3d42014-03-06 12:35:26 +01001170}
1171
Paul Cercueil07897d32014-03-06 12:46:08 +01001172static ssize_t network_write_dev_attr(const struct iio_device *dev,
Matt Fornero81f04a52017-11-30 14:36:37 -05001173 const char *attr, const char *src, size_t len, enum iio_attr_type type)
Paul Cercueil07897d32014-03-06 12:46:08 +01001174{
Paul Cercueil2e28d502015-11-30 18:46:49 +01001175 struct iio_context_pdata *pdata = dev->ctx->pdata;
Paul Cercueil5b577762014-06-03 15:31:42 +02001176
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +02001177 return iiod_client_write_attr(pdata->iiod_client,
Matt Fornero81f04a52017-11-30 14:36:37 -05001178 &pdata->io_ctx, dev, NULL, attr, src, len, type);
Paul Cercueil07897d32014-03-06 12:46:08 +01001179}
1180
Paul Cercueil99cf3d42014-03-06 12:35:26 +01001181static ssize_t network_read_chn_attr(const struct iio_channel *chn,
1182 const char *attr, char *dst, size_t len)
1183{
Paul Cercueil2e28d502015-11-30 18:46:49 +01001184 struct iio_context_pdata *pdata = chn->dev->ctx->pdata;
Paul Cercueil5b577762014-06-03 15:31:42 +02001185
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +02001186 return iiod_client_read_attr(pdata->iiod_client,
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +02001187 &pdata->io_ctx, chn->dev, chn, attr, dst, len, false);
Paul Cercueil99cf3d42014-03-06 12:35:26 +01001188}
1189
Paul Cercueil07897d32014-03-06 12:46:08 +01001190static ssize_t network_write_chn_attr(const struct iio_channel *chn,
Paul Cercueilcecda352014-05-06 18:14:29 +02001191 const char *attr, const char *src, size_t len)
Paul Cercueil07897d32014-03-06 12:46:08 +01001192{
Paul Cercueil2e28d502015-11-30 18:46:49 +01001193 struct iio_context_pdata *pdata = chn->dev->ctx->pdata;
Paul Cercueil5b577762014-06-03 15:31:42 +02001194
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +02001195 return iiod_client_write_attr(pdata->iiod_client,
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +02001196 &pdata->io_ctx, chn->dev, chn, attr, src, len, false);
Paul Cercueil07897d32014-03-06 12:46:08 +01001197}
1198
Paul Cercueildcab40c2014-03-11 10:59:14 +01001199static int network_get_trigger(const struct iio_device *dev,
1200 const struct iio_device **trigger)
1201{
1202 struct iio_context_pdata *pdata = dev->ctx->pdata;
Paul Cercueildcab40c2014-03-11 10:59:14 +01001203
Paul Cercueilcae6c2a2015-11-30 16:37:19 +01001204 return iiod_client_get_trigger(pdata->iiod_client,
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +02001205 &pdata->io_ctx, dev, trigger);
Paul Cercueildcab40c2014-03-11 10:59:14 +01001206}
1207
1208static int network_set_trigger(const struct iio_device *dev,
1209 const struct iio_device *trigger)
1210{
Paul Cercueila7b2aae2015-12-04 16:02:00 +01001211 struct iio_context_pdata *pdata = dev->ctx->pdata;
Paul Cercueil1494b862014-05-05 12:49:07 +02001212
Paul Cercueilcae6c2a2015-11-30 16:37:19 +01001213 return iiod_client_set_trigger(pdata->iiod_client,
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +02001214 &pdata->io_ctx, dev, trigger);
Paul Cercueildcab40c2014-03-11 10:59:14 +01001215}
1216
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +01001217static void network_shutdown(struct iio_context *ctx)
1218{
1219 struct iio_context_pdata *pdata = ctx->pdata;
Paul Cercueil44ae11c2014-03-17 09:56:29 +01001220 unsigned int i;
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +01001221
Paul Cercueil388dcd62015-11-27 15:15:48 +01001222 iio_mutex_lock(pdata->lock);
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +02001223 write_command(&pdata->io_ctx, "\r\nEXIT\r\n");
1224 close(pdata->io_ctx.fd);
Paul Cercueil388dcd62015-11-27 15:15:48 +01001225 iio_mutex_unlock(pdata->lock);
Paul Cercueil1494b862014-05-05 12:49:07 +02001226
Paul Cercueil439e1a22015-02-24 13:50:51 +01001227 for (i = 0; i < ctx->nb_devices; i++) {
1228 struct iio_device *dev = ctx->devices[i];
Paul Cercueilc5b00752015-02-24 14:29:53 +01001229 struct iio_device_pdata *dpdata = dev->pdata;
Paul Cercueil439e1a22015-02-24 13:50:51 +01001230
Paul Cercueilc5b00752015-02-24 14:29:53 +01001231 if (dpdata) {
Paul Cercueilaa0db142015-03-04 16:25:24 +01001232 network_close(dev);
Paul Cercueil388dcd62015-11-27 15:15:48 +01001233 iio_mutex_destroy(dpdata->lock);
Paul Cercueilc5b00752015-02-24 14:29:53 +01001234 free(dpdata);
Paul Cercueil439e1a22015-02-24 13:50:51 +01001235 }
1236 }
1237
Paul Cercueil157d43c2015-11-30 15:05:06 +01001238 iiod_client_destroy(pdata->iiod_client);
Paul Cercueil388dcd62015-11-27 15:15:48 +01001239 iio_mutex_destroy(pdata->lock);
Paul Cercueil2dd2c132015-02-24 10:41:01 +01001240 freeaddrinfo(pdata->addrinfo);
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +01001241 free(pdata);
1242}
1243
Paul Cercueil6691a3f2014-05-02 12:32:01 +02001244static int network_get_version(const struct iio_context *ctx,
Paul Cercueil9de9e9d2014-05-20 13:18:19 +02001245 unsigned int *major, unsigned int *minor, char git_tag[8])
Paul Cercueil6691a3f2014-05-02 12:32:01 +02001246{
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +02001247 return iiod_client_get_version(ctx->pdata->iiod_client,
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +02001248 &ctx->pdata->io_ctx, major, minor, git_tag);
Paul Cercueil6691a3f2014-05-02 12:32:01 +02001249}
1250
Paul Cercueil8a266f12014-06-10 16:06:31 +02001251static unsigned int calculate_remote_timeout(unsigned int timeout)
1252{
1253 /* XXX(pcercuei): We currently hardcode timeout / 2 for the backend used
1254 * by the remote. Is there something better to do here? */
1255 return timeout / 2;
1256}
1257
Paul Cercueilbca3dbc2014-06-11 12:00:21 +02001258static int network_set_timeout(struct iio_context *ctx, unsigned int timeout)
1259{
Paul Cercueilf996ae12015-12-03 12:29:13 +01001260 struct iio_context_pdata *pdata = ctx->pdata;
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +02001261 int ret, fd = pdata->io_ctx.fd;
Paul Cercueilf996ae12015-12-03 12:29:13 +01001262
1263 ret = set_socket_timeout(fd, timeout);
Paul Cercueilbca3dbc2014-06-11 12:00:21 +02001264 if (!ret) {
Paul Cercueil6a0eb582016-08-30 10:54:22 +02001265 unsigned int remote_timeout = calculate_remote_timeout(timeout);
1266
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +02001267 ret = iiod_client_set_timeout(pdata->iiod_client,
Paul Cercueil6a0eb582016-08-30 10:54:22 +02001268 &pdata->io_ctx, remote_timeout);
1269 if (!ret)
1270 pdata->io_ctx.timeout_ms = timeout;
Paul Cercueilbca3dbc2014-06-11 12:00:21 +02001271 }
1272 if (ret < 0) {
1273 char buf[1024];
Paul Cercueil53fc4852015-05-22 10:57:53 +02001274 iio_strerror(-ret, buf, sizeof(buf));
Paul Cercueil8a266f12014-06-10 16:06:31 +02001275 WARNING("Unable to set R/W timeout: %s\n", buf);
Paul Cercueil8a266f12014-06-10 16:06:31 +02001276 }
1277 return ret;
1278}
1279
Paul Cercueil61157f92015-11-19 17:48:22 +01001280static int network_set_kernel_buffers_count(const struct iio_device *dev,
1281 unsigned int nb_blocks)
1282{
Paul Cercueila9810a82015-11-30 16:55:07 +01001283 struct iio_context_pdata *pdata = dev->ctx->pdata;
Paul Cercueil61157f92015-11-19 17:48:22 +01001284
Paul Cercueila9810a82015-11-30 16:55:07 +01001285 return iiod_client_set_kernel_buffers_count(pdata->iiod_client,
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +02001286 &pdata->io_ctx, dev, nb_blocks);
Paul Cercueil61157f92015-11-19 17:48:22 +01001287}
1288
Paul Cercueil12d41832014-10-28 14:35:53 +01001289static struct iio_context * network_clone(const struct iio_context *ctx)
1290{
Paul Cercueilf2cc5112017-02-08 12:18:22 +01001291 const char *addr = iio_context_get_attr_value(ctx, "ip,ip-addr");
Paul Cercueil7ef45ce2015-03-16 14:36:16 +01001292
Paul Cercueilf2cc5112017-02-08 12:18:22 +01001293 return iio_create_network_context(addr);
Paul Cercueil12d41832014-10-28 14:35:53 +01001294}
1295
Lars-Peter Clausen09a59d72016-02-03 15:27:04 +01001296static const struct iio_backend_ops network_ops = {
Paul Cercueil12d41832014-10-28 14:35:53 +01001297 .clone = network_clone,
Paul Cercueilba059762014-03-14 11:02:02 +01001298 .open = network_open,
1299 .close = network_close,
Paul Cercueil9945bc82014-03-05 14:07:29 +01001300 .read = network_read,
Paul Cercueil2725f702014-05-02 11:02:16 +02001301 .write = network_write,
Paul Cercueil90189672015-03-16 11:41:53 +01001302#ifdef WITH_NETWORK_GET_BUFFER
Paul Cercueil09a43482015-03-04 15:50:27 +01001303 .get_buffer = network_get_buffer,
1304#endif
Paul Cercueil3e94a5b2014-03-04 13:00:41 +01001305 .read_device_attr = network_read_dev_attr,
1306 .write_device_attr = network_write_dev_attr,
Paul Cercueil99cf3d42014-03-06 12:35:26 +01001307 .read_channel_attr = network_read_chn_attr,
Paul Cercueil07897d32014-03-06 12:46:08 +01001308 .write_channel_attr = network_write_chn_attr,
Paul Cercueildcab40c2014-03-11 10:59:14 +01001309 .get_trigger = network_get_trigger,
1310 .set_trigger = network_set_trigger,
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +01001311 .shutdown = network_shutdown,
Paul Cercueil6691a3f2014-05-02 12:32:01 +02001312 .get_version = network_get_version,
Paul Cercueil8a266f12014-06-10 16:06:31 +02001313 .set_timeout = network_set_timeout,
Paul Cercueil61157f92015-11-19 17:48:22 +01001314 .set_kernel_buffers_count = network_set_kernel_buffers_count,
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +02001315
1316 .cancel = network_cancel,
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001317};
1318
Paul Cercueil157d43c2015-11-30 15:05:06 +01001319static ssize_t network_write_data(struct iio_context_pdata *pdata,
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +02001320 void *io_data, const char *src, size_t len)
Paul Cercueil157d43c2015-11-30 15:05:06 +01001321{
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +02001322 struct iio_network_io_context *io_ctx = io_data;
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +02001323
1324 return network_send(io_ctx, src, len, 0);
Paul Cercueil157d43c2015-11-30 15:05:06 +01001325}
1326
1327static ssize_t network_read_data(struct iio_context_pdata *pdata,
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +02001328 void *io_data, char *dst, size_t len)
Paul Cercueil157d43c2015-11-30 15:05:06 +01001329{
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +02001330 struct iio_network_io_context *io_ctx = io_data;
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +02001331
1332 return network_recv(io_ctx, dst, len, 0);
Paul Cercueil157d43c2015-11-30 15:05:06 +01001333}
1334
1335static ssize_t network_read_line(struct iio_context_pdata *pdata,
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +02001336 void *io_data, char *dst, size_t len)
Paul Cercueil157d43c2015-11-30 15:05:06 +01001337{
Paul Cercueil1cb01fe2016-11-16 16:34:00 +01001338 bool found = false;
Paul Cercueil157d43c2015-11-30 15:05:06 +01001339 size_t i;
Paul Cercueilce02dc92016-01-07 11:46:38 +01001340#ifdef __linux__
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +02001341 struct iio_network_io_context *io_ctx = io_data;
Paul Cercueilce02dc92016-01-07 11:46:38 +01001342 ssize_t ret;
Paul Cercueil1cb01fe2016-11-16 16:34:00 +01001343 size_t bytes_read = 0;
Paul Cercueilce02dc92016-01-07 11:46:38 +01001344
Paul Cercueil1cb01fe2016-11-16 16:34:00 +01001345 do {
1346 size_t to_trunc;
Paul Cercueilce02dc92016-01-07 11:46:38 +01001347
Paul Cercueil1cb01fe2016-11-16 16:34:00 +01001348 ret = network_recv(io_ctx, dst, len, MSG_PEEK);
1349 if (ret < 0)
1350 return ret;
Paul Cercueilce02dc92016-01-07 11:46:38 +01001351
Paul Cercueil1cb01fe2016-11-16 16:34:00 +01001352 /* Lookup for the trailing \n */
1353 for (i = 0; i < (size_t) ret && dst[i] != '\n'; i++);
1354 found = i < (size_t) ret;
1355
1356 len -= ret;
1357 dst += ret;
Paul Cercueil1cb01fe2016-11-16 16:34:00 +01001358
1359 if (found)
1360 to_trunc = i + 1;
1361 else
1362 to_trunc = (size_t) ret;
1363
1364 /* Advance the read offset to the byte following the \n if
1365 * found, or after the last charater read otherwise */
JaredD8cecbe52018-03-10 21:16:51 -08001366 if (pdata->msg_trunc_supported)
1367 ret = network_recv(io_ctx, NULL, to_trunc, MSG_TRUNC);
1368 else
1369 ret = network_recv(io_ctx, dst - ret, to_trunc, 0);
Robin Getzaf161e02020-02-12 10:54:06 -05001370 if (ret < 0) {
1371 ERROR("NETWORK RECV: %zu\n", ret);
Paul Cercueil1cb01fe2016-11-16 16:34:00 +01001372 return ret;
Robin Getzaf161e02020-02-12 10:54:06 -05001373 }
Paul Cercueil1cb01fe2016-11-16 16:34:00 +01001374
1375 bytes_read += to_trunc;
1376 } while (!found && len);
1377
Robin Getzaf161e02020-02-12 10:54:06 -05001378 if (!found) {
1379 ERROR("EIO: %zu\n", ret);
Paul Cercueilce02dc92016-01-07 11:46:38 +01001380 return -EIO;
Robin Getzaf161e02020-02-12 10:54:06 -05001381 } else
Paul Cercueil1cb01fe2016-11-16 16:34:00 +01001382 return bytes_read;
Paul Cercueilce02dc92016-01-07 11:46:38 +01001383#else
Paul Cercueil157d43c2015-11-30 15:05:06 +01001384 for (i = 0; i < len - 1; i++) {
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +02001385 ssize_t ret = network_read_data(pdata, io_data, dst + i, 1);
Paul Cercueil157d43c2015-11-30 15:05:06 +01001386
1387 if (ret < 0)
1388 return ret;
1389
1390 if (dst[i] != '\n')
1391 found = true;
1392 else if (found)
1393 break;
1394 }
1395
Paul Cercueil209def82016-04-08 14:47:59 +02001396 if (!found || i == len - 1)
1397 return -EIO;
1398
1399 return (ssize_t) i + 1;
Paul Cercueilce02dc92016-01-07 11:46:38 +01001400#endif
Paul Cercueil157d43c2015-11-30 15:05:06 +01001401}
1402
Lars-Peter Clausen09a59d72016-02-03 15:27:04 +01001403static const struct iiod_client_ops network_iiod_client_ops = {
Paul Cercueil157d43c2015-11-30 15:05:06 +01001404 .write = network_write_data,
1405 .read = network_read_data,
1406 .read_line = network_read_line,
1407};
1408
JaredD8cecbe52018-03-10 21:16:51 -08001409#ifdef __linux__
1410/*
1411 * As of build 16299, Windows Subsystem for Linux presents a Linux API but
1412 * without support for MSG_TRUNC. Since WSL allows running native Linux
1413 * applications this is not something that can be detected at compile time. If
1414 * we want to support WSL we have to have a runtime workaround.
1415 */
1416static bool msg_trunc_supported(struct iio_network_io_context *io_ctx)
1417{
1418 int ret;
1419
1420 ret = network_recv(io_ctx, NULL, 0, MSG_TRUNC | MSG_DONTWAIT);
1421
1422 return ret != -EFAULT && ret != -EINVAL;
1423}
1424#else
1425static bool msg_trunc_supported(struct iio_network_io_context *io_ctx)
1426{
1427 return false;
1428}
1429#endif
1430
Paul Cercueil63e52182014-12-11 12:52:48 +01001431struct iio_context * network_create_context(const char *host)
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001432{
Paul Cercueil2e38bbe2014-03-19 15:27:15 +01001433 struct addrinfo hints, *res;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001434 struct iio_context *ctx;
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +01001435 struct iio_context_pdata *pdata;
Paul Cercueil0e3c04d2015-05-13 17:37:11 +02001436 size_t i, len;
Paul Cercueil4970ac32015-02-24 10:59:00 +01001437 int fd, ret;
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001438 char *description;
Paul Cercueil1fef1a52014-04-07 16:31:15 +02001439#ifdef _WIN32
1440 WSADATA wsaData;
1441
1442 ret = WSAStartup(MAKEWORD(2, 0), &wsaData);
1443 if (ret < 0) {
1444 ERROR("WSAStartup failed with error %i\n", ret);
Paul Cercueilcc575532015-03-16 17:15:24 +01001445 errno = -ret;
Paul Cercueil1fef1a52014-04-07 16:31:15 +02001446 return NULL;
1447 }
1448#endif
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001449
Paul Cercueil2e38bbe2014-03-19 15:27:15 +01001450 memset(&hints, 0, sizeof(hints));
1451 hints.ai_family = AF_UNSPEC;
1452 hints.ai_socktype = SOCK_STREAM;
Paul Cercueilab114932014-05-19 13:03:17 +02001453
1454#ifdef HAVE_AVAHI
Robin Getzadaf80d2020-01-13 10:25:35 -05001455 if (!host || !host[0]) {
Paul Cercueilab114932014-05-19 13:03:17 +02001456 char addr_str[AVAHI_ADDRESS_STR_MAX];
1457 char port_str[6];
1458 AvahiAddress address;
Paul Cercueil0f729d32014-06-05 17:38:54 +02001459 uint16_t port = IIOD_PORT;
Paul Cercueilab114932014-05-19 13:03:17 +02001460
1461 memset(&address, 0, sizeof(address));
1462
1463 ret = discover_host(&address, &port);
1464 if (ret < 0) {
Lars-Peter Clausen3417a1a2016-04-18 14:29:02 +02001465 char buf[1024];
1466 iio_strerror(-ret, buf, sizeof(buf));
1467 DEBUG("Unable to find host: %s\n", buf);
Paul Cercueilcc575532015-03-16 17:15:24 +01001468 errno = -ret;
Paul Cercueilab114932014-05-19 13:03:17 +02001469 return NULL;
1470 }
1471
1472 avahi_address_snprint(addr_str, sizeof(addr_str), &address);
Paul Cercueil9c9a5562017-01-24 10:48:31 +01001473 iio_snprintf(port_str, sizeof(port_str), "%hu", port);
Paul Cercueilab114932014-05-19 13:03:17 +02001474 ret = getaddrinfo(addr_str, port_str, &hints, &res);
1475 } else
1476#endif
1477 {
1478 ret = getaddrinfo(host, IIOD_PORT_STR, &hints, &res);
1479 }
1480
Paul Cercueil2e38bbe2014-03-19 15:27:15 +01001481 if (ret) {
Paul Cercueilab114932014-05-19 13:03:17 +02001482 ERROR("Unable to find host: %s\n", gai_strerror(ret));
Paul Cercueild9eb4cb2015-03-23 14:30:20 +01001483#ifndef _WIN32
Paul Cercueilcc575532015-03-16 17:15:24 +01001484 if (ret != EAI_SYSTEM)
Paul Cercueil7cc85112016-11-15 14:59:40 +01001485 errno = -ret;
Paul Cercueild9eb4cb2015-03-23 14:30:20 +01001486#endif
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001487 return NULL;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001488 }
1489
Paul Cercueil6a0eb582016-08-30 10:54:22 +02001490 fd = create_socket(res, DEFAULT_TIMEOUT_MS);
Paul Cercueilcc575532015-03-16 17:15:24 +01001491 if (fd < 0) {
Paul Cercueilc3fe6042016-11-16 17:38:56 +01001492 errno = -fd;
Paul Cercueil2dd2c132015-02-24 10:41:01 +01001493 goto err_free_addrinfo;
Paul Cercueilcc575532015-03-16 17:15:24 +01001494 }
Paul Cercueilbca3dbc2014-06-11 12:00:21 +02001495
Lars-Peter Clausend1be8382016-02-24 11:13:45 +01001496 pdata = zalloc(sizeof(*pdata));
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +01001497 if (!pdata) {
Paul Cercueilcc575532015-03-16 17:15:24 +01001498 errno = ENOMEM;
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +01001499 goto err_close_socket;
1500 }
1501
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +02001502 pdata->io_ctx.fd = fd;
Paul Cercueil2dd2c132015-02-24 10:41:01 +01001503 pdata->addrinfo = res;
Paul Cercueil6a0eb582016-08-30 10:54:22 +02001504 pdata->io_ctx.timeout_ms = DEFAULT_TIMEOUT_MS;
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +01001505
Paul Cercueil157d43c2015-11-30 15:05:06 +01001506 pdata->lock = iio_mutex_create();
1507 if (!pdata->lock) {
1508 errno = ENOMEM;
1509 goto err_free_pdata;
1510 }
1511
1512 pdata->iiod_client = iiod_client_new(pdata, pdata->lock,
1513 &network_iiod_client_ops);
JaredD8cecbe52018-03-10 21:16:51 -08001514
1515 pdata->msg_trunc_supported = msg_trunc_supported(&pdata->io_ctx);
1516 if (pdata->msg_trunc_supported)
1517 DEBUG("MSG_TRUNC is supported\n");
1518 else
1519 DEBUG("MSG_TRUNC is NOT supported\n");
1520
Paul Cercueil157d43c2015-11-30 15:05:06 +01001521 if (!pdata->iiod_client)
1522 goto err_destroy_mutex;
1523
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001524 DEBUG("Creating context...\n");
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +02001525 ctx = iiod_client_create_context(pdata->iiod_client, &pdata->io_ctx);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001526 if (!ctx)
Paul Cercueil157d43c2015-11-30 15:05:06 +01001527 goto err_destroy_iiod_client;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001528
Paul Cercueil2057fd32014-10-28 14:44:19 +01001529 /* Override the name and low-level functions of the XML context
1530 * with those corresponding to the network context */
1531 ctx->name = "network";
1532 ctx->ops = &network_ops;
1533 ctx->pdata = pdata;
1534
Paul Cercueil06c479d2015-01-08 16:14:57 +01001535#ifdef HAVE_IPV6
Paul Cercueiled15e492015-01-12 15:52:28 +01001536 len = INET6_ADDRSTRLEN + IF_NAMESIZE + 2;
Paul Cercueil06c479d2015-01-08 16:14:57 +01001537#else
1538 len = INET_ADDRSTRLEN + 1;
1539#endif
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001540
1541 description = malloc(len);
1542 if (!description) {
Paul Cercueilcc575532015-03-16 17:15:24 +01001543 ret = -ENOMEM;
Paul Cercueil06c479d2015-01-08 16:14:57 +01001544 goto err_network_shutdown;
1545 }
1546
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001547 description[0] = '\0';
Paul Cercueil06c479d2015-01-08 16:14:57 +01001548
1549#ifdef HAVE_IPV6
1550 if (res->ai_family == AF_INET6) {
1551 struct sockaddr_in6 *in = (struct sockaddr_in6 *) res->ai_addr;
Paul Cercueiled15e492015-01-12 15:52:28 +01001552 char *ptr;
Paul Cercueil06c479d2015-01-08 16:14:57 +01001553 inet_ntop(AF_INET6, &in->sin6_addr,
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001554 description, INET6_ADDRSTRLEN);
Paul Cercueiled15e492015-01-12 15:52:28 +01001555
Jorik Jonkerbca23462019-07-26 09:32:32 +02001556 if (IN6_IS_ADDR_LINKLOCAL(&in->sin6_addr)) {
1557 ptr = if_indextoname(in->sin6_scope_id, description +
1558 strlen(description) + 1);
1559 if (!ptr) {
1560 ret = -errno;
1561 ERROR("Unable to lookup interface of IPv6 address\n");
1562 goto err_free_description;
1563 }
Paul Cercueiled15e492015-01-12 15:52:28 +01001564
Jorik Jonkerbca23462019-07-26 09:32:32 +02001565 *(ptr - 1) = '%';
1566 }
Paul Cercueil06c479d2015-01-08 16:14:57 +01001567 }
1568#endif
1569 if (res->ai_family == AF_INET) {
1570 struct sockaddr_in *in = (struct sockaddr_in *) res->ai_addr;
Paul Cercueile7a31692015-07-15 10:52:47 +02001571#if (!_WIN32 || _WIN32_WINNT >= 0x600)
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001572 inet_ntop(AF_INET, &in->sin_addr, description, INET_ADDRSTRLEN);
Paul Cercueile7a31692015-07-15 10:52:47 +02001573#else
1574 char *tmp = inet_ntoa(in->sin_addr);
1575 strncpy(description, tmp, len);
1576#endif
Paul Cercueil06c479d2015-01-08 16:14:57 +01001577 }
1578
Paul Cercueil554ef262017-02-08 12:16:57 +01001579 ret = iio_context_add_attr(ctx, "ip,ip-addr", description);
1580 if (ret < 0)
1581 goto err_free_description;
1582
Paul Cercueil44ae11c2014-03-17 09:56:29 +01001583 for (i = 0; i < ctx->nb_devices; i++) {
1584 struct iio_device *dev = ctx->devices[i];
Paul Cercueilff778232014-03-24 14:23:08 +01001585
Lars-Peter Clausend1be8382016-02-24 11:13:45 +01001586 dev->pdata = zalloc(sizeof(*dev->pdata));
Paul Cercueil439e1a22015-02-24 13:50:51 +01001587 if (!dev->pdata) {
Paul Cercueilcc575532015-03-16 17:15:24 +01001588 ret = -ENOMEM;
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001589 goto err_free_description;
Paul Cercueil439e1a22015-02-24 13:50:51 +01001590 }
1591
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +02001592 dev->pdata->io_ctx.fd = -1;
Paul Cercueil6a0eb582016-08-30 10:54:22 +02001593 dev->pdata->io_ctx.timeout_ms = DEFAULT_TIMEOUT_MS;
Paul Cercueil90189672015-03-16 11:41:53 +01001594#ifdef WITH_NETWORK_GET_BUFFER
Paul Cercueil09a43482015-03-04 15:50:27 +01001595 dev->pdata->memfd = -1;
Paul Cercueile6e5a092015-03-04 16:33:26 +01001596#endif
Paul Cercueilc5b00752015-02-24 14:29:53 +01001597
Paul Cercueil388dcd62015-11-27 15:15:48 +01001598 dev->pdata->lock = iio_mutex_create();
1599 if (!dev->pdata->lock) {
1600 ret = -ENOMEM;
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001601 goto err_free_description;
Paul Cercueil388dcd62015-11-27 15:15:48 +01001602 }
Paul Cercueil44ae11c2014-03-17 09:56:29 +01001603 }
1604
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001605 if (ctx->description) {
Paul Cercueil0e3c04d2015-05-13 17:37:11 +02001606 size_t desc_len = strlen(description);
1607 size_t new_size = desc_len + strlen(ctx->description) + 2;
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001608 char *ptr, *new_description = realloc(description, new_size);
Paul Cercueilcc575532015-03-16 17:15:24 +01001609 if (!new_description) {
1610 ret = -ENOMEM;
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001611 goto err_free_description;
Paul Cercueilcc575532015-03-16 17:15:24 +01001612 }
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001613
1614 ptr = strrchr(new_description, '\0');
Paul Cercueil9c9a5562017-01-24 10:48:31 +01001615 iio_snprintf(ptr, new_size - desc_len, " %s", ctx->description);
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001616 free(ctx->description);
1617
1618 ctx->description = new_description;
1619 } else {
1620 ctx->description = description;
1621 }
1622
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +02001623 iiod_client_set_timeout(pdata->iiod_client, &pdata->io_ctx,
Paul Cercueilf996ae12015-12-03 12:29:13 +01001624 calculate_remote_timeout(DEFAULT_TIMEOUT_MS));
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001625 return ctx;
1626
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001627err_free_description:
1628 free(description);
Paul Cercueil44ae11c2014-03-17 09:56:29 +01001629err_network_shutdown:
Paul Cercueil44ae11c2014-03-17 09:56:29 +01001630 iio_context_destroy(ctx);
Paul Cercueilcc575532015-03-16 17:15:24 +01001631 errno = -ret;
Paul Cercueil2057fd32014-10-28 14:44:19 +01001632 return NULL;
Paul Cercueil157d43c2015-11-30 15:05:06 +01001633
1634err_destroy_iiod_client:
1635 iiod_client_destroy(pdata->iiod_client);
1636err_destroy_mutex:
1637 iio_mutex_destroy(pdata->lock);
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +01001638err_free_pdata:
1639 free(pdata);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001640err_close_socket:
1641 close(fd);
Paul Cercueil2dd2c132015-02-24 10:41:01 +01001642err_free_addrinfo:
1643 freeaddrinfo(res);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001644 return NULL;
1645}