1 /* usbredirserver.c simple usb network redirection tcp/ip server (host).
2 
3    Copyright 2010-2011 Red Hat, Inc.
4 
5    Red Hat Authors:
6    Hans de Goede <hdegoede@redhat.com>
7 
8    This program is free software; you can redistribute it and/or
9    modify it under the terms of the GNU General Public
10    License as published by the Free Software Foundation; either
11    version 2 of the License, or (at your option) any later version.
12 
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    General Public License for more details.
17 
18    You should have received a copy of the GNU General Public License
19    along with this library; if not, see <http://www.gnu.org/licenses/>.
20 */
21 
22 #include "config.h"
23 
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <stdarg.h>
27 #include <string.h>
28 #include <getopt.h>
29 #include <unistd.h>
30 #include <errno.h>
31 #include <poll.h>
32 #include <fcntl.h>
33 #include <signal.h>
34 #include <sys/socket.h>
35 #include <sys/types.h>
36 #include <sys/time.h>
37 #include <netdb.h>
38 #include <netinet/in.h>
39 #include <arpa/inet.h>
40 #include <netinet/tcp.h>
41 #include "usbredirhost.h"
42 
43 
44 #define SERVER_VERSION "usbredirserver " PACKAGE_VERSION
45 
46 static int verbose = usbredirparser_info;
47 static int client_fd, running = 1;
48 static libusb_context *ctx;
49 static struct usbredirhost *host;
50 
51 static const struct option longopts[] = {
52     { "port", required_argument, NULL, 'p' },
53     { "verbose", required_argument, NULL, 'v' },
54     { "ipv4", required_argument, NULL, '4' },
55     { "ipv6", required_argument, NULL, '6' },
56     { "keepalive", required_argument, NULL, 'k' },
57     { "help", no_argument, NULL, 'h' },
58     { NULL, 0, NULL, 0 }
59 };
60 
usbredirserver_log(void * priv,int level,const char * msg)61 static void usbredirserver_log(void *priv, int level, const char *msg)
62 {
63     if (level <= verbose)
64         fprintf(stderr, "%s\n", msg);
65 }
66 
usbredirserver_read(void * priv,uint8_t * data,int count)67 static int usbredirserver_read(void *priv, uint8_t *data, int count)
68 {
69     int r = read(client_fd, data, count);
70     if (r < 0) {
71         if (errno == EAGAIN)
72             return 0;
73         return -1;
74     }
75     if (r == 0) { /* Client disconnected */
76         close(client_fd);
77         client_fd = -1;
78     }
79     return r;
80 }
81 
usbredirserver_write(void * priv,uint8_t * data,int count)82 static int usbredirserver_write(void *priv, uint8_t *data, int count)
83 {
84     int r = write(client_fd, data, count);
85     if (r < 0) {
86         if (errno == EAGAIN)
87             return 0;
88         if (errno == EPIPE) { /* Client disconnected */
89             close(client_fd);
90             client_fd = -1;
91             return 0;
92         }
93         return -1;
94     }
95     return r;
96 }
97 
usage(int exit_code,char * argv0)98 static void usage(int exit_code, char *argv0)
99 {
100     fprintf(exit_code? stderr:stdout,
101         "Usage: %s [-p|--port <port>] [-v|--verbose <0-5>] "
102         "[[-4|--ipv4 ipaddr]|[-6|--ipv6 ipaddr]] "
103         "[-k|--keepalive seconds] "
104         "<busnum-devnum|vendorid:prodid>\n",
105         argv0);
106     exit(exit_code);
107 }
108 
invalid_usb_device_id(char * usb_device_id,char * argv0)109 static void invalid_usb_device_id(char *usb_device_id, char *argv0)
110 {
111     fprintf(stderr, "Invalid usb device identifier: %s\n", usb_device_id);
112     usage(1, argv0);
113 }
114 
run_main_loop(void)115 static void run_main_loop(void)
116 {
117     const struct libusb_pollfd **pollfds = NULL;
118     fd_set readfds, writefds;
119     int i, n, nfds;
120     struct timeval timeout, *timeout_p;
121 
122     while (running && client_fd != -1) {
123         FD_ZERO(&readfds);
124         FD_ZERO(&writefds);
125 
126         FD_SET(client_fd, &readfds);
127         if (usbredirhost_has_data_to_write(host)) {
128             FD_SET(client_fd, &writefds);
129         }
130         nfds = client_fd + 1;
131 
132         free(pollfds);
133         pollfds = libusb_get_pollfds(ctx);
134         for (i = 0; pollfds && pollfds[i]; i++) {
135             if (pollfds[i]->events & POLLIN) {
136                 FD_SET(pollfds[i]->fd, &readfds);
137             }
138             if (pollfds[i]->events & POLLOUT) {
139                 FD_SET(pollfds[i]->fd, &writefds);
140             }
141             if (pollfds[i]->fd >= nfds)
142                 nfds = pollfds[i]->fd + 1;
143         }
144 
145         if (libusb_get_next_timeout(ctx, &timeout) == 1) {
146             timeout_p = &timeout;
147         } else {
148             timeout_p = NULL;
149         }
150         n = select(nfds, &readfds, &writefds, NULL, timeout_p);
151         if (n == -1) {
152             if (errno == EINTR) {
153                 continue;
154             }
155             perror("select");
156             break;
157         }
158         memset(&timeout, 0, sizeof(timeout));
159         if (n == 0) {
160             libusb_handle_events_timeout(ctx, &timeout);
161             continue;
162         }
163 
164         if (FD_ISSET(client_fd, &readfds)) {
165             if (usbredirhost_read_guest_data(host)) {
166                 break;
167             }
168         }
169         /* usbredirhost_read_guest_data may have detected client disconnect */
170         if (client_fd == -1)
171             break;
172 
173         if (FD_ISSET(client_fd, &writefds)) {
174             if (usbredirhost_write_guest_data(host)) {
175                 break;
176             }
177         }
178 
179         for (i = 0; pollfds && pollfds[i]; i++) {
180             if (FD_ISSET(pollfds[i]->fd, &readfds) ||
181                 FD_ISSET(pollfds[i]->fd, &writefds)) {
182                 libusb_handle_events_timeout(ctx, &timeout);
183                 break;
184             }
185         }
186     }
187     if (client_fd != -1) { /* Broken out of the loop because of an error ? */
188         close(client_fd);
189         client_fd = -1;
190     }
191     free(pollfds);
192 }
193 
quit_handler(int sig)194 static void quit_handler(int sig)
195 {
196     running = 0;
197 }
198 
main(int argc,char * argv[])199 int main(int argc, char *argv[])
200 {
201     int o, flags, server_fd = -1;
202     char *endptr, *delim;
203     int port       = 4000;
204     int usbbus     = -1;
205     int usbaddr    = -1;
206     int usbvendor  = -1;
207     int usbproduct = -1;
208     int on = 1;
209     int keepalive  = -1;
210     char *ipv4_addr = NULL, *ipv6_addr = NULL;
211     union {
212         struct sockaddr_in v4;
213         struct sockaddr_in6 v6;
214     } serveraddr;
215     struct sigaction act;
216     libusb_device_handle *handle = NULL;
217 
218     while ((o = getopt_long(argc, argv, "hp:v:4:6:k:", longopts, NULL)) != -1) {
219         switch (o) {
220         case 'p':
221             port = strtol(optarg, &endptr, 10);
222             if (*endptr != '\0') {
223                 fprintf(stderr, "Invalid value for --port: '%s'\n", optarg);
224                 usage(1, argv[0]);
225             }
226             break;
227         case 'v':
228             verbose = strtol(optarg, &endptr, 10);
229             if (*endptr != '\0') {
230                 fprintf(stderr, "Invalid value for --verbose: '%s'\n", optarg);
231                 usage(1, argv[0]);
232             }
233             break;
234         case '4':
235             ipv4_addr = optarg;
236             break;
237         case '6':
238             ipv6_addr = optarg;
239             break;
240         case 'k':
241             keepalive = strtol(optarg, &endptr, 10);
242             if (*endptr != '\0') {
243                 fprintf(stderr, "Invalid value for -k: '%s'\n", optarg);
244                 usage(1, argv[0]);
245             }
246             break;
247         case '?':
248         case 'h':
249             usage(o == '?', argv[0]);
250             break;
251         }
252     }
253     if (optind == argc) {
254         fprintf(stderr, "Missing usb device identifier argument\n");
255         usage(1, argv[0]);
256     }
257     delim = strchr(argv[optind], '-');
258     if (delim && delim[1]) {
259         usbbus = strtol(argv[optind], &endptr, 10);
260         if (*endptr != '-') {
261             invalid_usb_device_id(argv[optind], argv[0]);
262         }
263         usbaddr = strtol(delim + 1, &endptr, 10);
264         if (*endptr != '\0') {
265             invalid_usb_device_id(argv[optind], argv[0]);
266         }
267     } else {
268         delim = strchr(argv[optind], ':');
269         if (!delim || !delim[1]) {
270             invalid_usb_device_id(argv[optind], argv[0]);
271         }
272         usbvendor = strtol(argv[optind], &endptr, 16);
273         if (*endptr != ':' || usbvendor <= 0 || usbvendor > 0xffff) {
274             invalid_usb_device_id(argv[optind], argv[0]);
275         }
276         usbproduct = strtol(delim + 1, &endptr, 16);
277         /* Product ID 0000 is valid */
278         if (*endptr != '\0' || usbproduct < 0 || usbproduct > 0xffff) {
279             invalid_usb_device_id(argv[optind], argv[0]);
280         }
281     }
282     optind++;
283     if (optind != argc) {
284         fprintf(stderr, "Excess non option arguments\n");
285         usage(1, argv[0]);
286     }
287 
288     memset(&act, 0, sizeof(act));
289     act.sa_handler = quit_handler;
290     sigaction(SIGINT, &act, NULL);
291     sigaction(SIGHUP, &act, NULL);
292     sigaction(SIGTERM, &act, NULL);
293     sigaction(SIGQUIT, &act, NULL);
294 
295     if (libusb_init(&ctx)) {
296         fprintf(stderr, "Could not init libusb\n");
297         exit(1);
298     }
299 
300 #if LIBUSB_API_VERSION >= 0x01000106
301     libusb_set_option(ctx, LIBUSB_OPTION_LOG_LEVEL, verbose);
302 #else
303     libusb_set_debug(ctx, verbose);
304 #endif
305 
306     if (ipv4_addr) {
307         server_fd = socket(AF_INET, SOCK_STREAM, 0);
308     } else {
309         server_fd = socket(AF_INET6, SOCK_STREAM, 0);
310     }
311     if (server_fd == -1) {
312         perror("Error creating ip socket");
313         exit(1);
314     }
315 
316     if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) {
317         perror("Error setsockopt(SO_REUSEADDR) failed");
318         exit(1);
319     }
320 
321     memset(&serveraddr, 0, sizeof(serveraddr));
322 
323     if (ipv4_addr) {
324         serveraddr.v4.sin_family = AF_INET;
325         serveraddr.v4.sin_port   = htons(port);
326         if ((inet_pton(AF_INET, ipv4_addr,
327                        &serveraddr.v4.sin_addr)) != 1) {
328             perror("Error convert ipv4 address");
329             exit(1);
330         }
331     } else {
332         serveraddr.v6.sin6_family = AF_INET6;
333         serveraddr.v6.sin6_port   = htons(port);
334         if (ipv6_addr) {
335             if ((inet_pton(AF_INET6, ipv6_addr,
336                            &serveraddr.v6.sin6_addr)) != 1) {
337                 perror("Error convert ipv6 address");
338                 exit(1);
339             }
340         } else {
341             serveraddr.v6.sin6_addr   = in6addr_any;
342         }
343     }
344 
345     if (bind(server_fd, (struct sockaddr *)&serveraddr,
346              sizeof(serveraddr))) {
347         perror("Error bind");
348         exit(1);
349     }
350 
351     if (listen(server_fd, 1)) {
352         perror("Error listening");
353         exit(1);
354     }
355 
356     while (running) {
357         client_fd = accept(server_fd, NULL, 0);
358         if (client_fd == -1) {
359             if (errno == EINTR) {
360                 continue;
361             }
362             perror("accept");
363             break;
364         }
365 
366         if (keepalive > 0) {
367             int optval = 1;
368             socklen_t optlen = sizeof(optval);
369             if (setsockopt(client_fd, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen) == -1) {
370                 if (errno != ENOTSUP) {
371                     perror("setsockopt SO_KEEPALIVE error.");
372                     break;
373                 }
374             }
375             optval = keepalive;	/* set default TCP_KEEPIDLE time from cmdline */
376             if (setsockopt(client_fd, IPPROTO_TCP, TCP_KEEPIDLE, &optval, optlen) == -1) {
377                 if (errno != ENOTSUP) {
378                     perror("setsockopt TCP_KEEPIDLE error.");
379                     break;
380                 }
381             }
382             optval = 10;	/* set default TCP_KEEPINTVL time as 10s */
383             if (setsockopt(client_fd, IPPROTO_TCP, TCP_KEEPINTVL, &optval, optlen) == -1) {
384                 if (errno != ENOTSUP) {
385                     perror("setsockopt TCP_KEEPINTVL error.");
386                     break;
387                 }
388             }
389             optval = 3;	/* set default TCP_KEEPCNT as 3 */
390             if (setsockopt(client_fd, IPPROTO_TCP, TCP_KEEPCNT, &optval, optlen) == -1) {
391                 if (errno != ENOTSUP) {
392                     perror("setsockopt TCP_KEEPCNT error.");
393                     break;
394                 }
395             }
396         }
397 
398         flags = fcntl(client_fd, F_GETFL);
399         if (flags == -1) {
400             perror("fcntl F_GETFL");
401             break;
402         }
403         flags = fcntl(client_fd, F_SETFL, flags | O_NONBLOCK);
404         if (flags == -1) {
405             perror("fcntl F_SETFL O_NONBLOCK");
406             break;
407         }
408 
409         /* Try to find the specified usb device */
410         if (usbvendor != -1) {
411             handle = libusb_open_device_with_vid_pid(ctx, usbvendor,
412                                                      usbproduct);
413             if (!handle) {
414                 fprintf(stderr,
415                     "Could not open an usb-device with vid:pid %04x:%04x\n",
416                     usbvendor, usbproduct);
417             } else if (verbose >= usbredirparser_info) {
418                 libusb_device *dev;
419                 dev = libusb_get_device(handle);
420                 fprintf(stderr, "Open a usb-device with vid:pid %04x:%04x on "
421                         "bus %03x device %03x\n",
422                         usbvendor, usbproduct,
423                         libusb_get_bus_number(dev),
424                         libusb_get_device_address(dev));
425             }
426         } else {
427             libusb_device **list = NULL;
428             ssize_t i, n;
429 
430             n = libusb_get_device_list(ctx, &list);
431             for (i = 0; i < n; i++) {
432                 if (libusb_get_bus_number(list[i]) == usbbus &&
433                         libusb_get_device_address(list[i]) == usbaddr)
434                     break;
435             }
436             if (i < n) {
437                 if (libusb_open(list[i], &handle) != 0) {
438                     fprintf(stderr,
439                         "Could not open usb-device at busnum-devnum %d-%d\n",
440                         usbbus, usbaddr);
441                 }
442             } else {
443                 fprintf(stderr,
444                     "Could not find an usb-device at busnum-devnum %d-%d\n",
445                     usbbus, usbaddr);
446             }
447             libusb_free_device_list(list, 1);
448         }
449         if (!handle) {
450             close(client_fd);
451             continue;
452         }
453 
454         host = usbredirhost_open(ctx, handle, usbredirserver_log,
455                                  usbredirserver_read, usbredirserver_write,
456                                  NULL, SERVER_VERSION, verbose, 0);
457         if (!host)
458             exit(1);
459         run_main_loop();
460         usbredirhost_close(host);
461         handle = NULL;
462     }
463 
464     close(server_fd);
465     libusb_exit(ctx);
466     exit(0);
467 }
468