fd12a8
From e06a042c1c0eccefeccc63e419b9b09bef11e28f Mon Sep 17 00:00:00 2001
fd12a8
From: Victor Toso <victortoso@redhat.com>
fd12a8
Date: Wed, 30 Nov 2022 21:02:20 +0100
fd12a8
Subject: [PATCH] Revert "remove usbredirserver"
fd12a8
Content-type: text/plain
fd12a8
fd12a8
This reverts commit f4ffdce329305da2803684776f7659083a530819.
fd12a8
---
fd12a8
 README.md                       |   4 +
fd12a8
 meson.build                     |   1 +
fd12a8
 usbredirserver/meson.build      |  12 +
fd12a8
 usbredirserver/usbredirserver.1 |  41 +++
fd12a8
 usbredirserver/usbredirserver.c | 474 ++++++++++++++++++++++++++++++++
fd12a8
 5 files changed, 532 insertions(+)
fd12a8
 create mode 100644 usbredirserver/meson.build
fd12a8
 create mode 100644 usbredirserver/usbredirserver.1
fd12a8
 create mode 100644 usbredirserver/usbredirserver.c
fd12a8
fd12a8
diff --git a/README.md b/README.md
fd12a8
index ed04cca..2acb7b0 100644
fd12a8
--- a/README.md
fd12a8
+++ b/README.md
fd12a8
@@ -28,6 +28,10 @@ The usbredirect binary is an usbredir client for exporting an USB device either
fd12a8
 as TCP client or server, for use from another (virtual) machine through the
fd12a8
 usbredir protocol.
fd12a8
 
fd12a8
+## usbredirserver
fd12a8
+
fd12a8
+A simple tcp server usb-host, using usbredirhost
fd12a8
+
fd12a8
 ## usbredirtestclient
fd12a8
 
fd12a8
 A small testclient for the usbredir protocol over tcp, using usbredirparser
fd12a8
diff --git a/meson.build b/meson.build
fd12a8
index aac9909..e740778 100644
fd12a8
--- a/meson.build
fd12a8
+++ b/meson.build
fd12a8
@@ -103,6 +103,7 @@ if get_option('tools').enabled()
fd12a8
     subdir('tools')
fd12a8
 endif
fd12a8
 if host_machine.system() != 'windows'
fd12a8
+    subdir('usbredirserver')
fd12a8
     subdir('usbredirtestclient')
fd12a8
 
fd12a8
     if get_option('fuzzing').enabled()
fd12a8
diff --git a/usbredirserver/meson.build b/usbredirserver/meson.build
fd12a8
new file mode 100644
fd12a8
index 0000000..de40681
fd12a8
--- /dev/null
fd12a8
+++ b/usbredirserver/meson.build
fd12a8
@@ -0,0 +1,12 @@
fd12a8
+usbredirserver_sources = [
fd12a8
+    'usbredirserver.c',
fd12a8
+]
fd12a8
+
fd12a8
+executable('usbredirserver',
fd12a8
+    sources : usbredirserver_sources,
fd12a8
+    c_args : '-Wno-deprecated-declarations',
fd12a8
+    install : true,
fd12a8
+    install_dir: get_option('sbindir'),
fd12a8
+    dependencies : usbredir_host_lib_dep)
fd12a8
+
fd12a8
+install_man('usbredirserver.1')
fd12a8
diff --git a/usbredirserver/usbredirserver.1 b/usbredirserver/usbredirserver.1
fd12a8
new file mode 100644
fd12a8
index 0000000..d5a6793
fd12a8
--- /dev/null
fd12a8
+++ b/usbredirserver/usbredirserver.1
fd12a8
@@ -0,0 +1,41 @@
fd12a8
+.TH USBREDIRSERVER "1" "April 2012" "usbredirserver" "User Commands"
fd12a8
+.SH NAME
fd12a8
+usbredirserver \- exporting an USB device for use from another (virtual) machine
fd12a8
+.SH SYNOPSIS
fd12a8
+.B usbredirserver
fd12a8
+[\fI-p|--port <port>\fR] [\fI-v|--verbose <0-5>\fR] [\fI-4 <ipv4_addr|I-6 <ipv6_addr>]
fd12a8
+\fI<busnum-devnum|vendorid:prodid>\fR
fd12a8
+.SH DESCRIPTION
fd12a8
+usbredirserver is a small standalone server for exporting an USB device for
fd12a8
+use from another (virtual) machine through the usbredir protocol.
fd12a8
+.PP
fd12a8
+You can specify the USB device to export either by USB id in the form of
fd12a8
+\fI<vendorid>:<prodid>\fR, or by USB bus number and device address in the form
fd12a8
+of \fI<usbbus>-<usbaddr>\fR.
fd12a8
+.PP
fd12a8
+Notice that an instance of usbredirserver can only be used to export a
fd12a8
+single USB device. If you want to export multiple devices you can start
fd12a8
+multiple instances listening on different TCP ports.
fd12a8
+.SH OPTIONS
fd12a8
+.TP
fd12a8
+\fB\-p\fR, \fB\-\-port\fR=\fIPORT\fR
fd12a8
+Set the TCP port to listen on to \fIPORT\fR
fd12a8
+.TP
fd12a8
+\fB\-v\fR, \fB\-\-verbose\fR=\fIVERBOSE\fR
fd12a8
+Set usbredirserver's verbosity level to \fIVERBOSE\fR, this mostly affects USB
fd12a8
+redirection related messages. Valid values are 0-5:
fd12a8
+.br
fd12a8
+0:Silent 1:Errors 2:Warnings 3:Info 4:Debug 5:Debug++
fd12a8
+.SH AUTHOR
fd12a8
+Written by Hans de Goede <hdegoede@redhat.com>
fd12a8
+.SH REPORTING BUGS
fd12a8
+You can report bugs to the spice-devel mailinglist:
fd12a8
+http://lists.freedesktop.org/mailman/listinfo/spice-devel
fd12a8
+or filing an issue at:
fd12a8
+https://gitlab.freedesktop.org/spice/usbredir/issues/new
fd12a8
+.SH COPYRIGHT
fd12a8
+Copyright 2010-2012 Red Hat, Inc.
fd12a8
+License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html>.
fd12a8
+.br
fd12a8
+This is free software: you are free to change and redistribute it.
fd12a8
+There is NO WARRANTY, to the extent permitted by law.
fd12a8
diff --git a/usbredirserver/usbredirserver.c b/usbredirserver/usbredirserver.c
fd12a8
new file mode 100644
fd12a8
index 0000000..badb7bc
fd12a8
--- /dev/null
fd12a8
+++ b/usbredirserver/usbredirserver.c
fd12a8
@@ -0,0 +1,474 @@
fd12a8
+/* usbredirserver.c simple usb network redirection tcp/ip server (host).
fd12a8
+
fd12a8
+   Copyright 2010-2011 Red Hat, Inc.
fd12a8
+
fd12a8
+   Red Hat Authors:
fd12a8
+   Hans de Goede <hdegoede@redhat.com>
fd12a8
+
fd12a8
+   This program is free software; you can redistribute it and/or
fd12a8
+   modify it under the terms of the GNU General Public
fd12a8
+   License as published by the Free Software Foundation; either
fd12a8
+   version 2 of the License, or (at your option) any later version.
fd12a8
+
fd12a8
+   This program is distributed in the hope that it will be useful,
fd12a8
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
fd12a8
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
fd12a8
+   General Public License for more details.
fd12a8
+
fd12a8
+   You should have received a copy of the GNU General Public License
fd12a8
+   along with this library; if not, see <http://www.gnu.org/licenses/>.
fd12a8
+*/
fd12a8
+
fd12a8
+#include "config.h"
fd12a8
+
fd12a8
+#include <stdio.h>
fd12a8
+#include <stdlib.h>
fd12a8
+#include <stdarg.h>
fd12a8
+#include <string.h>
fd12a8
+#include <getopt.h>
fd12a8
+#include <unistd.h>
fd12a8
+#include <errno.h>
fd12a8
+#include <poll.h>
fd12a8
+#include <fcntl.h>
fd12a8
+#include <signal.h>
fd12a8
+#include <sys/socket.h>
fd12a8
+#include <sys/types.h>
fd12a8
+#include <sys/time.h>
fd12a8
+#include <netdb.h>
fd12a8
+#include <netinet/in.h>
fd12a8
+#include <arpa/inet.h>
fd12a8
+#include <netinet/tcp.h>
fd12a8
+#include "usbredirhost.h"
fd12a8
+
fd12a8
+
fd12a8
+#define SERVER_VERSION "usbredirserver " PACKAGE_VERSION
fd12a8
+
fd12a8
+#if !defined(SOL_TCP) && defined(IPPROTO_TCP)
fd12a8
+#define SOL_TCP IPPROTO_TCP
fd12a8
+#endif
fd12a8
+#if !defined(TCP_KEEPIDLE) && defined(TCP_KEEPALIVE) && defined(__APPLE__)
fd12a8
+#define TCP_KEEPIDLE TCP_KEEPALIVE
fd12a8
+#endif
fd12a8
+
fd12a8
+static int verbose = usbredirparser_info;
fd12a8
+static int client_fd, running = 1;
fd12a8
+static libusb_context *ctx;
fd12a8
+static struct usbredirhost *host;
fd12a8
+
fd12a8
+static const struct option longopts[] = {
fd12a8
+    { "port", required_argument, NULL, 'p' },
fd12a8
+    { "verbose", required_argument, NULL, 'v' },
fd12a8
+    { "ipv4", required_argument, NULL, '4' },
fd12a8
+    { "ipv6", required_argument, NULL, '6' },
fd12a8
+    { "keepalive", required_argument, NULL, 'k' },
fd12a8
+    { "help", no_argument, NULL, 'h' },
fd12a8
+    { NULL, 0, NULL, 0 }
fd12a8
+};
fd12a8
+
fd12a8
+static void usbredirserver_log(void *priv, int level, const char *msg)
fd12a8
+{
fd12a8
+    if (level <= verbose)
fd12a8
+        fprintf(stderr, "%s\n", msg);
fd12a8
+}
fd12a8
+
fd12a8
+static int usbredirserver_read(void *priv, uint8_t *data, int count)
fd12a8
+{
fd12a8
+    int r = read(client_fd, data, count);
fd12a8
+    if (r < 0) {
fd12a8
+        if (errno == EAGAIN)
fd12a8
+            return 0;
fd12a8
+        return -1;
fd12a8
+    }
fd12a8
+    if (r == 0) { /* Client disconnected */
fd12a8
+        close(client_fd);
fd12a8
+        client_fd = -1;
fd12a8
+    }
fd12a8
+    return r;
fd12a8
+}
fd12a8
+
fd12a8
+static int usbredirserver_write(void *priv, uint8_t *data, int count)
fd12a8
+{
fd12a8
+    int r = write(client_fd, data, count);
fd12a8
+    if (r < 0) {
fd12a8
+        if (errno == EAGAIN)
fd12a8
+            return 0;
fd12a8
+        if (errno == EPIPE) { /* Client disconnected */
fd12a8
+            close(client_fd);
fd12a8
+            client_fd = -1;
fd12a8
+            return 0;
fd12a8
+        }
fd12a8
+        return -1;
fd12a8
+    }
fd12a8
+    return r;
fd12a8
+}
fd12a8
+
fd12a8
+static void usage(int exit_code, char *argv0)
fd12a8
+{
fd12a8
+    fprintf(exit_code? stderr:stdout,
fd12a8
+        "Usage: %s [-p|--port <port>] [-v|--verbose <0-5>] "
fd12a8
+        "[[-4|--ipv4 ipaddr]|[-6|--ipv6 ipaddr]] "
fd12a8
+        "[-k|--keepalive seconds] "
fd12a8
+        "<busnum-devnum|vendorid:prodid>\n",
fd12a8
+        argv0);
fd12a8
+    exit(exit_code);
fd12a8
+}
fd12a8
+
fd12a8
+static void invalid_usb_device_id(char *usb_device_id, char *argv0)
fd12a8
+{
fd12a8
+    fprintf(stderr, "Invalid usb device identifier: %s\n", usb_device_id);
fd12a8
+    usage(1, argv0);
fd12a8
+}
fd12a8
+
fd12a8
+static void run_main_loop(void)
fd12a8
+{
fd12a8
+    const struct libusb_pollfd **pollfds = NULL;
fd12a8
+    fd_set readfds, writefds;
fd12a8
+    int i, n, nfds;
fd12a8
+    struct timeval timeout, *timeout_p;
fd12a8
+
fd12a8
+    while (running && client_fd != -1) {
fd12a8
+        FD_ZERO(&readfds);
fd12a8
+        FD_ZERO(&writefds);
fd12a8
+
fd12a8
+        FD_SET(client_fd, &readfds);
fd12a8
+        if (usbredirhost_has_data_to_write(host)) {
fd12a8
+            FD_SET(client_fd, &writefds);
fd12a8
+        }
fd12a8
+        nfds = client_fd + 1;
fd12a8
+
fd12a8
+        free(pollfds);
fd12a8
+        pollfds = libusb_get_pollfds(ctx);
fd12a8
+        for (i = 0; pollfds && pollfds[i]; i++) {
fd12a8
+            if (pollfds[i]->events & POLLIN) {
fd12a8
+                FD_SET(pollfds[i]->fd, &readfds);
fd12a8
+            }
fd12a8
+            if (pollfds[i]->events & POLLOUT) {
fd12a8
+                FD_SET(pollfds[i]->fd, &writefds);
fd12a8
+            }
fd12a8
+            if (pollfds[i]->fd >= nfds)
fd12a8
+                nfds = pollfds[i]->fd + 1;
fd12a8
+        }
fd12a8
+
fd12a8
+        if (libusb_get_next_timeout(ctx, &timeout) == 1) {
fd12a8
+            timeout_p = &timeout;
fd12a8
+        } else {
fd12a8
+            timeout_p = NULL;
fd12a8
+        }
fd12a8
+        n = select(nfds, &readfds, &writefds, NULL, timeout_p);
fd12a8
+        if (n == -1) {
fd12a8
+            if (errno == EINTR) {
fd12a8
+                continue;
fd12a8
+            }
fd12a8
+            perror("select");
fd12a8
+            break;
fd12a8
+        }
fd12a8
+        memset(&timeout, 0, sizeof(timeout));
fd12a8
+        if (n == 0) {
fd12a8
+            libusb_handle_events_timeout(ctx, &timeout);
fd12a8
+            continue;
fd12a8
+        }
fd12a8
+
fd12a8
+        if (FD_ISSET(client_fd, &readfds)) {
fd12a8
+            if (usbredirhost_read_guest_data(host)) {
fd12a8
+                break;
fd12a8
+            }
fd12a8
+        }
fd12a8
+        /* usbredirhost_read_guest_data may have detected client disconnect */
fd12a8
+        if (client_fd == -1)
fd12a8
+            break;
fd12a8
+
fd12a8
+        if (FD_ISSET(client_fd, &writefds)) {
fd12a8
+            if (usbredirhost_write_guest_data(host)) {
fd12a8
+                break;
fd12a8
+            }
fd12a8
+        }
fd12a8
+
fd12a8
+        for (i = 0; pollfds && pollfds[i]; i++) {
fd12a8
+            if (FD_ISSET(pollfds[i]->fd, &readfds) ||
fd12a8
+                FD_ISSET(pollfds[i]->fd, &writefds)) {
fd12a8
+                libusb_handle_events_timeout(ctx, &timeout);
fd12a8
+                break;
fd12a8
+            }
fd12a8
+        }
fd12a8
+    }
fd12a8
+    if (client_fd != -1) { /* Broken out of the loop because of an error ? */
fd12a8
+        close(client_fd);
fd12a8
+        client_fd = -1;
fd12a8
+    }
fd12a8
+    free(pollfds);
fd12a8
+}
fd12a8
+
fd12a8
+static void quit_handler(int sig)
fd12a8
+{
fd12a8
+    running = 0;
fd12a8
+}
fd12a8
+
fd12a8
+int main(int argc, char *argv[])
fd12a8
+{
fd12a8
+    int o, flags, server_fd = -1;
fd12a8
+    char *endptr, *delim;
fd12a8
+    int port       = 4000;
fd12a8
+    int usbbus     = -1;
fd12a8
+    int usbaddr    = -1;
fd12a8
+    int usbvendor  = -1;
fd12a8
+    int usbproduct = -1;
fd12a8
+    int on = 1;
fd12a8
+    int keepalive  = -1;
fd12a8
+    char *ipv4_addr = NULL, *ipv6_addr = NULL;
fd12a8
+    union {
fd12a8
+        struct sockaddr_in v4;
fd12a8
+        struct sockaddr_in6 v6;
fd12a8
+    } serveraddr;
fd12a8
+    struct sigaction act;
fd12a8
+    libusb_device_handle *handle = NULL;
fd12a8
+
fd12a8
+    while ((o = getopt_long(argc, argv, "hp:v:4:6:k:", longopts, NULL)) != -1) {
fd12a8
+        switch (o) {
fd12a8
+        case 'p':
fd12a8
+            port = strtol(optarg, &endptr, 10);
fd12a8
+            if (*endptr != '\0') {
fd12a8
+                fprintf(stderr, "Invalid value for --port: '%s'\n", optarg);
fd12a8
+                usage(1, argv[0]);
fd12a8
+            }
fd12a8
+            break;
fd12a8
+        case 'v':
fd12a8
+            verbose = strtol(optarg, &endptr, 10);
fd12a8
+            if (*endptr != '\0') {
fd12a8
+                fprintf(stderr, "Invalid value for --verbose: '%s'\n", optarg);
fd12a8
+                usage(1, argv[0]);
fd12a8
+            }
fd12a8
+            break;
fd12a8
+        case '4':
fd12a8
+            ipv4_addr = optarg;
fd12a8
+            break;
fd12a8
+        case '6':
fd12a8
+            ipv6_addr = optarg;
fd12a8
+            break;
fd12a8
+        case 'k':
fd12a8
+            keepalive = strtol(optarg, &endptr, 10);
fd12a8
+            if (*endptr != '\0') {
fd12a8
+                fprintf(stderr, "Invalid value for -k: '%s'\n", optarg);
fd12a8
+                usage(1, argv[0]);
fd12a8
+            }
fd12a8
+            break;
fd12a8
+        case '?':
fd12a8
+        case 'h':
fd12a8
+            usage(o == '?', argv[0]);
fd12a8
+            break;
fd12a8
+        }
fd12a8
+    }
fd12a8
+    if (optind == argc) {
fd12a8
+        fprintf(stderr, "Missing usb device identifier argument\n");
fd12a8
+        usage(1, argv[0]);
fd12a8
+    }
fd12a8
+    delim = strchr(argv[optind], '-');
fd12a8
+    if (delim && delim[1]) {
fd12a8
+        usbbus = strtol(argv[optind], &endptr, 10);
fd12a8
+        if (*endptr != '-') {
fd12a8
+            invalid_usb_device_id(argv[optind], argv[0]);
fd12a8
+        }
fd12a8
+        usbaddr = strtol(delim + 1, &endptr, 10);
fd12a8
+        if (*endptr != '\0') {
fd12a8
+            invalid_usb_device_id(argv[optind], argv[0]);
fd12a8
+        }
fd12a8
+    } else {
fd12a8
+        delim = strchr(argv[optind], ':');
fd12a8
+        if (!delim || !delim[1]) {
fd12a8
+            invalid_usb_device_id(argv[optind], argv[0]);
fd12a8
+        }
fd12a8
+        usbvendor = strtol(argv[optind], &endptr, 16);
fd12a8
+        if (*endptr != ':' || usbvendor <= 0 || usbvendor > 0xffff) {
fd12a8
+            invalid_usb_device_id(argv[optind], argv[0]);
fd12a8
+        }
fd12a8
+        usbproduct = strtol(delim + 1, &endptr, 16);
fd12a8
+        /* Product ID 0000 is valid */
fd12a8
+        if (*endptr != '\0' || usbproduct < 0 || usbproduct > 0xffff) {
fd12a8
+            invalid_usb_device_id(argv[optind], argv[0]);
fd12a8
+        }
fd12a8
+    }
fd12a8
+    optind++;
fd12a8
+    if (optind != argc) {
fd12a8
+        fprintf(stderr, "Excess non option arguments\n");
fd12a8
+        usage(1, argv[0]);
fd12a8
+    }
fd12a8
+
fd12a8
+    memset(&act, 0, sizeof(act));
fd12a8
+    act.sa_handler = quit_handler;
fd12a8
+    sigaction(SIGINT, &act, NULL);
fd12a8
+    sigaction(SIGHUP, &act, NULL);
fd12a8
+    sigaction(SIGTERM, &act, NULL);
fd12a8
+    sigaction(SIGQUIT, &act, NULL);
fd12a8
+
fd12a8
+    if (libusb_init(&ctx)) {
fd12a8
+        fprintf(stderr, "Could not init libusb\n");
fd12a8
+        exit(1);
fd12a8
+    }
fd12a8
+
fd12a8
+#if LIBUSB_API_VERSION >= 0x01000106
fd12a8
+    libusb_set_option(ctx, LIBUSB_OPTION_LOG_LEVEL, verbose);
fd12a8
+#else
fd12a8
+    libusb_set_debug(ctx, verbose);
fd12a8
+#endif
fd12a8
+
fd12a8
+    if (ipv4_addr) {
fd12a8
+        server_fd = socket(AF_INET, SOCK_STREAM, 0);
fd12a8
+    } else {
fd12a8
+        server_fd = socket(AF_INET6, SOCK_STREAM, 0);
fd12a8
+    }
fd12a8
+    if (server_fd == -1) {
fd12a8
+        perror("Error creating ip socket");
fd12a8
+        exit(1);
fd12a8
+    }
fd12a8
+
fd12a8
+    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) {
fd12a8
+        perror("Error setsockopt(SO_REUSEADDR) failed");
fd12a8
+        exit(1);
fd12a8
+    }
fd12a8
+
fd12a8
+    memset(&serveraddr, 0, sizeof(serveraddr));
fd12a8
+
fd12a8
+    if (ipv4_addr) {
fd12a8
+        serveraddr.v4.sin_family = AF_INET;
fd12a8
+        serveraddr.v4.sin_port   = htons(port);
fd12a8
+        if ((inet_pton(AF_INET, ipv4_addr,
fd12a8
+                       &serveraddr.v4.sin_addr)) != 1) {
fd12a8
+            perror("Error convert ipv4 address");
fd12a8
+            exit(1);
fd12a8
+        }
fd12a8
+    } else {
fd12a8
+        serveraddr.v6.sin6_family = AF_INET6;
fd12a8
+        serveraddr.v6.sin6_port   = htons(port);
fd12a8
+        if (ipv6_addr) {
fd12a8
+            if ((inet_pton(AF_INET6, ipv6_addr,
fd12a8
+                           &serveraddr.v6.sin6_addr)) != 1) {
fd12a8
+                perror("Error convert ipv6 address");
fd12a8
+                exit(1);
fd12a8
+            }
fd12a8
+        } else {
fd12a8
+            serveraddr.v6.sin6_addr   = in6addr_any;
fd12a8
+        }
fd12a8
+    }
fd12a8
+
fd12a8
+    if (bind(server_fd, (struct sockaddr *)&serveraddr,
fd12a8
+             sizeof(serveraddr))) {
fd12a8
+        perror("Error bind");
fd12a8
+        exit(1);
fd12a8
+    }
fd12a8
+
fd12a8
+    if (listen(server_fd, 1)) {
fd12a8
+        perror("Error listening");
fd12a8
+        exit(1);
fd12a8
+    }
fd12a8
+
fd12a8
+    while (running) {
fd12a8
+        client_fd = accept(server_fd, NULL, 0);
fd12a8
+        if (client_fd == -1) {
fd12a8
+            if (errno == EINTR) {
fd12a8
+                continue;
fd12a8
+            }
fd12a8
+            perror("accept");
fd12a8
+            break;
fd12a8
+        }
fd12a8
+
fd12a8
+        if (keepalive > 0) {
fd12a8
+            int optval = 1;
fd12a8
+            socklen_t optlen = sizeof(optval);
fd12a8
+            if (setsockopt(client_fd, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen) == -1) {
fd12a8
+                if (errno != ENOTSUP) {
fd12a8
+                    perror("setsockopt SO_KEEPALIVE error.");
fd12a8
+                    break;
fd12a8
+                }
fd12a8
+            }
fd12a8
+            optval = keepalive;	/* set default TCP_KEEPIDLE time from cmdline */
fd12a8
+            if (setsockopt(client_fd, SOL_TCP, TCP_KEEPIDLE, &optval, optlen) == -1) {
fd12a8
+                if (errno != ENOTSUP) {
fd12a8
+                    perror("setsockopt TCP_KEEPIDLE error.");
fd12a8
+                    break;
fd12a8
+                }
fd12a8
+            }
fd12a8
+            optval = 10;	/* set default TCP_KEEPINTVL time as 10s */
fd12a8
+            if (setsockopt(client_fd, SOL_TCP, TCP_KEEPINTVL, &optval, optlen) == -1) {
fd12a8
+                if (errno != ENOTSUP) {
fd12a8
+                    perror("setsockopt TCP_KEEPINTVL error.");
fd12a8
+                    break;
fd12a8
+                }
fd12a8
+            }
fd12a8
+            optval = 3;	/* set default TCP_KEEPCNT as 3 */
fd12a8
+            if (setsockopt(client_fd, SOL_TCP, TCP_KEEPCNT, &optval, optlen) == -1) {
fd12a8
+                if (errno != ENOTSUP) {
fd12a8
+                    perror("setsockopt TCP_KEEPCNT error.");
fd12a8
+                    break;
fd12a8
+                }
fd12a8
+            }
fd12a8
+        }
fd12a8
+
fd12a8
+        flags = fcntl(client_fd, F_GETFL);
fd12a8
+        if (flags == -1) {
fd12a8
+            perror("fcntl F_GETFL");
fd12a8
+            break;
fd12a8
+        }
fd12a8
+        flags = fcntl(client_fd, F_SETFL, flags | O_NONBLOCK);
fd12a8
+        if (flags == -1) {
fd12a8
+            perror("fcntl F_SETFL O_NONBLOCK");
fd12a8
+            break;
fd12a8
+        }
fd12a8
+
fd12a8
+        /* Try to find the specified usb device */
fd12a8
+        if (usbvendor != -1) {
fd12a8
+            handle = libusb_open_device_with_vid_pid(ctx, usbvendor,
fd12a8
+                                                     usbproduct);
fd12a8
+            if (!handle) {
fd12a8
+                fprintf(stderr,
fd12a8
+                    "Could not open an usb-device with vid:pid %04x:%04x\n",
fd12a8
+                    usbvendor, usbproduct);
fd12a8
+            } else if (verbose >= usbredirparser_info) {
fd12a8
+                libusb_device *dev;
fd12a8
+                dev = libusb_get_device(handle);
fd12a8
+                fprintf(stderr, "Open a usb-device with vid:pid %04x:%04x on "
fd12a8
+                        "bus %03x device %03x\n",
fd12a8
+                        usbvendor, usbproduct,
fd12a8
+                        libusb_get_bus_number(dev),
fd12a8
+                        libusb_get_device_address(dev));
fd12a8
+            }
fd12a8
+        } else {
fd12a8
+            libusb_device **list = NULL;
fd12a8
+            ssize_t i, n;
fd12a8
+
fd12a8
+            n = libusb_get_device_list(ctx, &list);
fd12a8
+            for (i = 0; i < n; i++) {
fd12a8
+                if (libusb_get_bus_number(list[i]) == usbbus &&
fd12a8
+                        libusb_get_device_address(list[i]) == usbaddr)
fd12a8
+                    break;
fd12a8
+            }
fd12a8
+            if (i < n) {
fd12a8
+                if (libusb_open(list[i], &handle) != 0) {
fd12a8
+                    fprintf(stderr,
fd12a8
+                        "Could not open usb-device at busnum-devnum %d-%d\n",
fd12a8
+                        usbbus, usbaddr);
fd12a8
+                }
fd12a8
+            } else {
fd12a8
+                fprintf(stderr,
fd12a8
+                    "Could not find an usb-device at busnum-devnum %d-%d\n",
fd12a8
+                    usbbus, usbaddr);
fd12a8
+            }
fd12a8
+            libusb_free_device_list(list, 1);
fd12a8
+        }
fd12a8
+        if (!handle) {
fd12a8
+            close(client_fd);
fd12a8
+            continue;
fd12a8
+        }
fd12a8
+
fd12a8
+        host = usbredirhost_open(ctx, handle, usbredirserver_log,
fd12a8
+                                 usbredirserver_read, usbredirserver_write,
fd12a8
+                                 NULL, SERVER_VERSION, verbose, 0);
fd12a8
+        if (!host)
fd12a8
+            exit(1);
fd12a8
+        run_main_loop();
fd12a8
+        usbredirhost_close(host);
fd12a8
+        handle = NULL;
fd12a8
+    }
fd12a8
+
fd12a8
+    close(server_fd);
fd12a8
+    libusb_exit(ctx);
fd12a8
+    exit(0);
fd12a8
+}
fd12a8
-- 
fd12a8
2.38.1
fd12a8