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