Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package usbredir for openSUSE:Factory checked in at 2022-08-10 17:12:46 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/usbredir (Old) and /work/SRC/openSUSE:Factory/.usbredir.new.1521 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "usbredir" Wed Aug 10 17:12:46 2022 rev:20 rq:993933 version:0.13.0 Changes: -------- --- /work/SRC/openSUSE:Factory/usbredir/usbredir.changes 2022-06-09 14:09:33.280348000 +0200 +++ /work/SRC/openSUSE:Factory/.usbredir.new.1521/usbredir.changes 2022-08-10 17:13:00.673662768 +0200 @@ -1,0 +2,15 @@ +Tue Aug 9 08:19:29 UTC 2022 - Dominique Leuenberger <[email protected]> + +- Update to version 0.13.0: + + Fix regression on unserialize data + + Removes usbredirserver + + Improved header length checks when unserialising data + + Fix usage of command line argument in usbredirect + + Fix small memory leak on usbredirect +- Drop 9426fdb1.patch and dffc41c3.patch: fixed upstream. +- Drop + 0001-Use-D_FORTIFY_SOURCE-instead-of-Wp-D_FORTIFY_SOURCE.patch: + fixed upstream. +- Add keyring to validate source signature. + +------------------------------------------------------------------- @@ -4 +19 @@ -- Add upstream backported patches: +- Add upstream backported patches (boo#1199354): Old: ---- 0001-Use-D_FORTIFY_SOURCE-instead-of-Wp-D_FORTIFY_SOURCE.patch 9426fdb1.patch dffc41c3.patch usbredir-0.12.0.tar.xz usbredir-0.12.0.tar.xz.sig New: ---- usbredir-0.13.0.tar.xz usbredir-0.13.0.tar.xz.sig usbredir.keyring ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ usbredir.spec ++++++ --- /var/tmp/diff_new_pack.b6tNOB/_old 2022-08-10 17:13:01.773665639 +0200 +++ /var/tmp/diff_new_pack.b6tNOB/_new 2022-08-10 17:13:01.781665660 +0200 @@ -18,7 +18,7 @@ Name: usbredir -Version: 0.12.0 +Version: 0.13.0 Release: 0 Summary: A protocol for redirecting USB traffic License: GPL-2.0-or-later AND LGPL-2.1-or-later @@ -26,9 +26,7 @@ URL: https://www.spice-space.org/usbredir.html Source: https://www.spice-space.org/download/usbredir/%{name}-%{version}.tar.xz Source1: https://www.spice-space.org/download/usbredir/%{name}-%{version}.tar.xz.sig -Patch0: https://gitlab.freedesktop.org/spice/usbredir/-/commit/9426fdb1.patch -Patch1: https://gitlab.freedesktop.org/spice/usbredir/-/commit/dffc41c3.patch -Patch2: 0001-Use-D_FORTIFY_SOURCE-instead-of-Wp-D_FORTIFY_SOURCE.patch +Source99: %{name}.keyring BuildRequires: gcc-c++ BuildRequires: glib2-devel >= 2.44 BuildRequires: meson >= 0.48 @@ -96,8 +94,6 @@ %license COPYING %{_bindir}/usbredirect %{_mandir}/man1/usbredirect.1.gz -%{_mandir}/man1/usbredirserver.1.gz -%{_sbindir}/usbredirserver %files -n libusbredirhost1 %defattr(-, root, root) ++++++ usbredir-0.12.0.tar.xz -> usbredir-0.13.0.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/usbredir-0.12.0/ChangeLog.md new/usbredir-0.13.0/ChangeLog.md --- old/usbredir-0.12.0/ChangeLog.md 2021-11-12 11:45:49.992210900 +0100 +++ new/usbredir-0.13.0/ChangeLog.md 2022-08-02 19:35:49.000000000 +0200 @@ -1,3 +1,11 @@ +# usbredir-0.13.0 - 01 Aug 2022 + +- !61 Fix regression on unserialize data +- !59 Removes usbredirserver +- !58 Improved header length checks when unserialising data +- !62 Fix usage of command line argument in usbredirect +- !57 Fix small memory leak on usbredirect + # usbredir-0.12.0 - 12 Nov 2021 - !47 Implement dropping packets from isochronous devices diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/usbredir-0.12.0/README.md new/usbredir-0.13.0/README.md --- old/usbredir-0.12.0/README.md 2021-11-12 11:45:49.992210900 +0100 +++ new/usbredir-0.13.0/README.md 2022-08-02 19:35:49.000000000 +0200 @@ -22,9 +22,11 @@ - Provide write and read callbacks for the actual transport of usbredir data - Monitor for usbredir and libusb read/write events and call their handlers -## usbredirserver +## usbredirect -A simple tcp server usb-host, using usbredirhost +The usbredirect binary is an usbredir client for exporting an USB device either +as TCP client or server, for use from another (virtual) machine through the +usbredir protocol. ## usbredirtestclient diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/usbredir-0.12.0/docs/how_to_release.md new/usbredir-0.13.0/docs/how_to_release.md --- old/usbredir-0.12.0/docs/how_to_release.md 1970-01-01 01:00:00.000000000 +0100 +++ new/usbredir-0.13.0/docs/how_to_release.md 2022-08-02 19:35:49.000000000 +0200 @@ -0,0 +1,48 @@ +How to do a usbredir release +============================ + +Some notes to prepare a release, not really strict but better to have in order +to avoid forgetting something. + +Preparing for the release +------------------------- + +* Update the root `meson.build` and also the ones in usbredirparser and + usbredirhost directories according to libtool rules. +* Update `ChangeLog.md` with list of changes done since last release +* Send a merge request with such changes, handle the review and merge it + +Generate source tarball and tags +-------------------------------- + +* Tag the merged commit with release version `git tag -s -m "Release $version" $version` +* Be sure to be in a clean environment: `git clean -xfd` +* Create the source tarball with: `meson . build && meson dist -C build` +* Sign generated tarball: `cd build/meson-dist && gpg2 -sb usbredir-$version.tar.xz` +* If you have a Fedora account, you can proceed and check if + a scratch-build works as expected. + +Generate the MSI installer +-------------------------- + +* On the usbredir srcdir `mkdir build-win64 && cd build-win64` +* `mingw64-meson` +* `DESTDIR=./install-root ninja install` +* `DESTDIR=./install-root ninja data/usbredirect-x64-$version.msi` +* The MSI installer is then located at `build-win64/data` + +Upload and update Info +---------------------- + +* Upload tarball and relative signature to + `https://www.spice-space.org/download/usbredir/` and the MSI installer to + `https://www.spice-space.org/download/windows/usbredirect/` with sftp + `[email protected]:/var/www/www.spice-space.org/download/` +* Push the tag to Gitlab `git push origin HEAD:main --tags` +* On Gitlab update tags (https://gitlab.freedesktop.org/spice/usbredir/-/tags) + * Add ChangeLog information + * Upload tarball with the signature + * Upload the MSI installer +* Update file `download.rst` in + https://gitlab.freedesktop.org/spice/spice-space-pages +* Create a merge request for `spice-space-pages` diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/usbredir-0.12.0/meson.build new/usbredir-0.13.0/meson.build --- old/usbredir-0.12.0/meson.build 2021-11-12 11:45:50.003210800 +0100 +++ new/usbredir-0.13.0/meson.build 2022-08-02 19:35:49.000000000 +0200 @@ -1,5 +1,5 @@ project('usbredir', 'c', - version: '0.12.0', + version: '0.13.0', license: 'LGPLv2.1+', meson_version : '>= 0.53', default_options : [ @@ -15,7 +15,7 @@ '--param=ssp-buffer-size=4', ] if host_machine.system() != 'windows' - cc_flags += [ '-Wp,-D_FORTIFY_SOURCE=2' ] + cc_flags += [ '-D_FORTIFY_SOURCE=2' ] if not get_option('stack_protector').disabled() cc_flags += [ '-fstack-protector' ] endif @@ -103,7 +103,6 @@ subdir('tools') endif if host_machine.system() != 'windows' - subdir('usbredirserver') subdir('usbredirtestclient') if get_option('fuzzing').enabled() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/usbredir-0.12.0/tests/meson.build new/usbredir-0.13.0/tests/meson.build --- old/usbredir-0.12.0/tests/meson.build 2021-11-12 11:45:50.006210800 +0100 +++ new/usbredir-0.13.0/tests/meson.build 2022-08-02 19:35:49.000000000 +0200 @@ -1,5 +1,6 @@ tests = [ 'filter', + 'serializer', ] deps = dependency('glib-2.0') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/usbredir-0.12.0/tests/serializer.c new/usbredir-0.13.0/tests/serializer.c --- old/usbredir-0.12.0/tests/serializer.c 1970-01-01 01:00:00.000000000 +0100 +++ new/usbredir-0.13.0/tests/serializer.c 2022-08-02 19:35:49.000000000 +0200 @@ -0,0 +1,113 @@ +/* + * Copyright 2022 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. +*/ +#include "config.h" + +#define G_LOG_DOMAIN "serializer" +#define G_LOG_USE_STRUCTURED + +#include "usbredirparser.h" + +#include <errno.h> +#include <locale.h> +#include <glib.h> +#include <stdlib.h> + + +static void +log_cb(void *priv, int level, const char *msg) +{ + GLogLevelFlags glog_level; + + switch(level) { + case usbredirparser_error: + glog_level = G_LOG_LEVEL_ERROR; + break; + case usbredirparser_warning: + glog_level = G_LOG_LEVEL_WARNING; + break; + case usbredirparser_info: + glog_level = G_LOG_LEVEL_INFO; + break; + case usbredirparser_debug: + case usbredirparser_debug_data: + glog_level = G_LOG_LEVEL_DEBUG; + break; + default: + g_warn_if_reached(); + return; + } + g_log_structured(G_LOG_DOMAIN, glog_level, "MESSAGE", msg); +} + +static struct usbredirparser * +get_usbredirparser(void) +{ + struct usbredirparser *parser = usbredirparser_create(); + g_assert_nonnull(parser); + + uint32_t caps[USB_REDIR_CAPS_SIZE] = { 0, }; + /* Typical caps set by usbredirhost */ + usbredirparser_caps_set_cap(caps, usb_redir_cap_connect_device_version); + usbredirparser_caps_set_cap(caps, usb_redir_cap_filter); + usbredirparser_caps_set_cap(caps, usb_redir_cap_device_disconnect_ack); + usbredirparser_caps_set_cap(caps, usb_redir_cap_ep_info_max_packet_size); + usbredirparser_caps_set_cap(caps, usb_redir_cap_64bits_ids); + usbredirparser_caps_set_cap(caps, usb_redir_cap_32bits_bulk_length); + usbredirparser_caps_set_cap(caps, usb_redir_cap_bulk_receiving); +#if LIBUSBX_API_VERSION >= 0x01000103 + usbredirparser_caps_set_cap(caps, usb_redir_cap_bulk_streams); +#endif + int parser_flags = usbredirparser_fl_usb_host; + + parser->log_func = log_cb; + usbredirparser_init(parser, + PACKAGE_STRING, + caps, + USB_REDIR_CAPS_SIZE, + parser_flags); + return parser; +} + +static void +simple (gconstpointer user_data) +{ + uint8_t *state = NULL; + int ret, len = -1; + + struct usbredirparser *source = get_usbredirparser(); + ret = usbredirparser_serialize(source, &state, &len); + g_assert_cmpint(ret, ==, 0); + + struct usbredirparser *target = get_usbredirparser(); + ret = usbredirparser_unserialize(target, state, len); + g_assert_cmpint(ret, ==, 0); + + g_clear_pointer(&state, free); + usbredirparser_destroy(source); + usbredirparser_destroy(target); +} + +int +main(int argc, char **argv) +{ + setlocale(LC_ALL, ""); + g_test_init(&argc, &argv, NULL); + + g_test_add_data_func("/serializer/serialize-and-unserialize", NULL, simple); + + return g_test_run(); +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/usbredir-0.12.0/tools/usbredirect.c new/usbredir-0.13.0/tools/usbredirect.c --- old/usbredir-0.12.0/tools/usbredirect.c 2021-11-12 11:45:50.009210800 +0100 +++ new/usbredir-0.13.0/tools/usbredirect.c 2022-08-02 19:35:49.000000000 +0200 @@ -59,6 +59,7 @@ } gint64 bus = g_ascii_strtoll(usbid[0], NULL, 10); gint64 addr = g_ascii_strtoll(usbid[1], NULL, 10); + g_strfreev(usbid); libusb_device **list = NULL; ssize_t i, n; @@ -566,7 +567,12 @@ GSocketService *socket_service; socket_service = g_socket_service_new (); - GInetAddress *iaddr = g_inet_address_new_loopback(G_SOCKET_FAMILY_IPV4); + GInetAddress *iaddr = g_inet_address_new_from_string(self->addr); + if (iaddr == NULL) { + g_warning("Failed to parse IP: %s", self->addr); + goto end; + } + GSocketAddress *saddr = g_inet_socket_address_new(iaddr, self->port); g_object_unref(iaddr); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/usbredir-0.12.0/usbredirparser/meson.build new/usbredir-0.13.0/usbredirparser/meson.build --- old/usbredir-0.12.0/usbredirparser/meson.build 2021-11-12 11:45:50.013210800 +0100 +++ new/usbredir-0.13.0/usbredirparser/meson.build 2022-08-02 19:35:49.000000000 +0200 @@ -1,7 +1,7 @@ # so verison, see: # http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html usbredir_parser_current = 3 -usbredir_parser_revision = 0 +usbredir_parser_revision = 1 usbredir_parser_age = 2 usbredir_parser_so_version = '@0@.@1@.@2@'.format( usbredir_parser_current - usbredir_parser_age, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/usbredir-0.12.0/usbredirparser/usbredirparser.c new/usbredir-0.13.0/usbredirparser/usbredirparser.c --- old/usbredir-0.12.0/usbredirparser/usbredirparser.c 2021-11-12 11:45:50.017210700 +0100 +++ new/usbredir-0.13.0/usbredirparser/usbredirparser.c 2022-08-02 19:35:49.000000000 +0200 @@ -1816,15 +1816,28 @@ return -1; } - if (!(parser->write_buf_count == 0 && parser->write_buf == NULL && - parser->write_buf_total_size == 0 && - parser->data == NULL && parser->header_read == 0 && + if (!(parser->data == NULL && parser->header_read == 0 && parser->type_header_read == 0 && parser->data_read == 0)) { ERROR("unserialization must use a pristine parser"); usbredirparser_assert_invariants(parser); return -1; } + { + /* We need to reset parser's state to receive unserialized + * data. */ + struct usbredirparser_buf *wbuf = parser->write_buf; + while (wbuf) { + struct usbredirparser_buf *next_wbuf = wbuf->next; + free(wbuf->buf); + free(wbuf); + wbuf = next_wbuf; + } + parser->write_buf = NULL; + parser->write_buf_count = 0; + parser->write_buf_total_size = 0; + } + if (unserialize_int(parser, &state, &remain, &i, "length")) { usbredirparser_assert_invariants(parser); return -1; @@ -1881,21 +1894,22 @@ header_len = usbredirparser_get_header_len(parser_pub); data = (uint8_t *)&parser->header; i = header_len; + memset(&parser->header, 0, sizeof(parser->header)); if (unserialize_data(parser, &state, &remain, &data, &i, "header")) { usbredirparser_assert_invariants(parser); return -1; } + if (parser->header.length > MAX_PACKET_SIZE) { + ERROR("packet length of %d larger than permitted %d bytes", + parser->header.length, MAX_PACKET_SIZE); + usbredirparser_assert_invariants(parser); + return -1; + } parser->header_read = i; parser->type_header_len = 0; /* Set various length field from the header (if any) */ if (parser->header_read == header_len) { - if (parser->header.length > MAX_PACKET_SIZE) { - ERROR("packet length of %d larger than permitted %d bytes", - parser->header.length, MAX_PACKET_SIZE); - return -1; - } - int type_header_len = usbredirparser_get_type_header_len(parser_pub, parser->header.type, 0); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/usbredir-0.12.0/usbredirserver/meson.build new/usbredir-0.13.0/usbredirserver/meson.build --- old/usbredir-0.12.0/usbredirserver/meson.build 2021-11-12 11:45:50.021210700 +0100 +++ new/usbredir-0.13.0/usbredirserver/meson.build 1970-01-01 01:00:00.000000000 +0100 @@ -1,12 +0,0 @@ -usbredirserver_sources = [ - 'usbredirserver.c', -] - -executable('usbredirserver', - sources : usbredirserver_sources, - c_args : '-Wno-deprecated-declarations', - install : true, - install_dir: get_option('sbindir'), - dependencies : usbredir_host_lib_dep) - -install_man('usbredirserver.1') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/usbredir-0.12.0/usbredirserver/usbredirserver.1 new/usbredir-0.13.0/usbredirserver/usbredirserver.1 --- old/usbredir-0.12.0/usbredirserver/usbredirserver.1 2021-11-12 11:45:50.021210700 +0100 +++ new/usbredir-0.13.0/usbredirserver/usbredirserver.1 1970-01-01 01:00:00.000000000 +0100 @@ -1,41 +0,0 @@ -.TH USBREDIRSERVER "1" "April 2012" "usbredirserver" "User Commands" -.SH NAME -usbredirserver \- exporting an USB device for use from another (virtual) machine -.SH SYNOPSIS -.B usbredirserver -[\fI-p|--port <port>\fR] [\fI-v|--verbose <0-5>\fR] [\fI-4 <ipv4_addr|I-6 <ipv6_addr>] -\fI<busnum-devnum|vendorid:prodid>\fR -.SH DESCRIPTION -usbredirserver is a small standalone server for exporting an USB device for -use from another (virtual) machine through the usbredir protocol. -.PP -You can specify the USB device to export either by USB id in the form of -\fI<vendorid>:<prodid>\fR, or by USB bus number and device address in the form -of \fI<usbbus>-<usbaddr>\fR. -.PP -Notice that an instance of usbredirserver can only be used to export a -single USB device. If you want to export multiple devices you can start -multiple instances listening on different TCP ports. -.SH OPTIONS -.TP -\fB\-p\fR, \fB\-\-port\fR=\fIPORT\fR -Set the TCP port to listen on to \fIPORT\fR -.TP -\fB\-v\fR, \fB\-\-verbose\fR=\fIVERBOSE\fR -Set usbredirserver's verbosity level to \fIVERBOSE\fR, this mostly affects USB -redirection related messages. Valid values are 0-5: -.br -0:Silent 1:Errors 2:Warnings 3:Info 4:Debug 5:Debug++ -.SH AUTHOR -Written by Hans de Goede <[email protected]> -.SH REPORTING BUGS -You can report bugs to the spice-devel mailinglist: -http://lists.freedesktop.org/mailman/listinfo/spice-devel -or filing an issue at: -https://gitlab.freedesktop.org/spice/usbredir/issues/new -.SH COPYRIGHT -Copyright 2010-2012 Red Hat, Inc. -License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html>. -.br -This is free software: you are free to change and redistribute it. -There is NO WARRANTY, to the extent permitted by law. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/usbredir-0.12.0/usbredirserver/usbredirserver.c new/usbredir-0.13.0/usbredirserver/usbredirserver.c --- old/usbredir-0.12.0/usbredirserver/usbredirserver.c 2021-11-12 11:45:50.021210700 +0100 +++ new/usbredir-0.13.0/usbredirserver/usbredirserver.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,474 +0,0 @@ -/* usbredirserver.c simple usb network redirection tcp/ip server (host). - - Copyright 2010-2011 Red Hat, Inc. - - Red Hat Authors: - Hans de Goede <[email protected]> - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this library; if not, see <http://www.gnu.org/licenses/>. -*/ - -#include "config.h" - -#include <stdio.h> -#include <stdlib.h> -#include <stdarg.h> -#include <string.h> -#include <getopt.h> -#include <unistd.h> -#include <errno.h> -#include <poll.h> -#include <fcntl.h> -#include <signal.h> -#include <sys/socket.h> -#include <sys/types.h> -#include <sys/time.h> -#include <netdb.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <netinet/tcp.h> -#include "usbredirhost.h" - - -#define SERVER_VERSION "usbredirserver " PACKAGE_VERSION - -#if !defined(SOL_TCP) && defined(IPPROTO_TCP) -#define SOL_TCP IPPROTO_TCP -#endif -#if !defined(TCP_KEEPIDLE) && defined(TCP_KEEPALIVE) && defined(__APPLE__) -#define TCP_KEEPIDLE TCP_KEEPALIVE -#endif - -static int verbose = usbredirparser_info; -static int client_fd, running = 1; -static libusb_context *ctx; -static struct usbredirhost *host; - -static const struct option longopts[] = { - { "port", required_argument, NULL, 'p' }, - { "verbose", required_argument, NULL, 'v' }, - { "ipv4", required_argument, NULL, '4' }, - { "ipv6", required_argument, NULL, '6' }, - { "keepalive", required_argument, NULL, 'k' }, - { "help", no_argument, NULL, 'h' }, - { NULL, 0, NULL, 0 } -}; - -static void usbredirserver_log(void *priv, int level, const char *msg) -{ - if (level <= verbose) - fprintf(stderr, "%s\n", msg); -} - -static int usbredirserver_read(void *priv, uint8_t *data, int count) -{ - int r = read(client_fd, data, count); - if (r < 0) { - if (errno == EAGAIN) - return 0; - return -1; - } - if (r == 0) { /* Client disconnected */ - close(client_fd); - client_fd = -1; - } - return r; -} - -static int usbredirserver_write(void *priv, uint8_t *data, int count) -{ - int r = write(client_fd, data, count); - if (r < 0) { - if (errno == EAGAIN) - return 0; - if (errno == EPIPE) { /* Client disconnected */ - close(client_fd); - client_fd = -1; - return 0; - } - return -1; - } - return r; -} - -static void usage(int exit_code, char *argv0) -{ - fprintf(exit_code? stderr:stdout, - "Usage: %s [-p|--port <port>] [-v|--verbose <0-5>] " - "[[-4|--ipv4 ipaddr]|[-6|--ipv6 ipaddr]] " - "[-k|--keepalive seconds] " - "<busnum-devnum|vendorid:prodid>\n", - argv0); - exit(exit_code); -} - -static void invalid_usb_device_id(char *usb_device_id, char *argv0) -{ - fprintf(stderr, "Invalid usb device identifier: %s\n", usb_device_id); - usage(1, argv0); -} - -static void run_main_loop(void) -{ - const struct libusb_pollfd **pollfds = NULL; - fd_set readfds, writefds; - int i, n, nfds; - struct timeval timeout, *timeout_p; - - while (running && client_fd != -1) { - FD_ZERO(&readfds); - FD_ZERO(&writefds); - - FD_SET(client_fd, &readfds); - if (usbredirhost_has_data_to_write(host)) { - FD_SET(client_fd, &writefds); - } - nfds = client_fd + 1; - - free(pollfds); - pollfds = libusb_get_pollfds(ctx); - for (i = 0; pollfds && pollfds[i]; i++) { - if (pollfds[i]->events & POLLIN) { - FD_SET(pollfds[i]->fd, &readfds); - } - if (pollfds[i]->events & POLLOUT) { - FD_SET(pollfds[i]->fd, &writefds); - } - if (pollfds[i]->fd >= nfds) - nfds = pollfds[i]->fd + 1; - } - - if (libusb_get_next_timeout(ctx, &timeout) == 1) { - timeout_p = &timeout; - } else { - timeout_p = NULL; - } - n = select(nfds, &readfds, &writefds, NULL, timeout_p); - if (n == -1) { - if (errno == EINTR) { - continue; - } - perror("select"); - break; - } - memset(&timeout, 0, sizeof(timeout)); - if (n == 0) { - libusb_handle_events_timeout(ctx, &timeout); - continue; - } - - if (FD_ISSET(client_fd, &readfds)) { - if (usbredirhost_read_guest_data(host)) { - break; - } - } - /* usbredirhost_read_guest_data may have detected client disconnect */ - if (client_fd == -1) - break; - - if (FD_ISSET(client_fd, &writefds)) { - if (usbredirhost_write_guest_data(host)) { - break; - } - } - - for (i = 0; pollfds && pollfds[i]; i++) { - if (FD_ISSET(pollfds[i]->fd, &readfds) || - FD_ISSET(pollfds[i]->fd, &writefds)) { - libusb_handle_events_timeout(ctx, &timeout); - break; - } - } - } - if (client_fd != -1) { /* Broken out of the loop because of an error ? */ - close(client_fd); - client_fd = -1; - } - free(pollfds); -} - -static void quit_handler(int sig) -{ - running = 0; -} - -int main(int argc, char *argv[]) -{ - int o, flags, server_fd = -1; - char *endptr, *delim; - int port = 4000; - int usbbus = -1; - int usbaddr = -1; - int usbvendor = -1; - int usbproduct = -1; - int on = 1; - int keepalive = -1; - char *ipv4_addr = NULL, *ipv6_addr = NULL; - union { - struct sockaddr_in v4; - struct sockaddr_in6 v6; - } serveraddr; - struct sigaction act; - libusb_device_handle *handle = NULL; - - while ((o = getopt_long(argc, argv, "hp:v:4:6:k:", longopts, NULL)) != -1) { - switch (o) { - case 'p': - port = strtol(optarg, &endptr, 10); - if (*endptr != '\0') { - fprintf(stderr, "Invalid value for --port: '%s'\n", optarg); - usage(1, argv[0]); - } - break; - case 'v': - verbose = strtol(optarg, &endptr, 10); - if (*endptr != '\0') { - fprintf(stderr, "Invalid value for --verbose: '%s'\n", optarg); - usage(1, argv[0]); - } - break; - case '4': - ipv4_addr = optarg; - break; - case '6': - ipv6_addr = optarg; - break; - case 'k': - keepalive = strtol(optarg, &endptr, 10); - if (*endptr != '\0') { - fprintf(stderr, "Invalid value for -k: '%s'\n", optarg); - usage(1, argv[0]); - } - break; - case '?': - case 'h': - usage(o == '?', argv[0]); - break; - } - } - if (optind == argc) { - fprintf(stderr, "Missing usb device identifier argument\n"); - usage(1, argv[0]); - } - delim = strchr(argv[optind], '-'); - if (delim && delim[1]) { - usbbus = strtol(argv[optind], &endptr, 10); - if (*endptr != '-') { - invalid_usb_device_id(argv[optind], argv[0]); - } - usbaddr = strtol(delim + 1, &endptr, 10); - if (*endptr != '\0') { - invalid_usb_device_id(argv[optind], argv[0]); - } - } else { - delim = strchr(argv[optind], ':'); - if (!delim || !delim[1]) { - invalid_usb_device_id(argv[optind], argv[0]); - } - usbvendor = strtol(argv[optind], &endptr, 16); - if (*endptr != ':' || usbvendor <= 0 || usbvendor > 0xffff) { - invalid_usb_device_id(argv[optind], argv[0]); - } - usbproduct = strtol(delim + 1, &endptr, 16); - /* Product ID 0000 is valid */ - if (*endptr != '\0' || usbproduct < 0 || usbproduct > 0xffff) { - invalid_usb_device_id(argv[optind], argv[0]); - } - } - optind++; - if (optind != argc) { - fprintf(stderr, "Excess non option arguments\n"); - usage(1, argv[0]); - } - - memset(&act, 0, sizeof(act)); - act.sa_handler = quit_handler; - sigaction(SIGINT, &act, NULL); - sigaction(SIGHUP, &act, NULL); - sigaction(SIGTERM, &act, NULL); - sigaction(SIGQUIT, &act, NULL); - - if (libusb_init(&ctx)) { - fprintf(stderr, "Could not init libusb\n"); - exit(1); - } - -#if LIBUSB_API_VERSION >= 0x01000106 - libusb_set_option(ctx, LIBUSB_OPTION_LOG_LEVEL, verbose); -#else - libusb_set_debug(ctx, verbose); -#endif - - if (ipv4_addr) { - server_fd = socket(AF_INET, SOCK_STREAM, 0); - } else { - server_fd = socket(AF_INET6, SOCK_STREAM, 0); - } - if (server_fd == -1) { - perror("Error creating ip socket"); - exit(1); - } - - if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) { - perror("Error setsockopt(SO_REUSEADDR) failed"); - exit(1); - } - - memset(&serveraddr, 0, sizeof(serveraddr)); - - if (ipv4_addr) { - serveraddr.v4.sin_family = AF_INET; - serveraddr.v4.sin_port = htons(port); - if ((inet_pton(AF_INET, ipv4_addr, - &serveraddr.v4.sin_addr)) != 1) { - perror("Error convert ipv4 address"); - exit(1); - } - } else { - serveraddr.v6.sin6_family = AF_INET6; - serveraddr.v6.sin6_port = htons(port); - if (ipv6_addr) { - if ((inet_pton(AF_INET6, ipv6_addr, - &serveraddr.v6.sin6_addr)) != 1) { - perror("Error convert ipv6 address"); - exit(1); - } - } else { - serveraddr.v6.sin6_addr = in6addr_any; - } - } - - if (bind(server_fd, (struct sockaddr *)&serveraddr, - sizeof(serveraddr))) { - perror("Error bind"); - exit(1); - } - - if (listen(server_fd, 1)) { - perror("Error listening"); - exit(1); - } - - while (running) { - client_fd = accept(server_fd, NULL, 0); - if (client_fd == -1) { - if (errno == EINTR) { - continue; - } - perror("accept"); - break; - } - - if (keepalive > 0) { - int optval = 1; - socklen_t optlen = sizeof(optval); - if (setsockopt(client_fd, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen) == -1) { - if (errno != ENOTSUP) { - perror("setsockopt SO_KEEPALIVE error."); - break; - } - } - optval = keepalive; /* set default TCP_KEEPIDLE time from cmdline */ - if (setsockopt(client_fd, SOL_TCP, TCP_KEEPIDLE, &optval, optlen) == -1) { - if (errno != ENOTSUP) { - perror("setsockopt TCP_KEEPIDLE error."); - break; - } - } - optval = 10; /* set default TCP_KEEPINTVL time as 10s */ - if (setsockopt(client_fd, SOL_TCP, TCP_KEEPINTVL, &optval, optlen) == -1) { - if (errno != ENOTSUP) { - perror("setsockopt TCP_KEEPINTVL error."); - break; - } - } - optval = 3; /* set default TCP_KEEPCNT as 3 */ - if (setsockopt(client_fd, SOL_TCP, TCP_KEEPCNT, &optval, optlen) == -1) { - if (errno != ENOTSUP) { - perror("setsockopt TCP_KEEPCNT error."); - break; - } - } - } - - flags = fcntl(client_fd, F_GETFL); - if (flags == -1) { - perror("fcntl F_GETFL"); - break; - } - flags = fcntl(client_fd, F_SETFL, flags | O_NONBLOCK); - if (flags == -1) { - perror("fcntl F_SETFL O_NONBLOCK"); - break; - } - - /* Try to find the specified usb device */ - if (usbvendor != -1) { - handle = libusb_open_device_with_vid_pid(ctx, usbvendor, - usbproduct); - if (!handle) { - fprintf(stderr, - "Could not open an usb-device with vid:pid %04x:%04x\n", - usbvendor, usbproduct); - } else if (verbose >= usbredirparser_info) { - libusb_device *dev; - dev = libusb_get_device(handle); - fprintf(stderr, "Open a usb-device with vid:pid %04x:%04x on " - "bus %03x device %03x\n", - usbvendor, usbproduct, - libusb_get_bus_number(dev), - libusb_get_device_address(dev)); - } - } else { - libusb_device **list = NULL; - ssize_t i, n; - - n = libusb_get_device_list(ctx, &list); - for (i = 0; i < n; i++) { - if (libusb_get_bus_number(list[i]) == usbbus && - libusb_get_device_address(list[i]) == usbaddr) - break; - } - if (i < n) { - if (libusb_open(list[i], &handle) != 0) { - fprintf(stderr, - "Could not open usb-device at busnum-devnum %d-%d\n", - usbbus, usbaddr); - } - } else { - fprintf(stderr, - "Could not find an usb-device at busnum-devnum %d-%d\n", - usbbus, usbaddr); - } - libusb_free_device_list(list, 1); - } - if (!handle) { - close(client_fd); - continue; - } - - host = usbredirhost_open(ctx, handle, usbredirserver_log, - usbredirserver_read, usbredirserver_write, - NULL, SERVER_VERSION, verbose, 0); - if (!host) - exit(1); - run_main_loop(); - usbredirhost_close(host); - handle = NULL; - } - - close(server_fd); - libusb_exit(ctx); - exit(0); -}
