blob: c42ea9ca073a0f1499d734bac518a81abf871f29 [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>
Paul Cercueil83628b32014-11-24 11:26:21 +010046#include <sys/select.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
104static int setup_cancel(struct iio_network_io_context *io_ctx)
105{
106 io_ctx->events[0] = WSACreateEvent();
107 if (io_ctx->events[0] == WSA_INVALID_EVENT)
108 return -ENOMEM; /* Pretty much the only error that can happen */
109
110 io_ctx->events[1] = WSACreateEvent();
111 if (io_ctx->events[1] == WSA_INVALID_EVENT) {
112 WSACloseEvent(io_ctx->events[0]);
113 return -ENOMEM;
114 }
115
116 return 0;
117}
118
119static void cleanup_cancel(struct iio_network_io_context *io_ctx)
120{
121 WSACloseEvent(io_ctx->events[0]);
122 WSACloseEvent(io_ctx->events[1]);
123}
124
125static void do_cancel(struct iio_network_io_context *io_ctx)
126{
127 WSASetEvent(io_ctx->events[1]);
128}
129
130static int wait_cancellable(struct iio_network_io_context *io_ctx, bool read)
131{
132 long wsa_events = FD_CLOSE;
133 DWORD ret;
134
135 if (!io_ctx->cancellable)
136 return 0;
137
138 if (read)
139 wsa_events |= FD_READ;
140 else
141 wsa_events |= FD_WRITE;
142
143 WSAEventSelect(io_ctx->fd, NULL, 0);
144 WSAResetEvent(io_ctx->events[0]);
145 WSAEventSelect(io_ctx->fd, io_ctx->events[0], wsa_events);
146
147 ret = WSAWaitForMultipleEvents(2, io_ctx->events, FALSE,
148 WSA_INFINITE, FALSE);
149
150 if (ret == WSA_WAIT_EVENT_0 + 1)
151 return -EBADF;
152
153 return 0;
154}
155
Lars-Peter Clausendd04e6a2016-02-10 14:56:36 +0100156static int network_get_error(void)
157{
158 return -WSAGetLastError();
159}
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200160
161static bool network_should_retry(int err)
162{
Paul Cercueil63a48ed2016-09-01 12:27:46 +0200163 return err == -WSAEWOULDBLOCK || err == -WSAETIMEDOUT;
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200164}
165
Paul Cercueilb419f1e2016-08-31 16:59:57 +0200166static bool network_is_interrupted(int err)
167{
168 return false;
169}
170
Lars-Peter Clausendd04e6a2016-02-10 14:56:36 +0100171#else
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200172
Paul Cercueil7a683272016-08-24 14:50:20 +0200173static int set_blocking_mode(int fd, bool blocking)
174{
175 int ret = fcntl(fd, F_GETFL, 0);
176 if (ret < 0)
177 return -errno;
178
179 if (blocking)
180 ret &= ~O_NONBLOCK;
181 else
182 ret |= O_NONBLOCK;
183
184 ret = fcntl(fd, F_SETFL, ret);
185 return ret < 0 ? -errno : 0;
186}
187
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200188#include <poll.h>
189
190#if defined(WITH_NETWORK_EVENTFD)
191
192#include <sys/eventfd.h>
193
194static int create_cancel_fd(struct iio_network_io_context *io_ctx)
195{
196 io_ctx->cancel_fd[0] = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
197 if (io_ctx->cancel_fd[0] < 0)
198 return -errno;
199 return 0;
200}
201
202static void cleanup_cancel(struct iio_network_io_context *io_ctx)
203{
204 close(io_ctx->cancel_fd[0]);
205}
206
207#define CANCEL_WR_FD 0
208
209#else
210
211static int create_cancel_fd(struct iio_network_io_context *io_ctx)
212{
213 int ret;
214
215#ifdef HAS_PIPE2
216 ret = pipe2(io_ctx->cancel_fd, O_CLOEXEC | O_NONBLOCK);
217 if (ret < 0 && errno != ENOSYS) /* If ENOSYS try pipe() */
218 return -errno;
219#endif
220 ret = pipe(io_ctx->cancel_fd);
221 if (ret < 0)
222 return -errno;
223 ret = set_blocking_mode(io_ctx->cancel_fd[0], false);
224 if (ret < 0)
225 goto err_close;
226 ret = set_blocking_mode(io_ctx->cancel_fd[1], false);
227 if (ret < 0)
228 goto err_close;
229
230 return 0;
231err_close:
232 close(io_ctx->cancel_fd[0]);
233 close(io_ctx->cancel_fd[1]);
234 return ret;
235}
236
237static void cleanup_cancel(struct iio_network_io_context *io_ctx)
238{
239 close(io_ctx->cancel_fd[0]);
240 close(io_ctx->cancel_fd[1]);
241}
242
243#define CANCEL_WR_FD 1
244
245#endif
246
247static int setup_cancel(struct iio_network_io_context *io_ctx)
248{
249 int ret;
250
251 ret = set_blocking_mode(io_ctx->fd, false);
252 if (ret)
253 return ret;
254
255 return create_cancel_fd(io_ctx);
256}
257
258static void do_cancel(struct iio_network_io_context *io_ctx)
259{
260 uint64_t event = 1;
261 int ret;
262
263 ret = write(io_ctx->cancel_fd[CANCEL_WR_FD], &event, sizeof(event));
264 if (ret == -1) {
265 /* If this happens something went very seriously wrong */
266 char err_str[1024];
267 iio_strerror(errno, err_str, sizeof(err_str));
268 ERROR("Unable to signal cancellation event: %s\n", err_str);
269 }
270}
271
272static int wait_cancellable(struct iio_network_io_context *io_ctx, bool read)
273{
274 struct pollfd pfd[2];
275 int ret;
276
277 if (!io_ctx->cancellable)
278 return 0;
279
280 memset(pfd, 0, sizeof(pfd));
281
282 pfd[0].fd = io_ctx->fd;
283 if (read)
284 pfd[0].events = POLLIN;
285 else
286 pfd[0].events = POLLOUT;
287 pfd[1].fd = io_ctx->cancel_fd[0];
288 pfd[1].events = POLLIN;
289
290 do {
Paul Cercueil6a0eb582016-08-30 10:54:22 +0200291 int timeout_ms;
292
293 if (io_ctx->timeout_ms > 0)
294 timeout_ms = (int) io_ctx->timeout_ms;
295 else
296 timeout_ms = -1;
297
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200298 do {
Paul Cercueil6a0eb582016-08-30 10:54:22 +0200299 ret = poll(pfd, 2, timeout_ms);
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200300 } while (ret == -1 && errno == EINTR);
301
302 if (ret == -1)
303 return -errno;
Paul Cercueil6a0eb582016-08-30 10:54:22 +0200304 if (!ret)
Paul Cercueile8e7aca2016-08-31 16:15:13 +0200305 return -EPIPE;
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200306
307 if (pfd[1].revents & POLLIN)
308 return -EBADF;
309 } while (!(pfd[0].revents & (pfd[0].events | POLLERR | POLLHUP)));
310
311 return 0;
312}
313
Lars-Peter Clausendd04e6a2016-02-10 14:56:36 +0100314static int network_get_error(void)
315{
316 return -errno;
317}
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200318
319static bool network_should_retry(int err)
320{
Paul Cercueilb419f1e2016-08-31 16:59:57 +0200321 return err == -EAGAIN;
322}
323
324static bool network_is_interrupted(int err)
325{
326 return err == -EINTR;
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200327}
328
Lars-Peter Clausendd04e6a2016-02-10 14:56:36 +0100329#endif
330
Paul Cercueilab114932014-05-19 13:03:17 +0200331#ifdef HAVE_AVAHI
332struct avahi_discovery_data {
333 AvahiSimplePoll *poll;
334 AvahiAddress *address;
335 uint16_t *port;
336 bool found, resolved;
337};
338
339static void __avahi_resolver_cb(AvahiServiceResolver *resolver,
340 __notused AvahiIfIndex iface, __notused AvahiProtocol proto,
341 __notused AvahiResolverEvent event, __notused const char *name,
342 __notused const char *type, __notused const char *domain,
343 __notused const char *host_name, const AvahiAddress *address,
344 uint16_t port, __notused AvahiStringList *txt,
345 __notused AvahiLookupResultFlags flags, void *d)
346{
347 struct avahi_discovery_data *ddata = (struct avahi_discovery_data *) d;
348
349 memcpy(ddata->address, address, sizeof(*address));
350 *ddata->port = port;
351 ddata->resolved = true;
352 avahi_service_resolver_free(resolver);
353}
354
355static void __avahi_browser_cb(AvahiServiceBrowser *browser,
356 AvahiIfIndex iface, AvahiProtocol proto,
357 AvahiBrowserEvent event, const char *name,
358 const char *type, const char *domain,
359 __notused AvahiLookupResultFlags flags, void *d)
360{
361 struct avahi_discovery_data *ddata = (struct avahi_discovery_data *) d;
362 struct AvahiClient *client = avahi_service_browser_get_client(browser);
363
364 switch (event) {
365 default:
366 case AVAHI_BROWSER_NEW:
367 ddata->found = !!avahi_service_resolver_new(client, iface,
368 proto, name, type, domain,
369 AVAHI_PROTO_UNSPEC, 0,
370 __avahi_resolver_cb, d);
371 break;
372 case AVAHI_BROWSER_ALL_FOR_NOW:
373 if (ddata->found) {
374 while (!ddata->resolved) {
375 struct timespec ts;
376 ts.tv_sec = 0;
377 ts.tv_nsec = 4000000;
378 nanosleep(&ts, NULL);
379 }
380 }
381 case AVAHI_BROWSER_FAILURE: /* fall-through */
382 avahi_simple_poll_quit(ddata->poll);
383 case AVAHI_BROWSER_CACHE_EXHAUSTED: /* fall-through */
384 break;
385 }
386}
387
388static int discover_host(AvahiAddress *addr, uint16_t *port)
389{
390 struct avahi_discovery_data ddata;
391 int ret = 0;
392 AvahiClient *client;
393 AvahiServiceBrowser *browser;
394 AvahiSimplePoll *poll = avahi_simple_poll_new();
395 if (!poll)
396 return -ENOMEM;
397
398 client = avahi_client_new(avahi_simple_poll_get(poll),
399 0, NULL, NULL, &ret);
400 if (!client) {
401 ERROR("Unable to start ZeroConf client :%s\n",
402 avahi_strerror(ret));
403 goto err_free_poll;
404 }
405
406 memset(&ddata, 0, sizeof(ddata));
407 ddata.poll = poll;
408 ddata.address = addr;
409 ddata.port = port;
410
411 browser = avahi_service_browser_new(client,
412 AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
413 "_iio._tcp", NULL, 0, __avahi_browser_cb, &ddata);
414 if (!browser) {
415 ret = avahi_client_errno(client);
416 ERROR("Unable to create ZeroConf browser: %s\n",
417 avahi_strerror(ret));
418 goto err_free_client;
419 }
420
421 DEBUG("Trying to discover host\n");
422 avahi_simple_poll_loop(poll);
423
424 if (!ddata.found)
425 ret = ENXIO;
426
427 avahi_service_browser_free(browser);
428err_free_client:
429 avahi_client_free(client);
430err_free_poll:
431 avahi_simple_poll_free(poll);
432 return -ret; /* we want a negative error code */
433}
434#endif /* HAVE_AVAHI */
435
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200436static ssize_t network_recv(struct iio_network_io_context *io_ctx,
437 void *data, size_t len, int flags)
Lars-Peter Clausen6a6c8662016-02-12 15:35:52 +0100438{
439 ssize_t ret;
440 int err;
441
442 while (1) {
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200443 ret = wait_cancellable(io_ctx, true);
444 if (ret < 0)
445 return ret;
446
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200447 ret = recv(io_ctx->fd, data, (int) len, flags);
Lars-Peter Clausen6a6c8662016-02-12 15:35:52 +0100448 if (ret == 0)
449 return -EPIPE;
450 else if (ret > 0)
451 break;
452
453 err = network_get_error();
Paul Cercueilb419f1e2016-08-31 16:59:57 +0200454 if (network_should_retry(err)) {
455 if (io_ctx->cancellable)
456 continue;
457 else
458 return -EPIPE;
459 } else if (!network_is_interrupted(err)) {
Lars-Peter Clausen6a6c8662016-02-12 15:35:52 +0100460 return (ssize_t) err;
Paul Cercueilb419f1e2016-08-31 16:59:57 +0200461 }
Lars-Peter Clausen6a6c8662016-02-12 15:35:52 +0100462 }
463 return ret;
464}
465
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200466static ssize_t network_send(struct iio_network_io_context *io_ctx,
467 const void *data, size_t len, int flags)
Lars-Peter Clausen6a6c8662016-02-12 15:35:52 +0100468{
469 ssize_t ret;
470 int err;
471
472 while (1) {
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200473 ret = wait_cancellable(io_ctx, false);
474 if (ret < 0)
475 return ret;
476
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200477 ret = send(io_ctx->fd, data, (int) len, flags);
Lars-Peter Clausen6a6c8662016-02-12 15:35:52 +0100478 if (ret == 0)
479 return -EPIPE;
480 else if (ret > 0)
481 break;
482
483 err = network_get_error();
Paul Cercueilb419f1e2016-08-31 16:59:57 +0200484 if (network_should_retry(err)) {
485 if (io_ctx->cancellable)
486 continue;
487 else
488 return -EPIPE;
489 } else if (!network_is_interrupted(err)) {
Lars-Peter Clausen6a6c8662016-02-12 15:35:52 +0100490 return (ssize_t) err;
Paul Cercueilb419f1e2016-08-31 16:59:57 +0200491 }
Lars-Peter Clausen6a6c8662016-02-12 15:35:52 +0100492 }
493
494 return ret;
495}
496
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200497static ssize_t write_all(struct iio_network_io_context *io_ctx,
498 const void *src, size_t len)
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100499{
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200500 uintptr_t ptr = (uintptr_t) src;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100501 while (len) {
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200502 ssize_t ret = network_send(io_ctx, (const void *) ptr, len, 0);
Lars-Peter Clausen27a53e42016-04-13 17:08:07 +0200503 if (ret < 0)
504 return ret;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100505 ptr += ret;
506 len -= ret;
507 }
Paul Cercueil4012cff2015-05-11 10:47:40 +0200508 return (ssize_t)(ptr - (uintptr_t) src);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100509}
510
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200511static ssize_t write_command(struct iio_network_io_context *io_ctx,
512 const char *cmd)
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100513{
514 ssize_t ret;
515
516 DEBUG("Writing command: %s\n", cmd);
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200517 ret = write_all(io_ctx, cmd, strlen(cmd));
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100518 if (ret < 0) {
519 char buf[1024];
Paul Cercueil53fc4852015-05-22 10:57:53 +0200520 iio_strerror(-ret, buf, sizeof(buf));
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100521 ERROR("Unable to send command: %s\n", buf);
522 }
523 return ret;
524}
525
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200526static void network_cancel(const struct iio_device *dev)
527{
528 struct iio_device_pdata *ppdata = dev->pdata;
529
530 do_cancel(&ppdata->io_ctx);
531
532 ppdata->io_ctx.cancelled = true;
533}
534
Paul Cercueil4970ac32015-02-24 10:59:00 +0100535#ifndef _WIN32
Lars-Peter Clausena2cbc812016-02-11 14:49:27 +0100536
537/* Use it if available */
Paul Cercueild454e012016-06-28 15:19:19 +0200538#ifndef SOCK_CLOEXEC
539#define SOCK_CLOEXEC 0
Lars-Peter Clausena2cbc812016-02-11 14:49:27 +0100540#endif
541
Paul Cercueil4970ac32015-02-24 10:59:00 +0100542/* The purpose of this function is to provide a version of connect()
543 * that does not ignore timeouts... */
Lars-Peter Clausen1ca01b72016-02-10 15:10:09 +0100544static int do_connect(const struct addrinfo *addrinfo,
545 struct timeval *timeout)
Paul Cercueil4970ac32015-02-24 10:59:00 +0100546{
547 int ret, error;
548 socklen_t len;
549 fd_set set;
Lars-Peter Clausen1ca01b72016-02-10 15:10:09 +0100550 int fd;
551
Lars-Peter Clausena2cbc812016-02-11 14:49:27 +0100552 fd = socket(addrinfo->ai_family, addrinfo->ai_socktype | SOCK_CLOEXEC, 0);
Lars-Peter Clausen1ca01b72016-02-10 15:10:09 +0100553 if (fd < 0)
554 return -errno;
Paul Cercueil4970ac32015-02-24 10:59:00 +0100555
556 FD_ZERO(&set);
557 FD_SET(fd, &set);
558
559 ret = set_blocking_mode(fd, false);
Lars-Peter Clausenebbd9072016-02-11 15:15:08 +0100560 if (ret < 0) {
561 close(fd);
Paul Cercueil4970ac32015-02-24 10:59:00 +0100562 return ret;
Lars-Peter Clausenebbd9072016-02-11 15:15:08 +0100563 }
Paul Cercueil4970ac32015-02-24 10:59:00 +0100564
Lars-Peter Clausen1ca01b72016-02-10 15:10:09 +0100565 ret = connect(fd, addrinfo->ai_addr, addrinfo->ai_addrlen);
Paul Cercueil4970ac32015-02-24 10:59:00 +0100566 if (ret < 0 && errno != EINPROGRESS) {
567 ret = -errno;
568 goto end;
569 }
570
571 ret = select(fd + 1, &set, &set, NULL, timeout);
572 if (ret < 0) {
573 ret = -errno;
574 goto end;
575 }
576 if (ret == 0) {
577 ret = -ETIMEDOUT;
578 goto end;
579 }
580
581 /* Verify that we don't have an error */
582 len = sizeof(error);
583 ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len);
584 if(ret < 0) {
585 ret = -errno;
586 goto end;
587 }
588 if (error) {
589 ret = -error;
590 goto end;
591 }
592
593end:
594 /* Restore blocking mode */
595 set_blocking_mode(fd, true);
Lars-Peter Clausenebbd9072016-02-11 15:15:08 +0100596 if (ret < 0) {
Lars-Peter Clausen1ca01b72016-02-10 15:10:09 +0100597 close(fd);
Lars-Peter Clausenebbd9072016-02-11 15:15:08 +0100598 return ret;
599 }
600
601 return fd;
Paul Cercueil4970ac32015-02-24 10:59:00 +0100602}
603
604static int set_socket_timeout(int fd, unsigned int timeout)
605{
606 struct timeval tv;
607
608 tv.tv_sec = timeout / 1000;
609 tv.tv_usec = (timeout % 1000) * 1000;
610 if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0 ||
611 setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO,
612 &tv, sizeof(tv)) < 0)
613 return -errno;
614 else
615 return 0;
616}
617#else
Lars-Peter Clausen1ca01b72016-02-10 15:10:09 +0100618
Lars-Peter Clausena2cbc812016-02-11 14:49:27 +0100619/* Use it if available */
620#ifndef WSA_FLAG_NO_HANDLE_INHERIT
621#define WSA_FLAG_NO_HANDLE_INHERIT 0
622#endif
623
Lars-Peter Clausen1ca01b72016-02-10 15:10:09 +0100624static int do_connect(const struct addrinfo *addrinfo,
625 struct timeval *timeout)
626{
627 int ret;
628 SOCKET s;
629
Paul Cercueilba16cea2016-04-18 12:14:58 +0200630 s = WSASocketW(addrinfo->ai_family, addrinfo->ai_socktype, 0, NULL, 0,
Paul Cercueil9dc0a622016-09-01 12:28:30 +0200631 WSA_FLAG_NO_HANDLE_INHERIT | WSA_FLAG_OVERLAPPED);
Lars-Peter Clausen1ca01b72016-02-10 15:10:09 +0100632 if (s == INVALID_SOCKET)
633 return -WSAGetLastError();
634
635 ret = connect(s, addrinfo->ai_addr, (int) addrinfo->ai_addrlen);
636 if (ret == SOCKET_ERROR) {
637 close(s);
638 return -WSAGetLastError();
639 }
640
641 return (int) s;
642}
643
Paul Cercueil4970ac32015-02-24 10:59:00 +0100644static int set_socket_timeout(int fd, unsigned int timeout)
645{
646 if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO,
647 (const char *) &timeout, sizeof(timeout)) < 0 ||
648 setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO,
649 (const char *) &timeout, sizeof(timeout)) < 0)
Paul Cercueil135b3612015-06-30 14:10:14 +0200650 return -WSAGetLastError();
Paul Cercueil4970ac32015-02-24 10:59:00 +0100651 else
652 return 0;
653}
654#endif /* !_WIN32 */
655
Paul Cercueil6a0eb582016-08-30 10:54:22 +0200656static int create_socket(const struct addrinfo *addrinfo, unsigned int timeout)
Paul Cercueil4970ac32015-02-24 10:59:00 +0100657{
Paul Cercueil6a0eb582016-08-30 10:54:22 +0200658 struct timeval tv;
Lars-Peter Clausen828b5482017-03-07 13:50:53 +0100659 struct timeval *ptv;
Paul Cercueilaf3370e2017-02-01 12:14:12 +0100660 int ret, fd, yes = 1;
Paul Cercueil4970ac32015-02-24 10:59:00 +0100661
Lars-Peter Clausen828b5482017-03-07 13:50:53 +0100662 if (timeout != 0) {
663 tv.tv_sec = timeout / 1000;
664 tv.tv_usec = (timeout % 1000) * 1000;
665 ptv = &tv;
666 } else {
667 ptv = NULL;
668 }
Paul Cercueil4970ac32015-02-24 10:59:00 +0100669
Lars-Peter Clausen828b5482017-03-07 13:50:53 +0100670 fd = do_connect(addrinfo, ptv);
Lars-Peter Clausen1ca01b72016-02-10 15:10:09 +0100671 if (fd < 0)
672 return fd;
Paul Cercueil4970ac32015-02-24 10:59:00 +0100673
Lars-Peter Clausen6f127f02017-03-09 15:20:04 +0100674 set_socket_timeout(fd, timeout);
Paul Cercueil32dce822016-12-12 14:51:59 +0100675 if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
Paul Cercueilaf3370e2017-02-01 12:14:12 +0100676 (const char *) &yes, sizeof(yes)) < 0) {
677 ret = -errno;
678 close(fd);
679 return ret;
680 }
Paul Cercueil32dce822016-12-12 14:51:59 +0100681
Paul Cercueil4970ac32015-02-24 10:59:00 +0100682 return fd;
683}
684
Paul Cercueil92f15c22015-04-20 11:36:51 +0200685static int network_open(const struct iio_device *dev,
686 size_t samples_count, bool cyclic)
Paul Cercueilba059762014-03-14 11:02:02 +0100687{
Paul Cercueil439e1a22015-02-24 13:50:51 +0100688 struct iio_context_pdata *pdata = dev->ctx->pdata;
Paul Cercueil80dc1082015-12-01 18:20:31 +0100689 struct iio_device_pdata *ppdata = dev->pdata;
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200690 int ret = -EBUSY;
Paul Cercueilba059762014-03-14 11:02:02 +0100691
Paul Cercueil80dc1082015-12-01 18:20:31 +0100692 iio_mutex_lock(ppdata->lock);
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200693 if (ppdata->io_ctx.fd >= 0)
Paul Cercueil80dc1082015-12-01 18:20:31 +0100694 goto out_mutex_unlock;
Paul Cercueil439e1a22015-02-24 13:50:51 +0100695
Lars-Peter Clausen6f127f02017-03-09 15:20:04 +0100696 ret = create_socket(pdata->addrinfo, DEFAULT_TIMEOUT_MS);
Paul Cercueil80dc1082015-12-01 18:20:31 +0100697 if (ret < 0)
698 goto out_mutex_unlock;
Paul Cercueilba059762014-03-14 11:02:02 +0100699
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200700 ppdata->io_ctx.fd = ret;
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200701 ppdata->io_ctx.cancelled = false;
Lars-Peter Clausen6f127f02017-03-09 15:20:04 +0100702 ppdata->io_ctx.timeout_ms = DEFAULT_TIMEOUT_MS;
703
704 ret = iiod_client_open_unlocked(pdata->iiod_client,
705 &ppdata->io_ctx, dev, samples_count, cyclic);
706 if (ret < 0)
707 goto err_close_socket;
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200708
709 ret = setup_cancel(&ppdata->io_ctx);
710 if (ret < 0)
711 goto err_close_socket;
Paul Cercueilba059762014-03-14 11:02:02 +0100712
Lars-Peter Clausen6f127f02017-03-09 15:20:04 +0100713 set_socket_timeout(ppdata->io_ctx.fd, pdata->io_ctx.timeout_ms);
Paul Cercueil439e1a22015-02-24 13:50:51 +0100714
Lars-Peter Clausen6f127f02017-03-09 15:20:04 +0100715 ppdata->io_ctx.timeout_ms = pdata->io_ctx.timeout_ms;
716 ppdata->io_ctx.cancellable = true;
Paul Cercueil80dc1082015-12-01 18:20:31 +0100717 ppdata->is_tx = iio_device_is_tx(dev);
718 ppdata->is_cyclic = cyclic;
Paul Cercueil80dc1082015-12-01 18:20:31 +0100719 ppdata->wait_for_err_code = false;
Paul Cercueild957b982015-08-05 14:39:01 +0200720#ifdef WITH_NETWORK_GET_BUFFER
Paul Cercueil80dc1082015-12-01 18:20:31 +0100721 ppdata->mmap_len = samples_count * iio_device_get_sample_size(dev);
Paul Cercueild957b982015-08-05 14:39:01 +0200722#endif
Paul Cercueil80dc1082015-12-01 18:20:31 +0100723
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200724 iio_mutex_unlock(ppdata->lock);
725
726 return 0;
727
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200728err_close_socket:
729 close(ppdata->io_ctx.fd);
730 ppdata->io_ctx.fd = -1;
Paul Cercueil80dc1082015-12-01 18:20:31 +0100731out_mutex_unlock:
732 iio_mutex_unlock(ppdata->lock);
733 return ret;
Paul Cercueilba059762014-03-14 11:02:02 +0100734}
735
Lars-Peter Clausen90e75a92016-02-22 11:34:34 +0100736static int network_close(const struct iio_device *dev)
737{
738 struct iio_device_pdata *pdata = dev->pdata;
739 int ret = -EBADF;
740
741 iio_mutex_lock(pdata->lock);
742
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200743 if (pdata->io_ctx.fd >= 0) {
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200744 if (!pdata->io_ctx.cancelled) {
745 ret = iiod_client_close_unlocked(
746 dev->ctx->pdata->iiod_client,
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +0200747 &pdata->io_ctx, dev);
Lars-Peter Clausen90e75a92016-02-22 11:34:34 +0100748
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200749 write_command(&pdata->io_ctx, "\r\nEXIT\r\n");
750 } else {
751 ret = 0;
752 }
Lars-Peter Clausen90e75a92016-02-22 11:34:34 +0100753
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200754 cleanup_cancel(&pdata->io_ctx);
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200755 close(pdata->io_ctx.fd);
756 pdata->io_ctx.fd = -1;
Lars-Peter Clausen90e75a92016-02-22 11:34:34 +0100757 }
758
759#ifdef WITH_NETWORK_GET_BUFFER
760 if (pdata->memfd >= 0)
761 close(pdata->memfd);
762 pdata->memfd = -1;
763
764 if (pdata->mmap_addr) {
765 munmap(pdata->mmap_addr, pdata->mmap_len);
766 pdata->mmap_addr = NULL;
767 }
768#endif
769
770 iio_mutex_unlock(pdata->lock);
771 return ret;
772}
773
774static ssize_t network_read(const struct iio_device *dev, void *dst, size_t len,
775 uint32_t *mask, size_t words)
776{
777 struct iio_device_pdata *pdata = dev->pdata;
778 ssize_t ret;
779
780 iio_mutex_lock(pdata->lock);
781 ret = iiod_client_read_unlocked(dev->ctx->pdata->iiod_client,
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +0200782 &pdata->io_ctx, dev, dst, len, mask, words);
Lars-Peter Clausen90e75a92016-02-22 11:34:34 +0100783 iio_mutex_unlock(pdata->lock);
784
785 return ret;
786}
787
788static ssize_t network_write(const struct iio_device *dev,
789 const void *src, size_t len)
790{
791 struct iio_device_pdata *pdata = dev->pdata;
792 ssize_t ret;
793
794 iio_mutex_lock(pdata->lock);
795 ret = iiod_client_write_unlocked(dev->ctx->pdata->iiod_client,
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +0200796 &pdata->io_ctx, dev, src, len);
Lars-Peter Clausen90e75a92016-02-22 11:34:34 +0100797 iio_mutex_unlock(pdata->lock);
798
799 return ret;
800}
801
802#ifdef WITH_NETWORK_GET_BUFFER
803
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200804static ssize_t read_all(struct iio_network_io_context *io_ctx,
805 void *dst, size_t len)
Lars-Peter Clausen90e75a92016-02-22 11:34:34 +0100806{
807 uintptr_t ptr = (uintptr_t) dst;
808 while (len) {
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200809 ssize_t ret = network_recv(io_ctx, (void *) ptr, len, 0);
Lars-Peter Clausen90e75a92016-02-22 11:34:34 +0100810 if (ret < 0)
811 return ret;
812 ptr += ret;
813 len -= ret;
814 }
815 return (ssize_t)(ptr - (uintptr_t) dst);
816}
817
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200818static int read_integer(struct iio_network_io_context *io_ctx, long *val)
Lars-Peter Clausen90e75a92016-02-22 11:34:34 +0100819{
820 unsigned int i;
821 char buf[1024], *ptr;
822 ssize_t ret;
823 bool found = false;
824
825 for (i = 0; i < sizeof(buf) - 1; i++) {
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200826 ret = read_all(io_ctx, buf + i, 1);
Lars-Peter Clausen90e75a92016-02-22 11:34:34 +0100827 if (ret < 0)
828 return (int) ret;
829
830 /* Skip the eventual first few carriage returns.
831 * Also stop when a dot is found (for parsing floats) */
832 if (buf[i] != '\n' && buf[i] != '.')
833 found = true;
834 else if (found)
835 break;
836 }
837
838 buf[i] = '\0';
839 ret = (ssize_t) strtol(buf, &ptr, 10);
840 if (ptr == buf)
841 return -EINVAL;
842 *val = (long) ret;
843 return 0;
844}
845
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200846static ssize_t network_read_mask(struct iio_network_io_context *io_ctx,
847 uint32_t *mask, size_t words)
Lars-Peter Clausen90e75a92016-02-22 11:34:34 +0100848{
849 long read_len;
850 ssize_t ret;
851
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200852 ret = read_integer(io_ctx, &read_len);
Lars-Peter Clausen90e75a92016-02-22 11:34:34 +0100853 if (ret < 0)
854 return ret;
855
856 if (read_len > 0 && mask) {
857 size_t i;
858 char buf[9];
859
860 buf[8] = '\0';
861 DEBUG("Reading mask\n");
862
863 for (i = words; i > 0; i--) {
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200864 ret = read_all(io_ctx, buf, 8);
Lars-Peter Clausen90e75a92016-02-22 11:34:34 +0100865 if (ret < 0)
866 return ret;
867
868 sscanf(buf, "%08x", &mask[i - 1]);
Paul Cercueilb133a0c2016-04-18 11:57:50 +0200869 DEBUG("mask[%lu] = 0x%x\n",
870 (unsigned long)(i - 1), mask[i - 1]);
Lars-Peter Clausen90e75a92016-02-22 11:34:34 +0100871 }
872 }
873
874 if (read_len > 0) {
875 char c;
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200876 ssize_t nb = read_all(io_ctx, &c, 1);
Lars-Peter Clausen90e75a92016-02-22 11:34:34 +0100877 if (nb > 0 && c != '\n')
878 read_len = -EIO;
879 }
880
881 return (ssize_t) read_len;
882}
883
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200884static ssize_t read_error_code(struct iio_network_io_context *io_ctx)
Paul Cercueil8f7f6c42015-02-24 15:00:35 +0100885{
886 /*
887 * The server returns two integer codes.
888 * The first one is returned right after the WRITEBUF command is issued,
889 * and corresponds to the error code returned when the server attempted
890 * to open the device.
891 * If zero, a second error code is returned, that corresponds (if positive)
892 * to the number of bytes written.
893 *
894 * To speed up things, we delay error reporting. We just send out the
895 * data without reading the error code that the server gives us, because
896 * the answer will take too much time. If an error occured, it will be
897 * reported by the next call to iio_buffer_push().
898 */
899
900 unsigned int i;
901 long resp = 0;
902
903 for (i = 0; i < 2; i++) {
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200904 ssize_t ret = read_integer(io_ctx, &resp);
Paul Cercueil8f7f6c42015-02-24 15:00:35 +0100905 if (ret < 0)
906 return ret;
907 if (resp < 0)
908 return (ssize_t) resp;
909 }
910
Paul Cercueil7d7e5d32015-03-05 10:51:41 +0100911 return (ssize_t) resp;
Paul Cercueil8f7f6c42015-02-24 15:00:35 +0100912}
913
Paul Cercueil3c0da372015-03-05 11:36:39 +0100914static ssize_t write_rwbuf_command(const struct iio_device *dev,
Lars-Peter Clausen2e380822016-02-11 20:36:13 +0100915 const char *cmd)
Paul Cercueil3c0da372015-03-05 11:36:39 +0100916{
917 struct iio_device_pdata *pdata = dev->pdata;
Paul Cercueil3c0da372015-03-05 11:36:39 +0100918
919 if (pdata->wait_for_err_code) {
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200920 ssize_t ret = read_error_code(&pdata->io_ctx);
Paul Cercueil3c0da372015-03-05 11:36:39 +0100921
922 pdata->wait_for_err_code = false;
923 if (ret < 0)
924 return ret;
925 }
926
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +0200927 return write_command(&pdata->io_ctx, cmd);
Paul Cercueil3c0da372015-03-05 11:36:39 +0100928}
929
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200930static ssize_t network_do_splice(struct iio_device_pdata *pdata, size_t len,
931 bool read)
Paul Cercueil09a43482015-03-04 15:50:27 +0100932{
933 int pipefd[2];
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200934 int fd_in, fd_out;
Lars-Peter Clausenf83877e2016-10-26 18:20:06 +0200935 ssize_t ret, read_len = len, write_len = 0;
Paul Cercueil09a43482015-03-04 15:50:27 +0100936
Lars-Peter Clausena2cbc812016-02-11 14:49:27 +0100937 ret = (ssize_t) pipe2(pipefd, O_CLOEXEC);
Paul Cercueil09a43482015-03-04 15:50:27 +0100938 if (ret < 0)
939 return -errno;
940
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200941 if (read) {
942 fd_in = pdata->io_ctx.fd;
943 fd_out = pdata->memfd;
944 } else {
945 fd_in = pdata->memfd;
946 fd_out = pdata->io_ctx.fd;
947 }
948
Paul Cercueil09a43482015-03-04 15:50:27 +0100949 do {
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +0200950 ret = wait_cancellable(&pdata->io_ctx, read);
951 if (ret < 0)
952 goto err_close_pipe;
953
Lars-Peter Clausenf83877e2016-10-26 18:20:06 +0200954 if (read_len) {
955 /*
956 * SPLICE_F_NONBLOCK is just here to avoid a deadlock when
957 * splicing from a socket. As the socket is not in
958 * non-blocking mode, it should never return -EAGAIN.
959 * TODO(pcercuei): Find why it locks...
960 * */
961 ret = splice(fd_in, NULL, pipefd[1], NULL, read_len,
962 SPLICE_F_MOVE | SPLICE_F_NONBLOCK);
963 if (!ret)
964 ret = -EIO;
965 if (ret < 0 && errno != EAGAIN) {
966 ret = -errno;
967 goto err_close_pipe;
968 } else if (ret > 0) {
969 write_len += ret;
970 read_len -= ret;
971 }
Lars-Peter Clausen7247b922016-10-26 18:34:23 +0200972 }
Paul Cercueil09a43482015-03-04 15:50:27 +0100973
Lars-Peter Clausenf83877e2016-10-26 18:20:06 +0200974 if (write_len) {
975 ret = splice(pipefd[0], NULL, fd_out, NULL, write_len,
976 SPLICE_F_MOVE | SPLICE_F_NONBLOCK);
977 if (!ret)
978 ret = -EIO;
979 if (ret < 0 && errno != EAGAIN) {
980 ret = -errno;
981 goto err_close_pipe;
982 } else if (ret > 0) {
983 write_len -= ret;
984 }
Lars-Peter Clausen7247b922016-10-26 18:34:23 +0200985 }
Paul Cercueil09a43482015-03-04 15:50:27 +0100986
Lars-Peter Clausenf83877e2016-10-26 18:20:06 +0200987 } while (write_len || read_len);
Paul Cercueil09a43482015-03-04 15:50:27 +0100988
989err_close_pipe:
990 close(pipefd[0]);
991 close(pipefd[1]);
Lars-Peter Clausenf83877e2016-10-26 18:20:06 +0200992 return ret < 0 ? ret : len;
Paul Cercueil09a43482015-03-04 15:50:27 +0100993}
994
995static ssize_t network_get_buffer(const struct iio_device *dev,
Paul Cercueil76ca8842015-03-05 11:16:16 +0100996 void **addr_ptr, size_t bytes_used,
997 uint32_t *mask, size_t words)
Paul Cercueil09a43482015-03-04 15:50:27 +0100998{
999 struct iio_device_pdata *pdata = dev->pdata;
Paul Cercueil04065c22015-03-05 14:08:16 +01001000 ssize_t ret, read = 0;
Paul Cercueilca9d3382015-05-04 14:30:09 +02001001 int memfd;
Paul Cercueil09a43482015-03-04 15:50:27 +01001002
Paul Cercueil04065c22015-03-05 14:08:16 +01001003 if (pdata->is_cyclic)
Paul Cercueil09a43482015-03-04 15:50:27 +01001004 return -ENOSYS;
Paul Cercueilca9d3382015-05-04 14:30:09 +02001005
1006 /* We check early that the temporary file can be created, so that we can
1007 * return -ENOSYS in case it fails, which will indicate that the
1008 * high-speed interface is not available.
1009 *
1010 * O_TMPFILE -> Linux 3.11.
1011 * TODO: use memfd_create (Linux 3.17) */
Lars-Peter Clausena2cbc812016-02-11 14:49:27 +01001012 memfd = open(P_tmpdir, O_RDWR | O_TMPFILE | O_EXCL | O_CLOEXEC, S_IRWXU);
Paul Cercueilca9d3382015-05-04 14:30:09 +02001013 if (memfd < 0)
1014 return -ENOSYS;
1015
1016 if (!addr_ptr || words != (dev->nb_channels + 31) / 32) {
1017 close(memfd);
Paul Cercueil09a43482015-03-04 15:50:27 +01001018 return -EINVAL;
Paul Cercueilca9d3382015-05-04 14:30:09 +02001019 }
Paul Cercueil09a43482015-03-04 15:50:27 +01001020
Paul Cercueile6e5a092015-03-04 16:33:26 +01001021 if (pdata->mmap_addr)
1022 munmap(pdata->mmap_addr, pdata->mmap_len);
Paul Cercueil09a43482015-03-04 15:50:27 +01001023
Paul Cercueile6e5a092015-03-04 16:33:26 +01001024 if (pdata->mmap_addr && pdata->is_tx) {
Paul Cercueil09a43482015-03-04 15:50:27 +01001025 char buf[1024];
Paul Cercueil9c9a5562017-01-24 10:48:31 +01001026
1027 iio_snprintf(buf, sizeof(buf), "WRITEBUF %s %lu\r\n",
Paul Cercueild957b982015-08-05 14:39:01 +02001028 dev->id, (unsigned long) bytes_used);
Paul Cercueil09a43482015-03-04 15:50:27 +01001029
Paul Cercueil388dcd62015-11-27 15:15:48 +01001030 iio_mutex_lock(pdata->lock);
Paul Cercueil09a43482015-03-04 15:50:27 +01001031
Lars-Peter Clausen78067fc2016-02-11 12:48:01 +01001032 ret = write_rwbuf_command(dev, buf);
Paul Cercueil09a43482015-03-04 15:50:27 +01001033 if (ret < 0)
Paul Cercueilca9d3382015-05-04 14:30:09 +02001034 goto err_close_memfd;
Paul Cercueil09a43482015-03-04 15:50:27 +01001035
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +02001036 ret = network_do_splice(pdata, bytes_used, false);
Paul Cercueil09a43482015-03-04 15:50:27 +01001037 if (ret < 0)
Paul Cercueilca9d3382015-05-04 14:30:09 +02001038 goto err_close_memfd;
Paul Cercueil09a43482015-03-04 15:50:27 +01001039
1040 pdata->wait_for_err_code = true;
Paul Cercueil388dcd62015-11-27 15:15:48 +01001041 iio_mutex_unlock(pdata->lock);
Paul Cercueil09a43482015-03-04 15:50:27 +01001042 }
1043
1044 if (pdata->memfd >= 0)
1045 close(pdata->memfd);
1046
Paul Cercueilca9d3382015-05-04 14:30:09 +02001047 pdata->memfd = memfd;
Paul Cercueil09a43482015-03-04 15:50:27 +01001048
Paul Cercueilef32d582015-03-05 11:18:35 +01001049 ret = (ssize_t) ftruncate(pdata->memfd, pdata->mmap_len);
1050 if (ret < 0) {
1051 ret = -errno;
1052 ERROR("Unable to truncate temp file: %zi\n", -ret);
1053 return ret;
1054 }
Paul Cercueil09a43482015-03-04 15:50:27 +01001055
Paul Cercueil04065c22015-03-05 14:08:16 +01001056 if (!pdata->is_tx) {
1057 char buf[1024];
1058 size_t len = pdata->mmap_len;
1059
Paul Cercueil9c9a5562017-01-24 10:48:31 +01001060 iio_snprintf(buf, sizeof(buf), "READBUF %s %lu\r\n",
Paul Cercueil04065c22015-03-05 14:08:16 +01001061 dev->id, (unsigned long) len);
1062
Paul Cercueil388dcd62015-11-27 15:15:48 +01001063 iio_mutex_lock(pdata->lock);
Lars-Peter Clausen78067fc2016-02-11 12:48:01 +01001064 ret = write_rwbuf_command(dev, buf);
Paul Cercueil04065c22015-03-05 14:08:16 +01001065 if (ret < 0)
1066 goto err_unlock;
1067
1068 do {
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +02001069 ret = network_read_mask(&pdata->io_ctx, mask, words);
Paul Cercueil04065c22015-03-05 14:08:16 +01001070 if (!ret)
1071 break;
1072 if (ret < 0)
1073 goto err_unlock;
1074
1075 mask = NULL; /* We read the mask only once */
1076
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +02001077 ret = network_do_splice(pdata, ret, true);
Paul Cercueil04065c22015-03-05 14:08:16 +01001078 if (ret < 0)
1079 goto err_unlock;
1080
1081 read += ret;
1082 len -= ret;
1083 } while (len);
1084
Paul Cercueil388dcd62015-11-27 15:15:48 +01001085 iio_mutex_unlock(pdata->lock);
Paul Cercueil04065c22015-03-05 14:08:16 +01001086 }
Paul Cercueil09a43482015-03-04 15:50:27 +01001087
Paul Cercueile6e5a092015-03-04 16:33:26 +01001088 pdata->mmap_addr = mmap(NULL, pdata->mmap_len,
Paul Cercueil09a43482015-03-04 15:50:27 +01001089 PROT_READ | PROT_WRITE, MAP_SHARED, pdata->memfd, 0);
Paul Cercueile6e5a092015-03-04 16:33:26 +01001090 if (pdata->mmap_addr == MAP_FAILED) {
1091 pdata->mmap_addr = NULL;
Paul Cercueil09a43482015-03-04 15:50:27 +01001092 ret = -errno;
Paul Cercueil7d7e5d32015-03-05 10:51:41 +01001093 ERROR("Unable to mmap: %zi\n", -ret);
Paul Cercueil09a43482015-03-04 15:50:27 +01001094 return ret;
1095 }
1096
Paul Cercueile6e5a092015-03-04 16:33:26 +01001097 *addr_ptr = pdata->mmap_addr;
Paul Cercueil7c3f5d22016-02-18 11:49:04 +01001098 return read ? read : (ssize_t) bytes_used;
Paul Cercueil09a43482015-03-04 15:50:27 +01001099
Paul Cercueilca9d3382015-05-04 14:30:09 +02001100err_close_memfd:
1101 close(memfd);
Paul Cercueil09a43482015-03-04 15:50:27 +01001102err_unlock:
Paul Cercueil388dcd62015-11-27 15:15:48 +01001103 iio_mutex_unlock(pdata->lock);
Paul Cercueil09a43482015-03-04 15:50:27 +01001104 return ret;
1105}
1106#endif
1107
Paul Cercueil99cf3d42014-03-06 12:35:26 +01001108static ssize_t network_read_dev_attr(const struct iio_device *dev,
Paul Cercueil50c762a2014-04-14 15:55:43 +02001109 const char *attr, char *dst, size_t len, bool is_debug)
Paul Cercueil99cf3d42014-03-06 12:35:26 +01001110{
Paul Cercueil2e28d502015-11-30 18:46:49 +01001111 struct iio_context_pdata *pdata = dev->ctx->pdata;
Paul Cercueil5b577762014-06-03 15:31:42 +02001112
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +02001113 return iiod_client_read_attr(pdata->iiod_client,
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +02001114 &pdata->io_ctx, dev, NULL, attr, dst, len, is_debug);
Paul Cercueil99cf3d42014-03-06 12:35:26 +01001115}
1116
Paul Cercueil07897d32014-03-06 12:46:08 +01001117static ssize_t network_write_dev_attr(const struct iio_device *dev,
Paul Cercueilcecda352014-05-06 18:14:29 +02001118 const char *attr, const char *src, size_t len, bool is_debug)
Paul Cercueil07897d32014-03-06 12:46:08 +01001119{
Paul Cercueil2e28d502015-11-30 18:46:49 +01001120 struct iio_context_pdata *pdata = dev->ctx->pdata;
Paul Cercueil5b577762014-06-03 15:31:42 +02001121
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +02001122 return iiod_client_write_attr(pdata->iiod_client,
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +02001123 &pdata->io_ctx, dev, NULL, attr, src, len, is_debug);
Paul Cercueil07897d32014-03-06 12:46:08 +01001124}
1125
Paul Cercueil99cf3d42014-03-06 12:35:26 +01001126static ssize_t network_read_chn_attr(const struct iio_channel *chn,
1127 const char *attr, char *dst, size_t len)
1128{
Paul Cercueil2e28d502015-11-30 18:46:49 +01001129 struct iio_context_pdata *pdata = chn->dev->ctx->pdata;
Paul Cercueil5b577762014-06-03 15:31:42 +02001130
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +02001131 return iiod_client_read_attr(pdata->iiod_client,
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +02001132 &pdata->io_ctx, chn->dev, chn, attr, dst, len, false);
Paul Cercueil99cf3d42014-03-06 12:35:26 +01001133}
1134
Paul Cercueil07897d32014-03-06 12:46:08 +01001135static ssize_t network_write_chn_attr(const struct iio_channel *chn,
Paul Cercueilcecda352014-05-06 18:14:29 +02001136 const char *attr, const char *src, size_t len)
Paul Cercueil07897d32014-03-06 12:46:08 +01001137{
Paul Cercueil2e28d502015-11-30 18:46:49 +01001138 struct iio_context_pdata *pdata = chn->dev->ctx->pdata;
Paul Cercueil5b577762014-06-03 15:31:42 +02001139
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +02001140 return iiod_client_write_attr(pdata->iiod_client,
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +02001141 &pdata->io_ctx, chn->dev, chn, attr, src, len, false);
Paul Cercueil07897d32014-03-06 12:46:08 +01001142}
1143
Paul Cercueildcab40c2014-03-11 10:59:14 +01001144static int network_get_trigger(const struct iio_device *dev,
1145 const struct iio_device **trigger)
1146{
1147 struct iio_context_pdata *pdata = dev->ctx->pdata;
Paul Cercueildcab40c2014-03-11 10:59:14 +01001148
Paul Cercueilcae6c2a2015-11-30 16:37:19 +01001149 return iiod_client_get_trigger(pdata->iiod_client,
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +02001150 &pdata->io_ctx, dev, trigger);
Paul Cercueildcab40c2014-03-11 10:59:14 +01001151}
1152
1153static int network_set_trigger(const struct iio_device *dev,
1154 const struct iio_device *trigger)
1155{
Paul Cercueila7b2aae2015-12-04 16:02:00 +01001156 struct iio_context_pdata *pdata = dev->ctx->pdata;
Paul Cercueil1494b862014-05-05 12:49:07 +02001157
Paul Cercueilcae6c2a2015-11-30 16:37:19 +01001158 return iiod_client_set_trigger(pdata->iiod_client,
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +02001159 &pdata->io_ctx, dev, trigger);
Paul Cercueildcab40c2014-03-11 10:59:14 +01001160}
1161
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +01001162static void network_shutdown(struct iio_context *ctx)
1163{
1164 struct iio_context_pdata *pdata = ctx->pdata;
Paul Cercueil44ae11c2014-03-17 09:56:29 +01001165 unsigned int i;
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +01001166
Paul Cercueil388dcd62015-11-27 15:15:48 +01001167 iio_mutex_lock(pdata->lock);
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +02001168 write_command(&pdata->io_ctx, "\r\nEXIT\r\n");
1169 close(pdata->io_ctx.fd);
Paul Cercueil388dcd62015-11-27 15:15:48 +01001170 iio_mutex_unlock(pdata->lock);
Paul Cercueil1494b862014-05-05 12:49:07 +02001171
Paul Cercueil439e1a22015-02-24 13:50:51 +01001172 for (i = 0; i < ctx->nb_devices; i++) {
1173 struct iio_device *dev = ctx->devices[i];
Paul Cercueilc5b00752015-02-24 14:29:53 +01001174 struct iio_device_pdata *dpdata = dev->pdata;
Paul Cercueil439e1a22015-02-24 13:50:51 +01001175
Paul Cercueilc5b00752015-02-24 14:29:53 +01001176 if (dpdata) {
Paul Cercueilaa0db142015-03-04 16:25:24 +01001177 network_close(dev);
Paul Cercueil388dcd62015-11-27 15:15:48 +01001178 iio_mutex_destroy(dpdata->lock);
Paul Cercueilc5b00752015-02-24 14:29:53 +01001179 free(dpdata);
Paul Cercueil439e1a22015-02-24 13:50:51 +01001180 }
1181 }
1182
Paul Cercueil157d43c2015-11-30 15:05:06 +01001183 iiod_client_destroy(pdata->iiod_client);
Paul Cercueil388dcd62015-11-27 15:15:48 +01001184 iio_mutex_destroy(pdata->lock);
Paul Cercueil2dd2c132015-02-24 10:41:01 +01001185 freeaddrinfo(pdata->addrinfo);
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +01001186 free(pdata);
1187}
1188
Paul Cercueil6691a3f2014-05-02 12:32:01 +02001189static int network_get_version(const struct iio_context *ctx,
Paul Cercueil9de9e9d2014-05-20 13:18:19 +02001190 unsigned int *major, unsigned int *minor, char git_tag[8])
Paul Cercueil6691a3f2014-05-02 12:32:01 +02001191{
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +02001192 return iiod_client_get_version(ctx->pdata->iiod_client,
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +02001193 &ctx->pdata->io_ctx, major, minor, git_tag);
Paul Cercueil6691a3f2014-05-02 12:32:01 +02001194}
1195
Paul Cercueil8a266f12014-06-10 16:06:31 +02001196static unsigned int calculate_remote_timeout(unsigned int timeout)
1197{
1198 /* XXX(pcercuei): We currently hardcode timeout / 2 for the backend used
1199 * by the remote. Is there something better to do here? */
1200 return timeout / 2;
1201}
1202
Paul Cercueilbca3dbc2014-06-11 12:00:21 +02001203static int network_set_timeout(struct iio_context *ctx, unsigned int timeout)
1204{
Paul Cercueilf996ae12015-12-03 12:29:13 +01001205 struct iio_context_pdata *pdata = ctx->pdata;
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +02001206 int ret, fd = pdata->io_ctx.fd;
Paul Cercueilf996ae12015-12-03 12:29:13 +01001207
1208 ret = set_socket_timeout(fd, timeout);
Paul Cercueilbca3dbc2014-06-11 12:00:21 +02001209 if (!ret) {
Paul Cercueil6a0eb582016-08-30 10:54:22 +02001210 unsigned int remote_timeout = calculate_remote_timeout(timeout);
1211
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +02001212 ret = iiod_client_set_timeout(pdata->iiod_client,
Paul Cercueil6a0eb582016-08-30 10:54:22 +02001213 &pdata->io_ctx, remote_timeout);
1214 if (!ret)
1215 pdata->io_ctx.timeout_ms = timeout;
Paul Cercueilbca3dbc2014-06-11 12:00:21 +02001216 }
1217 if (ret < 0) {
1218 char buf[1024];
Paul Cercueil53fc4852015-05-22 10:57:53 +02001219 iio_strerror(-ret, buf, sizeof(buf));
Paul Cercueil8a266f12014-06-10 16:06:31 +02001220 WARNING("Unable to set R/W timeout: %s\n", buf);
Paul Cercueil8a266f12014-06-10 16:06:31 +02001221 }
1222 return ret;
1223}
1224
Paul Cercueil61157f92015-11-19 17:48:22 +01001225static int network_set_kernel_buffers_count(const struct iio_device *dev,
1226 unsigned int nb_blocks)
1227{
Paul Cercueila9810a82015-11-30 16:55:07 +01001228 struct iio_context_pdata *pdata = dev->ctx->pdata;
Paul Cercueil61157f92015-11-19 17:48:22 +01001229
Paul Cercueila9810a82015-11-30 16:55:07 +01001230 return iiod_client_set_kernel_buffers_count(pdata->iiod_client,
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +02001231 &pdata->io_ctx, dev, nb_blocks);
Paul Cercueil61157f92015-11-19 17:48:22 +01001232}
1233
Paul Cercueil12d41832014-10-28 14:35:53 +01001234static struct iio_context * network_clone(const struct iio_context *ctx)
1235{
Paul Cercueilf2cc5112017-02-08 12:18:22 +01001236 const char *addr = iio_context_get_attr_value(ctx, "ip,ip-addr");
Paul Cercueil7ef45ce2015-03-16 14:36:16 +01001237
Paul Cercueilf2cc5112017-02-08 12:18:22 +01001238 return iio_create_network_context(addr);
Paul Cercueil12d41832014-10-28 14:35:53 +01001239}
1240
Lars-Peter Clausen09a59d72016-02-03 15:27:04 +01001241static const struct iio_backend_ops network_ops = {
Paul Cercueil12d41832014-10-28 14:35:53 +01001242 .clone = network_clone,
Paul Cercueilba059762014-03-14 11:02:02 +01001243 .open = network_open,
1244 .close = network_close,
Paul Cercueil9945bc82014-03-05 14:07:29 +01001245 .read = network_read,
Paul Cercueil2725f702014-05-02 11:02:16 +02001246 .write = network_write,
Paul Cercueil90189672015-03-16 11:41:53 +01001247#ifdef WITH_NETWORK_GET_BUFFER
Paul Cercueil09a43482015-03-04 15:50:27 +01001248 .get_buffer = network_get_buffer,
1249#endif
Paul Cercueil3e94a5b2014-03-04 13:00:41 +01001250 .read_device_attr = network_read_dev_attr,
1251 .write_device_attr = network_write_dev_attr,
Paul Cercueil99cf3d42014-03-06 12:35:26 +01001252 .read_channel_attr = network_read_chn_attr,
Paul Cercueil07897d32014-03-06 12:46:08 +01001253 .write_channel_attr = network_write_chn_attr,
Paul Cercueildcab40c2014-03-11 10:59:14 +01001254 .get_trigger = network_get_trigger,
1255 .set_trigger = network_set_trigger,
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +01001256 .shutdown = network_shutdown,
Paul Cercueil6691a3f2014-05-02 12:32:01 +02001257 .get_version = network_get_version,
Paul Cercueil8a266f12014-06-10 16:06:31 +02001258 .set_timeout = network_set_timeout,
Paul Cercueil61157f92015-11-19 17:48:22 +01001259 .set_kernel_buffers_count = network_set_kernel_buffers_count,
Lars-Peter Clausen55e52f22016-07-04 13:29:38 +02001260
1261 .cancel = network_cancel,
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001262};
1263
Paul Cercueil157d43c2015-11-30 15:05:06 +01001264static ssize_t network_write_data(struct iio_context_pdata *pdata,
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +02001265 void *io_data, const char *src, size_t len)
Paul Cercueil157d43c2015-11-30 15:05:06 +01001266{
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +02001267 struct iio_network_io_context *io_ctx = io_data;
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +02001268
1269 return network_send(io_ctx, src, len, 0);
Paul Cercueil157d43c2015-11-30 15:05:06 +01001270}
1271
1272static ssize_t network_read_data(struct iio_context_pdata *pdata,
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +02001273 void *io_data, char *dst, size_t len)
Paul Cercueil157d43c2015-11-30 15:05:06 +01001274{
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +02001275 struct iio_network_io_context *io_ctx = io_data;
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +02001276
1277 return network_recv(io_ctx, dst, len, 0);
Paul Cercueil157d43c2015-11-30 15:05:06 +01001278}
1279
1280static ssize_t network_read_line(struct iio_context_pdata *pdata,
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +02001281 void *io_data, char *dst, size_t len)
Paul Cercueil157d43c2015-11-30 15:05:06 +01001282{
Paul Cercueil1cb01fe2016-11-16 16:34:00 +01001283 bool found = false;
Paul Cercueil157d43c2015-11-30 15:05:06 +01001284 size_t i;
Paul Cercueilce02dc92016-01-07 11:46:38 +01001285#ifdef __linux__
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +02001286 struct iio_network_io_context *io_ctx = io_data;
Paul Cercueilce02dc92016-01-07 11:46:38 +01001287 ssize_t ret;
Paul Cercueil1cb01fe2016-11-16 16:34:00 +01001288 size_t bytes_read = 0;
Paul Cercueilce02dc92016-01-07 11:46:38 +01001289
Paul Cercueil1cb01fe2016-11-16 16:34:00 +01001290 do {
1291 size_t to_trunc;
Paul Cercueilce02dc92016-01-07 11:46:38 +01001292
Paul Cercueil1cb01fe2016-11-16 16:34:00 +01001293 ret = network_recv(io_ctx, dst, len, MSG_PEEK);
1294 if (ret < 0)
1295 return ret;
Paul Cercueilce02dc92016-01-07 11:46:38 +01001296
Paul Cercueil1cb01fe2016-11-16 16:34:00 +01001297 /* Lookup for the trailing \n */
1298 for (i = 0; i < (size_t) ret && dst[i] != '\n'; i++);
1299 found = i < (size_t) ret;
1300
1301 len -= ret;
1302 dst += ret;
Paul Cercueil1cb01fe2016-11-16 16:34:00 +01001303
1304 if (found)
1305 to_trunc = i + 1;
1306 else
1307 to_trunc = (size_t) ret;
1308
1309 /* Advance the read offset to the byte following the \n if
1310 * found, or after the last charater read otherwise */
1311 ret = network_recv(io_ctx, NULL, to_trunc, MSG_TRUNC);
1312 if (ret < 0)
1313 return ret;
1314
1315 bytes_read += to_trunc;
1316 } while (!found && len);
1317
1318 if (!found)
Paul Cercueilce02dc92016-01-07 11:46:38 +01001319 return -EIO;
Paul Cercueil1cb01fe2016-11-16 16:34:00 +01001320 else
1321 return bytes_read;
Paul Cercueilce02dc92016-01-07 11:46:38 +01001322#else
Paul Cercueil157d43c2015-11-30 15:05:06 +01001323 for (i = 0; i < len - 1; i++) {
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +02001324 ssize_t ret = network_read_data(pdata, io_data, dst + i, 1);
Paul Cercueil157d43c2015-11-30 15:05:06 +01001325
1326 if (ret < 0)
1327 return ret;
1328
1329 if (dst[i] != '\n')
1330 found = true;
1331 else if (found)
1332 break;
1333 }
1334
Paul Cercueil209def82016-04-08 14:47:59 +02001335 if (!found || i == len - 1)
1336 return -EIO;
1337
1338 return (ssize_t) i + 1;
Paul Cercueilce02dc92016-01-07 11:46:38 +01001339#endif
Paul Cercueil157d43c2015-11-30 15:05:06 +01001340}
1341
Lars-Peter Clausen09a59d72016-02-03 15:27:04 +01001342static const struct iiod_client_ops network_iiod_client_ops = {
Paul Cercueil157d43c2015-11-30 15:05:06 +01001343 .write = network_write_data,
1344 .read = network_read_data,
1345 .read_line = network_read_line,
1346};
1347
Paul Cercueil63e52182014-12-11 12:52:48 +01001348struct iio_context * network_create_context(const char *host)
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001349{
Paul Cercueil2e38bbe2014-03-19 15:27:15 +01001350 struct addrinfo hints, *res;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001351 struct iio_context *ctx;
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +01001352 struct iio_context_pdata *pdata;
Paul Cercueil0e3c04d2015-05-13 17:37:11 +02001353 size_t i, len;
Paul Cercueil4970ac32015-02-24 10:59:00 +01001354 int fd, ret;
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001355 char *description;
Paul Cercueil1fef1a52014-04-07 16:31:15 +02001356#ifdef _WIN32
1357 WSADATA wsaData;
1358
1359 ret = WSAStartup(MAKEWORD(2, 0), &wsaData);
1360 if (ret < 0) {
1361 ERROR("WSAStartup failed with error %i\n", ret);
Paul Cercueilcc575532015-03-16 17:15:24 +01001362 errno = -ret;
Paul Cercueil1fef1a52014-04-07 16:31:15 +02001363 return NULL;
1364 }
1365#endif
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001366
Paul Cercueil2e38bbe2014-03-19 15:27:15 +01001367 memset(&hints, 0, sizeof(hints));
1368 hints.ai_family = AF_UNSPEC;
1369 hints.ai_socktype = SOCK_STREAM;
Paul Cercueilab114932014-05-19 13:03:17 +02001370
1371#ifdef HAVE_AVAHI
1372 if (!host) {
1373 char addr_str[AVAHI_ADDRESS_STR_MAX];
1374 char port_str[6];
1375 AvahiAddress address;
Paul Cercueil0f729d32014-06-05 17:38:54 +02001376 uint16_t port = IIOD_PORT;
Paul Cercueilab114932014-05-19 13:03:17 +02001377
1378 memset(&address, 0, sizeof(address));
1379
1380 ret = discover_host(&address, &port);
1381 if (ret < 0) {
Lars-Peter Clausen3417a1a2016-04-18 14:29:02 +02001382 char buf[1024];
1383 iio_strerror(-ret, buf, sizeof(buf));
1384 DEBUG("Unable to find host: %s\n", buf);
Paul Cercueilcc575532015-03-16 17:15:24 +01001385 errno = -ret;
Paul Cercueilab114932014-05-19 13:03:17 +02001386 return NULL;
1387 }
1388
1389 avahi_address_snprint(addr_str, sizeof(addr_str), &address);
Paul Cercueil9c9a5562017-01-24 10:48:31 +01001390 iio_snprintf(port_str, sizeof(port_str), "%hu", port);
Paul Cercueilab114932014-05-19 13:03:17 +02001391 ret = getaddrinfo(addr_str, port_str, &hints, &res);
1392 } else
1393#endif
1394 {
1395 ret = getaddrinfo(host, IIOD_PORT_STR, &hints, &res);
1396 }
1397
Paul Cercueil2e38bbe2014-03-19 15:27:15 +01001398 if (ret) {
Paul Cercueilab114932014-05-19 13:03:17 +02001399 ERROR("Unable to find host: %s\n", gai_strerror(ret));
Paul Cercueild9eb4cb2015-03-23 14:30:20 +01001400#ifndef _WIN32
Paul Cercueilcc575532015-03-16 17:15:24 +01001401 if (ret != EAI_SYSTEM)
Paul Cercueil7cc85112016-11-15 14:59:40 +01001402 errno = -ret;
Paul Cercueild9eb4cb2015-03-23 14:30:20 +01001403#endif
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001404 return NULL;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001405 }
1406
Paul Cercueil6a0eb582016-08-30 10:54:22 +02001407 fd = create_socket(res, DEFAULT_TIMEOUT_MS);
Paul Cercueilcc575532015-03-16 17:15:24 +01001408 if (fd < 0) {
Paul Cercueilc3fe6042016-11-16 17:38:56 +01001409 errno = -fd;
Paul Cercueil2dd2c132015-02-24 10:41:01 +01001410 goto err_free_addrinfo;
Paul Cercueilcc575532015-03-16 17:15:24 +01001411 }
Paul Cercueilbca3dbc2014-06-11 12:00:21 +02001412
Lars-Peter Clausend1be8382016-02-24 11:13:45 +01001413 pdata = zalloc(sizeof(*pdata));
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +01001414 if (!pdata) {
Paul Cercueilcc575532015-03-16 17:15:24 +01001415 errno = ENOMEM;
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +01001416 goto err_close_socket;
1417 }
1418
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +02001419 pdata->io_ctx.fd = fd;
Paul Cercueil2dd2c132015-02-24 10:41:01 +01001420 pdata->addrinfo = res;
Paul Cercueil6a0eb582016-08-30 10:54:22 +02001421 pdata->io_ctx.timeout_ms = DEFAULT_TIMEOUT_MS;
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +01001422
Paul Cercueil157d43c2015-11-30 15:05:06 +01001423 pdata->lock = iio_mutex_create();
1424 if (!pdata->lock) {
1425 errno = ENOMEM;
1426 goto err_free_pdata;
1427 }
1428
1429 pdata->iiod_client = iiod_client_new(pdata, pdata->lock,
1430 &network_iiod_client_ops);
1431 if (!pdata->iiod_client)
1432 goto err_destroy_mutex;
1433
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001434 DEBUG("Creating context...\n");
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +02001435 ctx = iiod_client_create_context(pdata->iiod_client, &pdata->io_ctx);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001436 if (!ctx)
Paul Cercueil157d43c2015-11-30 15:05:06 +01001437 goto err_destroy_iiod_client;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001438
Paul Cercueil2057fd32014-10-28 14:44:19 +01001439 /* Override the name and low-level functions of the XML context
1440 * with those corresponding to the network context */
1441 ctx->name = "network";
1442 ctx->ops = &network_ops;
1443 ctx->pdata = pdata;
1444
Paul Cercueil06c479d2015-01-08 16:14:57 +01001445#ifdef HAVE_IPV6
Paul Cercueiled15e492015-01-12 15:52:28 +01001446 len = INET6_ADDRSTRLEN + IF_NAMESIZE + 2;
Paul Cercueil06c479d2015-01-08 16:14:57 +01001447#else
1448 len = INET_ADDRSTRLEN + 1;
1449#endif
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001450
1451 description = malloc(len);
1452 if (!description) {
Paul Cercueilcc575532015-03-16 17:15:24 +01001453 ret = -ENOMEM;
Paul Cercueil06c479d2015-01-08 16:14:57 +01001454 goto err_network_shutdown;
1455 }
1456
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001457 description[0] = '\0';
Paul Cercueil06c479d2015-01-08 16:14:57 +01001458
1459#ifdef HAVE_IPV6
1460 if (res->ai_family == AF_INET6) {
1461 struct sockaddr_in6 *in = (struct sockaddr_in6 *) res->ai_addr;
Paul Cercueiled15e492015-01-12 15:52:28 +01001462 char *ptr;
Paul Cercueil06c479d2015-01-08 16:14:57 +01001463 inet_ntop(AF_INET6, &in->sin6_addr,
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001464 description, INET6_ADDRSTRLEN);
Paul Cercueiled15e492015-01-12 15:52:28 +01001465
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001466 ptr = if_indextoname(in->sin6_scope_id, description +
1467 strlen(description) + 1);
Paul Cercueiled15e492015-01-12 15:52:28 +01001468 if (!ptr) {
Paul Cercueilcc575532015-03-16 17:15:24 +01001469 ret = -errno;
Paul Cercueiled15e492015-01-12 15:52:28 +01001470 ERROR("Unable to lookup interface of IPv6 address\n");
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001471 goto err_free_description;
Paul Cercueiled15e492015-01-12 15:52:28 +01001472 }
1473
1474 *(ptr - 1) = '%';
Paul Cercueil06c479d2015-01-08 16:14:57 +01001475 }
1476#endif
1477 if (res->ai_family == AF_INET) {
1478 struct sockaddr_in *in = (struct sockaddr_in *) res->ai_addr;
Paul Cercueile7a31692015-07-15 10:52:47 +02001479#if (!_WIN32 || _WIN32_WINNT >= 0x600)
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001480 inet_ntop(AF_INET, &in->sin_addr, description, INET_ADDRSTRLEN);
Paul Cercueile7a31692015-07-15 10:52:47 +02001481#else
1482 char *tmp = inet_ntoa(in->sin_addr);
1483 strncpy(description, tmp, len);
1484#endif
Paul Cercueil06c479d2015-01-08 16:14:57 +01001485 }
1486
Paul Cercueil554ef262017-02-08 12:16:57 +01001487 ret = iio_context_add_attr(ctx, "ip,ip-addr", description);
1488 if (ret < 0)
1489 goto err_free_description;
1490
Paul Cercueil44ae11c2014-03-17 09:56:29 +01001491 for (i = 0; i < ctx->nb_devices; i++) {
1492 struct iio_device *dev = ctx->devices[i];
Paul Cercueilff778232014-03-24 14:23:08 +01001493
Lars-Peter Clausend1be8382016-02-24 11:13:45 +01001494 dev->pdata = zalloc(sizeof(*dev->pdata));
Paul Cercueil439e1a22015-02-24 13:50:51 +01001495 if (!dev->pdata) {
Paul Cercueilcc575532015-03-16 17:15:24 +01001496 ret = -ENOMEM;
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001497 goto err_free_description;
Paul Cercueil439e1a22015-02-24 13:50:51 +01001498 }
1499
Lars-Peter Clausen7e8fa2d2016-06-22 10:57:02 +02001500 dev->pdata->io_ctx.fd = -1;
Paul Cercueil6a0eb582016-08-30 10:54:22 +02001501 dev->pdata->io_ctx.timeout_ms = DEFAULT_TIMEOUT_MS;
Paul Cercueil90189672015-03-16 11:41:53 +01001502#ifdef WITH_NETWORK_GET_BUFFER
Paul Cercueil09a43482015-03-04 15:50:27 +01001503 dev->pdata->memfd = -1;
Paul Cercueile6e5a092015-03-04 16:33:26 +01001504#endif
Paul Cercueilc5b00752015-02-24 14:29:53 +01001505
Paul Cercueil388dcd62015-11-27 15:15:48 +01001506 dev->pdata->lock = iio_mutex_create();
1507 if (!dev->pdata->lock) {
1508 ret = -ENOMEM;
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001509 goto err_free_description;
Paul Cercueil388dcd62015-11-27 15:15:48 +01001510 }
Paul Cercueil44ae11c2014-03-17 09:56:29 +01001511 }
1512
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001513 if (ctx->description) {
Paul Cercueil0e3c04d2015-05-13 17:37:11 +02001514 size_t desc_len = strlen(description);
1515 size_t new_size = desc_len + strlen(ctx->description) + 2;
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001516 char *ptr, *new_description = realloc(description, new_size);
Paul Cercueilcc575532015-03-16 17:15:24 +01001517 if (!new_description) {
1518 ret = -ENOMEM;
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001519 goto err_free_description;
Paul Cercueilcc575532015-03-16 17:15:24 +01001520 }
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001521
1522 ptr = strrchr(new_description, '\0');
Paul Cercueil9c9a5562017-01-24 10:48:31 +01001523 iio_snprintf(ptr, new_size - desc_len, " %s", ctx->description);
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001524 free(ctx->description);
1525
1526 ctx->description = new_description;
1527 } else {
1528 ctx->description = description;
1529 }
1530
Lars-Peter Clausen2767d4d2016-06-23 14:19:02 +02001531 iiod_client_set_timeout(pdata->iiod_client, &pdata->io_ctx,
Paul Cercueilf996ae12015-12-03 12:29:13 +01001532 calculate_remote_timeout(DEFAULT_TIMEOUT_MS));
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001533 return ctx;
1534
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001535err_free_description:
1536 free(description);
Paul Cercueil44ae11c2014-03-17 09:56:29 +01001537err_network_shutdown:
Paul Cercueil44ae11c2014-03-17 09:56:29 +01001538 iio_context_destroy(ctx);
Paul Cercueilcc575532015-03-16 17:15:24 +01001539 errno = -ret;
Paul Cercueil2057fd32014-10-28 14:44:19 +01001540 return NULL;
Paul Cercueil157d43c2015-11-30 15:05:06 +01001541
1542err_destroy_iiod_client:
1543 iiod_client_destroy(pdata->iiod_client);
1544err_destroy_mutex:
1545 iio_mutex_destroy(pdata->lock);
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +01001546err_free_pdata:
1547 free(pdata);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001548err_close_socket:
1549 close(fd);
Paul Cercueil2dd2c132015-02-24 10:41:01 +01001550err_free_addrinfo:
1551 freeaddrinfo(res);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001552 return NULL;
1553}