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