blob: 350efc58af566ce5f255d57682a1e49872dbc0b7 [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 Cercueilc7bad0f2014-03-03 17:06:48 +010019#include "iio-private.h"
20
Paul Cercueil9aabe892014-09-02 12:33:46 +020021#ifndef HAVE_PTHREAD
22#define HAVE_PTHREAD 1
23#endif
24
Paul Cercueilc7bad0f2014-03-03 17:06:48 +010025#include <errno.h>
Paul Cercueila7d445b2014-11-11 16:00:15 +010026#include <fcntl.h>
Paul Cercueile60c3ed2014-03-04 11:23:56 +010027#include <stdbool.h>
Paul Cercueilc7bad0f2014-03-03 17:06:48 +010028#include <string.h>
29#include <sys/types.h>
Paul Cercueilab114932014-05-19 13:03:17 +020030#include <time.h>
Paul Cercueil1fef1a52014-04-07 16:31:15 +020031
32#ifdef _WIN32
Paul Cercueil06c479d2015-01-08 16:14:57 +010033/* Override the default version of Windows supported by MinGW.
34 * This is required to use the function inet_ntop. */
35#undef _WIN32_WINNT
36#define _WIN32_WINNT 0x0600
37
Paul Cercueil1fef1a52014-04-07 16:31:15 +020038#include <winsock2.h>
39#include <ws2tcpip.h>
40#define close(s) closesocket(s)
41
42/* winsock2.h defines ERROR, we don't want that */
43#undef ERROR
44
45#else /* _WIN32 */
Paul Cercueil06c479d2015-01-08 16:14:57 +010046#include <arpa/inet.h>
Paul Cercueil1fef1a52014-04-07 16:31:15 +020047#include <netdb.h>
Paul Cercueil0c3ce452015-02-05 16:37:42 +010048#include <netinet/in.h>
Paul Cercueil0b584e12015-01-28 11:47:03 +010049#include <netinet/tcp.h>
Paul Cercueiled15e492015-01-12 15:52:28 +010050#include <net/if.h>
Paul Cercueil83628b32014-11-24 11:26:21 +010051#include <sys/select.h>
Paul Cercueilc7bad0f2014-03-03 17:06:48 +010052#include <sys/socket.h>
53#include <unistd.h>
Paul Cercueil1fef1a52014-04-07 16:31:15 +020054#endif /* _WIN32 */
55
Paul Cercueil257e6ca2014-12-09 17:32:47 +010056#if HAVE_PTHREAD
57#include <pthread.h>
58#endif
59
Paul Cercueilab114932014-05-19 13:03:17 +020060#ifdef HAVE_AVAHI
61#include <avahi-client/client.h>
62#include <avahi-common/error.h>
63#include <avahi-client/lookup.h>
64#include <avahi-common/simple-watch.h>
65#endif
66
Paul Cercueil1fef1a52014-04-07 16:31:15 +020067#include "debug.h"
Paul Cercueilc7bad0f2014-03-03 17:06:48 +010068
Paul Cercueil8a266f12014-06-10 16:06:31 +020069#define DEFAULT_TIMEOUT_MS 5000
70
Paul Cercueil2e38bbe2014-03-19 15:27:15 +010071#define _STRINGIFY(x) #x
72#define STRINGIFY(x) _STRINGIFY(x)
73
Paul Cercueilc7bad0f2014-03-03 17:06:48 +010074#define IIOD_PORT 30431
Paul Cercueil2e38bbe2014-03-19 15:27:15 +010075#define IIOD_PORT_STR STRINGIFY(IIOD_PORT)
Paul Cercueilc7bad0f2014-03-03 17:06:48 +010076
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +010077struct iio_context_pdata {
78 int fd;
Paul Cercueil2dd2c132015-02-24 10:41:01 +010079 struct addrinfo *addrinfo;
Paul Cercueil05e26262014-05-09 11:32:43 +020080#if HAVE_PTHREAD
Paul Cercueil1494b862014-05-05 12:49:07 +020081 pthread_mutex_t lock;
Paul Cercueil05e26262014-05-09 11:32:43 +020082#endif
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +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 Cercueil05e26262014-05-09 11:32:43 +0200190static void network_lock(struct iio_context_pdata *pdata)
191{
192#if HAVE_PTHREAD
193 pthread_mutex_lock(&pdata->lock);
194#endif
195}
196
197static void network_unlock(struct iio_context_pdata *pdata)
198{
199#if HAVE_PTHREAD
200 pthread_mutex_unlock(&pdata->lock);
201#endif
202}
203
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100204static ssize_t write_all(const void *src, size_t len, int fd)
205{
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200206 uintptr_t ptr = (uintptr_t) src;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100207 while (len) {
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200208 ssize_t ret = send(fd, (const void *) ptr, len, 0);
Lars-Peter Clausencb7b8bf2014-12-05 16:08:52 +0100209 if (ret < 0) {
210 if (errno == EINTR) {
211 continue;
212 }
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100213 return -errno;
Lars-Peter Clausencb7b8bf2014-12-05 16:08:52 +0100214 }
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100215 ptr += ret;
216 len -= ret;
217 }
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200218 return ptr - (uintptr_t) src;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100219}
220
221static ssize_t read_all(void *dst, size_t len, int fd)
222{
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200223 uintptr_t ptr = (uintptr_t) dst;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100224 while (len) {
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200225 ssize_t ret = recv(fd, (void *) ptr, len, 0);
Lars-Peter Clausencb7b8bf2014-12-05 16:08:52 +0100226 if (ret < 0) {
227 if (errno == EINTR)
228 continue;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100229 return -errno;
Lars-Peter Clausencb7b8bf2014-12-05 16:08:52 +0100230 }
Paul Cercueil43eb7e82014-11-13 12:46:59 +0100231 if (ret == 0)
232 return -EPIPE;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100233 ptr += ret;
234 len -= ret;
235 }
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200236 return ptr - (uintptr_t) dst;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100237}
238
Paul Cercueile60c3ed2014-03-04 11:23:56 +0100239static int read_integer(int fd, long *val)
240{
241 unsigned int i;
242 char buf[1024], *ptr;
243 ssize_t ret;
244 bool found = false;
245
246 for (i = 0; i < sizeof(buf) - 1; i++) {
247 ret = read_all(buf + i, 1, fd);
248 if (ret < 0)
249 return (int) ret;
250
Paul Cercueil6691a3f2014-05-02 12:32:01 +0200251 /* Skip the eventual first few carriage returns.
252 * Also stop when a dot is found (for parsing floats) */
253 if (buf[i] != '\n' && buf[i] != '.')
Paul Cercueile60c3ed2014-03-04 11:23:56 +0100254 found = true;
255 else if (found)
256 break;
257 }
258
259 buf[i] = '\0';
260 ret = (ssize_t) strtol(buf, &ptr, 10);
261 if (ptr == buf)
262 return -EINVAL;
263 *val = (long) ret;
264 return 0;
265}
266
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100267static ssize_t write_command(const char *cmd, int fd)
268{
269 ssize_t ret;
270
271 DEBUG("Writing command: %s\n", cmd);
272 ret = write_all(cmd, strlen(cmd), fd);
273 if (ret < 0) {
274 char buf[1024];
275 strerror_r(-ret, buf, sizeof(buf));
276 ERROR("Unable to send command: %s\n", buf);
277 }
278 return ret;
279}
280
281static long exec_command(const char *cmd, int fd)
282{
283 long resp;
284 ssize_t ret = write_command(cmd, fd);
285 if (ret < 0)
286 return (long) ret;
287
288 DEBUG("Reading response\n");
289 ret = read_integer(fd, &resp);
290 if (ret < 0) {
291 char buf[1024];
292 strerror_r(-ret, buf, sizeof(buf));
293 ERROR("Unable to read response: %s\n", buf);
294 return (long) ret;
295 }
296
Paul Cercueilc7fe2ea2014-03-28 11:38:45 +0100297#if LOG_LEVEL >= DEBUG_L
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100298 if (resp < 0) {
299 char buf[1024];
300 strerror_r(-resp, buf, sizeof(buf));
Paul Cercueilc7fe2ea2014-03-28 11:38:45 +0100301 DEBUG("Server returned an error: %s\n", buf);
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100302 }
Paul Cercueilc7fe2ea2014-03-28 11:38:45 +0100303#endif
304
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100305 return resp;
306}
307
Paul Cercueil71694c72014-05-22 14:02:13 +0200308static int network_open(const struct iio_device *dev, size_t samples_count,
309 uint32_t *mask, size_t nb, bool cyclic)
Paul Cercueilba059762014-03-14 11:02:02 +0100310{
311 char buf[1024], *ptr;
312 unsigned int i;
Paul Cercueil44ae11c2014-03-17 09:56:29 +0100313 int ret;
Paul Cercueilba059762014-03-14 11:02:02 +0100314
Paul Cercueilff778232014-03-24 14:23:08 +0100315 if (nb != dev->words)
Paul Cercueilba059762014-03-14 11:02:02 +0100316 return -EINVAL;
317
Paul Cercueil3c407f82014-04-02 14:11:59 +0200318 snprintf(buf, sizeof(buf), "OPEN %s %lu ",
319 dev->id, (unsigned long) samples_count);
Paul Cercueilba059762014-03-14 11:02:02 +0100320 ptr = buf + strlen(buf);
321
322 for (i = nb; i > 0; i--) {
Paul Cercueil8c29e412014-04-07 09:46:45 +0200323 snprintf(ptr, (ptr - buf) + i * 8, "%08x", mask[i - 1]);
Paul Cercueilba059762014-03-14 11:02:02 +0100324 ptr += 8;
325 }
Paul Cercueil71694c72014-05-22 14:02:13 +0200326
327 strcpy(ptr, cyclic ? " CYCLIC\r\n" : "\r\n");
Paul Cercueilba059762014-03-14 11:02:02 +0100328
Paul Cercueil05e26262014-05-09 11:32:43 +0200329 network_lock(dev->ctx->pdata);
Paul Cercueil44ae11c2014-03-17 09:56:29 +0100330 ret = (int) exec_command(buf, dev->ctx->pdata->fd);
Paul Cercueil05e26262014-05-09 11:32:43 +0200331 network_unlock(dev->ctx->pdata);
Paul Cercueil1494b862014-05-05 12:49:07 +0200332
Paul Cercueil44ae11c2014-03-17 09:56:29 +0100333 if (ret < 0) {
Paul Cercueil44ae11c2014-03-17 09:56:29 +0100334 return ret;
335 } else {
Paul Cercueilff778232014-03-24 14:23:08 +0100336 memcpy(dev->mask, mask, nb * sizeof(*mask));
Paul Cercueil44ae11c2014-03-17 09:56:29 +0100337 return 0;
338 }
Paul Cercueilba059762014-03-14 11:02:02 +0100339}
340
341static int network_close(const struct iio_device *dev)
342{
Paul Cercueil1494b862014-05-05 12:49:07 +0200343 int ret;
Paul Cercueilba059762014-03-14 11:02:02 +0100344 char buf[1024];
345 snprintf(buf, sizeof(buf), "CLOSE %s\r\n", dev->id);
Paul Cercueil1494b862014-05-05 12:49:07 +0200346
Paul Cercueil05e26262014-05-09 11:32:43 +0200347 network_lock(dev->ctx->pdata);
Paul Cercueil1494b862014-05-05 12:49:07 +0200348 ret = (int) exec_command(buf, dev->ctx->pdata->fd);
Paul Cercueil05e26262014-05-09 11:32:43 +0200349 network_unlock(dev->ctx->pdata);
Paul Cercueil1494b862014-05-05 12:49:07 +0200350
351 return ret;
Paul Cercueilba059762014-03-14 11:02:02 +0100352}
353
Paul Cercueil45c575d2014-03-20 15:14:01 +0100354static ssize_t network_read(const struct iio_device *dev, void *dst, size_t len,
355 uint32_t *mask, size_t words)
Paul Cercueilf9286452014-03-18 14:32:17 +0100356{
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200357 uintptr_t ptr = (uintptr_t) dst;
Paul Cercueil05e26262014-05-09 11:32:43 +0200358 struct iio_context_pdata *pdata = dev->ctx->pdata;
359 int fd = pdata->fd;
Paul Cercueil45c575d2014-03-20 15:14:01 +0100360 ssize_t ret, read = 0;
Paul Cercueil9945bc82014-03-05 14:07:29 +0100361 char buf[1024];
Paul Cercueil45c575d2014-03-20 15:14:01 +0100362 bool read_mask = true;
Paul Cercueil9945bc82014-03-05 14:07:29 +0100363
Paul Cercueil45c575d2014-03-20 15:14:01 +0100364 if (!len || words != (dev->nb_channels + 31) / 32)
Paul Cercueil9945bc82014-03-05 14:07:29 +0100365 return -EINVAL;
366
Paul Cercueila78b6eb2014-03-17 17:28:07 +0100367 snprintf(buf, sizeof(buf), "READBUF %s %lu\r\n",
368 dev->id, (unsigned long) len);
Paul Cercueil1494b862014-05-05 12:49:07 +0200369
Paul Cercueil05e26262014-05-09 11:32:43 +0200370 network_lock(pdata);
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100371 ret = write_command(buf, fd);
Paul Cercueil1494b862014-05-05 12:49:07 +0200372 if (ret < 0) {
Paul Cercueil05e26262014-05-09 11:32:43 +0200373 network_unlock(pdata);
Paul Cercueil9945bc82014-03-05 14:07:29 +0100374 return ret;
Paul Cercueil1494b862014-05-05 12:49:07 +0200375 }
Paul Cercueil9945bc82014-03-05 14:07:29 +0100376
377 do {
Paul Cercueil5cab3ae2014-03-14 11:23:56 +0100378 unsigned int i;
Paul Cercueil9945bc82014-03-05 14:07:29 +0100379 long read_len;
380
381 DEBUG("Reading READ response\n");
382 ret = read_integer(fd, &read_len);
383 if (ret < 0) {
384 strerror_r(-ret, buf, sizeof(buf));
385 ERROR("Unable to read response to READ: %s\n", buf);
Paul Cercueil05e26262014-05-09 11:32:43 +0200386 network_unlock(pdata);
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200387 return read ? read : ret;
Paul Cercueil9945bc82014-03-05 14:07:29 +0100388 }
389
390 if (read_len < 0) {
391 strerror_r(-read_len, buf, sizeof(buf));
392 ERROR("Server returned an error: %s\n", buf);
Paul Cercueil05e26262014-05-09 11:32:43 +0200393 network_unlock(pdata);
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200394 return read ? read : read_len;
Paul Cercueila78b6eb2014-03-17 17:28:07 +0100395 } else if (read_len == 0) {
396 break;
Paul Cercueil9945bc82014-03-05 14:07:29 +0100397 }
398
399 DEBUG("Bytes to read: %li\n", read_len);
400
Paul Cercueil43c1e6c2014-03-20 14:26:20 +0100401 if (read_mask) {
402 DEBUG("Reading mask\n");
403 buf[8] = '\0';
Paul Cercueil45c575d2014-03-20 15:14:01 +0100404 for (i = words; i > 0; i--) {
Paul Cercueil43c1e6c2014-03-20 14:26:20 +0100405 ret = read_all(buf, 8, fd);
406 if (ret < 0)
407 break;
408 sscanf(buf, "%08x", &mask[i - 1]);
409 DEBUG("mask[%i] = 0x%x\n", i - 1, mask[i - 1]);
Paul Cercueil43c1e6c2014-03-20 14:26:20 +0100410 }
411 read_mask = false;
Paul Cercueil5cab3ae2014-03-14 11:23:56 +0100412 }
413
414 if (ret > 0) {
415 char c;
Lars-Peter Clausencb7b8bf2014-12-05 16:08:52 +0100416 ret = read_all(&c, 1, fd);
Paul Cercueil5cab3ae2014-03-14 11:23:56 +0100417 if (ret > 0 && c != '\n')
418 ret = -EIO;
419 }
420
421 if (ret < 0) {
422 strerror_r(-ret, buf, sizeof(buf));
423 ERROR("Unable to read mask: %s\n", buf);
Paul Cercueil05e26262014-05-09 11:32:43 +0200424 network_unlock(pdata);
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200425 return read ? read : ret;
Paul Cercueil5cab3ae2014-03-14 11:23:56 +0100426 }
427
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200428 ret = read_all((void *) ptr, read_len, fd);
Paul Cercueil9945bc82014-03-05 14:07:29 +0100429 if (ret < 0) {
430 strerror_r(-ret, buf, sizeof(buf));
431 ERROR("Unable to read response to READ: %s\n", buf);
Paul Cercueil05e26262014-05-09 11:32:43 +0200432 network_unlock(pdata);
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200433 return read ? read : ret;
Paul Cercueil9945bc82014-03-05 14:07:29 +0100434 }
435
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200436 ptr += ret;
Paul Cercueilf9286452014-03-18 14:32:17 +0100437 read += ret;
Paul Cercueil9945bc82014-03-05 14:07:29 +0100438 len -= read_len;
439 } while (len);
440
Paul Cercueil05e26262014-05-09 11:32:43 +0200441 network_unlock(pdata);
Paul Cercueil9945bc82014-03-05 14:07:29 +0100442 return read;
443}
444
Paul Cercueild93215d2014-05-19 16:36:06 +0200445static ssize_t do_write(struct iio_context_pdata *pdata, bool attr,
Paul Cercueilcecda352014-05-06 18:14:29 +0200446 const char *command, const void *src, size_t len)
Paul Cercueil2725f702014-05-02 11:02:16 +0200447{
Paul Cercueilcecda352014-05-06 18:14:29 +0200448 int fd = pdata->fd;
Paul Cercueil2725f702014-05-02 11:02:16 +0200449 ssize_t ret;
Paul Cercueil2725f702014-05-02 11:02:16 +0200450 long resp;
451
Paul Cercueil05e26262014-05-09 11:32:43 +0200452 network_lock(pdata);
Paul Cercueild93215d2014-05-19 16:36:06 +0200453 if (attr)
454 ret = (ssize_t) write_command(command, fd);
455 else
456 ret = (ssize_t) exec_command(command, fd);
Paul Cercueil2725f702014-05-02 11:02:16 +0200457 if (ret < 0)
Paul Cercueil1494b862014-05-05 12:49:07 +0200458 goto err_unlock;
Paul Cercueil2725f702014-05-02 11:02:16 +0200459
460 ret = write_all(src, len, fd);
461 if (ret < 0)
Paul Cercueil1494b862014-05-05 12:49:07 +0200462 goto err_unlock;
Paul Cercueil2725f702014-05-02 11:02:16 +0200463
464 ret = read_integer(fd, &resp);
Paul Cercueil05e26262014-05-09 11:32:43 +0200465 network_unlock(pdata);
Paul Cercueil1494b862014-05-05 12:49:07 +0200466
Paul Cercueil2725f702014-05-02 11:02:16 +0200467 if (ret < 0)
468 return ret;
469 return (ssize_t) resp;
Paul Cercueil1494b862014-05-05 12:49:07 +0200470
471err_unlock:
Paul Cercueil05e26262014-05-09 11:32:43 +0200472 network_unlock(pdata);
Paul Cercueil1494b862014-05-05 12:49:07 +0200473 return ret;
Paul Cercueil2725f702014-05-02 11:02:16 +0200474}
475
Paul Cercueilcecda352014-05-06 18:14:29 +0200476static ssize_t network_write(const struct iio_device *dev,
477 const void *src, size_t len)
478{
479 char buf[1024];
480 snprintf(buf, sizeof(buf), "WRITEBUF %s %lu\r\n",
481 dev->id, (unsigned long) len);
Paul Cercueild93215d2014-05-19 16:36:06 +0200482 return do_write(dev->ctx->pdata, false, buf, src, len);
Paul Cercueilcecda352014-05-06 18:14:29 +0200483}
484
Paul Cercueil1494b862014-05-05 12:49:07 +0200485static ssize_t network_read_attr_helper(const struct iio_device *dev,
Paul Cercueil0cc0e162014-05-07 12:51:22 +0200486 const struct iio_channel *chn, const char *attr, char *dst,
Paul Cercueil1494b862014-05-05 12:49:07 +0200487 size_t len, bool is_debug)
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100488{
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100489 long read_len;
490 ssize_t ret;
491 char buf[1024];
Paul Cercueil05e26262014-05-09 11:32:43 +0200492 struct iio_context_pdata *pdata = dev->ctx->pdata;
493 int fd = pdata->fd;
Paul Cercueil1494b862014-05-05 12:49:07 +0200494 const char *id = dev->id;
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100495
Paul Cercueil99cf3d42014-03-06 12:35:26 +0100496 if (chn)
Paul Cercueil0cc0e162014-05-07 12:51:22 +0200497 snprintf(buf, sizeof(buf), "READ %s %s %s %s\r\n", id,
498 chn->is_output ? "OUTPUT" : "INPUT",
Paul Cercueil2a3e43d2014-05-21 16:58:45 +0200499 chn->id, attr ? attr : "");
Paul Cercueilc6f03612014-04-14 16:41:31 +0200500 else if (is_debug)
Paul Cercueil2a3e43d2014-05-21 16:58:45 +0200501 snprintf(buf, sizeof(buf), "READ %s DEBUG %s\r\n",
502 id, attr ? attr : "");
Paul Cercueil99cf3d42014-03-06 12:35:26 +0100503 else
Paul Cercueil2a3e43d2014-05-21 16:58:45 +0200504 snprintf(buf, sizeof(buf), "READ %s %s\r\n",
505 id, attr ? attr : "");
Paul Cercueil1494b862014-05-05 12:49:07 +0200506
Paul Cercueil05e26262014-05-09 11:32:43 +0200507 network_lock(pdata);
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100508 read_len = exec_command(buf, fd);
Paul Cercueil1494b862014-05-05 12:49:07 +0200509 if (read_len < 0) {
Paul Cercueil05e26262014-05-09 11:32:43 +0200510 network_unlock(pdata);
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100511 return (ssize_t) read_len;
Paul Cercueil1494b862014-05-05 12:49:07 +0200512 }
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100513
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200514 if ((unsigned long) read_len > len) {
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100515 ERROR("Value returned by server is too large\n");
Paul Cercueil05e26262014-05-09 11:32:43 +0200516 network_unlock(pdata);
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100517 return -EIO;
518 }
519
520 ret = read_all(dst, read_len, fd);
Paul Cercueil05e26262014-05-09 11:32:43 +0200521 network_unlock(pdata);
Paul Cercueil1494b862014-05-05 12:49:07 +0200522
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100523 if (ret < 0) {
524 strerror_r(-ret, buf, sizeof(buf));
525 ERROR("Unable to read response to READ: %s\n", buf);
526 return ret;
527 }
528
Paul Cercueil7d95fd72014-05-22 14:26:44 +0200529 return read_len;
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100530}
531
Paul Cercueil1494b862014-05-05 12:49:07 +0200532static ssize_t network_write_attr_helper(const struct iio_device *dev,
Paul Cercueil0cc0e162014-05-07 12:51:22 +0200533 const struct iio_channel *chn, const char *attr,
534 const char *src, size_t len, bool is_debug)
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100535{
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100536 char buf[1024];
Paul Cercueil1494b862014-05-05 12:49:07 +0200537 const char *id = dev->id;
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100538
Paul Cercueil07897d32014-03-06 12:46:08 +0100539 if (chn)
Paul Cercueil0cc0e162014-05-07 12:51:22 +0200540 snprintf(buf, sizeof(buf), "WRITE %s %s %s %s %lu\r\n",
541 id, chn->is_output ? "OUTPUT" : "INPUT",
Paul Cercueil8747efe2014-05-22 11:12:12 +0200542 chn->id, attr ? attr : "", (unsigned long) len);
Paul Cercueilc6f03612014-04-14 16:41:31 +0200543 else if (is_debug)
Paul Cercueil8747efe2014-05-22 11:12:12 +0200544 snprintf(buf, sizeof(buf), "WRITE %s DEBUG %s %lu\r\n",
545 id, attr ? attr : "", (unsigned long) len);
Paul Cercueil07897d32014-03-06 12:46:08 +0100546 else
Paul Cercueilcecda352014-05-06 18:14:29 +0200547 snprintf(buf, sizeof(buf), "WRITE %s %s %lu\r\n",
Paul Cercueil8747efe2014-05-22 11:12:12 +0200548 id, attr ? attr : "", (unsigned long) len);
Paul Cercueild93215d2014-05-19 16:36:06 +0200549 return do_write(dev->ctx->pdata, true, buf, src, len);
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100550}
551
Paul Cercueil99cf3d42014-03-06 12:35:26 +0100552static ssize_t network_read_dev_attr(const struct iio_device *dev,
Paul Cercueil50c762a2014-04-14 15:55:43 +0200553 const char *attr, char *dst, size_t len, bool is_debug)
Paul Cercueil99cf3d42014-03-06 12:35:26 +0100554{
Paul Cercueil5b577762014-06-03 15:31:42 +0200555 if (attr && ((is_debug && !iio_device_find_debug_attr(dev, attr)) ||
556 (!is_debug && !iio_device_find_attr(dev, attr))))
557 return -ENOENT;
558
Paul Cercueil1494b862014-05-05 12:49:07 +0200559 return network_read_attr_helper(dev, NULL, attr, dst, len, is_debug);
Paul Cercueil99cf3d42014-03-06 12:35:26 +0100560}
561
Paul Cercueil07897d32014-03-06 12:46:08 +0100562static ssize_t network_write_dev_attr(const struct iio_device *dev,
Paul Cercueilcecda352014-05-06 18:14:29 +0200563 const char *attr, const char *src, size_t len, bool is_debug)
Paul Cercueil07897d32014-03-06 12:46:08 +0100564{
Paul Cercueil5b577762014-06-03 15:31:42 +0200565 if (attr && ((is_debug && !iio_device_find_debug_attr(dev, attr)) ||
566 (!is_debug && !iio_device_find_attr(dev, attr))))
567 return -ENOENT;
568
Paul Cercueilcecda352014-05-06 18:14:29 +0200569 return network_write_attr_helper(dev, NULL, attr, src, len, is_debug);
Paul Cercueil07897d32014-03-06 12:46:08 +0100570}
571
Paul Cercueil99cf3d42014-03-06 12:35:26 +0100572static ssize_t network_read_chn_attr(const struct iio_channel *chn,
573 const char *attr, char *dst, size_t len)
574{
Paul Cercueil5b577762014-06-03 15:31:42 +0200575 if (attr && !iio_channel_find_attr(chn, attr))
576 return -ENOENT;
577
Paul Cercueil0cc0e162014-05-07 12:51:22 +0200578 return network_read_attr_helper(chn->dev, chn, attr, dst, len, false);
Paul Cercueil99cf3d42014-03-06 12:35:26 +0100579}
580
Paul Cercueil07897d32014-03-06 12:46:08 +0100581static ssize_t network_write_chn_attr(const struct iio_channel *chn,
Paul Cercueilcecda352014-05-06 18:14:29 +0200582 const char *attr, const char *src, size_t len)
Paul Cercueil07897d32014-03-06 12:46:08 +0100583{
Paul Cercueil5b577762014-06-03 15:31:42 +0200584 if (attr && !iio_channel_find_attr(chn, attr))
585 return -ENOENT;
586
Paul Cercueil0cc0e162014-05-07 12:51:22 +0200587 return network_write_attr_helper(chn->dev, chn, attr, src, len, false);
Paul Cercueil07897d32014-03-06 12:46:08 +0100588}
589
Paul Cercueildcab40c2014-03-11 10:59:14 +0100590static int network_get_trigger(const struct iio_device *dev,
591 const struct iio_device **trigger)
592{
593 struct iio_context_pdata *pdata = dev->ctx->pdata;
594 unsigned int i;
595 char buf[1024];
596 ssize_t ret;
597 long resp;
598
599 snprintf(buf, sizeof(buf), "GETTRIG %s\r\n", dev->id);
Paul Cercueil1494b862014-05-05 12:49:07 +0200600
Paul Cercueil05e26262014-05-09 11:32:43 +0200601 network_lock(dev->ctx->pdata);
Paul Cercueildcab40c2014-03-11 10:59:14 +0100602 resp = exec_command(buf, pdata->fd);
603 if (resp < 0) {
Paul Cercueil05e26262014-05-09 11:32:43 +0200604 network_unlock(pdata);
Paul Cercueildcab40c2014-03-11 10:59:14 +0100605 return (int) resp;
606 } else if (resp == 0) {
607 *trigger = NULL;
Paul Cercueil05e26262014-05-09 11:32:43 +0200608 network_unlock(pdata);
Paul Cercueildcab40c2014-03-11 10:59:14 +0100609 return 0;
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200610 } else if ((unsigned long) resp > sizeof(buf)) {
Paul Cercueildcab40c2014-03-11 10:59:14 +0100611 ERROR("Value returned by server is too large\n");
Paul Cercueil05e26262014-05-09 11:32:43 +0200612 network_unlock(pdata);
Paul Cercueildcab40c2014-03-11 10:59:14 +0100613 return -EIO;
614 }
615
616 ret = read_all(buf, resp, pdata->fd);
Paul Cercueil05e26262014-05-09 11:32:43 +0200617 network_unlock(pdata);
Paul Cercueil1494b862014-05-05 12:49:07 +0200618
Paul Cercueildcab40c2014-03-11 10:59:14 +0100619 if (ret < 0) {
620 strerror_r(-ret, buf, sizeof(buf));
621 ERROR("Unable to read response to GETTRIG: %s\n", buf);
622 return ret;
623 }
624
Lars-Peter Clausenb5cdc102014-08-21 14:45:52 +0200625 if (buf[0] == '\0') {
626 *trigger = NULL;
627 return 0;
628 }
629
Paul Cercueildcab40c2014-03-11 10:59:14 +0100630 for (i = 0; i < dev->ctx->nb_devices; i++) {
631 struct iio_device *cur = dev->ctx->devices[i];
632 if (iio_device_is_trigger(cur) &&
633 !strncmp(cur->name, buf, resp)) {
634 *trigger = cur;
635 return 0;
636 }
637 }
638
639 return -ENXIO;
640}
641
642static int network_set_trigger(const struct iio_device *dev,
643 const struct iio_device *trigger)
644{
Paul Cercueil1494b862014-05-05 12:49:07 +0200645 int ret;
Paul Cercueildcab40c2014-03-11 10:59:14 +0100646 char buf[1024];
647 if (trigger)
648 snprintf(buf, sizeof(buf), "SETTRIG %s %s\r\n",
649 dev->id, trigger->id);
650 else
651 snprintf(buf, sizeof(buf), "SETTRIG %s\r\n", dev->id);
Paul Cercueil1494b862014-05-05 12:49:07 +0200652
Paul Cercueil05e26262014-05-09 11:32:43 +0200653 network_lock(dev->ctx->pdata);
Paul Cercueil1494b862014-05-05 12:49:07 +0200654 ret = (int) exec_command(buf, dev->ctx->pdata->fd);
Paul Cercueil05e26262014-05-09 11:32:43 +0200655 network_unlock(dev->ctx->pdata);
Paul Cercueil1494b862014-05-05 12:49:07 +0200656 return ret;
Paul Cercueildcab40c2014-03-11 10:59:14 +0100657}
658
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100659static void network_shutdown(struct iio_context *ctx)
660{
661 struct iio_context_pdata *pdata = ctx->pdata;
Paul Cercueil44ae11c2014-03-17 09:56:29 +0100662 unsigned int i;
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100663
Paul Cercueil05e26262014-05-09 11:32:43 +0200664 network_lock(pdata);
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100665 write_command("\r\nEXIT\r\n", pdata->fd);
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100666 close(pdata->fd);
Paul Cercueil05e26262014-05-09 11:32:43 +0200667 network_unlock(pdata);
Paul Cercueil1494b862014-05-05 12:49:07 +0200668
Paul Cercueil05e26262014-05-09 11:32:43 +0200669#if HAVE_PTHREAD
Paul Cercueil1494b862014-05-05 12:49:07 +0200670 /* XXX(pcercuei): is this safe? */
671 pthread_mutex_destroy(&pdata->lock);
Paul Cercueil05e26262014-05-09 11:32:43 +0200672#endif
Paul Cercueil2dd2c132015-02-24 10:41:01 +0100673 freeaddrinfo(pdata->addrinfo);
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100674 free(pdata);
Paul Cercueil44ae11c2014-03-17 09:56:29 +0100675
676 for (i = 0; i < ctx->nb_devices; i++) {
677 struct iio_device *dev = ctx->devices[i];
678 if (dev->pdata)
679 free(dev->pdata);
680 }
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100681}
682
Paul Cercueil6691a3f2014-05-02 12:32:01 +0200683static int network_get_version(const struct iio_context *ctx,
Paul Cercueil9de9e9d2014-05-20 13:18:19 +0200684 unsigned int *major, unsigned int *minor, char git_tag[8])
Paul Cercueil6691a3f2014-05-02 12:32:01 +0200685{
686 struct iio_context_pdata *pdata = ctx->pdata;
687 long maj, min;
688 int ret;
Paul Cercueil6691a3f2014-05-02 12:32:01 +0200689
Paul Cercueil05e26262014-05-09 11:32:43 +0200690 network_lock(pdata);
Paul Cercueil1494b862014-05-05 12:49:07 +0200691 ret = (int) write_command("VERSION\r\n", pdata->fd);
692 if (ret < 0)
693 goto err_unlock;
694
695 ret = read_integer(pdata->fd, &maj);
696 if (!ret)
697 ret = read_integer(pdata->fd, &min);
698 if (!ret) {
Paul Cercueil9de9e9d2014-05-20 13:18:19 +0200699 char tag[8];
700 tag[7] = '\0';
701
702 ret = read_all(tag, sizeof(tag) - 1, pdata->fd);
703 if (ret < 0)
704 goto err_unlock;
705
Paul Cercueild15d9952014-05-20 11:40:08 +0200706 if (major)
707 *major = (unsigned int) maj;
708 if (minor)
709 *minor = (unsigned int) min;
Paul Cercueil9de9e9d2014-05-20 13:18:19 +0200710 if (git_tag)
711 strncpy(git_tag, tag, 8);
Paul Cercueil1494b862014-05-05 12:49:07 +0200712 }
713
Paul Cercueil8e8f8992014-06-12 16:58:12 +0200714 ret = 0;
Paul Cercueil1494b862014-05-05 12:49:07 +0200715err_unlock:
Paul Cercueil05e26262014-05-09 11:32:43 +0200716 network_unlock(pdata);
Paul Cercueil1494b862014-05-05 12:49:07 +0200717 return ret;
Paul Cercueil6691a3f2014-05-02 12:32:01 +0200718}
719
Paul Cercueil8a266f12014-06-10 16:06:31 +0200720static unsigned int calculate_remote_timeout(unsigned int timeout)
721{
722 /* XXX(pcercuei): We currently hardcode timeout / 2 for the backend used
723 * by the remote. Is there something better to do here? */
724 return timeout / 2;
725}
726
Paul Cercueilda342e52015-01-20 17:03:41 +0100727#ifdef _WIN32
Paul Cercueilbca3dbc2014-06-11 12:00:21 +0200728static int set_socket_timeout(int fd, unsigned int timeout)
Paul Cercueil8a266f12014-06-10 16:06:31 +0200729{
Paul Cercueil8a266f12014-06-10 16:06:31 +0200730 if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO,
Paul Cercueil52aaf332015-01-28 15:17:28 +0100731 (const char *) &timeout, sizeof(timeout)) < 0 ||
Paul Cercueil8a266f12014-06-10 16:06:31 +0200732 setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO,
Paul Cercueil52aaf332015-01-28 15:17:28 +0100733 (const char *) &timeout, sizeof(timeout)) < 0)
Paul Cercueilbca3dbc2014-06-11 12:00:21 +0200734 return -errno;
735 else
736 return 0;
737}
Paul Cercueilda342e52015-01-20 17:03:41 +0100738#else
739static int set_socket_timeout(int fd, unsigned int timeout)
740{
741 struct timeval tv;
742
743 tv.tv_sec = timeout / 1000;
744 tv.tv_usec = (timeout % 1000) * 1000;
745 if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0 ||
746 setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO,
747 &tv, sizeof(tv)) < 0)
748 return -errno;
749 else
750 return 0;
751}
752#endif /* _WIN32 */
Paul Cercueilbca3dbc2014-06-11 12:00:21 +0200753
754static int set_remote_timeout(struct iio_context *ctx, unsigned int timeout)
755{
756 char buf[1024];
757 int ret;
758
759 snprintf(buf, sizeof(buf), "TIMEOUT %u\r\n", timeout);
760 network_lock(ctx->pdata);
761 ret = (int) exec_command(buf, ctx->pdata->fd);
762 network_unlock(ctx->pdata);
763 return ret;
764}
765
766static int network_set_timeout(struct iio_context *ctx, unsigned int timeout)
767{
768 int ret = set_socket_timeout(ctx->pdata->fd, timeout);
769 if (!ret) {
770 timeout = calculate_remote_timeout(timeout);
771 ret = set_remote_timeout(ctx, timeout);
772 }
773 if (ret < 0) {
774 char buf[1024];
775 strerror_r(-ret, buf, sizeof(buf));
Paul Cercueil8a266f12014-06-10 16:06:31 +0200776 WARNING("Unable to set R/W timeout: %s\n", buf);
777 } else {
Paul Cercueil8a266f12014-06-10 16:06:31 +0200778 ctx->rw_timeout_ms = timeout;
779 }
780 return ret;
781}
782
Paul Cercueil12d41832014-10-28 14:35:53 +0100783static struct iio_context * network_clone(const struct iio_context *ctx)
784{
Paul Cercueild3d56ee2015-01-08 16:36:31 +0100785 return iio_create_network_context(ctx->description);
Paul Cercueil12d41832014-10-28 14:35:53 +0100786}
787
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100788static struct iio_backend_ops network_ops = {
Paul Cercueil12d41832014-10-28 14:35:53 +0100789 .clone = network_clone,
Paul Cercueilba059762014-03-14 11:02:02 +0100790 .open = network_open,
791 .close = network_close,
Paul Cercueil9945bc82014-03-05 14:07:29 +0100792 .read = network_read,
Paul Cercueil2725f702014-05-02 11:02:16 +0200793 .write = network_write,
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100794 .read_device_attr = network_read_dev_attr,
795 .write_device_attr = network_write_dev_attr,
Paul Cercueil99cf3d42014-03-06 12:35:26 +0100796 .read_channel_attr = network_read_chn_attr,
Paul Cercueil07897d32014-03-06 12:46:08 +0100797 .write_channel_attr = network_write_chn_attr,
Paul Cercueildcab40c2014-03-11 10:59:14 +0100798 .get_trigger = network_get_trigger,
799 .set_trigger = network_set_trigger,
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100800 .shutdown = network_shutdown,
Paul Cercueil6691a3f2014-05-02 12:32:01 +0200801 .get_version = network_get_version,
Paul Cercueil8a266f12014-06-10 16:06:31 +0200802 .set_timeout = network_set_timeout,
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100803};
804
805static struct iio_context * get_context(int fd)
806{
807 struct iio_context *ctx;
Paul Cercueile60c3ed2014-03-04 11:23:56 +0100808 char *xml;
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100809 long xml_len = exec_command("PRINT\r\n", fd);
810 if (xml_len < 0)
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100811 return NULL;
Paul Cercueile60c3ed2014-03-04 11:23:56 +0100812
813 DEBUG("Server returned a XML string of length %li\n", xml_len);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100814 xml = malloc(xml_len);
815 if (!xml) {
816 ERROR("Unable to allocate data\n");
817 return NULL;
818 }
819
820 DEBUG("Reading XML string...\n");
821 read_all(xml, xml_len, fd);
822
823 DEBUG("Creating context from XML...\n");
824 ctx = iio_create_xml_context_mem(xml, xml_len);
Paul Cercueilc1ed8482014-06-11 16:29:43 +0200825
826 if (ctx)
827 ctx->xml = xml;
828 else
829 free(xml);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100830 return ctx;
831}
832
Paul Cercueil83628b32014-11-24 11:26:21 +0100833#ifndef _WIN32
Paul Cercueila7d445b2014-11-11 16:00:15 +0100834/* The purpose of this function is to provide a version of connect()
835 * that does not ignore timeouts... */
836static int do_connect(int fd, const struct sockaddr *addr,
837 socklen_t addrlen, struct timeval *timeout)
838{
839 int ret, flags, error;
840 socklen_t len;
841 fd_set set;
842
843 FD_ZERO(&set);
844 FD_SET(fd, &set);
845
846 ret = fcntl(fd, F_GETFL, 0);
847 if (ret < 0)
848 return -errno;
849
850 flags = ret;
851
852 ret = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
853 if (ret < 0)
854 return -errno;
855
856 ret = connect(fd, addr, addrlen);
857 if (ret < 0 && errno != EINPROGRESS) {
858 ret = -errno;
859 goto end;
860 }
861
862 ret = select(fd + 1, &set, &set, NULL, timeout);
863 if (ret < 0) {
864 ret = -errno;
865 goto end;
866 }
867 if (ret == 0) {
868 ret = -ETIMEDOUT;
869 goto end;
870 }
871
872 /* Verify that we don't have an error */
873 len = sizeof(error);
874 ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len);
875 if(ret < 0) {
876 ret = -errno;
877 goto end;
878 }
879 if (error) {
880 ret = -error;
881 goto end;
882 }
883
884end:
885 /* Restore blocking mode */
886 fcntl(fd, F_SETFL, flags);
887 return ret;
888}
Paul Cercueil83628b32014-11-24 11:26:21 +0100889#endif
Paul Cercueila7d445b2014-11-11 16:00:15 +0100890
Paul Cercueil63e52182014-12-11 12:52:48 +0100891struct iio_context * network_create_context(const char *host)
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100892{
Paul Cercueil2e38bbe2014-03-19 15:27:15 +0100893 struct addrinfo hints, *res;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100894 struct iio_context *ctx;
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100895 struct iio_context_pdata *pdata;
Paul Cercueila7d445b2014-11-11 16:00:15 +0100896 struct timeval timeout;
Paul Cercueil06c479d2015-01-08 16:14:57 +0100897 unsigned int i, len;
Paul Cercueil0b584e12015-01-28 11:47:03 +0100898 int fd, ret, yes = 1;
Paul Cercueil1fef1a52014-04-07 16:31:15 +0200899#ifdef _WIN32
900 WSADATA wsaData;
901
902 ret = WSAStartup(MAKEWORD(2, 0), &wsaData);
903 if (ret < 0) {
904 ERROR("WSAStartup failed with error %i\n", ret);
905 return NULL;
906 }
907#endif
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100908
Paul Cercueil2e38bbe2014-03-19 15:27:15 +0100909 memset(&hints, 0, sizeof(hints));
910 hints.ai_family = AF_UNSPEC;
911 hints.ai_socktype = SOCK_STREAM;
Paul Cercueilab114932014-05-19 13:03:17 +0200912
913#ifdef HAVE_AVAHI
914 if (!host) {
915 char addr_str[AVAHI_ADDRESS_STR_MAX];
916 char port_str[6];
917 AvahiAddress address;
Paul Cercueil0f729d32014-06-05 17:38:54 +0200918 uint16_t port = IIOD_PORT;
Paul Cercueilab114932014-05-19 13:03:17 +0200919
920 memset(&address, 0, sizeof(address));
921
922 ret = discover_host(&address, &port);
923 if (ret < 0) {
924 ERROR("Unable to find host: %s\n", strerror(-ret));
925 return NULL;
926 }
927
928 avahi_address_snprint(addr_str, sizeof(addr_str), &address);
929 snprintf(port_str, sizeof(port_str), "%hu", port);
930 ret = getaddrinfo(addr_str, port_str, &hints, &res);
931 } else
932#endif
933 {
934 ret = getaddrinfo(host, IIOD_PORT_STR, &hints, &res);
935 }
936
Paul Cercueil2e38bbe2014-03-19 15:27:15 +0100937 if (ret) {
Paul Cercueilab114932014-05-19 13:03:17 +0200938 ERROR("Unable to find host: %s\n", gai_strerror(ret));
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100939 return NULL;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100940 }
941
Paul Cercueil2e38bbe2014-03-19 15:27:15 +0100942 fd = socket(res->ai_family, res->ai_socktype, 0);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100943 if (fd < 0) {
944 ERROR("Unable to open socket\n");
Paul Cercueil2dd2c132015-02-24 10:41:01 +0100945 goto err_free_addrinfo;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100946 }
947
Paul Cercueila7d445b2014-11-11 16:00:15 +0100948 timeout.tv_sec = DEFAULT_TIMEOUT_MS / 1000;
949 timeout.tv_usec = (DEFAULT_TIMEOUT_MS % 1000) * 1000;
Paul Cercueil83628b32014-11-24 11:26:21 +0100950
951#ifndef _WIN32
952 ret = do_connect(fd, res->ai_addr, res->ai_addrlen, &timeout);
953#else
954 ret = connect(fd, res->ai_addr, res->ai_addrlen);
955#endif
956 if (ret < 0) {
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100957 ERROR("Unable to connect\n");
958 goto err_close_socket;
959 }
960
Paul Cercueilbca3dbc2014-06-11 12:00:21 +0200961 set_socket_timeout(fd, DEFAULT_TIMEOUT_MS);
Paul Cercueil52aaf332015-01-28 15:17:28 +0100962 setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
963 (const char *) &yes, sizeof(yes));
Paul Cercueilbca3dbc2014-06-11 12:00:21 +0200964
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100965 pdata = calloc(1, sizeof(*pdata));
966 if (!pdata) {
967 ERROR("Unable to allocate memory\n");
968 goto err_close_socket;
969 }
970
971 pdata->fd = fd;
Paul Cercueil2dd2c132015-02-24 10:41:01 +0100972 pdata->addrinfo = res;
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100973
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100974 DEBUG("Creating context...\n");
975 ctx = get_context(fd);
976 if (!ctx)
Paul Cercueild3d56ee2015-01-08 16:36:31 +0100977 goto err_free_pdata;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100978
Paul Cercueil2057fd32014-10-28 14:44:19 +0100979 /* Override the name and low-level functions of the XML context
980 * with those corresponding to the network context */
981 ctx->name = "network";
982 ctx->ops = &network_ops;
983 ctx->pdata = pdata;
984
Paul Cercueil06c479d2015-01-08 16:14:57 +0100985#ifdef HAVE_IPV6
Paul Cercueiled15e492015-01-12 15:52:28 +0100986 len = INET6_ADDRSTRLEN + IF_NAMESIZE + 2;
Paul Cercueil06c479d2015-01-08 16:14:57 +0100987#else
988 len = INET_ADDRSTRLEN + 1;
989#endif
990 ctx->description = malloc(len);
991 if (!ctx->description) {
992 ERROR("Unable to allocate memory\n");
993 goto err_network_shutdown;
994 }
995
996 ctx->description[0] = '\0';
997
998#ifdef HAVE_IPV6
999 if (res->ai_family == AF_INET6) {
1000 struct sockaddr_in6 *in = (struct sockaddr_in6 *) res->ai_addr;
Paul Cercueiled15e492015-01-12 15:52:28 +01001001 char *ptr;
Paul Cercueil06c479d2015-01-08 16:14:57 +01001002 inet_ntop(AF_INET6, &in->sin6_addr,
1003 ctx->description, INET6_ADDRSTRLEN);
Paul Cercueiled15e492015-01-12 15:52:28 +01001004
1005 ptr = if_indextoname(in->sin6_scope_id, ctx->description +
1006 strlen(ctx->description) + 1);
1007 if (!ptr) {
1008 ERROR("Unable to lookup interface of IPv6 address\n");
1009 goto err_network_shutdown;
1010 }
1011
1012 *(ptr - 1) = '%';
Paul Cercueil06c479d2015-01-08 16:14:57 +01001013 }
1014#endif
1015 if (res->ai_family == AF_INET) {
1016 struct sockaddr_in *in = (struct sockaddr_in *) res->ai_addr;
1017 inet_ntop(AF_INET, &in->sin_addr,
1018 ctx->description, INET_ADDRSTRLEN);
1019 }
1020
Paul Cercueil44ae11c2014-03-17 09:56:29 +01001021 for (i = 0; i < ctx->nb_devices; i++) {
1022 struct iio_device *dev = ctx->devices[i];
Paul Cercueilff778232014-03-24 14:23:08 +01001023 uint32_t *mask = NULL;
1024
1025 dev->words = (dev->nb_channels + 31) / 32;
1026 if (dev->words) {
1027 mask = calloc(dev->words, sizeof(*mask));
Paul Cercueil2057fd32014-10-28 14:44:19 +01001028 if (!mask) {
1029 ERROR("Unable to allocate memory\n");
Paul Cercueilff778232014-03-24 14:23:08 +01001030 goto err_network_shutdown;
Paul Cercueil2057fd32014-10-28 14:44:19 +01001031 }
Paul Cercueilff778232014-03-24 14:23:08 +01001032 }
1033
1034 dev->mask = mask;
Paul Cercueil44ae11c2014-03-17 09:56:29 +01001035 }
1036
Paul Cercueilc1ed8482014-06-11 16:29:43 +02001037 iio_context_init(ctx);
Paul Cercueil4c6729d2014-04-04 17:24:41 +02001038
Paul Cercueil05e26262014-05-09 11:32:43 +02001039#if HAVE_PTHREAD
Paul Cercueil1494b862014-05-05 12:49:07 +02001040 ret = pthread_mutex_init(&pdata->lock, NULL);
1041 if (ret < 0) {
1042 char buf[1024];
1043 strerror_r(-ret, buf, sizeof(buf));
1044 ERROR("Unable to initialize mutex: %s\n", buf);
1045 goto err_network_shutdown;
1046 }
Paul Cercueil05e26262014-05-09 11:32:43 +02001047#endif
Paul Cercueil1494b862014-05-05 12:49:07 +02001048
Paul Cercueilbca3dbc2014-06-11 12:00:21 +02001049 set_remote_timeout(ctx, calculate_remote_timeout(DEFAULT_TIMEOUT_MS));
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001050 return ctx;
1051
Paul Cercueil44ae11c2014-03-17 09:56:29 +01001052err_network_shutdown:
Paul Cercueil44ae11c2014-03-17 09:56:29 +01001053 iio_context_destroy(ctx);
Paul Cercueil2057fd32014-10-28 14:44:19 +01001054 return NULL;
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +01001055err_free_pdata:
1056 free(pdata);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001057err_close_socket:
1058 close(fd);
Paul Cercueil2dd2c132015-02-24 10:41:01 +01001059err_free_addrinfo:
1060 freeaddrinfo(res);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +01001061 return NULL;
1062}