• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/simple-watch.h>
43 #include <avahi-client/client.h>
44 #include <avahi-client/publish.h>
45 #endif
46 
47 #define MY_NAME "iiod"
48 
49 #define IIOD_PORT 30431
50 
51 struct client_data {
52 	int fd;
53 	bool debug;
54 	struct iio_context *ctx;
55 };
56 
57 bool server_demux;
58 
59 struct thread_pool *main_thread_pool;
60 
61 
62 static struct sockaddr_in sockaddr = {
63 	.sin_family = AF_INET,
64 #if __BYTE_ORDER == __LITTLE_ENDIAN
65 	.sin_addr.s_addr = __bswap_constant_32(INADDR_ANY),
66 	.sin_port = __bswap_constant_16(IIOD_PORT),
67 #else
68 	.sin_addr.s_addr = INADDR_ANY,
69 	.sin_port = IIOD_PORT,
70 #endif
71 };
72 
73 #ifdef HAVE_IPV6
74 static struct sockaddr_in6 sockaddr6 = {
75 	.sin6_family = AF_INET6,
76 	.sin6_addr = IN6ADDR_ANY_INIT,
77 #if __BYTE_ORDER == __LITTLE_ENDIAN
78 	.sin6_port = __bswap_constant_16(IIOD_PORT),
79 #else
80 	.sin6_port = IIOD_PORT,
81 #endif
82 };
83 #endif /* HAVE_IPV6 */
84 
85 static const struct option options[] = {
86 	  {"help", no_argument, 0, 'h'},
87 	  {"version", no_argument, 0, 'V'},
88 	  {"debug", no_argument, 0, 'd'},
89 	  {"demux", no_argument, 0, 'D'},
90 	  {"interactive", no_argument, 0, 'i'},
91 	  {"aio", no_argument, 0, 'a'},
92 	  {"ffs", required_argument, 0, 'F'},
93 	  {"nb-pipes", required_argument, 0, 'n'},
94 	  {0, 0, 0, 0},
95 };
96 
97 static const char *options_descriptions[] = {
98 	"Show this help and quit.",
99 	"Display the version of this program.",
100 	"Use alternative (incompatible) debug interface.",
101 	"Demux channels directly on the server.",
102 	"Run " MY_NAME " in the controlling terminal.",
103 	"Use asynchronous I/O.",
104 	"Use the given FunctionFS mountpoint to serve over USB",
105 	"Specify the number of USB pipes (ep couples) to use",
106 };
107 
108 #ifdef HAVE_AVAHI
109 static AvahiSimplePoll *avahi_poll;
110 static AvahiClient *avahi_client;
111 
__avahi_group_cb(AvahiEntryGroup * group,AvahiEntryGroupState state,void * d)112 static void __avahi_group_cb(AvahiEntryGroup *group,
113 		AvahiEntryGroupState state, void *d)
114 {
115 }
116 
__avahi_client_cb(AvahiClient * client,AvahiClientState state,void * d)117 static void __avahi_client_cb(AvahiClient *client,
118 		AvahiClientState state, void *d)
119 {
120 	AvahiEntryGroup *group;
121 
122 	if (state != AVAHI_CLIENT_S_RUNNING)
123 		return;
124 
125 	group = avahi_entry_group_new(client, __avahi_group_cb, NULL);
126 
127 	if (group && !avahi_entry_group_add_service(group,
128 			AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
129 			0, "iio", "_iio._tcp", NULL, NULL, IIOD_PORT, NULL)) {
130 		avahi_entry_group_commit(group);
131 		INFO("Registered to ZeroConf server %s\n",
132 				avahi_client_get_version_string(client));
133 	}
134 
135 	/* NOTE: group is freed by avahi_client_free */
136 }
137 
start_avahi(void)138 static int start_avahi(void)
139 {
140 	int ret = ENOMEM;
141 
142 	avahi_poll = avahi_simple_poll_new();
143 	if (!avahi_poll)
144 		return -ENOMEM;
145 
146 	avahi_client = avahi_client_new(avahi_simple_poll_get(avahi_poll),
147 			0, __avahi_client_cb, NULL, &ret);
148 	if (!avahi_client) {
149 		avahi_simple_poll_free(avahi_poll);
150 		return -ret;
151 	}
152 
153 	return 0;
154 }
155 
stop_avahi(void)156 static void stop_avahi(void)
157 {
158 	avahi_client_free(avahi_client);
159 	avahi_simple_poll_free(avahi_poll);
160 }
161 #endif /* HAVE_AVAHI */
162 
163 
usage(void)164 static void usage(void)
165 {
166 	unsigned int i;
167 
168 	printf("Usage:\n\t" MY_NAME " [OPTIONS ...]\n\nOptions:\n");
169 	for (i = 0; options[i].name; i++)
170 		printf("\t-%c, --%s\n\t\t\t%s\n",
171 					options[i].val, options[i].name,
172 					options_descriptions[i]);
173 }
174 
client_thd(struct thread_pool * pool,void * d)175 static void client_thd(struct thread_pool *pool, void *d)
176 {
177 	struct client_data *cdata = d;
178 
179 	interpreter(cdata->ctx, cdata->fd, cdata->fd, cdata->debug,
180 			true, false, pool);
181 
182 	INFO("Client exited\n");
183 	close(cdata->fd);
184 	free(cdata);
185 }
186 
set_handler(int signal,void (* handler)(int))187 static void set_handler(int signal, void (*handler)(int))
188 {
189 	struct sigaction sig;
190 	sigaction(signal, NULL, &sig);
191 	sig.sa_handler = handler;
192 	sigaction(signal, &sig, NULL);
193 }
194 
sig_handler(int sig)195 static void sig_handler(int sig)
196 {
197 	thread_pool_stop(main_thread_pool);
198 }
199 
main_interactive(struct iio_context * ctx,bool verbose,bool use_aio)200 static int main_interactive(struct iio_context *ctx, bool verbose, bool use_aio)
201 {
202 	int flags;
203 
204 	if (!use_aio) {
205 		flags = fcntl(STDIN_FILENO, F_GETFL);
206 		fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK);
207 		flags = fcntl(STDOUT_FILENO, F_GETFL);
208 		fcntl(STDOUT_FILENO, F_SETFL, flags | O_NONBLOCK);
209 	}
210 
211 	interpreter(ctx, STDIN_FILENO, STDOUT_FILENO, verbose,
212 			false, use_aio, main_thread_pool);
213 	return EXIT_SUCCESS;
214 }
215 
main_server(struct iio_context * ctx,bool debug)216 static int main_server(struct iio_context *ctx, bool debug)
217 {
218 	int ret, fd = -1, yes = 1,
219 	    keepalive_time = 10,
220 	    keepalive_intvl = 10,
221 	    keepalive_probes = 6;
222 	struct pollfd pfd[2];
223 	char err_str[1024];
224 	bool ipv6;
225 #ifdef HAVE_AVAHI
226 	bool avahi_started;
227 #endif
228 
229 	INFO("Starting IIO Daemon version %u.%u\n",
230 			LIBIIO_VERSION_MAJOR, LIBIIO_VERSION_MINOR);
231 
232 #ifdef HAVE_IPV6
233 	fd = socket(AF_INET6, SOCK_STREAM | SOCK_NONBLOCK, 0);
234 #endif
235 	ipv6 = (fd >= 0);
236 	if (!ipv6)
237 		fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
238 	if (fd < 0) {
239 		iio_strerror(errno, err_str, sizeof(err_str));
240 		ERROR("Unable to create socket: %s\n", err_str);
241 		return EXIT_FAILURE;
242 	}
243 
244 	setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
245 
246 #ifdef HAVE_IPV6
247 	if (ipv6)
248 		ret = bind(fd, (struct sockaddr *) &sockaddr6,
249 				sizeof(sockaddr6));
250 #endif
251 	if (!ipv6)
252 		ret = bind(fd, (struct sockaddr *) &sockaddr, sizeof(sockaddr));
253 	if (ret < 0) {
254 		iio_strerror(errno, err_str, sizeof(err_str));
255 		ERROR("Bind failed: %s\n", err_str);
256 		goto err_close_socket;
257 	}
258 
259 	if (ipv6)
260 		INFO("IPv6 support enabled\n");
261 
262 	if (listen(fd, 16) < 0) {
263 		iio_strerror(errno, err_str, sizeof(err_str));
264 		ERROR("Unable to mark as passive socket: %s\n", err_str);
265 		goto err_close_socket;
266 	}
267 
268 #ifdef HAVE_AVAHI
269 	avahi_started = !start_avahi();
270 #endif
271 
272 	pfd[0].fd = fd;
273 	pfd[0].events = POLLIN;
274 	pfd[0].revents = 0;
275 	pfd[1].fd = thread_pool_get_poll_fd(main_thread_pool);
276 	pfd[1].events = POLLIN;
277 	pfd[1].revents = 0;
278 
279 	while (true) {
280 		struct client_data *cdata;
281 		struct sockaddr_in caddr;
282 		socklen_t addr_len = sizeof(caddr);
283 		int new;
284 
285 		poll_nointr(pfd, 2);
286 
287 		if (pfd[1].revents & POLLIN) /* STOP event */
288 			break;
289 
290 		new = accept4(fd, (struct sockaddr *) &caddr, &addr_len,
291 			SOCK_NONBLOCK);
292 		if (new == -1) {
293 			if (errno == EAGAIN || errno == EINTR)
294 				continue;
295 			iio_strerror(errno, err_str, sizeof(err_str));
296 			ERROR("Failed to create connection socket: %s\n",
297 				err_str);
298 			continue;
299 		}
300 
301 		cdata = malloc(sizeof(*cdata));
302 		if (!cdata) {
303 			WARNING("Unable to allocate memory for client\n");
304 			close(new);
305 			continue;
306 		}
307 
308 		/* Configure the socket to send keep-alive packets every 10s,
309 		 * and disconnect the client if no reply was received for one
310 		 * minute. */
311 		setsockopt(new, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(yes));
312 		setsockopt(new, IPPROTO_TCP, TCP_KEEPCNT, &keepalive_probes,
313 				sizeof(keepalive_probes));
314 		setsockopt(new, IPPROTO_TCP, TCP_KEEPIDLE, &keepalive_time,
315 				sizeof(keepalive_time));
316 		setsockopt(new, IPPROTO_TCP, TCP_KEEPINTVL, &keepalive_intvl,
317 				sizeof(keepalive_intvl));
318 		setsockopt(new, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes));
319 
320 		cdata->fd = new;
321 		cdata->ctx = ctx;
322 		cdata->debug = debug;
323 
324 		INFO("New client connected from %s\n",
325 				inet_ntoa(caddr.sin_addr));
326 
327 		ret = thread_pool_add_thread(main_thread_pool, client_thd, cdata, "net_client_thd");
328 		if (ret) {
329 			iio_strerror(ret, err_str, sizeof(err_str));
330 			ERROR("Failed to create new client thread: %s\n",
331 				err_str);
332 			close(new);
333 			free(cdata);
334 		}
335 	}
336 
337 	DEBUG("Cleaning up\n");
338 #ifdef HAVE_AVAHI
339 	if (avahi_started)
340 		stop_avahi();
341 #endif
342 	close(fd);
343 	return EXIT_SUCCESS;
344 
345 err_close_socket:
346 	close(fd);
347 	return EXIT_FAILURE;
348 }
349 
main(int argc,char ** argv)350 int main(int argc, char **argv)
351 {
352 	bool debug = false, interactive = false, use_aio = false;
353 #ifdef WITH_IIOD_USBD
354 	long nb_pipes = 3;
355 	char *end;
356 #endif
357 	struct iio_context *ctx;
358 	int c, option_index = 0;
359 	char *ffs_mountpoint = NULL;
360 	char err_str[1024];
361 	int ret;
362 
363 	while ((c = getopt_long(argc, argv, "+hVdDiaF:n:",
364 					options, &option_index)) != -1) {
365 		switch (c) {
366 		case 'd':
367 			debug = true;
368 			break;
369 		case 'D':
370 			server_demux = true;
371 			break;
372 		case 'i':
373 			interactive = true;
374 			break;
375 		case 'a':
376 #ifdef WITH_AIO
377 			use_aio = true;
378 			break;
379 #else
380 			ERROR("IIOD was not compiled with AIO support.\n");
381 			return EXIT_FAILURE;
382 #endif
383 		case 'F':
384 #ifdef WITH_IIOD_USBD
385 			ffs_mountpoint = optarg;
386 			break;
387 #else
388 			ERROR("IIOD was not compiled with USB support.\n");
389 			return EXIT_FAILURE;
390 #endif
391 		case 'n':
392 #ifdef WITH_IIOD_USBD
393 			nb_pipes = strtol(optarg, &end, 10);
394 			if (optarg == end || nb_pipes < 1) {
395 				ERROR("--nb-pipes: Invalid parameter\n");
396 				return EXIT_FAILURE;
397 			}
398 			break;
399 #else
400 			ERROR("IIOD was not compiled with USB support.\n");
401 			return EXIT_FAILURE;
402 #endif
403 		case 'h':
404 			usage();
405 			return EXIT_SUCCESS;
406 		case 'V':
407 			printf("%u.%u\n", LIBIIO_VERSION_MAJOR,
408 					LIBIIO_VERSION_MINOR);
409 			return EXIT_SUCCESS;
410 		case '?':
411 			return EXIT_FAILURE;
412 		}
413 	}
414 
415 	ctx = iio_create_local_context();
416 	if (!ctx) {
417 		iio_strerror(errno, err_str, sizeof(err_str));
418 		ERROR("Unable to create local context: %s\n", err_str);
419 		return EXIT_FAILURE;
420 	}
421 
422 	main_thread_pool = thread_pool_new();
423 	if (!main_thread_pool) {
424 		iio_strerror(errno, err_str, sizeof(err_str));
425 		ERROR("Unable to create thread pool: %s\n", err_str);
426 		ret = EXIT_FAILURE;
427 		goto out_destroy_context;
428 	}
429 
430 	set_handler(SIGHUP, sig_handler);
431 	set_handler(SIGPIPE, sig_handler);
432 	set_handler(SIGINT, sig_handler);
433 	set_handler(SIGTERM, sig_handler);
434 
435 	if (ffs_mountpoint) {
436 #ifdef WITH_IIOD_USBD
437 		/* We pass use_aio == true directly, this is ensured to be true
438 		 * by the CMake script. */
439 		ret = start_usb_daemon(ctx, ffs_mountpoint,
440 				debug, true, (unsigned int) nb_pipes,
441 				main_thread_pool);
442 		if (ret) {
443 			iio_strerror(-ret, err_str, sizeof(err_str));
444 			ERROR("Unable to start USB daemon: %s\n", err_str);
445 			ret = EXIT_FAILURE;
446 			goto out_destroy_thread_pool;
447 		}
448 #endif
449 	}
450 
451 	if (interactive)
452 		ret = main_interactive(ctx, debug, use_aio);
453 	else
454 		ret = main_server(ctx, debug);
455 
456 	/*
457 	 * In case we got here through an error in the main thread make sure all
458 	 * the worker threads are signaled to shutdown.
459 	 */
460 
461 #ifdef WITH_IIOD_USBD
462 out_destroy_thread_pool:
463 #endif
464 	thread_pool_stop_and_wait(main_thread_pool);
465 	thread_pool_destroy(main_thread_pool);
466 
467 out_destroy_context:
468 	iio_context_destroy(ctx);
469 
470 	return ret;
471 }
472