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