blob: afd2a9bd21c4a6a8c365e22b13f356359b9f200a [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 Cercueilc7bad0f2014-03-03 17:06:48 +010019#include "iio-private.h"
Paul Cercueil388dcd62015-11-27 15:15:48 +010020#include "iio-lock.h"
Paul Cercueil157d43c2015-11-30 15:05:06 +010021#include "iiod-client.h"
Paul Cercueil9aabe892014-09-02 12:33:46 +020022
Paul Cercueilc7bad0f2014-03-03 17:06:48 +010023#include <errno.h>
Paul Cercueila7d445b2014-11-11 16:00:15 +010024#include <fcntl.h>
Paul Cercueile60c3ed2014-03-04 11:23:56 +010025#include <stdbool.h>
Paul Cercueilc7bad0f2014-03-03 17:06:48 +010026#include <string.h>
27#include <sys/types.h>
Paul Cercueilab114932014-05-19 13:03:17 +020028#include <time.h>
Paul Cercueil1fef1a52014-04-07 16:31:15 +020029
30#ifdef _WIN32
31#include <winsock2.h>
32#include <ws2tcpip.h>
33#define close(s) closesocket(s)
34
35/* winsock2.h defines ERROR, we don't want that */
36#undef ERROR
37
38#else /* _WIN32 */
Paul Cercueil06c479d2015-01-08 16:14:57 +010039#include <arpa/inet.h>
Paul Cercueil1fef1a52014-04-07 16:31:15 +020040#include <netdb.h>
Paul Cercueil0c3ce452015-02-05 16:37:42 +010041#include <netinet/in.h>
Paul Cercueil0b584e12015-01-28 11:47:03 +010042#include <netinet/tcp.h>
Paul Cercueiled15e492015-01-12 15:52:28 +010043#include <net/if.h>
Paul Cercueil09a43482015-03-04 15:50:27 +010044#include <sys/mman.h>
Paul Cercueil83628b32014-11-24 11:26:21 +010045#include <sys/select.h>
Paul Cercueilc7bad0f2014-03-03 17:06:48 +010046#include <sys/socket.h>
47#include <unistd.h>
Paul Cercueil1fef1a52014-04-07 16:31:15 +020048#endif /* _WIN32 */
49
Paul Cercueilab114932014-05-19 13:03:17 +020050#ifdef HAVE_AVAHI
51#include <avahi-client/client.h>
52#include <avahi-common/error.h>
53#include <avahi-client/lookup.h>
54#include <avahi-common/simple-watch.h>
55#endif
56
Paul Cercueil1fef1a52014-04-07 16:31:15 +020057#include "debug.h"
Paul Cercueilc7bad0f2014-03-03 17:06:48 +010058
Paul Cercueil8a266f12014-06-10 16:06:31 +020059#define DEFAULT_TIMEOUT_MS 5000
60
Paul Cercueil2e38bbe2014-03-19 15:27:15 +010061#define _STRINGIFY(x) #x
62#define STRINGIFY(x) _STRINGIFY(x)
63
Paul Cercueilc7bad0f2014-03-03 17:06:48 +010064#define IIOD_PORT 30431
Paul Cercueil2e38bbe2014-03-19 15:27:15 +010065#define IIOD_PORT_STR STRINGIFY(IIOD_PORT)
Paul Cercueilc7bad0f2014-03-03 17:06:48 +010066
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +010067struct iio_context_pdata {
68 int fd;
Paul Cercueil2dd2c132015-02-24 10:41:01 +010069 struct addrinfo *addrinfo;
Paul Cercueil388dcd62015-11-27 15:15:48 +010070 struct iio_mutex *lock;
Paul Cercueil157d43c2015-11-30 15:05:06 +010071 struct iiod_client *iiod_client;
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +010072};
73
Paul Cercueil439e1a22015-02-24 13:50:51 +010074struct iio_device_pdata {
75 int fd;
Paul Cercueil90189672015-03-16 11:41:53 +010076#ifdef WITH_NETWORK_GET_BUFFER
Paul Cercueil09a43482015-03-04 15:50:27 +010077 int memfd;
Paul Cercueile6e5a092015-03-04 16:33:26 +010078 void *mmap_addr;
Paul Cercueil09a43482015-03-04 15:50:27 +010079 size_t mmap_len;
Paul Cercueile6e5a092015-03-04 16:33:26 +010080#endif
Paul Cercueil09a43482015-03-04 15:50:27 +010081 bool wait_for_err_code, is_cyclic, is_tx;
Paul Cercueil388dcd62015-11-27 15:15:48 +010082 struct iio_mutex *lock;
Paul Cercueil439e1a22015-02-24 13:50:51 +010083};
84
Lars-Peter Clausendd04e6a2016-02-10 14:56:36 +010085#ifdef _WIN32
86static int network_get_error(void)
87{
88 return -WSAGetLastError();
89}
90#else
91static int network_get_error(void)
92{
93 return -errno;
94}
95#endif
96
Paul Cercueilab114932014-05-19 13:03:17 +020097#ifdef HAVE_AVAHI
98struct avahi_discovery_data {
99 AvahiSimplePoll *poll;
100 AvahiAddress *address;
101 uint16_t *port;
102 bool found, resolved;
103};
104
105static void __avahi_resolver_cb(AvahiServiceResolver *resolver,
106 __notused AvahiIfIndex iface, __notused AvahiProtocol proto,
107 __notused AvahiResolverEvent event, __notused const char *name,
108 __notused const char *type, __notused const char *domain,
109 __notused const char *host_name, const AvahiAddress *address,
110 uint16_t port, __notused AvahiStringList *txt,
111 __notused AvahiLookupResultFlags flags, void *d)
112{
113 struct avahi_discovery_data *ddata = (struct avahi_discovery_data *) d;
114
115 memcpy(ddata->address, address, sizeof(*address));
116 *ddata->port = port;
117 ddata->resolved = true;
118 avahi_service_resolver_free(resolver);
119}
120
121static void __avahi_browser_cb(AvahiServiceBrowser *browser,
122 AvahiIfIndex iface, AvahiProtocol proto,
123 AvahiBrowserEvent event, const char *name,
124 const char *type, const char *domain,
125 __notused AvahiLookupResultFlags flags, void *d)
126{
127 struct avahi_discovery_data *ddata = (struct avahi_discovery_data *) d;
128 struct AvahiClient *client = avahi_service_browser_get_client(browser);
129
130 switch (event) {
131 default:
132 case AVAHI_BROWSER_NEW:
133 ddata->found = !!avahi_service_resolver_new(client, iface,
134 proto, name, type, domain,
135 AVAHI_PROTO_UNSPEC, 0,
136 __avahi_resolver_cb, d);
137 break;
138 case AVAHI_BROWSER_ALL_FOR_NOW:
139 if (ddata->found) {
140 while (!ddata->resolved) {
141 struct timespec ts;
142 ts.tv_sec = 0;
143 ts.tv_nsec = 4000000;
144 nanosleep(&ts, NULL);
145 }
146 }
147 case AVAHI_BROWSER_FAILURE: /* fall-through */
148 avahi_simple_poll_quit(ddata->poll);
149 case AVAHI_BROWSER_CACHE_EXHAUSTED: /* fall-through */
150 break;
151 }
152}
153
154static int discover_host(AvahiAddress *addr, uint16_t *port)
155{
156 struct avahi_discovery_data ddata;
157 int ret = 0;
158 AvahiClient *client;
159 AvahiServiceBrowser *browser;
160 AvahiSimplePoll *poll = avahi_simple_poll_new();
161 if (!poll)
162 return -ENOMEM;
163
164 client = avahi_client_new(avahi_simple_poll_get(poll),
165 0, NULL, NULL, &ret);
166 if (!client) {
167 ERROR("Unable to start ZeroConf client :%s\n",
168 avahi_strerror(ret));
169 goto err_free_poll;
170 }
171
172 memset(&ddata, 0, sizeof(ddata));
173 ddata.poll = poll;
174 ddata.address = addr;
175 ddata.port = port;
176
177 browser = avahi_service_browser_new(client,
178 AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
179 "_iio._tcp", NULL, 0, __avahi_browser_cb, &ddata);
180 if (!browser) {
181 ret = avahi_client_errno(client);
182 ERROR("Unable to create ZeroConf browser: %s\n",
183 avahi_strerror(ret));
184 goto err_free_client;
185 }
186
187 DEBUG("Trying to discover host\n");
188 avahi_simple_poll_loop(poll);
189
190 if (!ddata.found)
191 ret = ENXIO;
192
193 avahi_service_browser_free(browser);
194err_free_client:
195 avahi_client_free(client);
196err_free_poll:
197 avahi_simple_poll_free(poll);
198 return -ret; /* we want a negative error code */
199}
200#endif /* HAVE_AVAHI */
201
Lars-Peter Clausen6a6c8662016-02-12 15:35:52 +0100202static ssize_t network_recv(int fd, void *data, size_t len, int flags)
203{
204 ssize_t ret;
205 int err;
206
207 while (1) {
208 ret = recv(fd, data, (int) len, flags);
209 if (ret == 0)
210 return -EPIPE;
211 else if (ret > 0)
212 break;
213
214 err = network_get_error();
215 if (err != -EINTR)
216 return (ssize_t) err;
217 }
218 return ret;
219}
220
221static ssize_t network_send(int fd, const void *data, size_t len, int flags)
222{
223 ssize_t ret;
224 int err;
225
226 while (1) {
227 ret = send(fd, data, (int) len, flags);
228 if (ret == 0)
229 return -EPIPE;
230 else if (ret > 0)
231 break;
232
233 err = network_get_error();
234 if (err != -EINTR)
235 return (ssize_t) err;
236 }
237
238 return ret;
239}
240
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100241static ssize_t write_all(const void *src, size_t len, int fd)
242{
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200243 uintptr_t ptr = (uintptr_t) src;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100244 while (len) {
Lars-Peter Clausen6a6c8662016-02-12 15:35:52 +0100245 ssize_t ret = network_send(fd, (const void *) ptr, len, 0);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100246 ptr += ret;
247 len -= ret;
248 }
Paul Cercueil4012cff2015-05-11 10:47:40 +0200249 return (ssize_t)(ptr - (uintptr_t) src);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100250}
251
252static ssize_t read_all(void *dst, size_t len, int fd)
253{
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200254 uintptr_t ptr = (uintptr_t) dst;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100255 while (len) {
Lars-Peter Clausen6a6c8662016-02-12 15:35:52 +0100256 ssize_t ret = network_recv(fd, (void *) ptr, len, 0);
257 if (ret < 0)
258 return ret;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100259 ptr += ret;
260 len -= ret;
261 }
Paul Cercueil4012cff2015-05-11 10:47:40 +0200262 return (ssize_t)(ptr - (uintptr_t) dst);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100263}
264
Paul Cercueile60c3ed2014-03-04 11:23:56 +0100265static int read_integer(int fd, long *val)
266{
267 unsigned int i;
268 char buf[1024], *ptr;
269 ssize_t ret;
270 bool found = false;
271
272 for (i = 0; i < sizeof(buf) - 1; i++) {
273 ret = read_all(buf + i, 1, fd);
274 if (ret < 0)
275 return (int) ret;
276
Paul Cercueil6691a3f2014-05-02 12:32:01 +0200277 /* Skip the eventual first few carriage returns.
278 * Also stop when a dot is found (for parsing floats) */
279 if (buf[i] != '\n' && buf[i] != '.')
Paul Cercueile60c3ed2014-03-04 11:23:56 +0100280 found = true;
281 else if (found)
282 break;
283 }
284
285 buf[i] = '\0';
286 ret = (ssize_t) strtol(buf, &ptr, 10);
287 if (ptr == buf)
288 return -EINVAL;
289 *val = (long) ret;
290 return 0;
291}
292
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100293static ssize_t write_command(const char *cmd, int fd)
294{
295 ssize_t ret;
296
297 DEBUG("Writing command: %s\n", cmd);
298 ret = write_all(cmd, strlen(cmd), fd);
299 if (ret < 0) {
300 char buf[1024];
Paul Cercueil53fc4852015-05-22 10:57:53 +0200301 iio_strerror(-ret, buf, sizeof(buf));
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100302 ERROR("Unable to send command: %s\n", buf);
303 }
304 return ret;
305}
306
Paul Cercueil4970ac32015-02-24 10:59:00 +0100307#ifndef _WIN32
Lars-Peter Clausena2cbc812016-02-11 14:49:27 +0100308
309/* Use it if available */
310#ifndef SOCK_CLOSEXEC
311#define SOCK_CLOSEXEC 0
312#endif
313
Paul Cercueil4970ac32015-02-24 10:59:00 +0100314/* The purpose of this function is to provide a version of connect()
315 * that does not ignore timeouts... */
Lars-Peter Clausen1ca01b72016-02-10 15:10:09 +0100316static int do_connect(const struct addrinfo *addrinfo,
317 struct timeval *timeout)
Paul Cercueil4970ac32015-02-24 10:59:00 +0100318{
319 int ret, error;
320 socklen_t len;
321 fd_set set;
Lars-Peter Clausen1ca01b72016-02-10 15:10:09 +0100322 int fd;
323
Lars-Peter Clausena2cbc812016-02-11 14:49:27 +0100324 fd = socket(addrinfo->ai_family, addrinfo->ai_socktype | SOCK_CLOEXEC, 0);
Lars-Peter Clausen1ca01b72016-02-10 15:10:09 +0100325 if (fd < 0)
326 return -errno;
Paul Cercueil4970ac32015-02-24 10:59:00 +0100327
328 FD_ZERO(&set);
329 FD_SET(fd, &set);
330
331 ret = set_blocking_mode(fd, false);
Lars-Peter Clausenebbd9072016-02-11 15:15:08 +0100332 if (ret < 0) {
333 close(fd);
Paul Cercueil4970ac32015-02-24 10:59:00 +0100334 return ret;
Lars-Peter Clausenebbd9072016-02-11 15:15:08 +0100335 }
Paul Cercueil4970ac32015-02-24 10:59:00 +0100336
Lars-Peter Clausen1ca01b72016-02-10 15:10:09 +0100337 ret = connect(fd, addrinfo->ai_addr, addrinfo->ai_addrlen);
Paul Cercueil4970ac32015-02-24 10:59:00 +0100338 if (ret < 0 && errno != EINPROGRESS) {
339 ret = -errno;
340 goto end;
341 }
342
343 ret = select(fd + 1, &set, &set, NULL, timeout);
344 if (ret < 0) {
345 ret = -errno;
346 goto end;
347 }
348 if (ret == 0) {
349 ret = -ETIMEDOUT;
350 goto end;
351 }
352
353 /* Verify that we don't have an error */
354 len = sizeof(error);
355 ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len);
356 if(ret < 0) {
357 ret = -errno;
358 goto end;
359 }
360 if (error) {
361 ret = -error;
362 goto end;
363 }
364
365end:
366 /* Restore blocking mode */
367 set_blocking_mode(fd, true);
Lars-Peter Clausenebbd9072016-02-11 15:15:08 +0100368 if (ret < 0) {
Lars-Peter Clausen1ca01b72016-02-10 15:10:09 +0100369 close(fd);
Lars-Peter Clausenebbd9072016-02-11 15:15:08 +0100370 return ret;
371 }
372
373 return fd;
Paul Cercueil4970ac32015-02-24 10:59:00 +0100374}
375
376static int set_socket_timeout(int fd, unsigned int timeout)
377{
378 struct timeval tv;
379
380 tv.tv_sec = timeout / 1000;
381 tv.tv_usec = (timeout % 1000) * 1000;
382 if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0 ||
383 setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO,
384 &tv, sizeof(tv)) < 0)
385 return -errno;
386 else
387 return 0;
388}
389#else
Lars-Peter Clausen1ca01b72016-02-10 15:10:09 +0100390
Lars-Peter Clausena2cbc812016-02-11 14:49:27 +0100391/* Use it if available */
392#ifndef WSA_FLAG_NO_HANDLE_INHERIT
393#define WSA_FLAG_NO_HANDLE_INHERIT 0
394#endif
395
Lars-Peter Clausen1ca01b72016-02-10 15:10:09 +0100396static int do_connect(const struct addrinfo *addrinfo,
397 struct timeval *timeout)
398{
399 int ret;
400 SOCKET s;
401
Lars-Peter Clausena2cbc812016-02-11 14:49:27 +0100402 s = WSASocket(addrinfo->ai_family, addrinfo->ai_socktype, 0, NULL, 0,
403 WSA_FLAG_NO_HANDLE_INHERIT);
Lars-Peter Clausen1ca01b72016-02-10 15:10:09 +0100404 if (s == INVALID_SOCKET)
405 return -WSAGetLastError();
406
407 ret = connect(s, addrinfo->ai_addr, (int) addrinfo->ai_addrlen);
408 if (ret == SOCKET_ERROR) {
409 close(s);
410 return -WSAGetLastError();
411 }
412
413 return (int) s;
414}
415
Paul Cercueil4970ac32015-02-24 10:59:00 +0100416static int set_socket_timeout(int fd, unsigned int timeout)
417{
418 if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO,
419 (const char *) &timeout, sizeof(timeout)) < 0 ||
420 setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO,
421 (const char *) &timeout, sizeof(timeout)) < 0)
Paul Cercueil135b3612015-06-30 14:10:14 +0200422 return -WSAGetLastError();
Paul Cercueil4970ac32015-02-24 10:59:00 +0100423 else
424 return 0;
425}
426#endif /* !_WIN32 */
427
428static int create_socket(const struct addrinfo *addrinfo)
429{
430 struct timeval timeout;
Lars-Peter Clausen1ca01b72016-02-10 15:10:09 +0100431 int fd, yes = 1;
Paul Cercueil4970ac32015-02-24 10:59:00 +0100432
433 timeout.tv_sec = DEFAULT_TIMEOUT_MS / 1000;
434 timeout.tv_usec = (DEFAULT_TIMEOUT_MS % 1000) * 1000;
435
Lars-Peter Clausen1ca01b72016-02-10 15:10:09 +0100436 fd = do_connect(addrinfo, &timeout);
437 if (fd < 0)
438 return fd;
Paul Cercueil4970ac32015-02-24 10:59:00 +0100439
440 set_socket_timeout(fd, DEFAULT_TIMEOUT_MS);
441 setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
442 (const char *) &yes, sizeof(yes));
443 return fd;
444}
445
Paul Cercueil92f15c22015-04-20 11:36:51 +0200446static int network_open(const struct iio_device *dev,
447 size_t samples_count, bool cyclic)
Paul Cercueilba059762014-03-14 11:02:02 +0100448{
Paul Cercueil439e1a22015-02-24 13:50:51 +0100449 struct iio_context_pdata *pdata = dev->ctx->pdata;
Paul Cercueil80dc1082015-12-01 18:20:31 +0100450 struct iio_device_pdata *ppdata = dev->pdata;
451 int fd, ret = -EBUSY;
Paul Cercueilba059762014-03-14 11:02:02 +0100452
Paul Cercueil80dc1082015-12-01 18:20:31 +0100453 iio_mutex_lock(ppdata->lock);
454 if (ppdata->fd >= 0)
455 goto out_mutex_unlock;
Paul Cercueil439e1a22015-02-24 13:50:51 +0100456
Paul Cercueil80dc1082015-12-01 18:20:31 +0100457 ret = create_socket(pdata->addrinfo);
458 if (ret < 0)
459 goto out_mutex_unlock;
Paul Cercueilba059762014-03-14 11:02:02 +0100460
Paul Cercueil80dc1082015-12-01 18:20:31 +0100461 fd = ret;
Paul Cercueilba059762014-03-14 11:02:02 +0100462
Paul Cercueil80dc1082015-12-01 18:20:31 +0100463 ret = iiod_client_open_unlocked(pdata->iiod_client, fd,
464 dev, samples_count, cyclic);
Paul Cercueil44ae11c2014-03-17 09:56:29 +0100465 if (ret < 0) {
Paul Cercueil439e1a22015-02-24 13:50:51 +0100466 close(fd);
Paul Cercueil80dc1082015-12-01 18:20:31 +0100467 goto out_mutex_unlock;
Paul Cercueil44ae11c2014-03-17 09:56:29 +0100468 }
Paul Cercueil439e1a22015-02-24 13:50:51 +0100469
Paul Cercueil80dc1082015-12-01 18:20:31 +0100470 ppdata->is_tx = iio_device_is_tx(dev);
471 ppdata->is_cyclic = cyclic;
472 ppdata->fd = fd;
473 ppdata->wait_for_err_code = false;
Paul Cercueild957b982015-08-05 14:39:01 +0200474#ifdef WITH_NETWORK_GET_BUFFER
Paul Cercueil80dc1082015-12-01 18:20:31 +0100475 ppdata->mmap_len = samples_count * iio_device_get_sample_size(dev);
Paul Cercueild957b982015-08-05 14:39:01 +0200476#endif
Paul Cercueil80dc1082015-12-01 18:20:31 +0100477
478out_mutex_unlock:
479 iio_mutex_unlock(ppdata->lock);
480 return ret;
Paul Cercueilba059762014-03-14 11:02:02 +0100481}
482
Paul Cercueil8f7f6c42015-02-24 15:00:35 +0100483static ssize_t read_error_code(int fd)
484{
485 /*
486 * The server returns two integer codes.
487 * The first one is returned right after the WRITEBUF command is issued,
488 * and corresponds to the error code returned when the server attempted
489 * to open the device.
490 * If zero, a second error code is returned, that corresponds (if positive)
491 * to the number of bytes written.
492 *
493 * To speed up things, we delay error reporting. We just send out the
494 * data without reading the error code that the server gives us, because
495 * the answer will take too much time. If an error occured, it will be
496 * reported by the next call to iio_buffer_push().
497 */
498
499 unsigned int i;
500 long resp = 0;
501
502 for (i = 0; i < 2; i++) {
503 ssize_t ret = read_integer(fd, &resp);
504 if (ret < 0)
505 return ret;
506 if (resp < 0)
507 return (ssize_t) resp;
508 }
509
Paul Cercueil7d7e5d32015-03-05 10:51:41 +0100510 return (ssize_t) resp;
Paul Cercueil8f7f6c42015-02-24 15:00:35 +0100511}
512
Paul Cercueil3c0da372015-03-05 11:36:39 +0100513static ssize_t write_rwbuf_command(const struct iio_device *dev,
Lars-Peter Clausen2e380822016-02-11 20:36:13 +0100514 const char *cmd)
Paul Cercueil3c0da372015-03-05 11:36:39 +0100515{
516 struct iio_device_pdata *pdata = dev->pdata;
517 int fd = pdata->fd;
518
519 if (pdata->wait_for_err_code) {
520 ssize_t ret = read_error_code(fd);
521
522 pdata->wait_for_err_code = false;
523 if (ret < 0)
524 return ret;
525 }
526
Lars-Peter Clausen78067fc2016-02-11 12:48:01 +0100527 return write_command(cmd, fd);
Paul Cercueil3c0da372015-03-05 11:36:39 +0100528}
529
Paul Cercueilba059762014-03-14 11:02:02 +0100530static int network_close(const struct iio_device *dev)
531{
Paul Cercueil439e1a22015-02-24 13:50:51 +0100532 struct iio_device_pdata *pdata = dev->pdata;
Paul Cercueild5d84612015-06-08 21:24:15 +0200533 int ret = -EBADF;
Paul Cercueil80dc1082015-12-01 18:20:31 +0100534
535 iio_mutex_lock(pdata->lock);
Paul Cercueil439e1a22015-02-24 13:50:51 +0100536
Paul Cercueila34596e2015-03-05 14:33:46 +0100537 if (pdata->fd >= 0) {
Paul Cercueil80dc1082015-12-01 18:20:31 +0100538 ret = iiod_client_close_unlocked(dev->ctx->pdata->iiod_client,
539 pdata->fd, dev);
Paul Cercueil1494b862014-05-05 12:49:07 +0200540
Paul Cercueila34596e2015-03-05 14:33:46 +0100541 write_command("\r\nEXIT\r\n", pdata->fd);
Paul Cercueilaa0db142015-03-04 16:25:24 +0100542
Paul Cercueila34596e2015-03-05 14:33:46 +0100543 close(pdata->fd);
544 pdata->fd = -1;
Paul Cercueila34596e2015-03-05 14:33:46 +0100545 }
Paul Cercueile6e5a092015-03-04 16:33:26 +0100546
Paul Cercueil90189672015-03-16 11:41:53 +0100547#ifdef WITH_NETWORK_GET_BUFFER
Paul Cercueile6e5a092015-03-04 16:33:26 +0100548 if (pdata->memfd >= 0)
549 close(pdata->memfd);
550 pdata->memfd = -1;
551
552 if (pdata->mmap_addr) {
553 munmap(pdata->mmap_addr, pdata->mmap_len);
554 pdata->mmap_addr = NULL;
555 }
556#endif
Paul Cercueil80dc1082015-12-01 18:20:31 +0100557
558 iio_mutex_unlock(pdata->lock);
Paul Cercueil1494b862014-05-05 12:49:07 +0200559 return ret;
Paul Cercueilba059762014-03-14 11:02:02 +0100560}
561
Paul Cercueil7d7e5d32015-03-05 10:51:41 +0100562static ssize_t network_read_mask(int fd, uint32_t *mask, size_t words)
563{
564 long read_len;
565 ssize_t ret;
566
567 ret = read_integer(fd, &read_len);
568 if (ret < 0)
569 return ret;
570
571 if (read_len > 0 && mask) {
Paul Cercueil4012cff2015-05-11 10:47:40 +0200572 size_t i;
Paul Cercueil7d7e5d32015-03-05 10:51:41 +0100573 char buf[9];
574
575 buf[8] = '\0';
576 DEBUG("Reading mask\n");
577
578 for (i = words; i > 0; i--) {
579 ret = read_all(buf, 8, fd);
580 if (ret < 0)
581 return ret;
582
583 sscanf(buf, "%08x", &mask[i - 1]);
584 DEBUG("mask[%i] = 0x%x\n", i - 1, mask[i - 1]);
585 }
586 }
587
588 if (read_len > 0) {
589 char c;
590 ssize_t nb = read_all(&c, 1, fd);
591 if (nb > 0 && c != '\n')
592 read_len = -EIO;
593 }
594
595 return (ssize_t) read_len;
596}
597
Paul Cercueil45c575d2014-03-20 15:14:01 +0100598static ssize_t network_read(const struct iio_device *dev, void *dst, size_t len,
599 uint32_t *mask, size_t words)
Paul Cercueilf9286452014-03-18 14:32:17 +0100600{
Paul Cercueilc5b00752015-02-24 14:29:53 +0100601 struct iio_device_pdata *pdata = dev->pdata;
Paul Cercueil72793642015-12-02 11:57:10 +0100602 ssize_t ret;
Paul Cercueil1494b862014-05-05 12:49:07 +0200603
Paul Cercueil388dcd62015-11-27 15:15:48 +0100604 iio_mutex_lock(pdata->lock);
Paul Cercueil72793642015-12-02 11:57:10 +0100605 ret = iiod_client_read_unlocked(dev->ctx->pdata->iiod_client,
606 pdata->fd, dev, dst, len, mask, words);
Paul Cercueil388dcd62015-11-27 15:15:48 +0100607 iio_mutex_unlock(pdata->lock);
Paul Cercueil72793642015-12-02 11:57:10 +0100608
609 return ret;
Paul Cercueil9945bc82014-03-05 14:07:29 +0100610}
611
Paul Cercueila62f84e2015-02-24 14:16:08 +0100612static ssize_t network_write(const struct iio_device *dev,
613 const void *src, size_t len)
Paul Cercueil2725f702014-05-02 11:02:16 +0200614{
Paul Cercueilc5b00752015-02-24 14:29:53 +0100615 struct iio_device_pdata *pdata = dev->pdata;
Paul Cercueil2725f702014-05-02 11:02:16 +0200616 ssize_t ret;
Paul Cercueil2725f702014-05-02 11:02:16 +0200617
Paul Cercueil388dcd62015-11-27 15:15:48 +0100618 iio_mutex_lock(pdata->lock);
Paul Cercueilf19568a2015-12-02 17:57:51 +0100619 ret = iiod_client_write_unlocked(dev->ctx->pdata->iiod_client,
620 pdata->fd, dev, src, len);
Paul Cercueil388dcd62015-11-27 15:15:48 +0100621 iio_mutex_unlock(pdata->lock);
Paul Cercueil1494b862014-05-05 12:49:07 +0200622
Paul Cercueil1494b862014-05-05 12:49:07 +0200623 return ret;
Paul Cercueil2725f702014-05-02 11:02:16 +0200624}
625
Paul Cercueil90189672015-03-16 11:41:53 +0100626#ifdef WITH_NETWORK_GET_BUFFER
Paul Cercueil7d7e5d32015-03-05 10:51:41 +0100627static ssize_t network_do_splice(int fd_out, int fd_in, size_t len)
Paul Cercueil09a43482015-03-04 15:50:27 +0100628{
629 int pipefd[2];
Paul Cercueil04065c22015-03-05 14:08:16 +0100630 ssize_t ret, read_len = len;
Paul Cercueil09a43482015-03-04 15:50:27 +0100631
Lars-Peter Clausena2cbc812016-02-11 14:49:27 +0100632 ret = (ssize_t) pipe2(pipefd, O_CLOEXEC);
Paul Cercueil09a43482015-03-04 15:50:27 +0100633 if (ret < 0)
634 return -errno;
635
636 do {
Paul Cercueila107c6d2015-03-05 13:54:10 +0100637 /*
638 * SPLICE_F_NONBLOCK is just here to avoid a deadlock when
639 * splicing from a socket. As the socket is not in
640 * non-blocking mode, it should never return -EAGAIN.
641 * TODO(pcercuei): Find why it locks...
642 * */
643 ret = splice(fd_in, NULL, pipefd[1], NULL, len,
644 SPLICE_F_MOVE | SPLICE_F_NONBLOCK);
645 if (!ret)
646 ret = -EIO;
Paul Cercueil09a43482015-03-04 15:50:27 +0100647 if (ret < 0)
648 goto err_close_pipe;
649
Paul Cercueila107c6d2015-03-05 13:54:10 +0100650 ret = splice(pipefd[0], NULL, fd_out, NULL, ret,
651 SPLICE_F_MOVE | SPLICE_F_NONBLOCK);
652 if (!ret)
653 ret = -EIO;
Paul Cercueil09a43482015-03-04 15:50:27 +0100654 if (ret < 0)
655 goto err_close_pipe;
656
657 len -= ret;
658 } while (len);
659
660err_close_pipe:
661 close(pipefd[0]);
662 close(pipefd[1]);
Paul Cercueil04065c22015-03-05 14:08:16 +0100663 return ret < 0 ? ret : read_len;
Paul Cercueil09a43482015-03-04 15:50:27 +0100664}
665
666static ssize_t network_get_buffer(const struct iio_device *dev,
Paul Cercueil76ca8842015-03-05 11:16:16 +0100667 void **addr_ptr, size_t bytes_used,
668 uint32_t *mask, size_t words)
Paul Cercueil09a43482015-03-04 15:50:27 +0100669{
670 struct iio_device_pdata *pdata = dev->pdata;
Paul Cercueil04065c22015-03-05 14:08:16 +0100671 ssize_t ret, read = 0;
Paul Cercueilca9d3382015-05-04 14:30:09 +0200672 int memfd;
Paul Cercueil09a43482015-03-04 15:50:27 +0100673
Paul Cercueil04065c22015-03-05 14:08:16 +0100674 if (pdata->is_cyclic)
Paul Cercueil09a43482015-03-04 15:50:27 +0100675 return -ENOSYS;
Paul Cercueilca9d3382015-05-04 14:30:09 +0200676
677 /* We check early that the temporary file can be created, so that we can
678 * return -ENOSYS in case it fails, which will indicate that the
679 * high-speed interface is not available.
680 *
681 * O_TMPFILE -> Linux 3.11.
682 * TODO: use memfd_create (Linux 3.17) */
Lars-Peter Clausena2cbc812016-02-11 14:49:27 +0100683 memfd = open(P_tmpdir, O_RDWR | O_TMPFILE | O_EXCL | O_CLOEXEC, S_IRWXU);
Paul Cercueilca9d3382015-05-04 14:30:09 +0200684 if (memfd < 0)
685 return -ENOSYS;
686
687 if (!addr_ptr || words != (dev->nb_channels + 31) / 32) {
688 close(memfd);
Paul Cercueil09a43482015-03-04 15:50:27 +0100689 return -EINVAL;
Paul Cercueilca9d3382015-05-04 14:30:09 +0200690 }
Paul Cercueil09a43482015-03-04 15:50:27 +0100691
Paul Cercueile6e5a092015-03-04 16:33:26 +0100692 if (pdata->mmap_addr)
693 munmap(pdata->mmap_addr, pdata->mmap_len);
Paul Cercueil09a43482015-03-04 15:50:27 +0100694
Paul Cercueile6e5a092015-03-04 16:33:26 +0100695 if (pdata->mmap_addr && pdata->is_tx) {
Paul Cercueil09a43482015-03-04 15:50:27 +0100696 char buf[1024];
697 snprintf(buf, sizeof(buf), "WRITEBUF %s %lu\r\n",
Paul Cercueild957b982015-08-05 14:39:01 +0200698 dev->id, (unsigned long) bytes_used);
Paul Cercueil09a43482015-03-04 15:50:27 +0100699
Paul Cercueil388dcd62015-11-27 15:15:48 +0100700 iio_mutex_lock(pdata->lock);
Paul Cercueil09a43482015-03-04 15:50:27 +0100701
Lars-Peter Clausen78067fc2016-02-11 12:48:01 +0100702 ret = write_rwbuf_command(dev, buf);
Paul Cercueil09a43482015-03-04 15:50:27 +0100703 if (ret < 0)
Paul Cercueilca9d3382015-05-04 14:30:09 +0200704 goto err_close_memfd;
Paul Cercueil09a43482015-03-04 15:50:27 +0100705
Paul Cercueild957b982015-08-05 14:39:01 +0200706 ret = network_do_splice(pdata->fd, pdata->memfd, bytes_used);
Paul Cercueil09a43482015-03-04 15:50:27 +0100707 if (ret < 0)
Paul Cercueilca9d3382015-05-04 14:30:09 +0200708 goto err_close_memfd;
Paul Cercueil09a43482015-03-04 15:50:27 +0100709
710 pdata->wait_for_err_code = true;
Paul Cercueil388dcd62015-11-27 15:15:48 +0100711 iio_mutex_unlock(pdata->lock);
Paul Cercueil09a43482015-03-04 15:50:27 +0100712 }
713
714 if (pdata->memfd >= 0)
715 close(pdata->memfd);
716
Paul Cercueilca9d3382015-05-04 14:30:09 +0200717 pdata->memfd = memfd;
Paul Cercueil09a43482015-03-04 15:50:27 +0100718
Paul Cercueilef32d582015-03-05 11:18:35 +0100719 ret = (ssize_t) ftruncate(pdata->memfd, pdata->mmap_len);
720 if (ret < 0) {
721 ret = -errno;
722 ERROR("Unable to truncate temp file: %zi\n", -ret);
723 return ret;
724 }
Paul Cercueil09a43482015-03-04 15:50:27 +0100725
Paul Cercueil04065c22015-03-05 14:08:16 +0100726 if (!pdata->is_tx) {
727 char buf[1024];
728 size_t len = pdata->mmap_len;
729
730 snprintf(buf, sizeof(buf), "READBUF %s %lu\r\n",
731 dev->id, (unsigned long) len);
732
Paul Cercueil388dcd62015-11-27 15:15:48 +0100733 iio_mutex_lock(pdata->lock);
Lars-Peter Clausen78067fc2016-02-11 12:48:01 +0100734 ret = write_rwbuf_command(dev, buf);
Paul Cercueil04065c22015-03-05 14:08:16 +0100735 if (ret < 0)
736 goto err_unlock;
737
738 do {
739 ret = network_read_mask(pdata->fd, mask, words);
740 if (!ret)
741 break;
742 if (ret < 0)
743 goto err_unlock;
744
745 mask = NULL; /* We read the mask only once */
746
747 ret = network_do_splice(pdata->memfd, pdata->fd, ret);
748 if (ret < 0)
749 goto err_unlock;
750
751 read += ret;
752 len -= ret;
753 } while (len);
754
Paul Cercueil388dcd62015-11-27 15:15:48 +0100755 iio_mutex_unlock(pdata->lock);
Paul Cercueil04065c22015-03-05 14:08:16 +0100756 }
Paul Cercueil09a43482015-03-04 15:50:27 +0100757
Paul Cercueile6e5a092015-03-04 16:33:26 +0100758 pdata->mmap_addr = mmap(NULL, pdata->mmap_len,
Paul Cercueil09a43482015-03-04 15:50:27 +0100759 PROT_READ | PROT_WRITE, MAP_SHARED, pdata->memfd, 0);
Paul Cercueile6e5a092015-03-04 16:33:26 +0100760 if (pdata->mmap_addr == MAP_FAILED) {
761 pdata->mmap_addr = NULL;
Paul Cercueil09a43482015-03-04 15:50:27 +0100762 ret = -errno;
Paul Cercueil7d7e5d32015-03-05 10:51:41 +0100763 ERROR("Unable to mmap: %zi\n", -ret);
Paul Cercueil09a43482015-03-04 15:50:27 +0100764 return ret;
765 }
766
Paul Cercueile6e5a092015-03-04 16:33:26 +0100767 *addr_ptr = pdata->mmap_addr;
Paul Cercueil7c3f5d22016-02-18 11:49:04 +0100768 return read ? read : (ssize_t) bytes_used;
Paul Cercueil09a43482015-03-04 15:50:27 +0100769
Paul Cercueilca9d3382015-05-04 14:30:09 +0200770err_close_memfd:
771 close(memfd);
Paul Cercueil09a43482015-03-04 15:50:27 +0100772err_unlock:
Paul Cercueil388dcd62015-11-27 15:15:48 +0100773 iio_mutex_unlock(pdata->lock);
Paul Cercueil09a43482015-03-04 15:50:27 +0100774 return ret;
775}
776#endif
777
Paul Cercueil99cf3d42014-03-06 12:35:26 +0100778static ssize_t network_read_dev_attr(const struct iio_device *dev,
Paul Cercueil50c762a2014-04-14 15:55:43 +0200779 const char *attr, char *dst, size_t len, bool is_debug)
Paul Cercueil99cf3d42014-03-06 12:35:26 +0100780{
Paul Cercueil2e28d502015-11-30 18:46:49 +0100781 struct iio_context_pdata *pdata = dev->ctx->pdata;
Paul Cercueil5b577762014-06-03 15:31:42 +0200782
Paul Cercueil2e28d502015-11-30 18:46:49 +0100783 return iiod_client_read_attr(pdata->iiod_client, pdata->fd,
784 dev, NULL, attr, dst, len, is_debug);
Paul Cercueil99cf3d42014-03-06 12:35:26 +0100785}
786
Paul Cercueil07897d32014-03-06 12:46:08 +0100787static ssize_t network_write_dev_attr(const struct iio_device *dev,
Paul Cercueilcecda352014-05-06 18:14:29 +0200788 const char *attr, const char *src, size_t len, bool is_debug)
Paul Cercueil07897d32014-03-06 12:46:08 +0100789{
Paul Cercueil2e28d502015-11-30 18:46:49 +0100790 struct iio_context_pdata *pdata = dev->ctx->pdata;
Paul Cercueil5b577762014-06-03 15:31:42 +0200791
Paul Cercueil2e28d502015-11-30 18:46:49 +0100792 return iiod_client_write_attr(pdata->iiod_client, pdata->fd,
793 dev, NULL, attr, src, len, is_debug);
Paul Cercueil07897d32014-03-06 12:46:08 +0100794}
795
Paul Cercueil99cf3d42014-03-06 12:35:26 +0100796static ssize_t network_read_chn_attr(const struct iio_channel *chn,
797 const char *attr, char *dst, size_t len)
798{
Paul Cercueil2e28d502015-11-30 18:46:49 +0100799 struct iio_context_pdata *pdata = chn->dev->ctx->pdata;
Paul Cercueil5b577762014-06-03 15:31:42 +0200800
Paul Cercueil2e28d502015-11-30 18:46:49 +0100801 return iiod_client_read_attr(pdata->iiod_client, pdata->fd,
802 chn->dev, chn, attr, dst, len, false);
Paul Cercueil99cf3d42014-03-06 12:35:26 +0100803}
804
Paul Cercueil07897d32014-03-06 12:46:08 +0100805static ssize_t network_write_chn_attr(const struct iio_channel *chn,
Paul Cercueilcecda352014-05-06 18:14:29 +0200806 const char *attr, const char *src, size_t len)
Paul Cercueil07897d32014-03-06 12:46:08 +0100807{
Paul Cercueil2e28d502015-11-30 18:46:49 +0100808 struct iio_context_pdata *pdata = chn->dev->ctx->pdata;
Paul Cercueil5b577762014-06-03 15:31:42 +0200809
Paul Cercueil2e28d502015-11-30 18:46:49 +0100810 return iiod_client_write_attr(pdata->iiod_client, pdata->fd,
811 chn->dev, chn, attr, src, len, false);
Paul Cercueil07897d32014-03-06 12:46:08 +0100812}
813
Paul Cercueildcab40c2014-03-11 10:59:14 +0100814static int network_get_trigger(const struct iio_device *dev,
815 const struct iio_device **trigger)
816{
817 struct iio_context_pdata *pdata = dev->ctx->pdata;
Paul Cercueildcab40c2014-03-11 10:59:14 +0100818
Paul Cercueilcae6c2a2015-11-30 16:37:19 +0100819 return iiod_client_get_trigger(pdata->iiod_client,
820 pdata->fd, dev, trigger);
Paul Cercueildcab40c2014-03-11 10:59:14 +0100821}
822
823static int network_set_trigger(const struct iio_device *dev,
824 const struct iio_device *trigger)
825{
Paul Cercueila7b2aae2015-12-04 16:02:00 +0100826 struct iio_context_pdata *pdata = dev->ctx->pdata;
Paul Cercueil1494b862014-05-05 12:49:07 +0200827
Paul Cercueilcae6c2a2015-11-30 16:37:19 +0100828 return iiod_client_set_trigger(pdata->iiod_client,
829 pdata->fd, dev, trigger);
Paul Cercueildcab40c2014-03-11 10:59:14 +0100830}
831
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100832static void network_shutdown(struct iio_context *ctx)
833{
834 struct iio_context_pdata *pdata = ctx->pdata;
Paul Cercueil44ae11c2014-03-17 09:56:29 +0100835 unsigned int i;
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100836
Paul Cercueil388dcd62015-11-27 15:15:48 +0100837 iio_mutex_lock(pdata->lock);
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100838 write_command("\r\nEXIT\r\n", pdata->fd);
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100839 close(pdata->fd);
Paul Cercueil388dcd62015-11-27 15:15:48 +0100840 iio_mutex_unlock(pdata->lock);
Paul Cercueil1494b862014-05-05 12:49:07 +0200841
Paul Cercueil439e1a22015-02-24 13:50:51 +0100842 for (i = 0; i < ctx->nb_devices; i++) {
843 struct iio_device *dev = ctx->devices[i];
Paul Cercueilc5b00752015-02-24 14:29:53 +0100844 struct iio_device_pdata *dpdata = dev->pdata;
Paul Cercueil439e1a22015-02-24 13:50:51 +0100845
Paul Cercueilc5b00752015-02-24 14:29:53 +0100846 if (dpdata) {
Paul Cercueilaa0db142015-03-04 16:25:24 +0100847 network_close(dev);
Paul Cercueil388dcd62015-11-27 15:15:48 +0100848 iio_mutex_destroy(dpdata->lock);
Paul Cercueilc5b00752015-02-24 14:29:53 +0100849 free(dpdata);
Paul Cercueil439e1a22015-02-24 13:50:51 +0100850 }
851 }
852
Paul Cercueil157d43c2015-11-30 15:05:06 +0100853 iiod_client_destroy(pdata->iiod_client);
Paul Cercueil388dcd62015-11-27 15:15:48 +0100854 iio_mutex_destroy(pdata->lock);
Paul Cercueil2dd2c132015-02-24 10:41:01 +0100855 freeaddrinfo(pdata->addrinfo);
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100856 free(pdata);
857}
858
Paul Cercueil6691a3f2014-05-02 12:32:01 +0200859static int network_get_version(const struct iio_context *ctx,
Paul Cercueil9de9e9d2014-05-20 13:18:19 +0200860 unsigned int *major, unsigned int *minor, char git_tag[8])
Paul Cercueil6691a3f2014-05-02 12:32:01 +0200861{
Paul Cercueil2e209f92015-11-30 15:05:38 +0100862 return iiod_client_get_version(ctx->pdata->iiod_client, ctx->pdata->fd,
863 major, minor, git_tag);
Paul Cercueil6691a3f2014-05-02 12:32:01 +0200864}
865
Paul Cercueil8a266f12014-06-10 16:06:31 +0200866static unsigned int calculate_remote_timeout(unsigned int timeout)
867{
868 /* XXX(pcercuei): We currently hardcode timeout / 2 for the backend used
869 * by the remote. Is there something better to do here? */
870 return timeout / 2;
871}
872
Paul Cercueilbca3dbc2014-06-11 12:00:21 +0200873static int network_set_timeout(struct iio_context *ctx, unsigned int timeout)
874{
Paul Cercueilf996ae12015-12-03 12:29:13 +0100875 struct iio_context_pdata *pdata = ctx->pdata;
876 int ret, fd = pdata->fd;
877
878 ret = set_socket_timeout(fd, timeout);
Paul Cercueilbca3dbc2014-06-11 12:00:21 +0200879 if (!ret) {
880 timeout = calculate_remote_timeout(timeout);
Paul Cercueilf996ae12015-12-03 12:29:13 +0100881 ret = iiod_client_set_timeout(pdata->iiod_client, fd, timeout);
Paul Cercueilbca3dbc2014-06-11 12:00:21 +0200882 }
883 if (ret < 0) {
884 char buf[1024];
Paul Cercueil53fc4852015-05-22 10:57:53 +0200885 iio_strerror(-ret, buf, sizeof(buf));
Paul Cercueil8a266f12014-06-10 16:06:31 +0200886 WARNING("Unable to set R/W timeout: %s\n", buf);
887 } else {
Paul Cercueil8a266f12014-06-10 16:06:31 +0200888 ctx->rw_timeout_ms = timeout;
889 }
890 return ret;
891}
892
Paul Cercueil61157f92015-11-19 17:48:22 +0100893static int network_set_kernel_buffers_count(const struct iio_device *dev,
894 unsigned int nb_blocks)
895{
Paul Cercueila9810a82015-11-30 16:55:07 +0100896 struct iio_context_pdata *pdata = dev->ctx->pdata;
Paul Cercueil61157f92015-11-19 17:48:22 +0100897
Paul Cercueila9810a82015-11-30 16:55:07 +0100898 return iiod_client_set_kernel_buffers_count(pdata->iiod_client,
899 pdata->fd, dev, nb_blocks);
Paul Cercueil61157f92015-11-19 17:48:22 +0100900}
901
Paul Cercueil12d41832014-10-28 14:35:53 +0100902static struct iio_context * network_clone(const struct iio_context *ctx)
903{
Paul Cercueil7ef45ce2015-03-16 14:36:16 +0100904 if (ctx->description) {
905 char *ptr = strchr(ctx->description, ' ');
906 if (ptr) {
907#ifdef HAVE_IPV6
908 char buf[INET6_ADDRSTRLEN + IF_NAMESIZE + 2];
909#else
910 char buf[INET_ADDRSTRLEN + 1];
911#endif
912 strncpy(buf, ctx->description, sizeof(buf) - 1);
913 buf[ptr - ctx->description] = '\0';
914 return iio_create_network_context(buf);
915 }
916 }
917
Paul Cercueild3d56ee2015-01-08 16:36:31 +0100918 return iio_create_network_context(ctx->description);
Paul Cercueil12d41832014-10-28 14:35:53 +0100919}
920
Lars-Peter Clausen09a59d72016-02-03 15:27:04 +0100921static const struct iio_backend_ops network_ops = {
Paul Cercueil12d41832014-10-28 14:35:53 +0100922 .clone = network_clone,
Paul Cercueilba059762014-03-14 11:02:02 +0100923 .open = network_open,
924 .close = network_close,
Paul Cercueil9945bc82014-03-05 14:07:29 +0100925 .read = network_read,
Paul Cercueil2725f702014-05-02 11:02:16 +0200926 .write = network_write,
Paul Cercueil90189672015-03-16 11:41:53 +0100927#ifdef WITH_NETWORK_GET_BUFFER
Paul Cercueil09a43482015-03-04 15:50:27 +0100928 .get_buffer = network_get_buffer,
929#endif
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100930 .read_device_attr = network_read_dev_attr,
931 .write_device_attr = network_write_dev_attr,
Paul Cercueil99cf3d42014-03-06 12:35:26 +0100932 .read_channel_attr = network_read_chn_attr,
Paul Cercueil07897d32014-03-06 12:46:08 +0100933 .write_channel_attr = network_write_chn_attr,
Paul Cercueildcab40c2014-03-11 10:59:14 +0100934 .get_trigger = network_get_trigger,
935 .set_trigger = network_set_trigger,
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100936 .shutdown = network_shutdown,
Paul Cercueil6691a3f2014-05-02 12:32:01 +0200937 .get_version = network_get_version,
Paul Cercueil8a266f12014-06-10 16:06:31 +0200938 .set_timeout = network_set_timeout,
Paul Cercueil61157f92015-11-19 17:48:22 +0100939 .set_kernel_buffers_count = network_set_kernel_buffers_count,
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100940};
941
Paul Cercueil157d43c2015-11-30 15:05:06 +0100942static ssize_t network_write_data(struct iio_context_pdata *pdata,
943 int desc, const char *src, size_t len)
944{
Lars-Peter Clausen6a6c8662016-02-12 15:35:52 +0100945 return network_send(desc, src, len, 0);
Paul Cercueil157d43c2015-11-30 15:05:06 +0100946}
947
948static ssize_t network_read_data(struct iio_context_pdata *pdata,
949 int desc, char *dst, size_t len)
950{
Lars-Peter Clausen6a6c8662016-02-12 15:35:52 +0100951 return network_recv(desc, dst, len, 0);
Paul Cercueil157d43c2015-11-30 15:05:06 +0100952}
953
954static ssize_t network_read_line(struct iio_context_pdata *pdata,
955 int desc, char *dst, size_t len)
956{
957 size_t i;
Paul Cercueilce02dc92016-01-07 11:46:38 +0100958#ifdef __linux__
959 ssize_t ret;
960
Lars-Peter Clausen6a6c8662016-02-12 15:35:52 +0100961 ret = network_recv(desc, dst, len, MSG_PEEK);
Paul Cercueilce02dc92016-01-07 11:46:38 +0100962 if (ret < 0)
Lars-Peter Clausen6a6c8662016-02-12 15:35:52 +0100963 return ret;
Paul Cercueilce02dc92016-01-07 11:46:38 +0100964
965 /* Lookup for the trailing \n */
966 for (i = 0; i < (size_t) ret && dst[i] != '\n'; i++);
967
968 /* No \n found? Just garbage data */
969 if (i == (size_t) ret)
970 return -EIO;
971
972 /* Advance the read offset to the byte following the \n */
Lars-Peter Clausen6a6c8662016-02-12 15:35:52 +0100973 return network_recv(desc, dst, i + 1, MSG_TRUNC);
Paul Cercueilce02dc92016-01-07 11:46:38 +0100974#else
Paul Cercueil157d43c2015-11-30 15:05:06 +0100975 bool found = false;
976
977 for (i = 0; i < len - 1; i++) {
978 ssize_t ret = network_read_data(pdata, desc, dst + i, 1);
979
980 if (ret < 0)
981 return ret;
982
983 if (dst[i] != '\n')
984 found = true;
985 else if (found)
986 break;
987 }
988
989 dst[i] = '\0';
990 return (ssize_t) i;
Paul Cercueilce02dc92016-01-07 11:46:38 +0100991#endif
Paul Cercueil157d43c2015-11-30 15:05:06 +0100992}
993
Lars-Peter Clausen09a59d72016-02-03 15:27:04 +0100994static const struct iiod_client_ops network_iiod_client_ops = {
Paul Cercueil157d43c2015-11-30 15:05:06 +0100995 .write = network_write_data,
996 .read = network_read_data,
997 .read_line = network_read_line,
998};
999
Paul Cercueil63e52182014-12-11 12:52:48 +01001000struct iio_context * network_create_context(const char *host)
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001001{
Paul Cercueil2e38bbe2014-03-19 15:27:15 +01001002 struct addrinfo hints, *res;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001003 struct iio_context *ctx;
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +01001004 struct iio_context_pdata *pdata;
Paul Cercueil0e3c04d2015-05-13 17:37:11 +02001005 size_t i, len;
Paul Cercueil4970ac32015-02-24 10:59:00 +01001006 int fd, ret;
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001007 char *description;
Paul Cercueil1fef1a52014-04-07 16:31:15 +02001008#ifdef _WIN32
1009 WSADATA wsaData;
1010
1011 ret = WSAStartup(MAKEWORD(2, 0), &wsaData);
1012 if (ret < 0) {
1013 ERROR("WSAStartup failed with error %i\n", ret);
Paul Cercueilcc575532015-03-16 17:15:24 +01001014 errno = -ret;
Paul Cercueil1fef1a52014-04-07 16:31:15 +02001015 return NULL;
1016 }
1017#endif
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001018
Paul Cercueil2e38bbe2014-03-19 15:27:15 +01001019 memset(&hints, 0, sizeof(hints));
1020 hints.ai_family = AF_UNSPEC;
1021 hints.ai_socktype = SOCK_STREAM;
Paul Cercueilab114932014-05-19 13:03:17 +02001022
1023#ifdef HAVE_AVAHI
1024 if (!host) {
1025 char addr_str[AVAHI_ADDRESS_STR_MAX];
1026 char port_str[6];
1027 AvahiAddress address;
Paul Cercueil0f729d32014-06-05 17:38:54 +02001028 uint16_t port = IIOD_PORT;
Paul Cercueilab114932014-05-19 13:03:17 +02001029
1030 memset(&address, 0, sizeof(address));
1031
1032 ret = discover_host(&address, &port);
1033 if (ret < 0) {
Paul Cercueilcc575532015-03-16 17:15:24 +01001034 DEBUG("Unable to find host: %s\n", strerror(-ret));
1035 errno = -ret;
Paul Cercueilab114932014-05-19 13:03:17 +02001036 return NULL;
1037 }
1038
1039 avahi_address_snprint(addr_str, sizeof(addr_str), &address);
1040 snprintf(port_str, sizeof(port_str), "%hu", port);
1041 ret = getaddrinfo(addr_str, port_str, &hints, &res);
1042 } else
1043#endif
1044 {
1045 ret = getaddrinfo(host, IIOD_PORT_STR, &hints, &res);
1046 }
1047
Paul Cercueil2e38bbe2014-03-19 15:27:15 +01001048 if (ret) {
Paul Cercueilab114932014-05-19 13:03:17 +02001049 ERROR("Unable to find host: %s\n", gai_strerror(ret));
Paul Cercueild9eb4cb2015-03-23 14:30:20 +01001050#ifndef _WIN32
Paul Cercueilcc575532015-03-16 17:15:24 +01001051 if (ret != EAI_SYSTEM)
1052 errno = ret;
Paul Cercueild9eb4cb2015-03-23 14:30:20 +01001053#endif
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001054 return NULL;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001055 }
1056
Paul Cercueil4970ac32015-02-24 10:59:00 +01001057 fd = create_socket(res);
Paul Cercueilcc575532015-03-16 17:15:24 +01001058 if (fd < 0) {
1059 errno = fd;
Paul Cercueil2dd2c132015-02-24 10:41:01 +01001060 goto err_free_addrinfo;
Paul Cercueilcc575532015-03-16 17:15:24 +01001061 }
Paul Cercueilbca3dbc2014-06-11 12:00:21 +02001062
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +01001063 pdata = calloc(1, sizeof(*pdata));
1064 if (!pdata) {
Paul Cercueilcc575532015-03-16 17:15:24 +01001065 errno = ENOMEM;
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +01001066 goto err_close_socket;
1067 }
1068
1069 pdata->fd = fd;
Paul Cercueil2dd2c132015-02-24 10:41:01 +01001070 pdata->addrinfo = res;
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +01001071
Paul Cercueil157d43c2015-11-30 15:05:06 +01001072 pdata->lock = iio_mutex_create();
1073 if (!pdata->lock) {
1074 errno = ENOMEM;
1075 goto err_free_pdata;
1076 }
1077
1078 pdata->iiod_client = iiod_client_new(pdata, pdata->lock,
1079 &network_iiod_client_ops);
1080 if (!pdata->iiod_client)
1081 goto err_destroy_mutex;
1082
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001083 DEBUG("Creating context...\n");
Paul Cercueil94726b12015-12-01 11:15:54 +01001084 ctx = iiod_client_create_context(pdata->iiod_client, fd);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001085 if (!ctx)
Paul Cercueil157d43c2015-11-30 15:05:06 +01001086 goto err_destroy_iiod_client;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001087
Paul Cercueil2057fd32014-10-28 14:44:19 +01001088 /* Override the name and low-level functions of the XML context
1089 * with those corresponding to the network context */
1090 ctx->name = "network";
1091 ctx->ops = &network_ops;
1092 ctx->pdata = pdata;
1093
Paul Cercueil06c479d2015-01-08 16:14:57 +01001094#ifdef HAVE_IPV6
Paul Cercueiled15e492015-01-12 15:52:28 +01001095 len = INET6_ADDRSTRLEN + IF_NAMESIZE + 2;
Paul Cercueil06c479d2015-01-08 16:14:57 +01001096#else
1097 len = INET_ADDRSTRLEN + 1;
1098#endif
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001099
1100 description = malloc(len);
1101 if (!description) {
Paul Cercueilcc575532015-03-16 17:15:24 +01001102 ret = -ENOMEM;
Paul Cercueil06c479d2015-01-08 16:14:57 +01001103 goto err_network_shutdown;
1104 }
1105
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001106 description[0] = '\0';
Paul Cercueil06c479d2015-01-08 16:14:57 +01001107
1108#ifdef HAVE_IPV6
1109 if (res->ai_family == AF_INET6) {
1110 struct sockaddr_in6 *in = (struct sockaddr_in6 *) res->ai_addr;
Paul Cercueiled15e492015-01-12 15:52:28 +01001111 char *ptr;
Paul Cercueil06c479d2015-01-08 16:14:57 +01001112 inet_ntop(AF_INET6, &in->sin6_addr,
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001113 description, INET6_ADDRSTRLEN);
Paul Cercueiled15e492015-01-12 15:52:28 +01001114
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001115 ptr = if_indextoname(in->sin6_scope_id, description +
1116 strlen(description) + 1);
Paul Cercueiled15e492015-01-12 15:52:28 +01001117 if (!ptr) {
Paul Cercueilcc575532015-03-16 17:15:24 +01001118 ret = -errno;
Paul Cercueiled15e492015-01-12 15:52:28 +01001119 ERROR("Unable to lookup interface of IPv6 address\n");
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001120 goto err_free_description;
Paul Cercueiled15e492015-01-12 15:52:28 +01001121 }
1122
1123 *(ptr - 1) = '%';
Paul Cercueil06c479d2015-01-08 16:14:57 +01001124 }
1125#endif
1126 if (res->ai_family == AF_INET) {
1127 struct sockaddr_in *in = (struct sockaddr_in *) res->ai_addr;
Paul Cercueile7a31692015-07-15 10:52:47 +02001128#if (!_WIN32 || _WIN32_WINNT >= 0x600)
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001129 inet_ntop(AF_INET, &in->sin_addr, description, INET_ADDRSTRLEN);
Paul Cercueile7a31692015-07-15 10:52:47 +02001130#else
1131 char *tmp = inet_ntoa(in->sin_addr);
1132 strncpy(description, tmp, len);
1133#endif
Paul Cercueil06c479d2015-01-08 16:14:57 +01001134 }
1135
Paul Cercueil44ae11c2014-03-17 09:56:29 +01001136 for (i = 0; i < ctx->nb_devices; i++) {
1137 struct iio_device *dev = ctx->devices[i];
Paul Cercueilff778232014-03-24 14:23:08 +01001138
Paul Cercueil439e1a22015-02-24 13:50:51 +01001139 dev->pdata = calloc(1, sizeof(*dev->pdata));
1140 if (!dev->pdata) {
Paul Cercueilcc575532015-03-16 17:15:24 +01001141 ret = -ENOMEM;
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001142 goto err_free_description;
Paul Cercueil439e1a22015-02-24 13:50:51 +01001143 }
1144
1145 dev->pdata->fd = -1;
Paul Cercueil90189672015-03-16 11:41:53 +01001146#ifdef WITH_NETWORK_GET_BUFFER
Paul Cercueil09a43482015-03-04 15:50:27 +01001147 dev->pdata->memfd = -1;
Paul Cercueile6e5a092015-03-04 16:33:26 +01001148#endif
Paul Cercueilc5b00752015-02-24 14:29:53 +01001149
Paul Cercueil388dcd62015-11-27 15:15:48 +01001150 dev->pdata->lock = iio_mutex_create();
1151 if (!dev->pdata->lock) {
1152 ret = -ENOMEM;
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001153 goto err_free_description;
Paul Cercueil388dcd62015-11-27 15:15:48 +01001154 }
Paul Cercueil44ae11c2014-03-17 09:56:29 +01001155 }
1156
Paul Cercueilfd387472015-08-05 10:34:19 +02001157 ret = iio_context_init(ctx);
1158 if (ret < 0)
1159 goto err_free_description;
Paul Cercueil4c6729d2014-04-04 17:24:41 +02001160
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001161 if (ctx->description) {
Paul Cercueil0e3c04d2015-05-13 17:37:11 +02001162 size_t desc_len = strlen(description);
1163 size_t new_size = desc_len + strlen(ctx->description) + 2;
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001164 char *ptr, *new_description = realloc(description, new_size);
Paul Cercueilcc575532015-03-16 17:15:24 +01001165 if (!new_description) {
1166 ret = -ENOMEM;
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001167 goto err_free_description;
Paul Cercueilcc575532015-03-16 17:15:24 +01001168 }
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001169
1170 ptr = strrchr(new_description, '\0');
Paul Cercueil0e3c04d2015-05-13 17:37:11 +02001171 snprintf(ptr, new_size - desc_len, " %s", ctx->description);
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001172 free(ctx->description);
1173
1174 ctx->description = new_description;
1175 } else {
1176 ctx->description = description;
1177 }
1178
Paul Cercueilf996ae12015-12-03 12:29:13 +01001179 iiod_client_set_timeout(pdata->iiod_client, fd,
1180 calculate_remote_timeout(DEFAULT_TIMEOUT_MS));
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001181 return ctx;
1182
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001183err_free_description:
1184 free(description);
Paul Cercueil44ae11c2014-03-17 09:56:29 +01001185err_network_shutdown:
Paul Cercueil44ae11c2014-03-17 09:56:29 +01001186 iio_context_destroy(ctx);
Paul Cercueilcc575532015-03-16 17:15:24 +01001187 errno = -ret;
Paul Cercueil2057fd32014-10-28 14:44:19 +01001188 return NULL;
Paul Cercueil157d43c2015-11-30 15:05:06 +01001189
1190err_destroy_iiod_client:
1191 iiod_client_destroy(pdata->iiod_client);
1192err_destroy_mutex:
1193 iio_mutex_destroy(pdata->lock);
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +01001194err_free_pdata:
1195 free(pdata);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001196err_close_socket:
1197 close(fd);
Paul Cercueil2dd2c132015-02-24 10:41:01 +01001198err_free_addrinfo:
1199 freeaddrinfo(res);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001200 return NULL;
1201}