blob: 85e1e115b0e3f9d82d9bb0dbd82aee6ab847eb00 [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
Paul Cercueilab114932014-05-19 13:03:17 +020085#ifdef HAVE_AVAHI
86struct avahi_discovery_data {
87 AvahiSimplePoll *poll;
88 AvahiAddress *address;
89 uint16_t *port;
90 bool found, resolved;
91};
92
93static void __avahi_resolver_cb(AvahiServiceResolver *resolver,
94 __notused AvahiIfIndex iface, __notused AvahiProtocol proto,
95 __notused AvahiResolverEvent event, __notused const char *name,
96 __notused const char *type, __notused const char *domain,
97 __notused const char *host_name, const AvahiAddress *address,
98 uint16_t port, __notused AvahiStringList *txt,
99 __notused AvahiLookupResultFlags flags, void *d)
100{
101 struct avahi_discovery_data *ddata = (struct avahi_discovery_data *) d;
102
103 memcpy(ddata->address, address, sizeof(*address));
104 *ddata->port = port;
105 ddata->resolved = true;
106 avahi_service_resolver_free(resolver);
107}
108
109static void __avahi_browser_cb(AvahiServiceBrowser *browser,
110 AvahiIfIndex iface, AvahiProtocol proto,
111 AvahiBrowserEvent event, const char *name,
112 const char *type, const char *domain,
113 __notused AvahiLookupResultFlags flags, void *d)
114{
115 struct avahi_discovery_data *ddata = (struct avahi_discovery_data *) d;
116 struct AvahiClient *client = avahi_service_browser_get_client(browser);
117
118 switch (event) {
119 default:
120 case AVAHI_BROWSER_NEW:
121 ddata->found = !!avahi_service_resolver_new(client, iface,
122 proto, name, type, domain,
123 AVAHI_PROTO_UNSPEC, 0,
124 __avahi_resolver_cb, d);
125 break;
126 case AVAHI_BROWSER_ALL_FOR_NOW:
127 if (ddata->found) {
128 while (!ddata->resolved) {
129 struct timespec ts;
130 ts.tv_sec = 0;
131 ts.tv_nsec = 4000000;
132 nanosleep(&ts, NULL);
133 }
134 }
135 case AVAHI_BROWSER_FAILURE: /* fall-through */
136 avahi_simple_poll_quit(ddata->poll);
137 case AVAHI_BROWSER_CACHE_EXHAUSTED: /* fall-through */
138 break;
139 }
140}
141
142static int discover_host(AvahiAddress *addr, uint16_t *port)
143{
144 struct avahi_discovery_data ddata;
145 int ret = 0;
146 AvahiClient *client;
147 AvahiServiceBrowser *browser;
148 AvahiSimplePoll *poll = avahi_simple_poll_new();
149 if (!poll)
150 return -ENOMEM;
151
152 client = avahi_client_new(avahi_simple_poll_get(poll),
153 0, NULL, NULL, &ret);
154 if (!client) {
155 ERROR("Unable to start ZeroConf client :%s\n",
156 avahi_strerror(ret));
157 goto err_free_poll;
158 }
159
160 memset(&ddata, 0, sizeof(ddata));
161 ddata.poll = poll;
162 ddata.address = addr;
163 ddata.port = port;
164
165 browser = avahi_service_browser_new(client,
166 AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
167 "_iio._tcp", NULL, 0, __avahi_browser_cb, &ddata);
168 if (!browser) {
169 ret = avahi_client_errno(client);
170 ERROR("Unable to create ZeroConf browser: %s\n",
171 avahi_strerror(ret));
172 goto err_free_client;
173 }
174
175 DEBUG("Trying to discover host\n");
176 avahi_simple_poll_loop(poll);
177
178 if (!ddata.found)
179 ret = ENXIO;
180
181 avahi_service_browser_free(browser);
182err_free_client:
183 avahi_client_free(client);
184err_free_poll:
185 avahi_simple_poll_free(poll);
186 return -ret; /* we want a negative error code */
187}
188#endif /* HAVE_AVAHI */
189
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100190static ssize_t write_all(const void *src, size_t len, int fd)
191{
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200192 uintptr_t ptr = (uintptr_t) src;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100193 while (len) {
Paul Cercueil4012cff2015-05-11 10:47:40 +0200194 ssize_t ret = send(fd, (const void *) ptr, (int) len, 0);
Lars-Peter Clausencb7b8bf2014-12-05 16:08:52 +0100195 if (ret < 0) {
Paul Cercueil135b3612015-06-30 14:10:14 +0200196#ifdef _WIN32
197 int err = WSAGetLastError();
198#else
199 int err = errno;
200#endif
Paul Cercueil0a96c062015-07-02 11:16:33 +0200201 if (err == EINTR)
Lars-Peter Clausencb7b8bf2014-12-05 16:08:52 +0100202 continue;
Paul Cercueil135b3612015-06-30 14:10:14 +0200203 return (ssize_t) -err;
Lars-Peter Clausencb7b8bf2014-12-05 16:08:52 +0100204 }
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100205 ptr += ret;
206 len -= ret;
207 }
Paul Cercueil4012cff2015-05-11 10:47:40 +0200208 return (ssize_t)(ptr - (uintptr_t) src);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100209}
210
211static ssize_t read_all(void *dst, size_t len, int fd)
212{
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200213 uintptr_t ptr = (uintptr_t) dst;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100214 while (len) {
Paul Cercueil4012cff2015-05-11 10:47:40 +0200215 ssize_t ret = recv(fd, (void *) ptr, (int) len, 0);
Lars-Peter Clausencb7b8bf2014-12-05 16:08:52 +0100216 if (ret < 0) {
Paul Cercueil135b3612015-06-30 14:10:14 +0200217#ifdef _WIN32
218 int err = WSAGetLastError();
219#else
220 int err = errno;
221#endif
Paul Cercueil0a96c062015-07-02 11:16:33 +0200222 if (err == EINTR)
Lars-Peter Clausencb7b8bf2014-12-05 16:08:52 +0100223 continue;
Paul Cercueil135b3612015-06-30 14:10:14 +0200224 return (ssize_t) -err;
Lars-Peter Clausencb7b8bf2014-12-05 16:08:52 +0100225 }
Paul Cercueil43eb7e82014-11-13 12:46:59 +0100226 if (ret == 0)
227 return -EPIPE;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100228 ptr += ret;
229 len -= ret;
230 }
Paul Cercueil4012cff2015-05-11 10:47:40 +0200231 return (ssize_t)(ptr - (uintptr_t) dst);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100232}
233
Paul Cercueile60c3ed2014-03-04 11:23:56 +0100234static int read_integer(int fd, long *val)
235{
236 unsigned int i;
237 char buf[1024], *ptr;
238 ssize_t ret;
239 bool found = false;
240
241 for (i = 0; i < sizeof(buf) - 1; i++) {
242 ret = read_all(buf + i, 1, fd);
243 if (ret < 0)
244 return (int) ret;
245
Paul Cercueil6691a3f2014-05-02 12:32:01 +0200246 /* Skip the eventual first few carriage returns.
247 * Also stop when a dot is found (for parsing floats) */
248 if (buf[i] != '\n' && buf[i] != '.')
Paul Cercueile60c3ed2014-03-04 11:23:56 +0100249 found = true;
250 else if (found)
251 break;
252 }
253
254 buf[i] = '\0';
255 ret = (ssize_t) strtol(buf, &ptr, 10);
256 if (ptr == buf)
257 return -EINVAL;
258 *val = (long) ret;
259 return 0;
260}
261
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100262static ssize_t write_command(const char *cmd, int fd)
263{
264 ssize_t ret;
265
266 DEBUG("Writing command: %s\n", cmd);
267 ret = write_all(cmd, strlen(cmd), fd);
268 if (ret < 0) {
269 char buf[1024];
Paul Cercueil53fc4852015-05-22 10:57:53 +0200270 iio_strerror(-ret, buf, sizeof(buf));
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100271 ERROR("Unable to send command: %s\n", buf);
272 }
273 return ret;
274}
275
276static long exec_command(const char *cmd, int fd)
277{
278 long resp;
279 ssize_t ret = write_command(cmd, fd);
280 if (ret < 0)
281 return (long) ret;
282
283 DEBUG("Reading response\n");
284 ret = read_integer(fd, &resp);
285 if (ret < 0) {
286 char buf[1024];
Paul Cercueil53fc4852015-05-22 10:57:53 +0200287 iio_strerror(-ret, buf, sizeof(buf));
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100288 ERROR("Unable to read response: %s\n", buf);
289 return (long) ret;
290 }
291
Paul Cercueilc7fe2ea2014-03-28 11:38:45 +0100292#if LOG_LEVEL >= DEBUG_L
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100293 if (resp < 0) {
294 char buf[1024];
Paul Cercueil53fc4852015-05-22 10:57:53 +0200295 iio_strerror(-resp, buf, sizeof(buf));
Paul Cercueilc7fe2ea2014-03-28 11:38:45 +0100296 DEBUG("Server returned an error: %s\n", buf);
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100297 }
Paul Cercueilc7fe2ea2014-03-28 11:38:45 +0100298#endif
299
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100300 return resp;
301}
302
Paul Cercueil4970ac32015-02-24 10:59:00 +0100303#ifndef _WIN32
Paul Cercueil4970ac32015-02-24 10:59:00 +0100304/* The purpose of this function is to provide a version of connect()
305 * that does not ignore timeouts... */
306static int do_connect(int fd, const struct sockaddr *addr,
307 socklen_t addrlen, struct timeval *timeout)
308{
309 int ret, error;
310 socklen_t len;
311 fd_set set;
312
313 FD_ZERO(&set);
314 FD_SET(fd, &set);
315
316 ret = set_blocking_mode(fd, false);
317 if (ret < 0)
318 return ret;
319
320 ret = connect(fd, addr, addrlen);
321 if (ret < 0 && errno != EINPROGRESS) {
322 ret = -errno;
323 goto end;
324 }
325
326 ret = select(fd + 1, &set, &set, NULL, timeout);
327 if (ret < 0) {
328 ret = -errno;
329 goto end;
330 }
331 if (ret == 0) {
332 ret = -ETIMEDOUT;
333 goto end;
334 }
335
336 /* Verify that we don't have an error */
337 len = sizeof(error);
338 ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len);
339 if(ret < 0) {
340 ret = -errno;
341 goto end;
342 }
343 if (error) {
344 ret = -error;
345 goto end;
346 }
347
348end:
349 /* Restore blocking mode */
350 set_blocking_mode(fd, true);
351 return ret;
352}
353
354static int set_socket_timeout(int fd, unsigned int timeout)
355{
356 struct timeval tv;
357
358 tv.tv_sec = timeout / 1000;
359 tv.tv_usec = (timeout % 1000) * 1000;
360 if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0 ||
361 setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO,
362 &tv, sizeof(tv)) < 0)
363 return -errno;
364 else
365 return 0;
366}
367#else
368static int set_socket_timeout(int fd, unsigned int timeout)
369{
370 if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO,
371 (const char *) &timeout, sizeof(timeout)) < 0 ||
372 setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO,
373 (const char *) &timeout, sizeof(timeout)) < 0)
Paul Cercueil135b3612015-06-30 14:10:14 +0200374 return -WSAGetLastError();
Paul Cercueil4970ac32015-02-24 10:59:00 +0100375 else
376 return 0;
377}
378#endif /* !_WIN32 */
379
380static int create_socket(const struct addrinfo *addrinfo)
381{
382 struct timeval timeout;
383 int ret, fd, yes = 1;
384
Paul Cercueil4012cff2015-05-11 10:47:40 +0200385#ifdef _WIN32
386 SOCKET s = socket(addrinfo->ai_family, addrinfo->ai_socktype, 0);
387 fd = (s == INVALID_SOCKET) ? -1 : (int) s;
Paul Cercueil135b3612015-06-30 14:10:14 +0200388 if (fd < 0)
389 return -WSAGetLastError();
Paul Cercueil4012cff2015-05-11 10:47:40 +0200390#else
Paul Cercueil4970ac32015-02-24 10:59:00 +0100391 fd = socket(addrinfo->ai_family, addrinfo->ai_socktype, 0);
Paul Cercueil135b3612015-06-30 14:10:14 +0200392 if (fd < 0)
393 return -errno;
Paul Cercueil4012cff2015-05-11 10:47:40 +0200394#endif
Paul Cercueil4970ac32015-02-24 10:59:00 +0100395
396 timeout.tv_sec = DEFAULT_TIMEOUT_MS / 1000;
397 timeout.tv_usec = (DEFAULT_TIMEOUT_MS % 1000) * 1000;
398
399#ifndef _WIN32
400 ret = do_connect(fd, addrinfo->ai_addr, addrinfo->ai_addrlen, &timeout);
Paul Cercueil135b3612015-06-30 14:10:14 +0200401 if (ret < 0)
402 ret = -errno;
Paul Cercueil4970ac32015-02-24 10:59:00 +0100403#else
Paul Cercueil4012cff2015-05-11 10:47:40 +0200404 ret = connect(fd, addrinfo->ai_addr, (int) addrinfo->ai_addrlen);
Paul Cercueil135b3612015-06-30 14:10:14 +0200405 if (ret == SOCKET_ERROR)
406 ret = -WSAGetLastError();
Paul Cercueil4970ac32015-02-24 10:59:00 +0100407#endif
408 if (ret < 0) {
Paul Cercueil4970ac32015-02-24 10:59:00 +0100409 close(fd);
410 return ret;
411 }
412
413 set_socket_timeout(fd, DEFAULT_TIMEOUT_MS);
414 setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
415 (const char *) &yes, sizeof(yes));
416 return fd;
417}
418
Paul Cercueil92f15c22015-04-20 11:36:51 +0200419static int network_open(const struct iio_device *dev,
420 size_t samples_count, bool cyclic)
Paul Cercueilba059762014-03-14 11:02:02 +0100421{
Paul Cercueil439e1a22015-02-24 13:50:51 +0100422 struct iio_context_pdata *pdata = dev->ctx->pdata;
Paul Cercueil80dc1082015-12-01 18:20:31 +0100423 struct iio_device_pdata *ppdata = dev->pdata;
424 int fd, ret = -EBUSY;
Paul Cercueilba059762014-03-14 11:02:02 +0100425
Paul Cercueil80dc1082015-12-01 18:20:31 +0100426 iio_mutex_lock(ppdata->lock);
427 if (ppdata->fd >= 0)
428 goto out_mutex_unlock;
Paul Cercueil439e1a22015-02-24 13:50:51 +0100429
Paul Cercueil80dc1082015-12-01 18:20:31 +0100430 ret = create_socket(pdata->addrinfo);
431 if (ret < 0)
432 goto out_mutex_unlock;
Paul Cercueilba059762014-03-14 11:02:02 +0100433
Paul Cercueil80dc1082015-12-01 18:20:31 +0100434 fd = ret;
Paul Cercueilba059762014-03-14 11:02:02 +0100435
Paul Cercueil80dc1082015-12-01 18:20:31 +0100436 ret = iiod_client_open_unlocked(pdata->iiod_client, fd,
437 dev, samples_count, cyclic);
Paul Cercueil44ae11c2014-03-17 09:56:29 +0100438 if (ret < 0) {
Paul Cercueil439e1a22015-02-24 13:50:51 +0100439 close(fd);
Paul Cercueil80dc1082015-12-01 18:20:31 +0100440 goto out_mutex_unlock;
Paul Cercueil44ae11c2014-03-17 09:56:29 +0100441 }
Paul Cercueil439e1a22015-02-24 13:50:51 +0100442
Paul Cercueil80dc1082015-12-01 18:20:31 +0100443 ppdata->is_tx = iio_device_is_tx(dev);
444 ppdata->is_cyclic = cyclic;
445 ppdata->fd = fd;
446 ppdata->wait_for_err_code = false;
Paul Cercueild957b982015-08-05 14:39:01 +0200447#ifdef WITH_NETWORK_GET_BUFFER
Paul Cercueil80dc1082015-12-01 18:20:31 +0100448 ppdata->mmap_len = samples_count * iio_device_get_sample_size(dev);
Paul Cercueild957b982015-08-05 14:39:01 +0200449#endif
Paul Cercueil80dc1082015-12-01 18:20:31 +0100450
451out_mutex_unlock:
452 iio_mutex_unlock(ppdata->lock);
453 return ret;
Paul Cercueilba059762014-03-14 11:02:02 +0100454}
455
Paul Cercueil8f7f6c42015-02-24 15:00:35 +0100456static ssize_t read_error_code(int fd)
457{
458 /*
459 * The server returns two integer codes.
460 * The first one is returned right after the WRITEBUF command is issued,
461 * and corresponds to the error code returned when the server attempted
462 * to open the device.
463 * If zero, a second error code is returned, that corresponds (if positive)
464 * to the number of bytes written.
465 *
466 * To speed up things, we delay error reporting. We just send out the
467 * data without reading the error code that the server gives us, because
468 * the answer will take too much time. If an error occured, it will be
469 * reported by the next call to iio_buffer_push().
470 */
471
472 unsigned int i;
473 long resp = 0;
474
475 for (i = 0; i < 2; i++) {
476 ssize_t ret = read_integer(fd, &resp);
477 if (ret < 0)
478 return ret;
479 if (resp < 0)
480 return (ssize_t) resp;
481 }
482
Paul Cercueil7d7e5d32015-03-05 10:51:41 +0100483 return (ssize_t) resp;
Paul Cercueil8f7f6c42015-02-24 15:00:35 +0100484}
485
Paul Cercueil3c0da372015-03-05 11:36:39 +0100486static ssize_t write_rwbuf_command(const struct iio_device *dev,
487 const char *cmd, bool do_exec)
488{
489 struct iio_device_pdata *pdata = dev->pdata;
490 int fd = pdata->fd;
491
492 if (pdata->wait_for_err_code) {
493 ssize_t ret = read_error_code(fd);
494
495 pdata->wait_for_err_code = false;
496 if (ret < 0)
497 return ret;
498 }
499
500 return do_exec ? exec_command(cmd, fd) : write_command(cmd, fd);
501}
502
Paul Cercueilba059762014-03-14 11:02:02 +0100503static int network_close(const struct iio_device *dev)
504{
Paul Cercueil439e1a22015-02-24 13:50:51 +0100505 struct iio_device_pdata *pdata = dev->pdata;
Paul Cercueild5d84612015-06-08 21:24:15 +0200506 int ret = -EBADF;
Paul Cercueil80dc1082015-12-01 18:20:31 +0100507
508 iio_mutex_lock(pdata->lock);
Paul Cercueil439e1a22015-02-24 13:50:51 +0100509
Paul Cercueila34596e2015-03-05 14:33:46 +0100510 if (pdata->fd >= 0) {
Paul Cercueil80dc1082015-12-01 18:20:31 +0100511 ret = iiod_client_close_unlocked(dev->ctx->pdata->iiod_client,
512 pdata->fd, dev);
Paul Cercueil1494b862014-05-05 12:49:07 +0200513
Paul Cercueila34596e2015-03-05 14:33:46 +0100514 write_command("\r\nEXIT\r\n", pdata->fd);
Paul Cercueilaa0db142015-03-04 16:25:24 +0100515
Paul Cercueila34596e2015-03-05 14:33:46 +0100516 close(pdata->fd);
517 pdata->fd = -1;
Paul Cercueila34596e2015-03-05 14:33:46 +0100518 }
Paul Cercueile6e5a092015-03-04 16:33:26 +0100519
Paul Cercueil90189672015-03-16 11:41:53 +0100520#ifdef WITH_NETWORK_GET_BUFFER
Paul Cercueile6e5a092015-03-04 16:33:26 +0100521 if (pdata->memfd >= 0)
522 close(pdata->memfd);
523 pdata->memfd = -1;
524
525 if (pdata->mmap_addr) {
526 munmap(pdata->mmap_addr, pdata->mmap_len);
527 pdata->mmap_addr = NULL;
528 }
529#endif
Paul Cercueil80dc1082015-12-01 18:20:31 +0100530
531 iio_mutex_unlock(pdata->lock);
Paul Cercueil1494b862014-05-05 12:49:07 +0200532 return ret;
Paul Cercueilba059762014-03-14 11:02:02 +0100533}
534
Paul Cercueil7d7e5d32015-03-05 10:51:41 +0100535static ssize_t network_read_mask(int fd, uint32_t *mask, size_t words)
536{
537 long read_len;
538 ssize_t ret;
539
540 ret = read_integer(fd, &read_len);
541 if (ret < 0)
542 return ret;
543
544 if (read_len > 0 && mask) {
Paul Cercueil4012cff2015-05-11 10:47:40 +0200545 size_t i;
Paul Cercueil7d7e5d32015-03-05 10:51:41 +0100546 char buf[9];
547
548 buf[8] = '\0';
549 DEBUG("Reading mask\n");
550
551 for (i = words; i > 0; i--) {
552 ret = read_all(buf, 8, fd);
553 if (ret < 0)
554 return ret;
555
556 sscanf(buf, "%08x", &mask[i - 1]);
557 DEBUG("mask[%i] = 0x%x\n", i - 1, mask[i - 1]);
558 }
559 }
560
561 if (read_len > 0) {
562 char c;
563 ssize_t nb = read_all(&c, 1, fd);
564 if (nb > 0 && c != '\n')
565 read_len = -EIO;
566 }
567
568 return (ssize_t) read_len;
569}
570
Paul Cercueil45c575d2014-03-20 15:14:01 +0100571static ssize_t network_read(const struct iio_device *dev, void *dst, size_t len,
572 uint32_t *mask, size_t words)
Paul Cercueilf9286452014-03-18 14:32:17 +0100573{
Paul Cercueilc5b00752015-02-24 14:29:53 +0100574 struct iio_device_pdata *pdata = dev->pdata;
Paul Cercueil72793642015-12-02 11:57:10 +0100575 ssize_t ret;
Paul Cercueil1494b862014-05-05 12:49:07 +0200576
Paul Cercueil388dcd62015-11-27 15:15:48 +0100577 iio_mutex_lock(pdata->lock);
Paul Cercueil72793642015-12-02 11:57:10 +0100578 ret = iiod_client_read_unlocked(dev->ctx->pdata->iiod_client,
579 pdata->fd, dev, dst, len, mask, words);
Paul Cercueil388dcd62015-11-27 15:15:48 +0100580 iio_mutex_unlock(pdata->lock);
Paul Cercueil72793642015-12-02 11:57:10 +0100581
582 return ret;
Paul Cercueil9945bc82014-03-05 14:07:29 +0100583}
584
Paul Cercueila62f84e2015-02-24 14:16:08 +0100585static ssize_t network_write(const struct iio_device *dev,
586 const void *src, size_t len)
Paul Cercueil2725f702014-05-02 11:02:16 +0200587{
Paul Cercueilc5b00752015-02-24 14:29:53 +0100588 struct iio_device_pdata *pdata = dev->pdata;
Paul Cercueil2725f702014-05-02 11:02:16 +0200589 ssize_t ret;
Paul Cercueil2725f702014-05-02 11:02:16 +0200590
Paul Cercueil388dcd62015-11-27 15:15:48 +0100591 iio_mutex_lock(pdata->lock);
Paul Cercueilf19568a2015-12-02 17:57:51 +0100592 ret = iiod_client_write_unlocked(dev->ctx->pdata->iiod_client,
593 pdata->fd, dev, src, len);
Paul Cercueil388dcd62015-11-27 15:15:48 +0100594 iio_mutex_unlock(pdata->lock);
Paul Cercueil1494b862014-05-05 12:49:07 +0200595
Paul Cercueil1494b862014-05-05 12:49:07 +0200596 return ret;
Paul Cercueil2725f702014-05-02 11:02:16 +0200597}
598
Paul Cercueil90189672015-03-16 11:41:53 +0100599#ifdef WITH_NETWORK_GET_BUFFER
Paul Cercueil7d7e5d32015-03-05 10:51:41 +0100600static ssize_t network_do_splice(int fd_out, int fd_in, size_t len)
Paul Cercueil09a43482015-03-04 15:50:27 +0100601{
602 int pipefd[2];
Paul Cercueil04065c22015-03-05 14:08:16 +0100603 ssize_t ret, read_len = len;
Paul Cercueil09a43482015-03-04 15:50:27 +0100604
605 ret = (ssize_t) pipe(pipefd);
606 if (ret < 0)
607 return -errno;
608
609 do {
Paul Cercueila107c6d2015-03-05 13:54:10 +0100610 /*
611 * SPLICE_F_NONBLOCK is just here to avoid a deadlock when
612 * splicing from a socket. As the socket is not in
613 * non-blocking mode, it should never return -EAGAIN.
614 * TODO(pcercuei): Find why it locks...
615 * */
616 ret = splice(fd_in, NULL, pipefd[1], NULL, len,
617 SPLICE_F_MOVE | SPLICE_F_NONBLOCK);
618 if (!ret)
619 ret = -EIO;
Paul Cercueil09a43482015-03-04 15:50:27 +0100620 if (ret < 0)
621 goto err_close_pipe;
622
Paul Cercueila107c6d2015-03-05 13:54:10 +0100623 ret = splice(pipefd[0], NULL, fd_out, NULL, ret,
624 SPLICE_F_MOVE | SPLICE_F_NONBLOCK);
625 if (!ret)
626 ret = -EIO;
Paul Cercueil09a43482015-03-04 15:50:27 +0100627 if (ret < 0)
628 goto err_close_pipe;
629
630 len -= ret;
631 } while (len);
632
633err_close_pipe:
634 close(pipefd[0]);
635 close(pipefd[1]);
Paul Cercueil04065c22015-03-05 14:08:16 +0100636 return ret < 0 ? ret : read_len;
Paul Cercueil09a43482015-03-04 15:50:27 +0100637}
638
639static ssize_t network_get_buffer(const struct iio_device *dev,
Paul Cercueil76ca8842015-03-05 11:16:16 +0100640 void **addr_ptr, size_t bytes_used,
641 uint32_t *mask, size_t words)
Paul Cercueil09a43482015-03-04 15:50:27 +0100642{
643 struct iio_device_pdata *pdata = dev->pdata;
Paul Cercueil04065c22015-03-05 14:08:16 +0100644 ssize_t ret, read = 0;
Paul Cercueilca9d3382015-05-04 14:30:09 +0200645 int memfd;
Paul Cercueil09a43482015-03-04 15:50:27 +0100646 bool tx;
Paul Cercueil09a43482015-03-04 15:50:27 +0100647
Paul Cercueil04065c22015-03-05 14:08:16 +0100648 if (pdata->is_cyclic)
Paul Cercueil09a43482015-03-04 15:50:27 +0100649 return -ENOSYS;
Paul Cercueilca9d3382015-05-04 14:30:09 +0200650
651 /* We check early that the temporary file can be created, so that we can
652 * return -ENOSYS in case it fails, which will indicate that the
653 * high-speed interface is not available.
654 *
655 * O_TMPFILE -> Linux 3.11.
656 * TODO: use memfd_create (Linux 3.17) */
657 memfd = open(P_tmpdir, O_RDWR | O_TMPFILE | O_EXCL, S_IRWXU);
658 if (memfd < 0)
659 return -ENOSYS;
660
661 if (!addr_ptr || words != (dev->nb_channels + 31) / 32) {
662 close(memfd);
Paul Cercueil09a43482015-03-04 15:50:27 +0100663 return -EINVAL;
Paul Cercueilca9d3382015-05-04 14:30:09 +0200664 }
Paul Cercueil09a43482015-03-04 15:50:27 +0100665
Paul Cercueile6e5a092015-03-04 16:33:26 +0100666 if (pdata->mmap_addr)
667 munmap(pdata->mmap_addr, pdata->mmap_len);
Paul Cercueil09a43482015-03-04 15:50:27 +0100668
Paul Cercueile6e5a092015-03-04 16:33:26 +0100669 if (pdata->mmap_addr && pdata->is_tx) {
Paul Cercueil09a43482015-03-04 15:50:27 +0100670 char buf[1024];
671 snprintf(buf, sizeof(buf), "WRITEBUF %s %lu\r\n",
Paul Cercueild957b982015-08-05 14:39:01 +0200672 dev->id, (unsigned long) bytes_used);
Paul Cercueil09a43482015-03-04 15:50:27 +0100673
Paul Cercueil388dcd62015-11-27 15:15:48 +0100674 iio_mutex_lock(pdata->lock);
Paul Cercueil09a43482015-03-04 15:50:27 +0100675
Paul Cercueil3c0da372015-03-05 11:36:39 +0100676 ret = write_rwbuf_command(dev, buf, false);
Paul Cercueil09a43482015-03-04 15:50:27 +0100677 if (ret < 0)
Paul Cercueilca9d3382015-05-04 14:30:09 +0200678 goto err_close_memfd;
Paul Cercueil09a43482015-03-04 15:50:27 +0100679
Paul Cercueild957b982015-08-05 14:39:01 +0200680 ret = network_do_splice(pdata->fd, pdata->memfd, bytes_used);
Paul Cercueil09a43482015-03-04 15:50:27 +0100681 if (ret < 0)
Paul Cercueilca9d3382015-05-04 14:30:09 +0200682 goto err_close_memfd;
Paul Cercueil09a43482015-03-04 15:50:27 +0100683
684 pdata->wait_for_err_code = true;
Paul Cercueil388dcd62015-11-27 15:15:48 +0100685 iio_mutex_unlock(pdata->lock);
Paul Cercueil09a43482015-03-04 15:50:27 +0100686 }
687
688 if (pdata->memfd >= 0)
689 close(pdata->memfd);
690
Paul Cercueilca9d3382015-05-04 14:30:09 +0200691 pdata->memfd = memfd;
Paul Cercueil09a43482015-03-04 15:50:27 +0100692
Paul Cercueilef32d582015-03-05 11:18:35 +0100693 ret = (ssize_t) ftruncate(pdata->memfd, pdata->mmap_len);
694 if (ret < 0) {
695 ret = -errno;
696 ERROR("Unable to truncate temp file: %zi\n", -ret);
697 return ret;
698 }
Paul Cercueil09a43482015-03-04 15:50:27 +0100699
Paul Cercueil04065c22015-03-05 14:08:16 +0100700 if (!pdata->is_tx) {
701 char buf[1024];
702 size_t len = pdata->mmap_len;
703
704 snprintf(buf, sizeof(buf), "READBUF %s %lu\r\n",
705 dev->id, (unsigned long) len);
706
Paul Cercueil388dcd62015-11-27 15:15:48 +0100707 iio_mutex_lock(pdata->lock);
Paul Cercueil04065c22015-03-05 14:08:16 +0100708 ret = write_rwbuf_command(dev, buf, false);
709 if (ret < 0)
710 goto err_unlock;
711
712 do {
713 ret = network_read_mask(pdata->fd, mask, words);
714 if (!ret)
715 break;
716 if (ret < 0)
717 goto err_unlock;
718
719 mask = NULL; /* We read the mask only once */
720
721 ret = network_do_splice(pdata->memfd, pdata->fd, ret);
722 if (ret < 0)
723 goto err_unlock;
724
725 read += ret;
726 len -= ret;
727 } while (len);
728
Paul Cercueil388dcd62015-11-27 15:15:48 +0100729 iio_mutex_unlock(pdata->lock);
Paul Cercueil04065c22015-03-05 14:08:16 +0100730 }
Paul Cercueil09a43482015-03-04 15:50:27 +0100731
Paul Cercueile6e5a092015-03-04 16:33:26 +0100732 pdata->mmap_addr = mmap(NULL, pdata->mmap_len,
Paul Cercueil09a43482015-03-04 15:50:27 +0100733 PROT_READ | PROT_WRITE, MAP_SHARED, pdata->memfd, 0);
Paul Cercueile6e5a092015-03-04 16:33:26 +0100734 if (pdata->mmap_addr == MAP_FAILED) {
735 pdata->mmap_addr = NULL;
Paul Cercueil09a43482015-03-04 15:50:27 +0100736 ret = -errno;
Paul Cercueil7d7e5d32015-03-05 10:51:41 +0100737 ERROR("Unable to mmap: %zi\n", -ret);
Paul Cercueil09a43482015-03-04 15:50:27 +0100738 return ret;
739 }
740
Paul Cercueile6e5a092015-03-04 16:33:26 +0100741 *addr_ptr = pdata->mmap_addr;
Paul Cercueil04065c22015-03-05 14:08:16 +0100742 return read ? read : bytes_used;
Paul Cercueil09a43482015-03-04 15:50:27 +0100743
Paul Cercueilca9d3382015-05-04 14:30:09 +0200744err_close_memfd:
745 close(memfd);
Paul Cercueil09a43482015-03-04 15:50:27 +0100746err_unlock:
Paul Cercueil388dcd62015-11-27 15:15:48 +0100747 iio_mutex_unlock(pdata->lock);
Paul Cercueil09a43482015-03-04 15:50:27 +0100748 return ret;
749}
750#endif
751
Paul Cercueil99cf3d42014-03-06 12:35:26 +0100752static ssize_t network_read_dev_attr(const struct iio_device *dev,
Paul Cercueil50c762a2014-04-14 15:55:43 +0200753 const char *attr, char *dst, size_t len, bool is_debug)
Paul Cercueil99cf3d42014-03-06 12:35:26 +0100754{
Paul Cercueil2e28d502015-11-30 18:46:49 +0100755 struct iio_context_pdata *pdata = dev->ctx->pdata;
Paul Cercueil5b577762014-06-03 15:31:42 +0200756
Paul Cercueil2e28d502015-11-30 18:46:49 +0100757 return iiod_client_read_attr(pdata->iiod_client, pdata->fd,
758 dev, NULL, attr, dst, len, is_debug);
Paul Cercueil99cf3d42014-03-06 12:35:26 +0100759}
760
Paul Cercueil07897d32014-03-06 12:46:08 +0100761static ssize_t network_write_dev_attr(const struct iio_device *dev,
Paul Cercueilcecda352014-05-06 18:14:29 +0200762 const char *attr, const char *src, size_t len, bool is_debug)
Paul Cercueil07897d32014-03-06 12:46:08 +0100763{
Paul Cercueil2e28d502015-11-30 18:46:49 +0100764 struct iio_context_pdata *pdata = dev->ctx->pdata;
Paul Cercueil5b577762014-06-03 15:31:42 +0200765
Paul Cercueil2e28d502015-11-30 18:46:49 +0100766 return iiod_client_write_attr(pdata->iiod_client, pdata->fd,
767 dev, NULL, attr, src, len, is_debug);
Paul Cercueil07897d32014-03-06 12:46:08 +0100768}
769
Paul Cercueil99cf3d42014-03-06 12:35:26 +0100770static ssize_t network_read_chn_attr(const struct iio_channel *chn,
771 const char *attr, char *dst, size_t len)
772{
Paul Cercueil2e28d502015-11-30 18:46:49 +0100773 struct iio_context_pdata *pdata = chn->dev->ctx->pdata;
Paul Cercueil5b577762014-06-03 15:31:42 +0200774
Paul Cercueil2e28d502015-11-30 18:46:49 +0100775 return iiod_client_read_attr(pdata->iiod_client, pdata->fd,
776 chn->dev, chn, attr, dst, len, false);
Paul Cercueil99cf3d42014-03-06 12:35:26 +0100777}
778
Paul Cercueil07897d32014-03-06 12:46:08 +0100779static ssize_t network_write_chn_attr(const struct iio_channel *chn,
Paul Cercueilcecda352014-05-06 18:14:29 +0200780 const char *attr, const char *src, size_t len)
Paul Cercueil07897d32014-03-06 12:46:08 +0100781{
Paul Cercueil2e28d502015-11-30 18:46:49 +0100782 struct iio_context_pdata *pdata = chn->dev->ctx->pdata;
Paul Cercueil5b577762014-06-03 15:31:42 +0200783
Paul Cercueil2e28d502015-11-30 18:46:49 +0100784 return iiod_client_write_attr(pdata->iiod_client, pdata->fd,
785 chn->dev, chn, attr, src, len, false);
Paul Cercueil07897d32014-03-06 12:46:08 +0100786}
787
Paul Cercueildcab40c2014-03-11 10:59:14 +0100788static int network_get_trigger(const struct iio_device *dev,
789 const struct iio_device **trigger)
790{
791 struct iio_context_pdata *pdata = dev->ctx->pdata;
Paul Cercueildcab40c2014-03-11 10:59:14 +0100792
Paul Cercueilcae6c2a2015-11-30 16:37:19 +0100793 return iiod_client_get_trigger(pdata->iiod_client,
794 pdata->fd, dev, trigger);
Paul Cercueildcab40c2014-03-11 10:59:14 +0100795}
796
797static int network_set_trigger(const struct iio_device *dev,
798 const struct iio_device *trigger)
799{
Paul Cercueila7b2aae2015-12-04 16:02:00 +0100800 struct iio_context_pdata *pdata = dev->ctx->pdata;
Paul Cercueil1494b862014-05-05 12:49:07 +0200801
Paul Cercueilcae6c2a2015-11-30 16:37:19 +0100802 return iiod_client_set_trigger(pdata->iiod_client,
803 pdata->fd, dev, trigger);
Paul Cercueildcab40c2014-03-11 10:59:14 +0100804}
805
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100806static void network_shutdown(struct iio_context *ctx)
807{
808 struct iio_context_pdata *pdata = ctx->pdata;
Paul Cercueil44ae11c2014-03-17 09:56:29 +0100809 unsigned int i;
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100810
Paul Cercueil388dcd62015-11-27 15:15:48 +0100811 iio_mutex_lock(pdata->lock);
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100812 write_command("\r\nEXIT\r\n", pdata->fd);
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100813 close(pdata->fd);
Paul Cercueil388dcd62015-11-27 15:15:48 +0100814 iio_mutex_unlock(pdata->lock);
Paul Cercueil1494b862014-05-05 12:49:07 +0200815
Paul Cercueil439e1a22015-02-24 13:50:51 +0100816 for (i = 0; i < ctx->nb_devices; i++) {
817 struct iio_device *dev = ctx->devices[i];
Paul Cercueilc5b00752015-02-24 14:29:53 +0100818 struct iio_device_pdata *dpdata = dev->pdata;
Paul Cercueil439e1a22015-02-24 13:50:51 +0100819
Paul Cercueilc5b00752015-02-24 14:29:53 +0100820 if (dpdata) {
Paul Cercueilaa0db142015-03-04 16:25:24 +0100821 network_close(dev);
Paul Cercueil388dcd62015-11-27 15:15:48 +0100822 iio_mutex_destroy(dpdata->lock);
Paul Cercueilc5b00752015-02-24 14:29:53 +0100823 free(dpdata);
Paul Cercueil439e1a22015-02-24 13:50:51 +0100824 }
825 }
826
Paul Cercueil157d43c2015-11-30 15:05:06 +0100827 iiod_client_destroy(pdata->iiod_client);
Paul Cercueil388dcd62015-11-27 15:15:48 +0100828 iio_mutex_destroy(pdata->lock);
Paul Cercueil2dd2c132015-02-24 10:41:01 +0100829 freeaddrinfo(pdata->addrinfo);
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100830 free(pdata);
831}
832
Paul Cercueil6691a3f2014-05-02 12:32:01 +0200833static int network_get_version(const struct iio_context *ctx,
Paul Cercueil9de9e9d2014-05-20 13:18:19 +0200834 unsigned int *major, unsigned int *minor, char git_tag[8])
Paul Cercueil6691a3f2014-05-02 12:32:01 +0200835{
Paul Cercueil2e209f92015-11-30 15:05:38 +0100836 return iiod_client_get_version(ctx->pdata->iiod_client, ctx->pdata->fd,
837 major, minor, git_tag);
Paul Cercueil6691a3f2014-05-02 12:32:01 +0200838}
839
Paul Cercueil8a266f12014-06-10 16:06:31 +0200840static unsigned int calculate_remote_timeout(unsigned int timeout)
841{
842 /* XXX(pcercuei): We currently hardcode timeout / 2 for the backend used
843 * by the remote. Is there something better to do here? */
844 return timeout / 2;
845}
846
Paul Cercueilbca3dbc2014-06-11 12:00:21 +0200847static int network_set_timeout(struct iio_context *ctx, unsigned int timeout)
848{
Paul Cercueilf996ae12015-12-03 12:29:13 +0100849 struct iio_context_pdata *pdata = ctx->pdata;
850 int ret, fd = pdata->fd;
851
852 ret = set_socket_timeout(fd, timeout);
Paul Cercueilbca3dbc2014-06-11 12:00:21 +0200853 if (!ret) {
854 timeout = calculate_remote_timeout(timeout);
Paul Cercueilf996ae12015-12-03 12:29:13 +0100855 ret = iiod_client_set_timeout(pdata->iiod_client, fd, timeout);
Paul Cercueilbca3dbc2014-06-11 12:00:21 +0200856 }
857 if (ret < 0) {
858 char buf[1024];
Paul Cercueil53fc4852015-05-22 10:57:53 +0200859 iio_strerror(-ret, buf, sizeof(buf));
Paul Cercueil8a266f12014-06-10 16:06:31 +0200860 WARNING("Unable to set R/W timeout: %s\n", buf);
861 } else {
Paul Cercueil8a266f12014-06-10 16:06:31 +0200862 ctx->rw_timeout_ms = timeout;
863 }
864 return ret;
865}
866
Paul Cercueil61157f92015-11-19 17:48:22 +0100867static int network_set_kernel_buffers_count(const struct iio_device *dev,
868 unsigned int nb_blocks)
869{
Paul Cercueila9810a82015-11-30 16:55:07 +0100870 struct iio_context_pdata *pdata = dev->ctx->pdata;
Paul Cercueil61157f92015-11-19 17:48:22 +0100871
Paul Cercueila9810a82015-11-30 16:55:07 +0100872 return iiod_client_set_kernel_buffers_count(pdata->iiod_client,
873 pdata->fd, dev, nb_blocks);
Paul Cercueil61157f92015-11-19 17:48:22 +0100874}
875
Paul Cercueil12d41832014-10-28 14:35:53 +0100876static struct iio_context * network_clone(const struct iio_context *ctx)
877{
Paul Cercueil7ef45ce2015-03-16 14:36:16 +0100878 if (ctx->description) {
879 char *ptr = strchr(ctx->description, ' ');
880 if (ptr) {
881#ifdef HAVE_IPV6
882 char buf[INET6_ADDRSTRLEN + IF_NAMESIZE + 2];
883#else
884 char buf[INET_ADDRSTRLEN + 1];
885#endif
886 strncpy(buf, ctx->description, sizeof(buf) - 1);
887 buf[ptr - ctx->description] = '\0';
888 return iio_create_network_context(buf);
889 }
890 }
891
Paul Cercueild3d56ee2015-01-08 16:36:31 +0100892 return iio_create_network_context(ctx->description);
Paul Cercueil12d41832014-10-28 14:35:53 +0100893}
894
Lars-Peter Clausen09a59d72016-02-03 15:27:04 +0100895static const struct iio_backend_ops network_ops = {
Paul Cercueil12d41832014-10-28 14:35:53 +0100896 .clone = network_clone,
Paul Cercueilba059762014-03-14 11:02:02 +0100897 .open = network_open,
898 .close = network_close,
Paul Cercueil9945bc82014-03-05 14:07:29 +0100899 .read = network_read,
Paul Cercueil2725f702014-05-02 11:02:16 +0200900 .write = network_write,
Paul Cercueil90189672015-03-16 11:41:53 +0100901#ifdef WITH_NETWORK_GET_BUFFER
Paul Cercueil09a43482015-03-04 15:50:27 +0100902 .get_buffer = network_get_buffer,
903#endif
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100904 .read_device_attr = network_read_dev_attr,
905 .write_device_attr = network_write_dev_attr,
Paul Cercueil99cf3d42014-03-06 12:35:26 +0100906 .read_channel_attr = network_read_chn_attr,
Paul Cercueil07897d32014-03-06 12:46:08 +0100907 .write_channel_attr = network_write_chn_attr,
Paul Cercueildcab40c2014-03-11 10:59:14 +0100908 .get_trigger = network_get_trigger,
909 .set_trigger = network_set_trigger,
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100910 .shutdown = network_shutdown,
Paul Cercueil6691a3f2014-05-02 12:32:01 +0200911 .get_version = network_get_version,
Paul Cercueil8a266f12014-06-10 16:06:31 +0200912 .set_timeout = network_set_timeout,
Paul Cercueil61157f92015-11-19 17:48:22 +0100913 .set_kernel_buffers_count = network_set_kernel_buffers_count,
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100914};
915
Paul Cercueil157d43c2015-11-30 15:05:06 +0100916static ssize_t network_write_data(struct iio_context_pdata *pdata,
917 int desc, const char *src, size_t len)
918{
919 ssize_t ret;
920
921 ret = send(desc, src, (int) len, 0);
922 if (ret < 0) {
923#ifdef _WIN32
924 return (ssize_t) -WSAGetLastError();
925#else
926 return (ssize_t) -errno;
927#endif
928 } else if (ret == 0) {
929 return -EPIPE;
930 } else {
931 return ret;
932 }
933}
934
935static ssize_t network_read_data(struct iio_context_pdata *pdata,
936 int desc, char *dst, size_t len)
937{
938 ssize_t ret;
939
940 ret = recv(desc, dst, (int) len, 0);
941 if (ret < 0) {
942#ifdef _WIN32
943 return (ssize_t) -WSAGetLastError();
944#else
945 return (ssize_t) -errno;
946#endif
947 } else if (ret == 0) {
948 return -EPIPE;
949 } else {
950 return ret;
951 }
952}
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
961 /* First read from the socket without advancing the read offset */
962 ret = recv(desc, dst, len, MSG_PEEK);
963 if (ret < 0)
964 return ret;
965
966 /* Lookup for the trailing \n */
967 for (i = 0; i < (size_t) ret && dst[i] != '\n'; i++);
968
969 /* No \n found? Just garbage data */
970 if (i == (size_t) ret)
971 return -EIO;
972
973 /* Advance the read offset to the byte following the \n */
974 return recv(desc, dst, i + 1, MSG_TRUNC);
975#else
Paul Cercueil157d43c2015-11-30 15:05:06 +0100976 bool found = false;
977
978 for (i = 0; i < len - 1; i++) {
979 ssize_t ret = network_read_data(pdata, desc, dst + i, 1);
980
981 if (ret < 0)
982 return ret;
983
984 if (dst[i] != '\n')
985 found = true;
986 else if (found)
987 break;
988 }
989
990 dst[i] = '\0';
991 return (ssize_t) i;
Paul Cercueilce02dc92016-01-07 11:46:38 +0100992#endif
Paul Cercueil157d43c2015-11-30 15:05:06 +0100993}
994
Lars-Peter Clausen09a59d72016-02-03 15:27:04 +0100995static const struct iiod_client_ops network_iiod_client_ops = {
Paul Cercueil157d43c2015-11-30 15:05:06 +0100996 .write = network_write_data,
997 .read = network_read_data,
998 .read_line = network_read_line,
999};
1000
Paul Cercueil63e52182014-12-11 12:52:48 +01001001struct iio_context * network_create_context(const char *host)
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001002{
Paul Cercueil2e38bbe2014-03-19 15:27:15 +01001003 struct addrinfo hints, *res;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001004 struct iio_context *ctx;
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +01001005 struct iio_context_pdata *pdata;
Paul Cercueil0e3c04d2015-05-13 17:37:11 +02001006 size_t i, len;
Paul Cercueil4970ac32015-02-24 10:59:00 +01001007 int fd, ret;
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001008 char *description;
Paul Cercueil1fef1a52014-04-07 16:31:15 +02001009#ifdef _WIN32
1010 WSADATA wsaData;
1011
1012 ret = WSAStartup(MAKEWORD(2, 0), &wsaData);
1013 if (ret < 0) {
1014 ERROR("WSAStartup failed with error %i\n", ret);
Paul Cercueilcc575532015-03-16 17:15:24 +01001015 errno = -ret;
Paul Cercueil1fef1a52014-04-07 16:31:15 +02001016 return NULL;
1017 }
1018#endif
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001019
Paul Cercueil2e38bbe2014-03-19 15:27:15 +01001020 memset(&hints, 0, sizeof(hints));
1021 hints.ai_family = AF_UNSPEC;
1022 hints.ai_socktype = SOCK_STREAM;
Paul Cercueilab114932014-05-19 13:03:17 +02001023
1024#ifdef HAVE_AVAHI
1025 if (!host) {
1026 char addr_str[AVAHI_ADDRESS_STR_MAX];
1027 char port_str[6];
1028 AvahiAddress address;
Paul Cercueil0f729d32014-06-05 17:38:54 +02001029 uint16_t port = IIOD_PORT;
Paul Cercueilab114932014-05-19 13:03:17 +02001030
1031 memset(&address, 0, sizeof(address));
1032
1033 ret = discover_host(&address, &port);
1034 if (ret < 0) {
Paul Cercueilcc575532015-03-16 17:15:24 +01001035 DEBUG("Unable to find host: %s\n", strerror(-ret));
1036 errno = -ret;
Paul Cercueilab114932014-05-19 13:03:17 +02001037 return NULL;
1038 }
1039
1040 avahi_address_snprint(addr_str, sizeof(addr_str), &address);
1041 snprintf(port_str, sizeof(port_str), "%hu", port);
1042 ret = getaddrinfo(addr_str, port_str, &hints, &res);
1043 } else
1044#endif
1045 {
1046 ret = getaddrinfo(host, IIOD_PORT_STR, &hints, &res);
1047 }
1048
Paul Cercueil2e38bbe2014-03-19 15:27:15 +01001049 if (ret) {
Paul Cercueilab114932014-05-19 13:03:17 +02001050 ERROR("Unable to find host: %s\n", gai_strerror(ret));
Paul Cercueild9eb4cb2015-03-23 14:30:20 +01001051#ifndef _WIN32
Paul Cercueilcc575532015-03-16 17:15:24 +01001052 if (ret != EAI_SYSTEM)
1053 errno = ret;
Paul Cercueild9eb4cb2015-03-23 14:30:20 +01001054#endif
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001055 return NULL;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001056 }
1057
Paul Cercueil4970ac32015-02-24 10:59:00 +01001058 fd = create_socket(res);
Paul Cercueilcc575532015-03-16 17:15:24 +01001059 if (fd < 0) {
1060 errno = fd;
Paul Cercueil2dd2c132015-02-24 10:41:01 +01001061 goto err_free_addrinfo;
Paul Cercueilcc575532015-03-16 17:15:24 +01001062 }
Paul Cercueilbca3dbc2014-06-11 12:00:21 +02001063
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +01001064 pdata = calloc(1, sizeof(*pdata));
1065 if (!pdata) {
Paul Cercueilcc575532015-03-16 17:15:24 +01001066 errno = ENOMEM;
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +01001067 goto err_close_socket;
1068 }
1069
1070 pdata->fd = fd;
Paul Cercueil2dd2c132015-02-24 10:41:01 +01001071 pdata->addrinfo = res;
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +01001072
Paul Cercueil157d43c2015-11-30 15:05:06 +01001073 pdata->lock = iio_mutex_create();
1074 if (!pdata->lock) {
1075 errno = ENOMEM;
1076 goto err_free_pdata;
1077 }
1078
1079 pdata->iiod_client = iiod_client_new(pdata, pdata->lock,
1080 &network_iiod_client_ops);
1081 if (!pdata->iiod_client)
1082 goto err_destroy_mutex;
1083
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001084 DEBUG("Creating context...\n");
Paul Cercueil94726b12015-12-01 11:15:54 +01001085 ctx = iiod_client_create_context(pdata->iiod_client, fd);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001086 if (!ctx)
Paul Cercueil157d43c2015-11-30 15:05:06 +01001087 goto err_destroy_iiod_client;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001088
Paul Cercueil2057fd32014-10-28 14:44:19 +01001089 /* Override the name and low-level functions of the XML context
1090 * with those corresponding to the network context */
1091 ctx->name = "network";
1092 ctx->ops = &network_ops;
1093 ctx->pdata = pdata;
1094
Paul Cercueil06c479d2015-01-08 16:14:57 +01001095#ifdef HAVE_IPV6
Paul Cercueiled15e492015-01-12 15:52:28 +01001096 len = INET6_ADDRSTRLEN + IF_NAMESIZE + 2;
Paul Cercueil06c479d2015-01-08 16:14:57 +01001097#else
1098 len = INET_ADDRSTRLEN + 1;
1099#endif
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001100
1101 description = malloc(len);
1102 if (!description) {
Paul Cercueilcc575532015-03-16 17:15:24 +01001103 ret = -ENOMEM;
Paul Cercueil06c479d2015-01-08 16:14:57 +01001104 goto err_network_shutdown;
1105 }
1106
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001107 description[0] = '\0';
Paul Cercueil06c479d2015-01-08 16:14:57 +01001108
1109#ifdef HAVE_IPV6
1110 if (res->ai_family == AF_INET6) {
1111 struct sockaddr_in6 *in = (struct sockaddr_in6 *) res->ai_addr;
Paul Cercueiled15e492015-01-12 15:52:28 +01001112 char *ptr;
Paul Cercueil06c479d2015-01-08 16:14:57 +01001113 inet_ntop(AF_INET6, &in->sin6_addr,
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001114 description, INET6_ADDRSTRLEN);
Paul Cercueiled15e492015-01-12 15:52:28 +01001115
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001116 ptr = if_indextoname(in->sin6_scope_id, description +
1117 strlen(description) + 1);
Paul Cercueiled15e492015-01-12 15:52:28 +01001118 if (!ptr) {
Paul Cercueilcc575532015-03-16 17:15:24 +01001119 ret = -errno;
Paul Cercueiled15e492015-01-12 15:52:28 +01001120 ERROR("Unable to lookup interface of IPv6 address\n");
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001121 goto err_free_description;
Paul Cercueiled15e492015-01-12 15:52:28 +01001122 }
1123
1124 *(ptr - 1) = '%';
Paul Cercueil06c479d2015-01-08 16:14:57 +01001125 }
1126#endif
1127 if (res->ai_family == AF_INET) {
1128 struct sockaddr_in *in = (struct sockaddr_in *) res->ai_addr;
Paul Cercueile7a31692015-07-15 10:52:47 +02001129#if (!_WIN32 || _WIN32_WINNT >= 0x600)
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001130 inet_ntop(AF_INET, &in->sin_addr, description, INET_ADDRSTRLEN);
Paul Cercueile7a31692015-07-15 10:52:47 +02001131#else
1132 char *tmp = inet_ntoa(in->sin_addr);
1133 strncpy(description, tmp, len);
1134#endif
Paul Cercueil06c479d2015-01-08 16:14:57 +01001135 }
1136
Paul Cercueil44ae11c2014-03-17 09:56:29 +01001137 for (i = 0; i < ctx->nb_devices; i++) {
1138 struct iio_device *dev = ctx->devices[i];
Paul Cercueilff778232014-03-24 14:23:08 +01001139
Paul Cercueil439e1a22015-02-24 13:50:51 +01001140 dev->pdata = calloc(1, sizeof(*dev->pdata));
1141 if (!dev->pdata) {
Paul Cercueilcc575532015-03-16 17:15:24 +01001142 ret = -ENOMEM;
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001143 goto err_free_description;
Paul Cercueil439e1a22015-02-24 13:50:51 +01001144 }
1145
1146 dev->pdata->fd = -1;
Paul Cercueil90189672015-03-16 11:41:53 +01001147#ifdef WITH_NETWORK_GET_BUFFER
Paul Cercueil09a43482015-03-04 15:50:27 +01001148 dev->pdata->memfd = -1;
Paul Cercueile6e5a092015-03-04 16:33:26 +01001149#endif
Paul Cercueilc5b00752015-02-24 14:29:53 +01001150
Paul Cercueil388dcd62015-11-27 15:15:48 +01001151 dev->pdata->lock = iio_mutex_create();
1152 if (!dev->pdata->lock) {
1153 ret = -ENOMEM;
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001154 goto err_free_description;
Paul Cercueil388dcd62015-11-27 15:15:48 +01001155 }
Paul Cercueil44ae11c2014-03-17 09:56:29 +01001156 }
1157
Paul Cercueilfd387472015-08-05 10:34:19 +02001158 ret = iio_context_init(ctx);
1159 if (ret < 0)
1160 goto err_free_description;
Paul Cercueil4c6729d2014-04-04 17:24:41 +02001161
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001162 if (ctx->description) {
Paul Cercueil0e3c04d2015-05-13 17:37:11 +02001163 size_t desc_len = strlen(description);
1164 size_t new_size = desc_len + strlen(ctx->description) + 2;
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001165 char *ptr, *new_description = realloc(description, new_size);
Paul Cercueilcc575532015-03-16 17:15:24 +01001166 if (!new_description) {
1167 ret = -ENOMEM;
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001168 goto err_free_description;
Paul Cercueilcc575532015-03-16 17:15:24 +01001169 }
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001170
1171 ptr = strrchr(new_description, '\0');
Paul Cercueil0e3c04d2015-05-13 17:37:11 +02001172 snprintf(ptr, new_size - desc_len, " %s", ctx->description);
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001173 free(ctx->description);
1174
1175 ctx->description = new_description;
1176 } else {
1177 ctx->description = description;
1178 }
1179
Paul Cercueilf996ae12015-12-03 12:29:13 +01001180 iiod_client_set_timeout(pdata->iiod_client, fd,
1181 calculate_remote_timeout(DEFAULT_TIMEOUT_MS));
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001182 return ctx;
1183
Paul Cercueilb03c9ef2015-03-16 14:07:58 +01001184err_free_description:
1185 free(description);
Paul Cercueil44ae11c2014-03-17 09:56:29 +01001186err_network_shutdown:
Paul Cercueil44ae11c2014-03-17 09:56:29 +01001187 iio_context_destroy(ctx);
Paul Cercueilcc575532015-03-16 17:15:24 +01001188 errno = -ret;
Paul Cercueil2057fd32014-10-28 14:44:19 +01001189 return NULL;
Paul Cercueil157d43c2015-11-30 15:05:06 +01001190
1191err_destroy_iiod_client:
1192 iiod_client_destroy(pdata->iiod_client);
1193err_destroy_mutex:
1194 iio_mutex_destroy(pdata->lock);
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +01001195err_free_pdata:
1196 free(pdata);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001197err_close_socket:
1198 close(fd);
Paul Cercueil2dd2c132015-02-24 10:41:01 +01001199err_free_addrinfo:
1200 freeaddrinfo(res);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001201 return NULL;
1202}