blob: 3d9be2d7a21316674f92e5bbbc3440b1521a44ef [file] [log] [blame]
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001/*
2 * libiio - Library for interfacing industrial I/O (IIO) devices
3 *
4 * Copyright (C) 2014 Analog Devices, Inc.
5 * 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 Cercueil09a43482015-03-04 15:50:27 +010019#ifdef __linux__
20#define _GNU_SOURCE 1 /* Required for splice() */
21#endif
22
Paul Cercueilc7bad0f2014-03-03 17:06:48 +010023#include "iio-private.h"
24
Paul Cercueil9aabe892014-09-02 12:33:46 +020025#ifndef HAVE_PTHREAD
26#define HAVE_PTHREAD 1
27#endif
28
Paul Cercueilc7bad0f2014-03-03 17:06:48 +010029#include <errno.h>
Paul Cercueila7d445b2014-11-11 16:00:15 +010030#include <fcntl.h>
Paul Cercueile60c3ed2014-03-04 11:23:56 +010031#include <stdbool.h>
Paul Cercueilc7bad0f2014-03-03 17:06:48 +010032#include <string.h>
33#include <sys/types.h>
Paul Cercueilab114932014-05-19 13:03:17 +020034#include <time.h>
Paul Cercueil1fef1a52014-04-07 16:31:15 +020035
36#ifdef _WIN32
Paul Cercueil06c479d2015-01-08 16:14:57 +010037/* Override the default version of Windows supported by MinGW.
38 * This is required to use the function inet_ntop. */
39#undef _WIN32_WINNT
40#define _WIN32_WINNT 0x0600
41
Paul Cercueil1fef1a52014-04-07 16:31:15 +020042#include <winsock2.h>
43#include <ws2tcpip.h>
44#define close(s) closesocket(s)
45
46/* winsock2.h defines ERROR, we don't want that */
47#undef ERROR
48
49#else /* _WIN32 */
Paul Cercueil06c479d2015-01-08 16:14:57 +010050#include <arpa/inet.h>
Paul Cercueil1fef1a52014-04-07 16:31:15 +020051#include <netdb.h>
Paul Cercueil0c3ce452015-02-05 16:37:42 +010052#include <netinet/in.h>
Paul Cercueil0b584e12015-01-28 11:47:03 +010053#include <netinet/tcp.h>
Paul Cercueiled15e492015-01-12 15:52:28 +010054#include <net/if.h>
Paul Cercueil09a43482015-03-04 15:50:27 +010055#include <sys/mman.h>
Paul Cercueil83628b32014-11-24 11:26:21 +010056#include <sys/select.h>
Paul Cercueilc7bad0f2014-03-03 17:06:48 +010057#include <sys/socket.h>
58#include <unistd.h>
Paul Cercueil1fef1a52014-04-07 16:31:15 +020059#endif /* _WIN32 */
60
Paul Cercueil257e6ca2014-12-09 17:32:47 +010061#if HAVE_PTHREAD
62#include <pthread.h>
63#endif
64
Paul Cercueilab114932014-05-19 13:03:17 +020065#ifdef HAVE_AVAHI
66#include <avahi-client/client.h>
67#include <avahi-common/error.h>
68#include <avahi-client/lookup.h>
69#include <avahi-common/simple-watch.h>
70#endif
71
Paul Cercueil1fef1a52014-04-07 16:31:15 +020072#include "debug.h"
Paul Cercueilc7bad0f2014-03-03 17:06:48 +010073
Paul Cercueil8a266f12014-06-10 16:06:31 +020074#define DEFAULT_TIMEOUT_MS 5000
75
Paul Cercueil2e38bbe2014-03-19 15:27:15 +010076#define _STRINGIFY(x) #x
77#define STRINGIFY(x) _STRINGIFY(x)
78
Paul Cercueilc7bad0f2014-03-03 17:06:48 +010079#define IIOD_PORT 30431
Paul Cercueil2e38bbe2014-03-19 15:27:15 +010080#define IIOD_PORT_STR STRINGIFY(IIOD_PORT)
Paul Cercueilc7bad0f2014-03-03 17:06:48 +010081
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +010082struct iio_context_pdata {
83 int fd;
Paul Cercueil2dd2c132015-02-24 10:41:01 +010084 struct addrinfo *addrinfo;
Paul Cercueil05e26262014-05-09 11:32:43 +020085#if HAVE_PTHREAD
Paul Cercueil1494b862014-05-05 12:49:07 +020086 pthread_mutex_t lock;
Paul Cercueil05e26262014-05-09 11:32:43 +020087#endif
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +010088};
89
Paul Cercueil439e1a22015-02-24 13:50:51 +010090struct iio_device_pdata {
91 int fd;
Paul Cercueil09a43482015-03-04 15:50:27 +010092 int memfd;
93 size_t mmap_len;
94 bool wait_for_err_code, is_cyclic, is_tx;
Paul Cercueilc5b00752015-02-24 14:29:53 +010095#if HAVE_PTHREAD
96 pthread_mutex_t lock;
97#endif
Paul Cercueil439e1a22015-02-24 13:50:51 +010098};
99
Paul Cercueilab114932014-05-19 13:03:17 +0200100#ifdef HAVE_AVAHI
101struct avahi_discovery_data {
102 AvahiSimplePoll *poll;
103 AvahiAddress *address;
104 uint16_t *port;
105 bool found, resolved;
106};
107
108static void __avahi_resolver_cb(AvahiServiceResolver *resolver,
109 __notused AvahiIfIndex iface, __notused AvahiProtocol proto,
110 __notused AvahiResolverEvent event, __notused const char *name,
111 __notused const char *type, __notused const char *domain,
112 __notused const char *host_name, const AvahiAddress *address,
113 uint16_t port, __notused AvahiStringList *txt,
114 __notused AvahiLookupResultFlags flags, void *d)
115{
116 struct avahi_discovery_data *ddata = (struct avahi_discovery_data *) d;
117
118 memcpy(ddata->address, address, sizeof(*address));
119 *ddata->port = port;
120 ddata->resolved = true;
121 avahi_service_resolver_free(resolver);
122}
123
124static void __avahi_browser_cb(AvahiServiceBrowser *browser,
125 AvahiIfIndex iface, AvahiProtocol proto,
126 AvahiBrowserEvent event, const char *name,
127 const char *type, const char *domain,
128 __notused AvahiLookupResultFlags flags, void *d)
129{
130 struct avahi_discovery_data *ddata = (struct avahi_discovery_data *) d;
131 struct AvahiClient *client = avahi_service_browser_get_client(browser);
132
133 switch (event) {
134 default:
135 case AVAHI_BROWSER_NEW:
136 ddata->found = !!avahi_service_resolver_new(client, iface,
137 proto, name, type, domain,
138 AVAHI_PROTO_UNSPEC, 0,
139 __avahi_resolver_cb, d);
140 break;
141 case AVAHI_BROWSER_ALL_FOR_NOW:
142 if (ddata->found) {
143 while (!ddata->resolved) {
144 struct timespec ts;
145 ts.tv_sec = 0;
146 ts.tv_nsec = 4000000;
147 nanosleep(&ts, NULL);
148 }
149 }
150 case AVAHI_BROWSER_FAILURE: /* fall-through */
151 avahi_simple_poll_quit(ddata->poll);
152 case AVAHI_BROWSER_CACHE_EXHAUSTED: /* fall-through */
153 break;
154 }
155}
156
157static int discover_host(AvahiAddress *addr, uint16_t *port)
158{
159 struct avahi_discovery_data ddata;
160 int ret = 0;
161 AvahiClient *client;
162 AvahiServiceBrowser *browser;
163 AvahiSimplePoll *poll = avahi_simple_poll_new();
164 if (!poll)
165 return -ENOMEM;
166
167 client = avahi_client_new(avahi_simple_poll_get(poll),
168 0, NULL, NULL, &ret);
169 if (!client) {
170 ERROR("Unable to start ZeroConf client :%s\n",
171 avahi_strerror(ret));
172 goto err_free_poll;
173 }
174
175 memset(&ddata, 0, sizeof(ddata));
176 ddata.poll = poll;
177 ddata.address = addr;
178 ddata.port = port;
179
180 browser = avahi_service_browser_new(client,
181 AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
182 "_iio._tcp", NULL, 0, __avahi_browser_cb, &ddata);
183 if (!browser) {
184 ret = avahi_client_errno(client);
185 ERROR("Unable to create ZeroConf browser: %s\n",
186 avahi_strerror(ret));
187 goto err_free_client;
188 }
189
190 DEBUG("Trying to discover host\n");
191 avahi_simple_poll_loop(poll);
192
193 if (!ddata.found)
194 ret = ENXIO;
195
196 avahi_service_browser_free(browser);
197err_free_client:
198 avahi_client_free(client);
199err_free_poll:
200 avahi_simple_poll_free(poll);
201 return -ret; /* we want a negative error code */
202}
203#endif /* HAVE_AVAHI */
204
Paul Cercueil05e26262014-05-09 11:32:43 +0200205static void network_lock(struct iio_context_pdata *pdata)
206{
207#if HAVE_PTHREAD
208 pthread_mutex_lock(&pdata->lock);
209#endif
210}
211
212static void network_unlock(struct iio_context_pdata *pdata)
213{
214#if HAVE_PTHREAD
215 pthread_mutex_unlock(&pdata->lock);
216#endif
217}
218
Paul Cercueilc5b00752015-02-24 14:29:53 +0100219static void network_lock_dev(struct iio_device_pdata *pdata)
220{
221#if HAVE_PTHREAD
222 pthread_mutex_lock(&pdata->lock);
223#endif
224}
225
226static void network_unlock_dev(struct iio_device_pdata *pdata)
227{
228#if HAVE_PTHREAD
229 pthread_mutex_unlock(&pdata->lock);
230#endif
231}
232
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100233static ssize_t write_all(const void *src, size_t len, int fd)
234{
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200235 uintptr_t ptr = (uintptr_t) src;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100236 while (len) {
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200237 ssize_t ret = send(fd, (const void *) ptr, len, 0);
Lars-Peter Clausencb7b8bf2014-12-05 16:08:52 +0100238 if (ret < 0) {
239 if (errno == EINTR) {
240 continue;
241 }
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100242 return -errno;
Lars-Peter Clausencb7b8bf2014-12-05 16:08:52 +0100243 }
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100244 ptr += ret;
245 len -= ret;
246 }
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200247 return ptr - (uintptr_t) src;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100248}
249
250static ssize_t read_all(void *dst, size_t len, int fd)
251{
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200252 uintptr_t ptr = (uintptr_t) dst;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100253 while (len) {
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200254 ssize_t ret = recv(fd, (void *) ptr, len, 0);
Lars-Peter Clausencb7b8bf2014-12-05 16:08:52 +0100255 if (ret < 0) {
256 if (errno == EINTR)
257 continue;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100258 return -errno;
Lars-Peter Clausencb7b8bf2014-12-05 16:08:52 +0100259 }
Paul Cercueil43eb7e82014-11-13 12:46:59 +0100260 if (ret == 0)
261 return -EPIPE;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100262 ptr += ret;
263 len -= ret;
264 }
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200265 return ptr - (uintptr_t) dst;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100266}
267
Paul Cercueile60c3ed2014-03-04 11:23:56 +0100268static int read_integer(int fd, long *val)
269{
270 unsigned int i;
271 char buf[1024], *ptr;
272 ssize_t ret;
273 bool found = false;
274
275 for (i = 0; i < sizeof(buf) - 1; i++) {
276 ret = read_all(buf + i, 1, fd);
277 if (ret < 0)
278 return (int) ret;
279
Paul Cercueil6691a3f2014-05-02 12:32:01 +0200280 /* Skip the eventual first few carriage returns.
281 * Also stop when a dot is found (for parsing floats) */
282 if (buf[i] != '\n' && buf[i] != '.')
Paul Cercueile60c3ed2014-03-04 11:23:56 +0100283 found = true;
284 else if (found)
285 break;
286 }
287
288 buf[i] = '\0';
289 ret = (ssize_t) strtol(buf, &ptr, 10);
290 if (ptr == buf)
291 return -EINVAL;
292 *val = (long) ret;
293 return 0;
294}
295
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100296static ssize_t write_command(const char *cmd, int fd)
297{
298 ssize_t ret;
299
300 DEBUG("Writing command: %s\n", cmd);
301 ret = write_all(cmd, strlen(cmd), fd);
302 if (ret < 0) {
303 char buf[1024];
304 strerror_r(-ret, buf, sizeof(buf));
305 ERROR("Unable to send command: %s\n", buf);
306 }
307 return ret;
308}
309
310static long exec_command(const char *cmd, int fd)
311{
312 long resp;
313 ssize_t ret = write_command(cmd, fd);
314 if (ret < 0)
315 return (long) ret;
316
317 DEBUG("Reading response\n");
318 ret = read_integer(fd, &resp);
319 if (ret < 0) {
320 char buf[1024];
321 strerror_r(-ret, buf, sizeof(buf));
322 ERROR("Unable to read response: %s\n", buf);
323 return (long) ret;
324 }
325
Paul Cercueilc7fe2ea2014-03-28 11:38:45 +0100326#if LOG_LEVEL >= DEBUG_L
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100327 if (resp < 0) {
328 char buf[1024];
329 strerror_r(-resp, buf, sizeof(buf));
Paul Cercueilc7fe2ea2014-03-28 11:38:45 +0100330 DEBUG("Server returned an error: %s\n", buf);
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100331 }
Paul Cercueilc7fe2ea2014-03-28 11:38:45 +0100332#endif
333
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100334 return resp;
335}
336
Paul Cercueil4970ac32015-02-24 10:59:00 +0100337#ifndef _WIN32
338static int set_blocking_mode(int fd, bool blocking)
339{
340 int ret = fcntl(fd, F_GETFL, 0);
341 if (ret < 0)
342 return -errno;
343
344 if (blocking)
345 ret &= ~O_NONBLOCK;
346 else
347 ret |= O_NONBLOCK;
348
349 ret = fcntl(fd, F_SETFL, ret);
350 return ret < 0 ? -errno : 0;
351}
352
353/* The purpose of this function is to provide a version of connect()
354 * that does not ignore timeouts... */
355static int do_connect(int fd, const struct sockaddr *addr,
356 socklen_t addrlen, struct timeval *timeout)
357{
358 int ret, error;
359 socklen_t len;
360 fd_set set;
361
362 FD_ZERO(&set);
363 FD_SET(fd, &set);
364
365 ret = set_blocking_mode(fd, false);
366 if (ret < 0)
367 return ret;
368
369 ret = connect(fd, addr, addrlen);
370 if (ret < 0 && errno != EINPROGRESS) {
371 ret = -errno;
372 goto end;
373 }
374
375 ret = select(fd + 1, &set, &set, NULL, timeout);
376 if (ret < 0) {
377 ret = -errno;
378 goto end;
379 }
380 if (ret == 0) {
381 ret = -ETIMEDOUT;
382 goto end;
383 }
384
385 /* Verify that we don't have an error */
386 len = sizeof(error);
387 ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len);
388 if(ret < 0) {
389 ret = -errno;
390 goto end;
391 }
392 if (error) {
393 ret = -error;
394 goto end;
395 }
396
397end:
398 /* Restore blocking mode */
399 set_blocking_mode(fd, true);
400 return ret;
401}
402
403static int set_socket_timeout(int fd, unsigned int timeout)
404{
405 struct timeval tv;
406
407 tv.tv_sec = timeout / 1000;
408 tv.tv_usec = (timeout % 1000) * 1000;
409 if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0 ||
410 setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO,
411 &tv, sizeof(tv)) < 0)
412 return -errno;
413 else
414 return 0;
415}
416#else
417static int set_socket_timeout(int fd, unsigned int timeout)
418{
419 if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO,
420 (const char *) &timeout, sizeof(timeout)) < 0 ||
421 setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO,
422 (const char *) &timeout, sizeof(timeout)) < 0)
423 return -errno;
424 else
425 return 0;
426}
427#endif /* !_WIN32 */
428
429static int create_socket(const struct addrinfo *addrinfo)
430{
431 struct timeval timeout;
432 int ret, fd, yes = 1;
433
434 fd = socket(addrinfo->ai_family, addrinfo->ai_socktype, 0);
435 if (fd < 0) {
436 ERROR("Unable to open socket\n");
437 return fd;
438 }
439
440 timeout.tv_sec = DEFAULT_TIMEOUT_MS / 1000;
441 timeout.tv_usec = (DEFAULT_TIMEOUT_MS % 1000) * 1000;
442
443#ifndef _WIN32
444 ret = do_connect(fd, addrinfo->ai_addr, addrinfo->ai_addrlen, &timeout);
445#else
446 ret = connect(fd, addrinfo->ai_addr, addrinfo->ai_addrlen);
447#endif
448 if (ret < 0) {
449 ERROR("Unable to connect\n");
450 close(fd);
451 return ret;
452 }
453
454 set_socket_timeout(fd, DEFAULT_TIMEOUT_MS);
455 setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
456 (const char *) &yes, sizeof(yes));
457 return fd;
458}
459
Paul Cercueil09a43482015-03-04 15:50:27 +0100460static bool is_tx(const struct iio_device *dev)
461{
462 unsigned int i;
463
464 for (i = 0; i < dev->nb_channels; i++) {
465 struct iio_channel *ch = dev->channels[i];
466 if (iio_channel_is_output(ch) && iio_channel_is_enabled(ch))
467 return true;
468 }
469
470 return false;
471}
472
Paul Cercueil71694c72014-05-22 14:02:13 +0200473static int network_open(const struct iio_device *dev, size_t samples_count,
474 uint32_t *mask, size_t nb, bool cyclic)
Paul Cercueilba059762014-03-14 11:02:02 +0100475{
Paul Cercueil439e1a22015-02-24 13:50:51 +0100476 struct iio_context_pdata *pdata = dev->ctx->pdata;
Paul Cercueilba059762014-03-14 11:02:02 +0100477 char buf[1024], *ptr;
478 unsigned int i;
Paul Cercueil439e1a22015-02-24 13:50:51 +0100479 int ret, fd;
Paul Cercueilba059762014-03-14 11:02:02 +0100480
Paul Cercueilff778232014-03-24 14:23:08 +0100481 if (nb != dev->words)
Paul Cercueilba059762014-03-14 11:02:02 +0100482 return -EINVAL;
Paul Cercueil439e1a22015-02-24 13:50:51 +0100483 if (dev->pdata->fd >= 0)
484 return -EBUSY;
485
486 fd = create_socket(pdata->addrinfo);
487 if (fd < 0)
488 return fd;
Paul Cercueilba059762014-03-14 11:02:02 +0100489
Paul Cercueil3c407f82014-04-02 14:11:59 +0200490 snprintf(buf, sizeof(buf), "OPEN %s %lu ",
491 dev->id, (unsigned long) samples_count);
Paul Cercueilba059762014-03-14 11:02:02 +0100492 ptr = buf + strlen(buf);
493
494 for (i = nb; i > 0; i--) {
Paul Cercueil8c29e412014-04-07 09:46:45 +0200495 snprintf(ptr, (ptr - buf) + i * 8, "%08x", mask[i - 1]);
Paul Cercueilba059762014-03-14 11:02:02 +0100496 ptr += 8;
497 }
Paul Cercueil71694c72014-05-22 14:02:13 +0200498
499 strcpy(ptr, cyclic ? " CYCLIC\r\n" : "\r\n");
Paul Cercueilba059762014-03-14 11:02:02 +0100500
Paul Cercueilc5b00752015-02-24 14:29:53 +0100501 network_lock_dev(dev->pdata);
Paul Cercueil439e1a22015-02-24 13:50:51 +0100502 ret = (int) exec_command(buf, fd);
Paul Cercueilc5b00752015-02-24 14:29:53 +0100503 network_unlock_dev(dev->pdata);
Paul Cercueil1494b862014-05-05 12:49:07 +0200504
Paul Cercueil44ae11c2014-03-17 09:56:29 +0100505 if (ret < 0) {
Paul Cercueil439e1a22015-02-24 13:50:51 +0100506 close(fd);
Paul Cercueil44ae11c2014-03-17 09:56:29 +0100507 return ret;
Paul Cercueil44ae11c2014-03-17 09:56:29 +0100508 }
Paul Cercueil439e1a22015-02-24 13:50:51 +0100509
Paul Cercueil09a43482015-03-04 15:50:27 +0100510 dev->pdata->is_tx = is_tx(dev);
Paul Cercueil1d70d442015-03-04 15:00:37 +0100511 dev->pdata->is_cyclic = cyclic;
Paul Cercueil439e1a22015-02-24 13:50:51 +0100512 dev->pdata->fd = fd;
Paul Cercueil8f7f6c42015-02-24 15:00:35 +0100513 dev->pdata->wait_for_err_code = false;
Paul Cercueil439e1a22015-02-24 13:50:51 +0100514 memcpy(dev->mask, mask, nb * sizeof(*mask));
515 return 0;
Paul Cercueilba059762014-03-14 11:02:02 +0100516}
517
Paul Cercueil8f7f6c42015-02-24 15:00:35 +0100518static ssize_t read_error_code(int fd)
519{
520 /*
521 * The server returns two integer codes.
522 * The first one is returned right after the WRITEBUF command is issued,
523 * and corresponds to the error code returned when the server attempted
524 * to open the device.
525 * If zero, a second error code is returned, that corresponds (if positive)
526 * to the number of bytes written.
527 *
528 * To speed up things, we delay error reporting. We just send out the
529 * data without reading the error code that the server gives us, because
530 * the answer will take too much time. If an error occured, it will be
531 * reported by the next call to iio_buffer_push().
532 */
533
534 unsigned int i;
535 long resp = 0;
536
537 for (i = 0; i < 2; i++) {
538 ssize_t ret = read_integer(fd, &resp);
539 if (ret < 0)
540 return ret;
541 if (resp < 0)
542 return (ssize_t) resp;
543 }
544
545 return resp;
546}
547
Paul Cercueilba059762014-03-14 11:02:02 +0100548static int network_close(const struct iio_device *dev)
549{
Paul Cercueil439e1a22015-02-24 13:50:51 +0100550 struct iio_device_pdata *pdata = dev->pdata;
Paul Cercueil1494b862014-05-05 12:49:07 +0200551 int ret;
Paul Cercueilba059762014-03-14 11:02:02 +0100552 char buf[1024];
Paul Cercueil439e1a22015-02-24 13:50:51 +0100553
Paul Cercueilba059762014-03-14 11:02:02 +0100554 snprintf(buf, sizeof(buf), "CLOSE %s\r\n", dev->id);
Paul Cercueil1494b862014-05-05 12:49:07 +0200555
Paul Cercueilc5b00752015-02-24 14:29:53 +0100556 network_lock_dev(pdata);
Paul Cercueil8f7f6c42015-02-24 15:00:35 +0100557 if (pdata->wait_for_err_code)
558 read_error_code(pdata->fd);
559
Paul Cercueil439e1a22015-02-24 13:50:51 +0100560 ret = (int) exec_command(buf, pdata->fd);
Paul Cercueil1494b862014-05-05 12:49:07 +0200561
Paul Cercueilaa0db142015-03-04 16:25:24 +0100562 write_command("\r\nEXIT\r\n", pdata->fd);
563
Paul Cercueil439e1a22015-02-24 13:50:51 +0100564 close(pdata->fd);
565 pdata->fd = -1;
Paul Cercueilc5b00752015-02-24 14:29:53 +0100566 network_unlock_dev(pdata);
Paul Cercueil1494b862014-05-05 12:49:07 +0200567 return ret;
Paul Cercueilba059762014-03-14 11:02:02 +0100568}
569
Paul Cercueil45c575d2014-03-20 15:14:01 +0100570static ssize_t network_read(const struct iio_device *dev, void *dst, size_t len,
571 uint32_t *mask, size_t words)
Paul Cercueilf9286452014-03-18 14:32:17 +0100572{
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200573 uintptr_t ptr = (uintptr_t) dst;
Paul Cercueilc5b00752015-02-24 14:29:53 +0100574 struct iio_device_pdata *pdata = dev->pdata;
575 int fd = pdata->fd;
Paul Cercueil45c575d2014-03-20 15:14:01 +0100576 ssize_t ret, read = 0;
Paul Cercueil9945bc82014-03-05 14:07:29 +0100577 char buf[1024];
Paul Cercueil45c575d2014-03-20 15:14:01 +0100578 bool read_mask = true;
Paul Cercueil9945bc82014-03-05 14:07:29 +0100579
Paul Cercueil45c575d2014-03-20 15:14:01 +0100580 if (!len || words != (dev->nb_channels + 31) / 32)
Paul Cercueil9945bc82014-03-05 14:07:29 +0100581 return -EINVAL;
582
Paul Cercueila78b6eb2014-03-17 17:28:07 +0100583 snprintf(buf, sizeof(buf), "READBUF %s %lu\r\n",
584 dev->id, (unsigned long) len);
Paul Cercueil1494b862014-05-05 12:49:07 +0200585
Paul Cercueilc5b00752015-02-24 14:29:53 +0100586 network_lock_dev(pdata);
Paul Cercueil8f7f6c42015-02-24 15:00:35 +0100587 if (pdata->wait_for_err_code) {
588 pdata->wait_for_err_code = false;
589 ret = read_error_code(fd);
590 if (ret < 0) {
591 network_unlock_dev(pdata);
592 return ret;
593 }
594 }
595
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100596 ret = write_command(buf, fd);
Paul Cercueil1494b862014-05-05 12:49:07 +0200597 if (ret < 0) {
Paul Cercueilc5b00752015-02-24 14:29:53 +0100598 network_unlock_dev(pdata);
Paul Cercueil9945bc82014-03-05 14:07:29 +0100599 return ret;
Paul Cercueil1494b862014-05-05 12:49:07 +0200600 }
Paul Cercueil9945bc82014-03-05 14:07:29 +0100601
602 do {
Paul Cercueil5cab3ae2014-03-14 11:23:56 +0100603 unsigned int i;
Paul Cercueil9945bc82014-03-05 14:07:29 +0100604 long read_len;
605
606 DEBUG("Reading READ response\n");
607 ret = read_integer(fd, &read_len);
608 if (ret < 0) {
609 strerror_r(-ret, buf, sizeof(buf));
610 ERROR("Unable to read response to READ: %s\n", buf);
Paul Cercueilc5b00752015-02-24 14:29:53 +0100611 network_unlock_dev(pdata);
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200612 return read ? read : ret;
Paul Cercueil9945bc82014-03-05 14:07:29 +0100613 }
614
615 if (read_len < 0) {
616 strerror_r(-read_len, buf, sizeof(buf));
617 ERROR("Server returned an error: %s\n", buf);
Paul Cercueilc5b00752015-02-24 14:29:53 +0100618 network_unlock_dev(pdata);
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200619 return read ? read : read_len;
Paul Cercueila78b6eb2014-03-17 17:28:07 +0100620 } else if (read_len == 0) {
621 break;
Paul Cercueil9945bc82014-03-05 14:07:29 +0100622 }
623
624 DEBUG("Bytes to read: %li\n", read_len);
625
Paul Cercueil43c1e6c2014-03-20 14:26:20 +0100626 if (read_mask) {
627 DEBUG("Reading mask\n");
628 buf[8] = '\0';
Paul Cercueil45c575d2014-03-20 15:14:01 +0100629 for (i = words; i > 0; i--) {
Paul Cercueil43c1e6c2014-03-20 14:26:20 +0100630 ret = read_all(buf, 8, fd);
631 if (ret < 0)
632 break;
633 sscanf(buf, "%08x", &mask[i - 1]);
634 DEBUG("mask[%i] = 0x%x\n", i - 1, mask[i - 1]);
Paul Cercueil43c1e6c2014-03-20 14:26:20 +0100635 }
636 read_mask = false;
Paul Cercueil5cab3ae2014-03-14 11:23:56 +0100637 }
638
639 if (ret > 0) {
640 char c;
Lars-Peter Clausencb7b8bf2014-12-05 16:08:52 +0100641 ret = read_all(&c, 1, fd);
Paul Cercueil5cab3ae2014-03-14 11:23:56 +0100642 if (ret > 0 && c != '\n')
643 ret = -EIO;
644 }
645
646 if (ret < 0) {
647 strerror_r(-ret, buf, sizeof(buf));
648 ERROR("Unable to read mask: %s\n", buf);
Paul Cercueilc5b00752015-02-24 14:29:53 +0100649 network_unlock_dev(pdata);
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200650 return read ? read : ret;
Paul Cercueil5cab3ae2014-03-14 11:23:56 +0100651 }
652
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200653 ret = read_all((void *) ptr, read_len, fd);
Paul Cercueil9945bc82014-03-05 14:07:29 +0100654 if (ret < 0) {
655 strerror_r(-ret, buf, sizeof(buf));
656 ERROR("Unable to read response to READ: %s\n", buf);
Paul Cercueilc5b00752015-02-24 14:29:53 +0100657 network_unlock_dev(pdata);
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200658 return read ? read : ret;
Paul Cercueil9945bc82014-03-05 14:07:29 +0100659 }
660
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200661 ptr += ret;
Paul Cercueilf9286452014-03-18 14:32:17 +0100662 read += ret;
Paul Cercueil9945bc82014-03-05 14:07:29 +0100663 len -= read_len;
664 } while (len);
665
Paul Cercueilc5b00752015-02-24 14:29:53 +0100666 network_unlock_dev(pdata);
Paul Cercueil9945bc82014-03-05 14:07:29 +0100667 return read;
668}
669
Paul Cercueila62f84e2015-02-24 14:16:08 +0100670static ssize_t network_write(const struct iio_device *dev,
671 const void *src, size_t len)
Paul Cercueil2725f702014-05-02 11:02:16 +0200672{
Paul Cercueilc5b00752015-02-24 14:29:53 +0100673 struct iio_device_pdata *pdata = dev->pdata;
Paul Cercueil439e1a22015-02-24 13:50:51 +0100674 int fd;
Paul Cercueil2725f702014-05-02 11:02:16 +0200675 ssize_t ret;
Paul Cercueil2725f702014-05-02 11:02:16 +0200676 long resp;
Paul Cercueila62f84e2015-02-24 14:16:08 +0100677 char buf[1024];
678
679 snprintf(buf, sizeof(buf), "WRITEBUF %s %lu\r\n",
680 dev->id, (unsigned long) len);
Paul Cercueil2725f702014-05-02 11:02:16 +0200681
Paul Cercueilc5b00752015-02-24 14:29:53 +0100682 network_lock_dev(pdata);
683 fd = pdata->fd;
Paul Cercueil8f7f6c42015-02-24 15:00:35 +0100684
685 if (pdata->wait_for_err_code) {
686 pdata->wait_for_err_code = false;
687 ret = read_error_code(fd);
688 if (ret < 0)
689 goto err_unlock;
690 }
691
Paul Cercueil1d70d442015-03-04 15:00:37 +0100692 if (pdata->is_cyclic)
693 ret = (ssize_t) exec_command(buf, fd);
694 else
695 ret = (ssize_t) write_command(buf, fd);
Paul Cercueil2725f702014-05-02 11:02:16 +0200696 if (ret < 0)
Paul Cercueil1494b862014-05-05 12:49:07 +0200697 goto err_unlock;
Paul Cercueil2725f702014-05-02 11:02:16 +0200698
699 ret = write_all(src, len, fd);
700 if (ret < 0)
Paul Cercueil1494b862014-05-05 12:49:07 +0200701 goto err_unlock;
Paul Cercueil2725f702014-05-02 11:02:16 +0200702
Paul Cercueil1d70d442015-03-04 15:00:37 +0100703 if (pdata->is_cyclic) {
704 ret = read_integer(fd, &resp);
705 if (ret < 0)
706 goto err_unlock;
707 if (resp < 0) {
708 ret = (ssize_t) resp;
709 goto err_unlock;
710 }
711 } else {
712 pdata->wait_for_err_code = true;
713 }
Paul Cercueilc5b00752015-02-24 14:29:53 +0100714 network_unlock_dev(pdata);
Paul Cercueil1494b862014-05-05 12:49:07 +0200715
Paul Cercueil8f7f6c42015-02-24 15:00:35 +0100716 /* We assume that the whole buffer was submitted.
717 * The error code will be returned by the next call to this function. */
718 return (ssize_t) len;
Paul Cercueil1494b862014-05-05 12:49:07 +0200719
720err_unlock:
Paul Cercueilc5b00752015-02-24 14:29:53 +0100721 network_unlock_dev(pdata);
Paul Cercueil1494b862014-05-05 12:49:07 +0200722 return ret;
Paul Cercueil2725f702014-05-02 11:02:16 +0200723}
724
Paul Cercueil09a43482015-03-04 15:50:27 +0100725#ifdef __linux__
726static int network_do_splice(int fd_out, int fd_in, size_t len)
727{
728 int pipefd[2];
729 ssize_t ret;
730
731 ret = (ssize_t) pipe(pipefd);
732 if (ret < 0)
733 return -errno;
734
735 do {
736 ret = splice(fd_in, NULL, pipefd[1], NULL, len, SPLICE_F_MOVE);
737 if (ret < 0)
738 goto err_close_pipe;
739
740 ret = splice(pipefd[0], NULL, fd_out, NULL, len, SPLICE_F_MOVE);
741 if (ret < 0)
742 goto err_close_pipe;
743
744 len -= ret;
745 } while (len);
746
747err_close_pipe:
748 close(pipefd[0]);
749 close(pipefd[1]);
750 return (int) ret;
751}
752
753static ssize_t network_get_buffer(const struct iio_device *dev,
754 void **addr_ptr, size_t bytes_used)
755{
756 struct iio_device_pdata *pdata = dev->pdata;
757 int ret;
758 bool tx;
759 void *ptr;
760
761 if (!pdata->is_tx || pdata->is_cyclic)
762 return -ENOSYS;
763 if (!addr_ptr)
764 return -EINVAL;
765
766 if (*addr_ptr)
767 munmap(*addr_ptr, pdata->mmap_len);
768
769 if (*addr_ptr && pdata->is_tx) {
770 long resp;
771 char buf[1024];
772 snprintf(buf, sizeof(buf), "WRITEBUF %s %lu\r\n",
773 dev->id, (unsigned long) pdata->mmap_len);
774
775 network_lock_dev(pdata);
776
777 if (pdata->wait_for_err_code) {
778 pdata->wait_for_err_code = false;
779 ret = read_error_code(pdata->fd);
780 if (ret < 0)
781 goto err_unlock;
782 }
783
784 ret = (ssize_t) write_command(buf, pdata->fd);
785 if (ret < 0)
786 goto err_unlock;
787
788 ret = network_do_splice(pdata->fd,
789 pdata->memfd, pdata->mmap_len);
790 if (ret < 0)
791 goto err_unlock;
792
793 pdata->wait_for_err_code = true;
794 network_unlock_dev(pdata);
795 }
796
797 if (pdata->memfd >= 0)
798 close(pdata->memfd);
799
800 if (bytes_used)
801 pdata->mmap_len = bytes_used;
802
803 /* O_TMPFILE -> Linux 3.11.
804 * TODO: use memfd_create (Linux 3.17) */
805 pdata->memfd = open(P_tmpdir, O_RDWR | O_TMPFILE | O_EXCL, S_IRWXU);
806 if (pdata->memfd < 0) {
807 ret = -errno;
808 ERROR("Unable to create temp file: %i\n", -ret);
809 return ret;
810 }
811
812 ftruncate(pdata->memfd, pdata->mmap_len);
813
814 /* TODO: READBUF */
815
816 ptr = mmap(NULL, pdata->mmap_len,
817 PROT_READ | PROT_WRITE, MAP_SHARED, pdata->memfd, 0);
818 if (ptr == MAP_FAILED) {
819 ret = -errno;
820 ERROR("Unable to mmap: %i\n", -ret);
821 return ret;
822 }
823
824 *addr_ptr = ptr;
825 return bytes_used;
826
827err_unlock:
828 network_unlock_dev(pdata);
829 return ret;
830}
831#endif
832
Paul Cercueil1494b862014-05-05 12:49:07 +0200833static ssize_t network_read_attr_helper(const struct iio_device *dev,
Paul Cercueil0cc0e162014-05-07 12:51:22 +0200834 const struct iio_channel *chn, const char *attr, char *dst,
Paul Cercueil1494b862014-05-05 12:49:07 +0200835 size_t len, bool is_debug)
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100836{
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100837 long read_len;
838 ssize_t ret;
839 char buf[1024];
Paul Cercueil05e26262014-05-09 11:32:43 +0200840 struct iio_context_pdata *pdata = dev->ctx->pdata;
841 int fd = pdata->fd;
Paul Cercueil1494b862014-05-05 12:49:07 +0200842 const char *id = dev->id;
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100843
Paul Cercueil99cf3d42014-03-06 12:35:26 +0100844 if (chn)
Paul Cercueil0cc0e162014-05-07 12:51:22 +0200845 snprintf(buf, sizeof(buf), "READ %s %s %s %s\r\n", id,
846 chn->is_output ? "OUTPUT" : "INPUT",
Paul Cercueil2a3e43d2014-05-21 16:58:45 +0200847 chn->id, attr ? attr : "");
Paul Cercueilc6f03612014-04-14 16:41:31 +0200848 else if (is_debug)
Paul Cercueil2a3e43d2014-05-21 16:58:45 +0200849 snprintf(buf, sizeof(buf), "READ %s DEBUG %s\r\n",
850 id, attr ? attr : "");
Paul Cercueil99cf3d42014-03-06 12:35:26 +0100851 else
Paul Cercueil2a3e43d2014-05-21 16:58:45 +0200852 snprintf(buf, sizeof(buf), "READ %s %s\r\n",
853 id, attr ? attr : "");
Paul Cercueil1494b862014-05-05 12:49:07 +0200854
Paul Cercueil05e26262014-05-09 11:32:43 +0200855 network_lock(pdata);
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100856 read_len = exec_command(buf, fd);
Paul Cercueil1494b862014-05-05 12:49:07 +0200857 if (read_len < 0) {
Paul Cercueil05e26262014-05-09 11:32:43 +0200858 network_unlock(pdata);
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100859 return (ssize_t) read_len;
Paul Cercueil1494b862014-05-05 12:49:07 +0200860 }
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100861
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200862 if ((unsigned long) read_len > len) {
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100863 ERROR("Value returned by server is too large\n");
Paul Cercueil05e26262014-05-09 11:32:43 +0200864 network_unlock(pdata);
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100865 return -EIO;
866 }
867
868 ret = read_all(dst, read_len, fd);
Paul Cercueil05e26262014-05-09 11:32:43 +0200869 network_unlock(pdata);
Paul Cercueil1494b862014-05-05 12:49:07 +0200870
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100871 if (ret < 0) {
872 strerror_r(-ret, buf, sizeof(buf));
873 ERROR("Unable to read response to READ: %s\n", buf);
874 return ret;
875 }
876
Paul Cercueil7d95fd72014-05-22 14:26:44 +0200877 return read_len;
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100878}
879
Paul Cercueil1494b862014-05-05 12:49:07 +0200880static ssize_t network_write_attr_helper(const struct iio_device *dev,
Paul Cercueil0cc0e162014-05-07 12:51:22 +0200881 const struct iio_channel *chn, const char *attr,
882 const char *src, size_t len, bool is_debug)
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100883{
Paul Cercueila62f84e2015-02-24 14:16:08 +0100884 struct iio_context_pdata *pdata = dev->ctx->pdata;
885 int fd;
886 ssize_t ret;
887 long resp;
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100888 char buf[1024];
Paul Cercueil1494b862014-05-05 12:49:07 +0200889 const char *id = dev->id;
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100890
Paul Cercueil07897d32014-03-06 12:46:08 +0100891 if (chn)
Paul Cercueil0cc0e162014-05-07 12:51:22 +0200892 snprintf(buf, sizeof(buf), "WRITE %s %s %s %s %lu\r\n",
893 id, chn->is_output ? "OUTPUT" : "INPUT",
Paul Cercueil8747efe2014-05-22 11:12:12 +0200894 chn->id, attr ? attr : "", (unsigned long) len);
Paul Cercueilc6f03612014-04-14 16:41:31 +0200895 else if (is_debug)
Paul Cercueil8747efe2014-05-22 11:12:12 +0200896 snprintf(buf, sizeof(buf), "WRITE %s DEBUG %s %lu\r\n",
897 id, attr ? attr : "", (unsigned long) len);
Paul Cercueil07897d32014-03-06 12:46:08 +0100898 else
Paul Cercueilcecda352014-05-06 18:14:29 +0200899 snprintf(buf, sizeof(buf), "WRITE %s %s %lu\r\n",
Paul Cercueil8747efe2014-05-22 11:12:12 +0200900 id, attr ? attr : "", (unsigned long) len);
Paul Cercueila62f84e2015-02-24 14:16:08 +0100901
902 network_lock(pdata);
903 fd = pdata->fd;
904 ret = (ssize_t) write_command(buf, fd);
905 if (ret < 0)
906 goto err_unlock;
907
908 ret = write_all(src, len, fd);
909 if (ret < 0)
910 goto err_unlock;
911
912 ret = read_integer(fd, &resp);
913 network_unlock(pdata);
914
915 if (ret < 0)
916 return ret;
917 return (ssize_t) resp;
918
919err_unlock:
920 network_unlock(pdata);
921 return ret;
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100922}
923
Paul Cercueil99cf3d42014-03-06 12:35:26 +0100924static ssize_t network_read_dev_attr(const struct iio_device *dev,
Paul Cercueil50c762a2014-04-14 15:55:43 +0200925 const char *attr, char *dst, size_t len, bool is_debug)
Paul Cercueil99cf3d42014-03-06 12:35:26 +0100926{
Paul Cercueil5b577762014-06-03 15:31:42 +0200927 if (attr && ((is_debug && !iio_device_find_debug_attr(dev, attr)) ||
928 (!is_debug && !iio_device_find_attr(dev, attr))))
929 return -ENOENT;
930
Paul Cercueil1494b862014-05-05 12:49:07 +0200931 return network_read_attr_helper(dev, NULL, attr, dst, len, is_debug);
Paul Cercueil99cf3d42014-03-06 12:35:26 +0100932}
933
Paul Cercueil07897d32014-03-06 12:46:08 +0100934static ssize_t network_write_dev_attr(const struct iio_device *dev,
Paul Cercueilcecda352014-05-06 18:14:29 +0200935 const char *attr, const char *src, size_t len, bool is_debug)
Paul Cercueil07897d32014-03-06 12:46:08 +0100936{
Paul Cercueil5b577762014-06-03 15:31:42 +0200937 if (attr && ((is_debug && !iio_device_find_debug_attr(dev, attr)) ||
938 (!is_debug && !iio_device_find_attr(dev, attr))))
939 return -ENOENT;
940
Paul Cercueilcecda352014-05-06 18:14:29 +0200941 return network_write_attr_helper(dev, NULL, attr, src, len, is_debug);
Paul Cercueil07897d32014-03-06 12:46:08 +0100942}
943
Paul Cercueil99cf3d42014-03-06 12:35:26 +0100944static ssize_t network_read_chn_attr(const struct iio_channel *chn,
945 const char *attr, char *dst, size_t len)
946{
Paul Cercueil5b577762014-06-03 15:31:42 +0200947 if (attr && !iio_channel_find_attr(chn, attr))
948 return -ENOENT;
949
Paul Cercueil0cc0e162014-05-07 12:51:22 +0200950 return network_read_attr_helper(chn->dev, chn, attr, dst, len, false);
Paul Cercueil99cf3d42014-03-06 12:35:26 +0100951}
952
Paul Cercueil07897d32014-03-06 12:46:08 +0100953static ssize_t network_write_chn_attr(const struct iio_channel *chn,
Paul Cercueilcecda352014-05-06 18:14:29 +0200954 const char *attr, const char *src, size_t len)
Paul Cercueil07897d32014-03-06 12:46:08 +0100955{
Paul Cercueil5b577762014-06-03 15:31:42 +0200956 if (attr && !iio_channel_find_attr(chn, attr))
957 return -ENOENT;
958
Paul Cercueil0cc0e162014-05-07 12:51:22 +0200959 return network_write_attr_helper(chn->dev, chn, attr, src, len, false);
Paul Cercueil07897d32014-03-06 12:46:08 +0100960}
961
Paul Cercueildcab40c2014-03-11 10:59:14 +0100962static int network_get_trigger(const struct iio_device *dev,
963 const struct iio_device **trigger)
964{
965 struct iio_context_pdata *pdata = dev->ctx->pdata;
966 unsigned int i;
967 char buf[1024];
968 ssize_t ret;
969 long resp;
970
971 snprintf(buf, sizeof(buf), "GETTRIG %s\r\n", dev->id);
Paul Cercueil1494b862014-05-05 12:49:07 +0200972
Paul Cercueil05e26262014-05-09 11:32:43 +0200973 network_lock(dev->ctx->pdata);
Paul Cercueildcab40c2014-03-11 10:59:14 +0100974 resp = exec_command(buf, pdata->fd);
975 if (resp < 0) {
Paul Cercueil05e26262014-05-09 11:32:43 +0200976 network_unlock(pdata);
Paul Cercueildcab40c2014-03-11 10:59:14 +0100977 return (int) resp;
978 } else if (resp == 0) {
979 *trigger = NULL;
Paul Cercueil05e26262014-05-09 11:32:43 +0200980 network_unlock(pdata);
Paul Cercueildcab40c2014-03-11 10:59:14 +0100981 return 0;
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200982 } else if ((unsigned long) resp > sizeof(buf)) {
Paul Cercueildcab40c2014-03-11 10:59:14 +0100983 ERROR("Value returned by server is too large\n");
Paul Cercueil05e26262014-05-09 11:32:43 +0200984 network_unlock(pdata);
Paul Cercueildcab40c2014-03-11 10:59:14 +0100985 return -EIO;
986 }
987
988 ret = read_all(buf, resp, pdata->fd);
Paul Cercueil05e26262014-05-09 11:32:43 +0200989 network_unlock(pdata);
Paul Cercueil1494b862014-05-05 12:49:07 +0200990
Paul Cercueildcab40c2014-03-11 10:59:14 +0100991 if (ret < 0) {
992 strerror_r(-ret, buf, sizeof(buf));
993 ERROR("Unable to read response to GETTRIG: %s\n", buf);
994 return ret;
995 }
996
Lars-Peter Clausenb5cdc102014-08-21 14:45:52 +0200997 if (buf[0] == '\0') {
998 *trigger = NULL;
999 return 0;
1000 }
1001
Paul Cercueildcab40c2014-03-11 10:59:14 +01001002 for (i = 0; i < dev->ctx->nb_devices; i++) {
1003 struct iio_device *cur = dev->ctx->devices[i];
1004 if (iio_device_is_trigger(cur) &&
1005 !strncmp(cur->name, buf, resp)) {
1006 *trigger = cur;
1007 return 0;
1008 }
1009 }
1010
1011 return -ENXIO;
1012}
1013
1014static int network_set_trigger(const struct iio_device *dev,
1015 const struct iio_device *trigger)
1016{
Paul Cercueil1494b862014-05-05 12:49:07 +02001017 int ret;
Paul Cercueildcab40c2014-03-11 10:59:14 +01001018 char buf[1024];
1019 if (trigger)
1020 snprintf(buf, sizeof(buf), "SETTRIG %s %s\r\n",
1021 dev->id, trigger->id);
1022 else
1023 snprintf(buf, sizeof(buf), "SETTRIG %s\r\n", dev->id);
Paul Cercueil1494b862014-05-05 12:49:07 +02001024
Paul Cercueil05e26262014-05-09 11:32:43 +02001025 network_lock(dev->ctx->pdata);
Paul Cercueil1494b862014-05-05 12:49:07 +02001026 ret = (int) exec_command(buf, dev->ctx->pdata->fd);
Paul Cercueil05e26262014-05-09 11:32:43 +02001027 network_unlock(dev->ctx->pdata);
Paul Cercueil1494b862014-05-05 12:49:07 +02001028 return ret;
Paul Cercueildcab40c2014-03-11 10:59:14 +01001029}
1030
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +01001031static void network_shutdown(struct iio_context *ctx)
1032{
1033 struct iio_context_pdata *pdata = ctx->pdata;
Paul Cercueil44ae11c2014-03-17 09:56:29 +01001034 unsigned int i;
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +01001035
Paul Cercueil05e26262014-05-09 11:32:43 +02001036 network_lock(pdata);
Paul Cercueilbb76bf92014-03-11 10:20:18 +01001037 write_command("\r\nEXIT\r\n", pdata->fd);
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +01001038 close(pdata->fd);
Paul Cercueil05e26262014-05-09 11:32:43 +02001039 network_unlock(pdata);
Paul Cercueil1494b862014-05-05 12:49:07 +02001040
Paul Cercueil439e1a22015-02-24 13:50:51 +01001041 for (i = 0; i < ctx->nb_devices; i++) {
1042 struct iio_device *dev = ctx->devices[i];
Paul Cercueilc5b00752015-02-24 14:29:53 +01001043 struct iio_device_pdata *dpdata = dev->pdata;
Paul Cercueil439e1a22015-02-24 13:50:51 +01001044
Paul Cercueilc5b00752015-02-24 14:29:53 +01001045 if (dpdata) {
Paul Cercueilaa0db142015-03-04 16:25:24 +01001046 network_close(dev);
Paul Cercueilc5b00752015-02-24 14:29:53 +01001047#if HAVE_PTHREAD
Paul Cercueilaa0db142015-03-04 16:25:24 +01001048 pthread_mutex_destroy(&dpdata->lock);
Paul Cercueilc5b00752015-02-24 14:29:53 +01001049#endif
Paul Cercueilc5b00752015-02-24 14:29:53 +01001050 free(dpdata);
Paul Cercueil439e1a22015-02-24 13:50:51 +01001051 }
1052 }
1053
Paul Cercueil05e26262014-05-09 11:32:43 +02001054#if HAVE_PTHREAD
Paul Cercueil1494b862014-05-05 12:49:07 +02001055 pthread_mutex_destroy(&pdata->lock);
Paul Cercueil05e26262014-05-09 11:32:43 +02001056#endif
Paul Cercueil2dd2c132015-02-24 10:41:01 +01001057 freeaddrinfo(pdata->addrinfo);
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +01001058 free(pdata);
1059}
1060
Paul Cercueil6691a3f2014-05-02 12:32:01 +02001061static int network_get_version(const struct iio_context *ctx,
Paul Cercueil9de9e9d2014-05-20 13:18:19 +02001062 unsigned int *major, unsigned int *minor, char git_tag[8])
Paul Cercueil6691a3f2014-05-02 12:32:01 +02001063{
1064 struct iio_context_pdata *pdata = ctx->pdata;
1065 long maj, min;
1066 int ret;
Paul Cercueil6691a3f2014-05-02 12:32:01 +02001067
Paul Cercueil05e26262014-05-09 11:32:43 +02001068 network_lock(pdata);
Paul Cercueil1494b862014-05-05 12:49:07 +02001069 ret = (int) write_command("VERSION\r\n", pdata->fd);
1070 if (ret < 0)
1071 goto err_unlock;
1072
1073 ret = read_integer(pdata->fd, &maj);
1074 if (!ret)
1075 ret = read_integer(pdata->fd, &min);
1076 if (!ret) {
Paul Cercueil9de9e9d2014-05-20 13:18:19 +02001077 char tag[8];
1078 tag[7] = '\0';
1079
1080 ret = read_all(tag, sizeof(tag) - 1, pdata->fd);
1081 if (ret < 0)
1082 goto err_unlock;
1083
Paul Cercueild15d9952014-05-20 11:40:08 +02001084 if (major)
1085 *major = (unsigned int) maj;
1086 if (minor)
1087 *minor = (unsigned int) min;
Paul Cercueil9de9e9d2014-05-20 13:18:19 +02001088 if (git_tag)
1089 strncpy(git_tag, tag, 8);
Paul Cercueil1494b862014-05-05 12:49:07 +02001090 }
1091
Paul Cercueil8e8f8992014-06-12 16:58:12 +02001092 ret = 0;
Paul Cercueil1494b862014-05-05 12:49:07 +02001093err_unlock:
Paul Cercueil05e26262014-05-09 11:32:43 +02001094 network_unlock(pdata);
Paul Cercueil1494b862014-05-05 12:49:07 +02001095 return ret;
Paul Cercueil6691a3f2014-05-02 12:32:01 +02001096}
1097
Paul Cercueil8a266f12014-06-10 16:06:31 +02001098static unsigned int calculate_remote_timeout(unsigned int timeout)
1099{
1100 /* XXX(pcercuei): We currently hardcode timeout / 2 for the backend used
1101 * by the remote. Is there something better to do here? */
1102 return timeout / 2;
1103}
1104
Paul Cercueilbca3dbc2014-06-11 12:00:21 +02001105static int set_remote_timeout(struct iio_context *ctx, unsigned int timeout)
1106{
1107 char buf[1024];
1108 int ret;
1109
1110 snprintf(buf, sizeof(buf), "TIMEOUT %u\r\n", timeout);
1111 network_lock(ctx->pdata);
1112 ret = (int) exec_command(buf, ctx->pdata->fd);
1113 network_unlock(ctx->pdata);
1114 return ret;
1115}
1116
1117static int network_set_timeout(struct iio_context *ctx, unsigned int timeout)
1118{
1119 int ret = set_socket_timeout(ctx->pdata->fd, timeout);
1120 if (!ret) {
1121 timeout = calculate_remote_timeout(timeout);
1122 ret = set_remote_timeout(ctx, timeout);
1123 }
1124 if (ret < 0) {
1125 char buf[1024];
1126 strerror_r(-ret, buf, sizeof(buf));
Paul Cercueil8a266f12014-06-10 16:06:31 +02001127 WARNING("Unable to set R/W timeout: %s\n", buf);
1128 } else {
Paul Cercueil8a266f12014-06-10 16:06:31 +02001129 ctx->rw_timeout_ms = timeout;
1130 }
1131 return ret;
1132}
1133
Paul Cercueil12d41832014-10-28 14:35:53 +01001134static struct iio_context * network_clone(const struct iio_context *ctx)
1135{
Paul Cercueild3d56ee2015-01-08 16:36:31 +01001136 return iio_create_network_context(ctx->description);
Paul Cercueil12d41832014-10-28 14:35:53 +01001137}
1138
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001139static struct iio_backend_ops network_ops = {
Paul Cercueil12d41832014-10-28 14:35:53 +01001140 .clone = network_clone,
Paul Cercueilba059762014-03-14 11:02:02 +01001141 .open = network_open,
1142 .close = network_close,
Paul Cercueil9945bc82014-03-05 14:07:29 +01001143 .read = network_read,
Paul Cercueil2725f702014-05-02 11:02:16 +02001144 .write = network_write,
Paul Cercueil09a43482015-03-04 15:50:27 +01001145#ifdef __linux__
1146 .get_buffer = network_get_buffer,
1147#endif
Paul Cercueil3e94a5b2014-03-04 13:00:41 +01001148 .read_device_attr = network_read_dev_attr,
1149 .write_device_attr = network_write_dev_attr,
Paul Cercueil99cf3d42014-03-06 12:35:26 +01001150 .read_channel_attr = network_read_chn_attr,
Paul Cercueil07897d32014-03-06 12:46:08 +01001151 .write_channel_attr = network_write_chn_attr,
Paul Cercueildcab40c2014-03-11 10:59:14 +01001152 .get_trigger = network_get_trigger,
1153 .set_trigger = network_set_trigger,
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +01001154 .shutdown = network_shutdown,
Paul Cercueil6691a3f2014-05-02 12:32:01 +02001155 .get_version = network_get_version,
Paul Cercueil8a266f12014-06-10 16:06:31 +02001156 .set_timeout = network_set_timeout,
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001157};
1158
1159static struct iio_context * get_context(int fd)
1160{
1161 struct iio_context *ctx;
Paul Cercueile60c3ed2014-03-04 11:23:56 +01001162 char *xml;
Paul Cercueilbb76bf92014-03-11 10:20:18 +01001163 long xml_len = exec_command("PRINT\r\n", fd);
1164 if (xml_len < 0)
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001165 return NULL;
Paul Cercueile60c3ed2014-03-04 11:23:56 +01001166
1167 DEBUG("Server returned a XML string of length %li\n", xml_len);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001168 xml = malloc(xml_len);
1169 if (!xml) {
1170 ERROR("Unable to allocate data\n");
1171 return NULL;
1172 }
1173
1174 DEBUG("Reading XML string...\n");
1175 read_all(xml, xml_len, fd);
1176
1177 DEBUG("Creating context from XML...\n");
1178 ctx = iio_create_xml_context_mem(xml, xml_len);
Paul Cercueilc1ed8482014-06-11 16:29:43 +02001179
1180 if (ctx)
1181 ctx->xml = xml;
1182 else
1183 free(xml);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001184 return ctx;
1185}
1186
Paul Cercueil63e52182014-12-11 12:52:48 +01001187struct iio_context * network_create_context(const char *host)
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001188{
Paul Cercueil2e38bbe2014-03-19 15:27:15 +01001189 struct addrinfo hints, *res;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001190 struct iio_context *ctx;
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +01001191 struct iio_context_pdata *pdata;
Paul Cercueil06c479d2015-01-08 16:14:57 +01001192 unsigned int i, len;
Paul Cercueil4970ac32015-02-24 10:59:00 +01001193 int fd, ret;
Paul Cercueil1fef1a52014-04-07 16:31:15 +02001194#ifdef _WIN32
1195 WSADATA wsaData;
1196
1197 ret = WSAStartup(MAKEWORD(2, 0), &wsaData);
1198 if (ret < 0) {
1199 ERROR("WSAStartup failed with error %i\n", ret);
1200 return NULL;
1201 }
1202#endif
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001203
Paul Cercueil2e38bbe2014-03-19 15:27:15 +01001204 memset(&hints, 0, sizeof(hints));
1205 hints.ai_family = AF_UNSPEC;
1206 hints.ai_socktype = SOCK_STREAM;
Paul Cercueilab114932014-05-19 13:03:17 +02001207
1208#ifdef HAVE_AVAHI
1209 if (!host) {
1210 char addr_str[AVAHI_ADDRESS_STR_MAX];
1211 char port_str[6];
1212 AvahiAddress address;
Paul Cercueil0f729d32014-06-05 17:38:54 +02001213 uint16_t port = IIOD_PORT;
Paul Cercueilab114932014-05-19 13:03:17 +02001214
1215 memset(&address, 0, sizeof(address));
1216
1217 ret = discover_host(&address, &port);
1218 if (ret < 0) {
1219 ERROR("Unable to find host: %s\n", strerror(-ret));
1220 return NULL;
1221 }
1222
1223 avahi_address_snprint(addr_str, sizeof(addr_str), &address);
1224 snprintf(port_str, sizeof(port_str), "%hu", port);
1225 ret = getaddrinfo(addr_str, port_str, &hints, &res);
1226 } else
1227#endif
1228 {
1229 ret = getaddrinfo(host, IIOD_PORT_STR, &hints, &res);
1230 }
1231
Paul Cercueil2e38bbe2014-03-19 15:27:15 +01001232 if (ret) {
Paul Cercueilab114932014-05-19 13:03:17 +02001233 ERROR("Unable to find host: %s\n", gai_strerror(ret));
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001234 return NULL;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001235 }
1236
Paul Cercueil4970ac32015-02-24 10:59:00 +01001237 fd = create_socket(res);
1238 if (fd < 0)
Paul Cercueil2dd2c132015-02-24 10:41:01 +01001239 goto err_free_addrinfo;
Paul Cercueilbca3dbc2014-06-11 12:00:21 +02001240
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +01001241 pdata = calloc(1, sizeof(*pdata));
1242 if (!pdata) {
1243 ERROR("Unable to allocate memory\n");
1244 goto err_close_socket;
1245 }
1246
1247 pdata->fd = fd;
Paul Cercueil2dd2c132015-02-24 10:41:01 +01001248 pdata->addrinfo = res;
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +01001249
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001250 DEBUG("Creating context...\n");
1251 ctx = get_context(fd);
1252 if (!ctx)
Paul Cercueild3d56ee2015-01-08 16:36:31 +01001253 goto err_free_pdata;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001254
Paul Cercueil2057fd32014-10-28 14:44:19 +01001255 /* Override the name and low-level functions of the XML context
1256 * with those corresponding to the network context */
1257 ctx->name = "network";
1258 ctx->ops = &network_ops;
1259 ctx->pdata = pdata;
1260
Paul Cercueil06c479d2015-01-08 16:14:57 +01001261#ifdef HAVE_IPV6
Paul Cercueiled15e492015-01-12 15:52:28 +01001262 len = INET6_ADDRSTRLEN + IF_NAMESIZE + 2;
Paul Cercueil06c479d2015-01-08 16:14:57 +01001263#else
1264 len = INET_ADDRSTRLEN + 1;
1265#endif
1266 ctx->description = malloc(len);
1267 if (!ctx->description) {
1268 ERROR("Unable to allocate memory\n");
1269 goto err_network_shutdown;
1270 }
1271
1272 ctx->description[0] = '\0';
1273
1274#ifdef HAVE_IPV6
1275 if (res->ai_family == AF_INET6) {
1276 struct sockaddr_in6 *in = (struct sockaddr_in6 *) res->ai_addr;
Paul Cercueiled15e492015-01-12 15:52:28 +01001277 char *ptr;
Paul Cercueil06c479d2015-01-08 16:14:57 +01001278 inet_ntop(AF_INET6, &in->sin6_addr,
1279 ctx->description, INET6_ADDRSTRLEN);
Paul Cercueiled15e492015-01-12 15:52:28 +01001280
1281 ptr = if_indextoname(in->sin6_scope_id, ctx->description +
1282 strlen(ctx->description) + 1);
1283 if (!ptr) {
1284 ERROR("Unable to lookup interface of IPv6 address\n");
1285 goto err_network_shutdown;
1286 }
1287
1288 *(ptr - 1) = '%';
Paul Cercueil06c479d2015-01-08 16:14:57 +01001289 }
1290#endif
1291 if (res->ai_family == AF_INET) {
1292 struct sockaddr_in *in = (struct sockaddr_in *) res->ai_addr;
1293 inet_ntop(AF_INET, &in->sin_addr,
1294 ctx->description, INET_ADDRSTRLEN);
1295 }
1296
Paul Cercueil44ae11c2014-03-17 09:56:29 +01001297 for (i = 0; i < ctx->nb_devices; i++) {
1298 struct iio_device *dev = ctx->devices[i];
Paul Cercueilff778232014-03-24 14:23:08 +01001299
1300 dev->words = (dev->nb_channels + 31) / 32;
1301 if (dev->words) {
Paul Cercueil439e1a22015-02-24 13:50:51 +01001302 dev->mask = calloc(dev->words, sizeof(*dev->mask));
1303 if (!dev->mask) {
Paul Cercueil2057fd32014-10-28 14:44:19 +01001304 ERROR("Unable to allocate memory\n");
Paul Cercueilff778232014-03-24 14:23:08 +01001305 goto err_network_shutdown;
Paul Cercueil2057fd32014-10-28 14:44:19 +01001306 }
Paul Cercueilff778232014-03-24 14:23:08 +01001307 }
1308
Paul Cercueil439e1a22015-02-24 13:50:51 +01001309 dev->pdata = calloc(1, sizeof(*dev->pdata));
1310 if (!dev->pdata) {
1311 ERROR("Unable to allocate memory\n");
1312 goto err_network_shutdown;
1313 }
1314
1315 dev->pdata->fd = -1;
Paul Cercueil09a43482015-03-04 15:50:27 +01001316 dev->pdata->memfd = -1;
Paul Cercueilc5b00752015-02-24 14:29:53 +01001317
1318#if HAVE_PTHREAD
1319 ret = pthread_mutex_init(&dev->pdata->lock, NULL);
1320 if (ret < 0) {
1321 char buf[1024];
1322 strerror_r(-ret, buf, sizeof(buf));
1323 ERROR("Unable to initialize mutex: %s\n", buf);
1324 goto err_network_shutdown;
1325 }
1326#endif
Paul Cercueil44ae11c2014-03-17 09:56:29 +01001327 }
1328
Paul Cercueilc1ed8482014-06-11 16:29:43 +02001329 iio_context_init(ctx);
Paul Cercueil4c6729d2014-04-04 17:24:41 +02001330
Paul Cercueil05e26262014-05-09 11:32:43 +02001331#if HAVE_PTHREAD
Paul Cercueil1494b862014-05-05 12:49:07 +02001332 ret = pthread_mutex_init(&pdata->lock, NULL);
1333 if (ret < 0) {
1334 char buf[1024];
1335 strerror_r(-ret, buf, sizeof(buf));
1336 ERROR("Unable to initialize mutex: %s\n", buf);
1337 goto err_network_shutdown;
1338 }
Paul Cercueil05e26262014-05-09 11:32:43 +02001339#endif
Paul Cercueil1494b862014-05-05 12:49:07 +02001340
Paul Cercueilbca3dbc2014-06-11 12:00:21 +02001341 set_remote_timeout(ctx, calculate_remote_timeout(DEFAULT_TIMEOUT_MS));
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001342 return ctx;
1343
Paul Cercueil44ae11c2014-03-17 09:56:29 +01001344err_network_shutdown:
Paul Cercueil44ae11c2014-03-17 09:56:29 +01001345 iio_context_destroy(ctx);
Paul Cercueil2057fd32014-10-28 14:44:19 +01001346 return NULL;
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +01001347err_free_pdata:
1348 free(pdata);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001349err_close_socket:
1350 close(fd);
Paul Cercueil2dd2c132015-02-24 10:41:01 +01001351err_free_addrinfo:
1352 freeaddrinfo(res);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001353 return NULL;
1354}