1 /*
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
19 #include "../debug.h"
20 #include "../iio.h"
21 #include "../iio-config.h"
22 #include "ops.h"
23 #include "thread-pool.h"
24
25 #include <arpa/inet.h>
26 #include <errno.h>
27 #include <fcntl.h>
28 #include <getopt.h>
29 #include <netinet/in.h>
30 #include <netinet/tcp.h>
31 #include <poll.h>
32 #include <pthread.h>
33 #include <signal.h>
34 #include <stdbool.h>
35 #include <string.h>
36 #include <sys/eventfd.h>
37 #include <sys/types.h>
38 #include <sys/socket.h>
39 #include <unistd.h>
40
41 #ifdef HAVE_AVAHI
42 #include <avahi-common/thread-watch.h>
43 #include <avahi-common/error.h>
44 #include <avahi-common/alternative.h>
45 #include <avahi-common/malloc.h>
46 #include <avahi-client/client.h>
47 #include <avahi-client/publish.h>
48 #include <avahi-common/domain.h>
49 #endif
50
51 #define MY_NAME "iiod"
52
53 #define IIOD_PORT 30431
54
55 struct client_data {
56 int fd;
57 bool debug;
58 struct iio_context *ctx;
59 };
60
61 bool server_demux;
62
63 struct thread_pool *main_thread_pool;
64
65
66 static struct sockaddr_in sockaddr = {
67 .sin_family = AF_INET,
68 #if __BYTE_ORDER == __LITTLE_ENDIAN
69 .sin_addr.s_addr = __bswap_constant_32(INADDR_ANY),
70 .sin_port = __bswap_constant_16(IIOD_PORT),
71 #else
72 .sin_addr.s_addr = INADDR_ANY,
73 .sin_port = IIOD_PORT,
74 #endif
75 };
76
77 #ifdef HAVE_IPV6
78 static struct sockaddr_in6 sockaddr6 = {
79 .sin6_family = AF_INET6,
80 .sin6_addr = IN6ADDR_ANY_INIT,
81 #if __BYTE_ORDER == __LITTLE_ENDIAN
82 .sin6_port = __bswap_constant_16(IIOD_PORT),
83 #else
84 .sin6_port = IIOD_PORT,
85 #endif
86 };
87 #endif /* HAVE_IPV6 */
88
89 static const struct option options[] = {
90 {"help", no_argument, 0, 'h'},
91 {"version", no_argument, 0, 'V'},
92 {"debug", no_argument, 0, 'd'},
93 {"demux", no_argument, 0, 'D'},
94 {"interactive", no_argument, 0, 'i'},
95 {"aio", no_argument, 0, 'a'},
96 {"ffs", required_argument, 0, 'F'},
97 {"nb-pipes", required_argument, 0, 'n'},
98 {0, 0, 0, 0},
99 };
100
101 static const char *options_descriptions[] = {
102 "Show this help and quit.",
103 "Display the version of this program.",
104 "Use alternative (incompatible) debug interface.",
105 "Demux channels directly on the server.",
106 "Run " MY_NAME " in the controlling terminal.",
107 "Use asynchronous I/O.",
108 "Use the given FunctionFS mountpoint to serve over USB",
109 "Specify the number of USB pipes (ep couples) to use",
110 };
111
112 #ifdef HAVE_AVAHI
113
114 /***
115 * Parts of the avahi code are borrowed from the client-publish-service.c
116 * https://www.avahi.org/doxygen/html/client-publish-service_8c-example.html
117 * which is an example in the avahi library. Copyright Lennart Poettering
118 * released under the LGPL 2.1 or (at your option) any later version.
119 */
120
121 /* Global Data */
122
123 static struct avahi_data {
124 AvahiThreadedPoll *poll;
125 AvahiClient *client;
126 AvahiEntryGroup *group;
127 char * name;
128 } avahi;
129
130 static void create_services(AvahiClient *c);
131 static AvahiClient * client_new(void);
132
client_free()133 static void client_free()
134 {
135 /* This also frees the entry group, if any. */
136 if (avahi.client) {
137 avahi_client_free(avahi.client);
138 avahi.client = NULL;
139 avahi.group = NULL;
140 }
141 }
142
shutdown_avahi()143 static void shutdown_avahi()
144 {
145 /* Stop the avahi client, if it's running. */
146 if (avahi.poll)
147 avahi_threaded_poll_stop(avahi.poll);
148
149 /* Clean up the avahi objects. The order is significant. */
150 client_free();
151 if (avahi.poll) {
152 avahi_threaded_poll_free(avahi.poll);
153 avahi.poll = NULL;
154 }
155 if (avahi.name) {
156 IIO_INFO("Avahi: Removing service '%s'\n", avahi.name);
157 avahi_free(avahi.name);
158 avahi.name = NULL;
159 }
160 }
161
__avahi_group_cb(AvahiEntryGroup * group,AvahiEntryGroupState state,void * d)162 static void __avahi_group_cb(AvahiEntryGroup *group,
163 AvahiEntryGroupState state, void *d)
164 {
165 /* Called whenever the entry group state changes */
166 if (!group) {
167 IIO_ERROR("__avahi_group_cb with no valid group\n");
168 return;
169 }
170
171 avahi.group = group;
172
173 switch (state) {
174 case AVAHI_ENTRY_GROUP_ESTABLISHED :
175 IIO_INFO("Avahi: Service '%s' successfully established.\n",
176 avahi.name);
177 break;
178 case AVAHI_ENTRY_GROUP_COLLISION : {
179 char *n;
180 /* A service name collision, pick a new name */
181 n = avahi_alternative_service_name(avahi.name);
182 avahi_free(avahi.name);
183 avahi.name = n;
184 IIO_INFO("Avahi: Group Service name collision, renaming service to '%s'\n",
185 avahi.name);
186 create_services(avahi_entry_group_get_client(group));
187 break;
188 }
189 case AVAHI_ENTRY_GROUP_FAILURE :
190 IIO_ERROR("Entry group failure: %s\n",
191 avahi_strerror(avahi_client_errno(
192 avahi_entry_group_get_client(group))));
193 break;
194 case AVAHI_ENTRY_GROUP_UNCOMMITED:
195 /* This is normal,
196 * since we commit things in the create_services()
197 */
198 IIO_DEBUG("Avahi: Group uncommitted\n");
199 break;
200 case AVAHI_ENTRY_GROUP_REGISTERING:
201 IIO_DEBUG("Avahi: Group registering\n");
202 break;
203 }
204 }
205
__avahi_client_cb(AvahiClient * client,AvahiClientState state,void * d)206 static void __avahi_client_cb(AvahiClient *client,
207 AvahiClientState state, void *d)
208 {
209 if (!client) {
210 IIO_ERROR("__avahi_client_cb with no valid client\n");
211 return;
212 }
213
214 switch (state) {
215 case AVAHI_CLIENT_S_RUNNING:
216 /* Same as AVAHI_SERVER_RUNNING */
217 IIO_DEBUG("Avahi: create services\n");
218 /* The server has startup successfully, so create our services */
219 create_services(client);
220 break;
221 case AVAHI_CLIENT_FAILURE:
222 if (avahi_client_errno(client) != AVAHI_ERR_DISCONNECTED) {
223 IIO_ERROR("Avahi: Client failure: %s\n",
224 avahi_strerror(avahi_client_errno(client)));
225 break;
226 }
227 IIO_INFO("Avahi: server disconnected\n");
228 avahi_client_free(client);
229 avahi.group = NULL;
230 avahi.client = client_new();
231 break;
232 case AVAHI_CLIENT_S_COLLISION:
233 /* Same as AVAHI_SERVER_COLLISION */
234 /* When the server is back in AVAHI_SERVER_RUNNING state
235 * we will register them again with the new host name. */
236 IIO_DEBUG("Avahi: Client collision\n");
237 /* Let's drop our registered services.*/
238 if (avahi.group)
239 avahi_entry_group_reset(avahi.group);
240 break;
241 case AVAHI_CLIENT_S_REGISTERING:
242 /* Same as AVAHI_SERVER_REGISTERING */
243 IIO_DEBUG("Avahi: Client group reset\n");
244 if (avahi.group)
245 avahi_entry_group_reset(avahi.group);
246 break;
247 case AVAHI_CLIENT_CONNECTING:
248 IIO_DEBUG("Avahi: Client Connecting\n");
249 break;
250 }
251
252 /* NOTE: group is freed by avahi_client_free */
253 }
254
client_new(void)255 static AvahiClient * client_new(void)
256 {
257 int ret;
258 AvahiClient * client;
259
260 client = avahi_client_new(avahi_threaded_poll_get(avahi.poll),
261 AVAHI_CLIENT_NO_FAIL, __avahi_client_cb, NULL, &ret);
262
263 /* No Daemon is handled by the avahi_start thread */
264 if (!client && ret != AVAHI_ERR_NO_DAEMON) {
265 IIO_ERROR("Avahi: failure creating client: %s (%d)\n",
266 avahi_strerror(ret), ret);
267 }
268
269 return client;
270 }
271
272
create_services(AvahiClient * c)273 static void create_services(AvahiClient *c)
274 {
275 int ret;
276
277 if (!c) {
278 IIO_ERROR("create_services called with no valid client\n");
279 goto fail;
280 }
281
282 if (!avahi.group) {
283 avahi.group = avahi_entry_group_new(c, __avahi_group_cb, NULL);
284 if (!avahi.group) {
285 IIO_ERROR("avahi_entry_group_new() failed: %s\n",
286 avahi_strerror(avahi_client_errno(c)));
287 goto fail;
288 }
289 }
290
291 if (!avahi_entry_group_is_empty(avahi.group)) {
292 IIO_DEBUG("Avahi group not empty\n");
293 return;
294 }
295
296 ret = avahi_entry_group_add_service(avahi.group,
297 AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
298 0, avahi.name, "_iio._tcp", NULL, NULL, IIOD_PORT, NULL);
299 if (ret < 0) {
300 if (ret == AVAHI_ERR_COLLISION) {
301 char *n;
302 n = avahi_alternative_service_name(avahi.name);
303 avahi_free(avahi.name);
304 avahi.name = n;
305 IIO_DEBUG("Service name collision, renaming service to '%s'\n",
306 avahi.name);
307 avahi_entry_group_reset(avahi.group);
308 create_services(c);
309 return;
310 }
311 IIO_ERROR("Failed to add _iio._tcp service: %s\n", avahi_strerror(ret));
312 goto fail;
313 }
314
315 ret = avahi_entry_group_commit(avahi.group);
316 if (ret < 0) {
317 IIO_ERROR("Failed to commit entry group: %s\n", avahi_strerror(ret));
318 goto fail;
319 }
320
321 IIO_INFO("Avahi: Registered '%s' to ZeroConf server %s\n",
322 avahi.name, avahi_client_get_version_string(c));
323
324 return;
325
326 fail:
327 avahi_entry_group_reset(avahi.group);
328 }
329
330 #define IIOD_ON "iiod on "
331
start_avahi_thd(struct thread_pool * pool,void * d)332 static void start_avahi_thd(struct thread_pool *pool, void *d)
333 {
334
335 struct pollfd pfd[2];
336 int ret = ENOMEM;
337 char label[AVAHI_LABEL_MAX];
338 char host[AVAHI_LABEL_MAX - sizeof(IIOD_ON)];
339 struct timespec ts;
340 ts.tv_nsec = 0;
341 ts.tv_sec = 1;
342
343 pfd[1].fd = thread_pool_get_poll_fd(main_thread_pool);
344 pfd[1].events = POLLIN;
345 pfd[1].revents = 0;
346
347 while(true) {
348 if (pfd[1].revents & POLLIN) /* STOP event */
349 break;
350
351 ret = gethostname(host, sizeof(host));
352 IIO_ERROR("host %s\n", host);
353 if (ret || !strncmp(host, "none", sizeof("none") - 1))
354 goto again;
355
356 iio_snprintf(label, sizeof(label), "%s%s", IIOD_ON, host);
357
358 if (!avahi.name)
359 avahi.name = avahi_strdup(label);
360 if (!avahi.name)
361 break;
362
363 if (!avahi.poll)
364 avahi.poll = avahi_threaded_poll_new();
365 if (!avahi.poll) {
366 goto again;
367 }
368
369 if (!avahi.client)
370 avahi.client = client_new();
371 if (avahi.client)
372 break;
373 again:
374 IIO_INFO("Avahi didn't start, try again later\n");
375 nanosleep(&ts, NULL);
376 ts.tv_sec++;
377 /* If it hasn't started in 10 times over 60 seconds,
378 * it is not going to, so stop
379 */
380 if (ts.tv_sec >= 11)
381 break;
382 }
383
384 if (avahi.client && avahi.poll) {
385 avahi_threaded_poll_start(avahi.poll);
386 IIO_INFO("Avahi: Started.\n");
387 } else {
388 shutdown_avahi();
389 IIO_INFO("Avahi: Failed to start.\n");
390 }
391 }
392
start_avahi(void)393 static void start_avahi(void)
394 {
395 int ret;
396 char err_str[1024];
397
398 IIO_INFO("Attempting to start Avahi\n");
399
400 avahi.poll = NULL;
401 avahi.client = NULL;
402 avahi.group = NULL;
403 avahi.name = NULL;
404
405 /* In case dbus, or avahi deamon are not started, we create a thread
406 * that tries a few times to attach, if it can't within the first
407 * minute, it gives up.
408 */
409 ret = thread_pool_add_thread(main_thread_pool, start_avahi_thd, NULL, "avahi_thd");
410 if (ret) {
411 iio_strerror(ret, err_str, sizeof(err_str));
412 IIO_ERROR("Failed to create new Avahi thread: %s\n",
413 err_str);
414 }
415 }
stop_avahi(void)416 static void stop_avahi(void)
417 {
418 shutdown_avahi();
419 IIO_INFO("Avahi: Stopped\n");
420 }
421 #endif /* HAVE_AVAHI */
422
423
usage(void)424 static void usage(void)
425 {
426 unsigned int i;
427
428 printf("Usage:\n\t" MY_NAME " [OPTIONS ...]\n\nOptions:\n");
429 for (i = 0; options[i].name; i++)
430 printf("\t-%c, --%s\n\t\t\t%s\n",
431 options[i].val, options[i].name,
432 options_descriptions[i]);
433 }
434
client_thd(struct thread_pool * pool,void * d)435 static void client_thd(struct thread_pool *pool, void *d)
436 {
437 struct client_data *cdata = d;
438
439 interpreter(cdata->ctx, cdata->fd, cdata->fd, cdata->debug,
440 true, false, pool);
441
442 IIO_INFO("Client exited\n");
443 close(cdata->fd);
444 free(cdata);
445 }
446
set_handler(int signal,void (* handler)(int))447 static void set_handler(int signal, void (*handler)(int))
448 {
449 struct sigaction sig;
450 sigaction(signal, NULL, &sig);
451 sig.sa_handler = handler;
452 sigaction(signal, &sig, NULL);
453 }
454
sig_handler(int sig)455 static void sig_handler(int sig)
456 {
457 thread_pool_stop(main_thread_pool);
458 }
459
main_interactive(struct iio_context * ctx,bool verbose,bool use_aio)460 static int main_interactive(struct iio_context *ctx, bool verbose, bool use_aio)
461 {
462 int flags;
463
464 if (!use_aio) {
465 flags = fcntl(STDIN_FILENO, F_GETFL);
466 if (flags >= 0)
467 flags = fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK);
468 if (flags < 0) {
469 char err_str[1024];
470 iio_strerror(errno, err_str, sizeof(err_str));
471 IIO_ERROR("Could not get/set O_NONBLOCK on STDIN_FILENO"
472 " %s (%d)\n", err_str, -errno);
473 }
474
475 flags = fcntl(STDOUT_FILENO, F_GETFL);
476 if (flags >= 0)
477 flags = fcntl(STDOUT_FILENO, F_SETFL, flags | O_NONBLOCK);
478 if (flags < 0) {
479 char err_str[1024];
480 iio_strerror(errno, err_str, sizeof(err_str));
481 IIO_ERROR("Could not get/set O_NONBLOCK on STDOUT_FILENO"
482 " %s (%d)\n", err_str, -errno);
483 }
484 }
485
486 interpreter(ctx, STDIN_FILENO, STDOUT_FILENO, verbose,
487 false, use_aio, main_thread_pool);
488 return EXIT_SUCCESS;
489 }
490
main_server(struct iio_context * ctx,bool debug)491 static int main_server(struct iio_context *ctx, bool debug)
492 {
493 int ret, fd = -1, yes = 1,
494 keepalive_time = 10,
495 keepalive_intvl = 10,
496 keepalive_probes = 6;
497 struct pollfd pfd[2];
498 char err_str[1024];
499 bool ipv6;
500
501 IIO_INFO("Starting IIO Daemon version %u.%u.%s\n",
502 LIBIIO_VERSION_MAJOR, LIBIIO_VERSION_MINOR,
503 LIBIIO_VERSION_GIT);
504
505 #ifdef HAVE_IPV6
506 fd = socket(AF_INET6, SOCK_STREAM | SOCK_NONBLOCK, 0);
507 #endif
508 ipv6 = (fd >= 0);
509 if (!ipv6)
510 fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
511 if (fd < 0) {
512 iio_strerror(errno, err_str, sizeof(err_str));
513 IIO_ERROR("Unable to create socket: %s\n", err_str);
514 return EXIT_FAILURE;
515 }
516
517 ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
518 if (ret < 0) {
519 iio_strerror(errno, err_str, sizeof(err_str));
520 IIO_WARNING("setsockopt SO_REUSEADDR : %s (%d)", err_str, -errno);
521 }
522
523 #ifdef HAVE_IPV6
524 if (ipv6)
525 ret = bind(fd, (struct sockaddr *) &sockaddr6,
526 sizeof(sockaddr6));
527 #endif
528 if (!ipv6)
529 ret = bind(fd, (struct sockaddr *) &sockaddr, sizeof(sockaddr));
530 if (ret < 0) {
531 iio_strerror(errno, err_str, sizeof(err_str));
532 IIO_ERROR("Bind failed: %s\n", err_str);
533 goto err_close_socket;
534 }
535
536 if (ipv6)
537 IIO_INFO("IPv6 support enabled\n");
538
539 if (listen(fd, 16) < 0) {
540 iio_strerror(errno, err_str, sizeof(err_str));
541 IIO_ERROR("Unable to mark as passive socket: %s\n", err_str);
542 goto err_close_socket;
543 }
544
545 #ifdef HAVE_AVAHI
546 start_avahi();
547 #endif
548
549 pfd[0].fd = fd;
550 pfd[0].events = POLLIN;
551 pfd[0].revents = 0;
552 pfd[1].fd = thread_pool_get_poll_fd(main_thread_pool);
553 pfd[1].events = POLLIN;
554 pfd[1].revents = 0;
555
556 while (true) {
557 struct client_data *cdata;
558 struct sockaddr_in caddr;
559 socklen_t addr_len = sizeof(caddr);
560 int new;
561
562 poll_nointr(pfd, 2);
563
564 if (pfd[1].revents & POLLIN) /* STOP event */
565 break;
566
567 new = accept4(fd, (struct sockaddr *) &caddr, &addr_len,
568 SOCK_NONBLOCK);
569 if (new == -1) {
570 if (errno == EAGAIN || errno == EINTR)
571 continue;
572 iio_strerror(errno, err_str, sizeof(err_str));
573 IIO_ERROR("Failed to create connection socket: %s\n",
574 err_str);
575 continue;
576 }
577
578 cdata = malloc(sizeof(*cdata));
579 if (!cdata) {
580 IIO_WARNING("Unable to allocate memory for client\n");
581 close(new);
582 continue;
583 }
584
585 /* Configure the socket to send keep-alive packets every 10s,
586 * and disconnect the client if no reply was received for one
587 * minute. */
588 ret = setsockopt(new, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(yes));
589 if (ret < 0) {
590 iio_strerror(errno, err_str, sizeof(err_str));
591 IIO_WARNING("setsockopt SO_KEEPALIVE : %s (%d)", err_str, -errno);
592 }
593 ret = setsockopt(new, IPPROTO_TCP, TCP_KEEPCNT, &keepalive_probes,
594 sizeof(keepalive_probes));
595 if (ret < 0) {
596 iio_strerror(errno, err_str, sizeof(err_str));
597 IIO_WARNING("setsockopt TCP_KEEPCNT : %s (%d)", err_str, -errno);
598 }
599 ret = setsockopt(new, IPPROTO_TCP, TCP_KEEPIDLE, &keepalive_time,
600 sizeof(keepalive_time));
601 if (ret < 0) {
602 iio_strerror(errno, err_str, sizeof(err_str));
603 IIO_WARNING("setsockopt TCP_KEEPIDLE : %s (%d)", err_str, -errno);
604 }
605 ret = setsockopt(new, IPPROTO_TCP, TCP_KEEPINTVL, &keepalive_intvl,
606 sizeof(keepalive_intvl));
607 if (ret < 0) {
608 iio_strerror(errno, err_str, sizeof(err_str));
609 IIO_WARNING("setsockopt TCP_KEEPINTVL : %s (%d)", err_str, -errno);
610 }
611 ret = setsockopt(new, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes));
612 if (ret < 0) {
613 iio_strerror(errno, err_str, sizeof(err_str));
614 IIO_WARNING("setsockopt TCP_NODELAY : %s (%d)", err_str, -errno);
615 }
616
617 cdata->fd = new;
618 cdata->ctx = ctx;
619 cdata->debug = debug;
620
621 IIO_INFO("New client connected from %s\n",
622 inet_ntoa(caddr.sin_addr));
623
624 ret = thread_pool_add_thread(main_thread_pool, client_thd, cdata, "net_client_thd");
625 if (ret) {
626 iio_strerror(ret, err_str, sizeof(err_str));
627 IIO_ERROR("Failed to create new client thread: %s\n",
628 err_str);
629 close(new);
630 free(cdata);
631 }
632 }
633
634 IIO_DEBUG("Cleaning up\n");
635 #ifdef HAVE_AVAHI
636 stop_avahi();
637 #endif
638 close(fd);
639 return EXIT_SUCCESS;
640
641 err_close_socket:
642 close(fd);
643 return EXIT_FAILURE;
644 }
645
main(int argc,char ** argv)646 int main(int argc, char **argv)
647 {
648 bool debug = false, interactive = false, use_aio = false;
649 #ifdef WITH_IIOD_USBD
650 long nb_pipes = 3;
651 char *end;
652 #endif
653 struct iio_context *ctx;
654 int c, option_index = 0;
655 char *ffs_mountpoint = NULL;
656 char err_str[1024];
657 int ret;
658
659 while ((c = getopt_long(argc, argv, "+hVdDiaF:n:",
660 options, &option_index)) != -1) {
661 switch (c) {
662 case 'd':
663 debug = true;
664 break;
665 case 'D':
666 server_demux = true;
667 break;
668 case 'i':
669 interactive = true;
670 break;
671 case 'a':
672 #ifdef WITH_AIO
673 use_aio = true;
674 break;
675 #else
676 IIO_ERROR("IIOD was not compiled with AIO support.\n");
677 return EXIT_FAILURE;
678 #endif
679 case 'F':
680 #ifdef WITH_IIOD_USBD
681 ffs_mountpoint = optarg;
682 break;
683 #else
684 IIO_ERROR("IIOD was not compiled with USB support.\n");
685 return EXIT_FAILURE;
686 #endif
687 case 'n':
688 #ifdef WITH_IIOD_USBD
689 errno = 0;
690 nb_pipes = strtol(optarg, &end, 10);
691 if (optarg == end || nb_pipes < 1 || errno == ERANGE) {
692 IIO_ERROR("--nb-pipes: Invalid parameter\n");
693 return EXIT_FAILURE;
694 }
695 break;
696 #else
697 IIO_ERROR("IIOD was not compiled with USB support.\n");
698 return EXIT_FAILURE;
699 #endif
700 case 'h':
701 usage();
702 return EXIT_SUCCESS;
703 case 'V':
704 printf("%u.%u\n", LIBIIO_VERSION_MAJOR,
705 LIBIIO_VERSION_MINOR);
706 return EXIT_SUCCESS;
707 case '?':
708 return EXIT_FAILURE;
709 }
710 }
711
712 ctx = iio_create_local_context();
713 if (!ctx) {
714 iio_strerror(errno, err_str, sizeof(err_str));
715 IIO_ERROR("Unable to create local context: %s\n", err_str);
716 return EXIT_FAILURE;
717 }
718
719 main_thread_pool = thread_pool_new();
720 if (!main_thread_pool) {
721 iio_strerror(errno, err_str, sizeof(err_str));
722 IIO_ERROR("Unable to create thread pool: %s\n", err_str);
723 ret = EXIT_FAILURE;
724 goto out_destroy_context;
725 }
726
727 set_handler(SIGHUP, sig_handler);
728 set_handler(SIGPIPE, sig_handler);
729 set_handler(SIGINT, sig_handler);
730 set_handler(SIGTERM, sig_handler);
731
732 if (ffs_mountpoint) {
733 #ifdef WITH_IIOD_USBD
734 /* We pass use_aio == true directly, this is ensured to be true
735 * by the CMake script. */
736 ret = start_usb_daemon(ctx, ffs_mountpoint,
737 debug, true, (unsigned int) nb_pipes,
738 main_thread_pool);
739 if (ret) {
740 iio_strerror(-ret, err_str, sizeof(err_str));
741 IIO_ERROR("Unable to start USB daemon: %s\n", err_str);
742 ret = EXIT_FAILURE;
743 goto out_destroy_thread_pool;
744 }
745 #endif
746 }
747
748 if (interactive)
749 ret = main_interactive(ctx, debug, use_aio);
750 else
751 ret = main_server(ctx, debug);
752
753 /*
754 * In case we got here through an error in the main thread make sure all
755 * the worker threads are signaled to shutdown.
756 */
757
758 #ifdef WITH_IIOD_USBD
759 out_destroy_thread_pool:
760 #endif
761 thread_pool_stop_and_wait(main_thread_pool);
762 thread_pool_destroy(main_thread_pool);
763
764 out_destroy_context:
765 iio_context_destroy(ctx);
766
767 return ret;
768 }
769