commit
bdbd151ca0
@ -0,0 +1 @@
|
||||
SOURCES/usbredir-0.12.0.tar.xz
|
@ -0,0 +1 @@
|
||||
70940f6dc409b3bdb9ee98f24690c438f1ae999e SOURCES/usbredir-0.12.0.tar.xz
|
@ -0,0 +1,193 @@
|
||||
From 6bf41a231b445ac5190c32e281b698b1ee5379b4 Mon Sep 17 00:00:00 2001
|
||||
From: Victor Toso <victortoso@redhat.com>
|
||||
Date: Fri, 24 Jun 2022 23:29:08 +0200
|
||||
Subject: [PATCH 1/2] usbredirparser: Fix unserialize on pristine check
|
||||
Content-type: text/plain
|
||||
|
||||
As mentioned in the bug below, the user is trying to migrate QEMU and
|
||||
it is failing on the unserialization of usbredirparser at the target
|
||||
host. The user does not have USB attached to the VM at all.
|
||||
|
||||
I've added a test that shows that serialization is currently broken.
|
||||
It fails at the 'pristine' check in usbredirparser_unserialize().
|
||||
|
||||
This check was added with e37d86c "Skip empty write buffers when
|
||||
unserializing parser" and restricted further with 186c4c7 "Avoid
|
||||
memory leak from ill-formatted serialization data"
|
||||
|
||||
The issue here is that usbredirparser's initialization sets some
|
||||
fields and thus it isn't guaranteed to be pristine.
|
||||
|
||||
The parser's basic data is:
|
||||
|
||||
| write_buf_count ... : 1
|
||||
| write_buf ........ : 0xbc03e0
|
||||
| write_buf_total_size: 80
|
||||
| data ............. : (nil)
|
||||
| header_read: ...... : 0
|
||||
| type_header_read .. : 0
|
||||
| data_read: ........ : 0
|
||||
|
||||
The current fix is to to ignore write_buf checks as, again, they are
|
||||
not guaranteed to be pristine. usbredirparser library should properly
|
||||
overwrite them when unserializing the data and if there were pending
|
||||
buffers, they should be freed.
|
||||
|
||||
Related: https://bugzilla.redhat.com/show_bug.cgi?id=2096008
|
||||
|
||||
Signed-off-by: Victor Toso <victortoso@redhat.com>
|
||||
---
|
||||
tests/meson.build | 1 +
|
||||
tests/serializer.c | 113 ++++++++++++++++++++++++++++++++
|
||||
usbredirparser/usbredirparser.c | 4 +-
|
||||
3 files changed, 115 insertions(+), 3 deletions(-)
|
||||
create mode 100644 tests/serializer.c
|
||||
|
||||
diff --git a/tests/meson.build b/tests/meson.build
|
||||
index 0d4397b..2a179c9 100644
|
||||
--- a/tests/meson.build
|
||||
+++ b/tests/meson.build
|
||||
@@ -1,5 +1,6 @@
|
||||
tests = [
|
||||
'filter',
|
||||
+ 'serializer',
|
||||
]
|
||||
|
||||
deps = dependency('glib-2.0')
|
||||
diff --git a/tests/serializer.c b/tests/serializer.c
|
||||
new file mode 100644
|
||||
index 0000000..4bd669e
|
||||
--- /dev/null
|
||||
+++ b/tests/serializer.c
|
||||
@@ -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 --git a/usbredirparser/usbredirparser.c b/usbredirparser/usbredirparser.c
|
||||
index cd1136b..a5dd0e7 100644
|
||||
--- a/usbredirparser/usbredirparser.c
|
||||
+++ b/usbredirparser/usbredirparser.c
|
||||
@@ -1816,9 +1816,7 @@ int usbredirparser_unserialize(struct usbredirparser *parser_pub,
|
||||
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);
|
||||
--
|
||||
2.37.1
|
||||
|
@ -0,0 +1,63 @@
|
||||
From b93c4cae1aebda786a478677d6364308e4579ade Mon Sep 17 00:00:00 2001
|
||||
From: Victor Toso <victortoso@redhat.com>
|
||||
Date: Sat, 25 Jun 2022 00:29:12 +0200
|
||||
Subject: [PATCH 2/2] usbredirparser: reset parser's fields on unserialize
|
||||
Content-type: text/plain
|
||||
|
||||
This is a followup from previous commit and fixes the following leak.
|
||||
|
||||
| 104 (24 direct, 80 indirect) bytes in 1 blocks are definitely lost in loss record 15 of 19
|
||||
| at 0x484A464: calloc (vg_replace_malloc.c:1328)
|
||||
| by 0x485A238: usbredirparser_queue (usbredirparser.c:1235)
|
||||
| by 0x485A571: usbredirparser_init (usbredirparser.c:227)
|
||||
| by 0x40130B: get_usbredirparser (serializer.c:77)
|
||||
| by 0x401379: simple (serializer.c:95)
|
||||
| by 0x48FA3DD: ??? (in /usr/lib64/libglib-2.0.so.0.7200.2)
|
||||
| by 0x48FA144: ??? (in /usr/lib64/libglib-2.0.so.0.7200.2)
|
||||
| by 0x48FA8E1: g_test_run_suite (in /usr/lib64/libglib-2.0.so.0.7200.2)
|
||||
| by 0x48FA94C: g_test_run (in /usr/lib64/libglib-2.0.so.0.7200.2)
|
||||
| by 0x401161: main (serializer.c:112)
|
||||
|
|
||||
| LEAK SUMMARY:
|
||||
| definitely lost: 24 bytes in 1 blocks
|
||||
| indirectly lost: 80 bytes in 1 blocks
|
||||
| possibly lost: 0 bytes in 0 blocks
|
||||
| still reachable: 25,500 bytes in 17 blocks
|
||||
| suppressed: 0 bytes in 0 blocks
|
||||
| Reachable blocks (those to which a pointer was found) are not shown.
|
||||
| To see them, rerun with: --leak-check=full --show-leak-kinds=all
|
||||
|
||||
Signed-off-by: Victor Toso <victortoso@redhat.com>
|
||||
---
|
||||
usbredirparser/usbredirparser.c | 15 +++++++++++++++
|
||||
1 file changed, 15 insertions(+)
|
||||
|
||||
diff --git a/usbredirparser/usbredirparser.c b/usbredirparser/usbredirparser.c
|
||||
index a5dd0e7..9bfc27c 100644
|
||||
--- a/usbredirparser/usbredirparser.c
|
||||
+++ b/usbredirparser/usbredirparser.c
|
||||
@@ -1823,6 +1823,21 @@ int usbredirparser_unserialize(struct usbredirparser *parser_pub,
|
||||
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;
|
||||
--
|
||||
2.37.1
|
||||
|
@ -0,0 +1,135 @@
|
||||
From e30b0ce5c46c0e2a75b6e38759876ba1369b2168 Mon Sep 17 00:00:00 2001
|
||||
From: Frediano Ziglio <freddy77@gmail.com>
|
||||
Date: Fri, 16 Sep 2022 20:14:28 +0100
|
||||
Subject: [PATCH 3/8] Use typedef on redirect structure to simplify some
|
||||
statements
|
||||
|
||||
Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
|
||||
---
|
||||
tools/usbredirect.c | 26 +++++++++++++-------------
|
||||
1 file changed, 13 insertions(+), 13 deletions(-)
|
||||
|
||||
diff --git a/tools/usbredirect.c b/tools/usbredirect.c
|
||||
index 98e5a8c..89a42a6 100644
|
||||
--- a/tools/usbredirect.c
|
||||
+++ b/tools/usbredirect.c
|
||||
@@ -22,7 +22,7 @@
|
||||
#include <gio/gwin32outputstream.h>
|
||||
#endif
|
||||
|
||||
-struct redirect {
|
||||
+typedef struct redirect {
|
||||
struct {
|
||||
int vendor;
|
||||
int product;
|
||||
@@ -40,7 +40,7 @@ struct redirect {
|
||||
int watch_server_id;
|
||||
|
||||
GMainLoop *main_loop;
|
||||
-};
|
||||
+} redirect;
|
||||
|
||||
static bool
|
||||
parse_opt_device(const char *device, int *vendor, int *product)
|
||||
@@ -124,7 +124,7 @@ parse_opt_uri(const char *uri, char **adr, int *port)
|
||||
return true;
|
||||
}
|
||||
|
||||
-static struct redirect *
|
||||
+static redirect *
|
||||
parse_opts(int *argc, char ***argv)
|
||||
{
|
||||
char *device = NULL;
|
||||
@@ -132,7 +132,7 @@ parse_opts(int *argc, char ***argv)
|
||||
char *localaddr = NULL;
|
||||
gboolean keepalive = FALSE;
|
||||
gint verbosity = 0; /* none */
|
||||
- struct redirect *self = NULL;
|
||||
+ redirect *self = NULL;
|
||||
|
||||
GOptionEntry entries[] = {
|
||||
{ "device", 0, 0, G_OPTION_ARG_STRING, &device, "Local USB device to be redirected", NULL },
|
||||
@@ -161,7 +161,7 @@ parse_opts(int *argc, char ***argv)
|
||||
goto end;
|
||||
}
|
||||
|
||||
- self = g_new0(struct redirect, 1);
|
||||
+ self = g_new0(redirect, 1);
|
||||
if (!parse_opt_device(device, &self->device.vendor, &self->device.product)) {
|
||||
g_printerr("Failed to parse device: '%s' - expected: vendor:product or busnum-devnum\n", device);
|
||||
g_clear_pointer(&self, g_free);
|
||||
@@ -201,7 +201,7 @@ end:
|
||||
static gpointer
|
||||
thread_handle_libusb_events(gpointer user_data)
|
||||
{
|
||||
- struct redirect *self = (struct redirect *) user_data;
|
||||
+ redirect *self = (redirect *) user_data;
|
||||
|
||||
int res = 0;
|
||||
const char *desc = "";
|
||||
@@ -279,7 +279,7 @@ usbredir_log_cb(void *priv, int level, const char *msg)
|
||||
static int
|
||||
usbredir_read_cb(void *priv, uint8_t *data, int count)
|
||||
{
|
||||
- struct redirect *self = (struct redirect *) priv;
|
||||
+ redirect *self = (redirect *) priv;
|
||||
GIOStream *iostream = G_IO_STREAM(self->connection);
|
||||
GError *err = NULL;
|
||||
|
||||
@@ -307,7 +307,7 @@ usbredir_read_cb(void *priv, uint8_t *data, int count)
|
||||
static int
|
||||
usbredir_write_cb(void *priv, uint8_t *data, int count)
|
||||
{
|
||||
- struct redirect *self = (struct redirect *) priv;
|
||||
+ redirect *self = (redirect *) priv;
|
||||
GIOStream *iostream = G_IO_STREAM(self->connection);
|
||||
GError *err = NULL;
|
||||
|
||||
@@ -335,7 +335,7 @@ usbredir_write_cb(void *priv, uint8_t *data, int count)
|
||||
static void
|
||||
usbredir_write_flush_cb(void *user_data)
|
||||
{
|
||||
- struct redirect *self = (struct redirect *) user_data;
|
||||
+ redirect *self = (redirect *) user_data;
|
||||
if (!self || !self->usbredirhost) {
|
||||
return;
|
||||
}
|
||||
@@ -386,7 +386,7 @@ usbredir_unlock_lock(void *user_data)
|
||||
static gboolean
|
||||
connection_handle_io_cb(GIOChannel *source, GIOCondition condition, gpointer user_data)
|
||||
{
|
||||
- struct redirect *self = (struct redirect *) user_data;
|
||||
+ redirect *self = (redirect *) user_data;
|
||||
|
||||
if (condition & G_IO_ERR || condition & G_IO_HUP) {
|
||||
g_warning("Connection: err=%d, hup=%d - exiting", (condition & G_IO_ERR), (condition & G_IO_HUP));
|
||||
@@ -418,7 +418,7 @@ end:
|
||||
static gboolean
|
||||
signal_handler(gpointer user_data)
|
||||
{
|
||||
- struct redirect *self = (struct redirect *) user_data;
|
||||
+ redirect *self = (redirect *) user_data;
|
||||
g_main_loop_quit(self->main_loop);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
@@ -430,7 +430,7 @@ connection_incoming_cb(GSocketService *service,
|
||||
GObject *source_object,
|
||||
gpointer user_data)
|
||||
{
|
||||
- struct redirect *self = (struct redirect *) user_data;
|
||||
+ redirect *self = (redirect *) user_data;
|
||||
self->connection = g_object_ref(client_connection);
|
||||
|
||||
/* Add a GSource watch to handle polling for us and handle IO in the callback */
|
||||
@@ -455,7 +455,7 @@ main(int argc, char *argv[])
|
||||
goto err_init;
|
||||
}
|
||||
|
||||
- struct redirect *self = parse_opts(&argc, &argv);
|
||||
+ redirect *self = parse_opts(&argc, &argv);
|
||||
if (!self) {
|
||||
/* specific issues logged in parse_opts() */
|
||||
return 1;
|
||||
--
|
||||
2.39.0
|
||||
|
@ -0,0 +1,74 @@
|
||||
From 5399d3d5ce420891adfd4beedb023515a28ceab1 Mon Sep 17 00:00:00 2001
|
||||
From: Frediano Ziglio <freddy77@gmail.com>
|
||||
Date: Fri, 16 Sep 2022 20:14:28 +0100
|
||||
Subject: [PATCH 4/8] Factor out a function to create watches
|
||||
|
||||
---
|
||||
tools/usbredirect.c | 37 ++++++++++++++++++++-----------------
|
||||
1 file changed, 20 insertions(+), 17 deletions(-)
|
||||
|
||||
diff --git a/tools/usbredirect.c b/tools/usbredirect.c
|
||||
index 89a42a6..6a8b68b 100644
|
||||
--- a/tools/usbredirect.c
|
||||
+++ b/tools/usbredirect.c
|
||||
@@ -414,6 +414,24 @@ end:
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
+static void
|
||||
+create_watch(redirect *self)
|
||||
+{
|
||||
+ GSocket *socket = g_socket_connection_get_socket(self->connection);
|
||||
+ int socket_fd = g_socket_get_fd(socket);
|
||||
+ GIOChannel *io_channel =
|
||||
+#ifdef G_OS_UNIX
|
||||
+ g_io_channel_unix_new(socket_fd);
|
||||
+#else
|
||||
+ g_io_channel_win32_new_socket(socket_fd);
|
||||
+#endif
|
||||
+
|
||||
+ self->watch_server_id = g_io_add_watch(io_channel,
|
||||
+ G_IO_IN | G_IO_OUT | G_IO_HUP | G_IO_ERR,
|
||||
+ connection_handle_io_cb,
|
||||
+ self);
|
||||
+}
|
||||
+
|
||||
#ifdef G_OS_UNIX
|
||||
static gboolean
|
||||
signal_handler(gpointer user_data)
|
||||
@@ -436,12 +454,7 @@ connection_incoming_cb(GSocketService *service,
|
||||
/* Add a GSource watch to handle polling for us and handle IO in the callback */
|
||||
GSocket *connection_socket = g_socket_connection_get_socket(self->connection);
|
||||
g_socket_set_keepalive(connection_socket, self->keepalive);
|
||||
- int socket_fd = g_socket_get_fd(connection_socket);
|
||||
- GIOChannel *io_channel = g_io_channel_unix_new(socket_fd);
|
||||
- self->watch_server_id = g_io_add_watch(io_channel,
|
||||
- G_IO_IN | G_IO_OUT | G_IO_HUP | G_IO_ERR,
|
||||
- connection_handle_io_cb,
|
||||
- self);
|
||||
+ create_watch(self);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
@@ -551,17 +564,7 @@ main(int argc, char *argv[])
|
||||
|
||||
GSocket *connection_socket = g_socket_connection_get_socket(self->connection);
|
||||
g_socket_set_keepalive(connection_socket, self->keepalive);
|
||||
- int socket_fd = g_socket_get_fd(connection_socket);
|
||||
- GIOChannel *io_channel =
|
||||
-#ifdef G_OS_UNIX
|
||||
- g_io_channel_unix_new(socket_fd);
|
||||
-#else
|
||||
- g_io_channel_win32_new_socket(socket_fd);
|
||||
-#endif
|
||||
- self->watch_server_id = g_io_add_watch(io_channel,
|
||||
- G_IO_IN | G_IO_OUT | G_IO_HUP | G_IO_ERR,
|
||||
- connection_handle_io_cb,
|
||||
- self);
|
||||
+ create_watch(self);
|
||||
} else {
|
||||
GSocketService *socket_service;
|
||||
|
||||
--
|
||||
2.39.0
|
||||
|
@ -0,0 +1,106 @@
|
||||
From f5e24c5cf77b92ab2737eb230db7ae0b2fb102cc Mon Sep 17 00:00:00 2001
|
||||
From: Frediano Ziglio <freddy77@gmail.com>
|
||||
Date: Sat, 17 Sep 2022 09:28:08 +0100
|
||||
Subject: [PATCH 5/8] Recreate watch if needed
|
||||
|
||||
Do not always watch for output buffer.
|
||||
Watching for output buffer if we don't have nothing to write
|
||||
(which is the usual case) is consuming a lot of CPU.
|
||||
|
||||
This fixes https://gitlab.freedesktop.org/spice/usbredir/-/issues/24.
|
||||
|
||||
Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
|
||||
---
|
||||
tools/usbredirect.c | 28 ++++++++++++++++++++++++++--
|
||||
1 file changed, 26 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/tools/usbredirect.c b/tools/usbredirect.c
|
||||
index 6a8b68b..b6a30ad 100644
|
||||
--- a/tools/usbredirect.c
|
||||
+++ b/tools/usbredirect.c
|
||||
@@ -29,6 +29,7 @@ typedef struct redirect {
|
||||
} device;
|
||||
bool is_client;
|
||||
bool keepalive;
|
||||
+ bool watch_inout;
|
||||
char *addr;
|
||||
int port;
|
||||
int verbosity;
|
||||
@@ -42,6 +43,8 @@ typedef struct redirect {
|
||||
GMainLoop *main_loop;
|
||||
} redirect;
|
||||
|
||||
+static void create_watch(redirect *self);
|
||||
+
|
||||
static bool
|
||||
parse_opt_device(const char *device, int *vendor, int *product)
|
||||
{
|
||||
@@ -162,6 +165,7 @@ parse_opts(int *argc, char ***argv)
|
||||
}
|
||||
|
||||
self = g_new0(redirect, 1);
|
||||
+ self->watch_inout = true;
|
||||
if (!parse_opt_device(device, &self->device.vendor, &self->device.product)) {
|
||||
g_printerr("Failed to parse device: '%s' - expected: vendor:product or busnum-devnum\n", device);
|
||||
g_clear_pointer(&self, g_free);
|
||||
@@ -276,6 +280,20 @@ usbredir_log_cb(void *priv, int level, const char *msg)
|
||||
g_log_structured(G_LOG_DOMAIN, glog_level, "MESSAGE", msg);
|
||||
}
|
||||
|
||||
+static void
|
||||
+update_watch(redirect *self)
|
||||
+{
|
||||
+ const bool watch_inout = usbredirhost_has_data_to_write(self->usbredirhost) != 0;
|
||||
+ if (watch_inout == self->watch_inout) {
|
||||
+ return;
|
||||
+ }
|
||||
+ g_source_remove(self->watch_server_id);
|
||||
+ self->watch_server_id = 0;
|
||||
+ self->watch_inout = watch_inout;
|
||||
+
|
||||
+ create_watch(self);
|
||||
+}
|
||||
+
|
||||
static int
|
||||
usbredir_read_cb(void *priv, uint8_t *data, int count)
|
||||
{
|
||||
@@ -321,6 +339,7 @@ usbredir_write_cb(void *priv, uint8_t *data, int count)
|
||||
if (g_error_matches(err, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) {
|
||||
/* Try again later */
|
||||
nbytes = 0;
|
||||
+ update_watch(self);
|
||||
} else {
|
||||
if (err != NULL) {
|
||||
g_warning("Failure at %s: %s", __func__, err->message);
|
||||
@@ -400,13 +419,18 @@ connection_handle_io_cb(GIOChannel *source, GIOCondition condition, gpointer use
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
- if (condition & G_IO_OUT) {
|
||||
+ // try to write data in any case, to avoid having another iteration and
|
||||
+ // creation of another watch if there is space in output buffer
|
||||
+ if (usbredirhost_has_data_to_write(self->usbredirhost) != 0) {
|
||||
int ret = usbredirhost_write_guest_data(self->usbredirhost);
|
||||
if (ret < 0) {
|
||||
g_critical("%s: Failed to write to guest", __func__);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
+
|
||||
+ // update the watch if needed
|
||||
+ update_watch(self);
|
||||
return G_SOURCE_CONTINUE;
|
||||
|
||||
end:
|
||||
@@ -427,7 +451,7 @@ create_watch(redirect *self)
|
||||
#endif
|
||||
|
||||
self->watch_server_id = g_io_add_watch(io_channel,
|
||||
- G_IO_IN | G_IO_OUT | G_IO_HUP | G_IO_ERR,
|
||||
+ G_IO_IN | G_IO_HUP | G_IO_ERR | (self->watch_inout ? G_IO_OUT : 0),
|
||||
connection_handle_io_cb,
|
||||
self);
|
||||
}
|
||||
--
|
||||
2.39.0
|
||||
|
@ -0,0 +1,51 @@
|
||||
From b3482e8d8f8970d481b9bfdb6662a8b67a973537 Mon Sep 17 00:00:00 2001
|
||||
From: John Call <johnsimcall@gmail.com>
|
||||
Date: Mon, 19 Dec 2022 19:01:50 +0000
|
||||
Subject: [PATCH 6/8] Add documentation examples for using bus-device
|
||||
identification
|
||||
|
||||
---
|
||||
tools/usbredirect.1 | 6 ++++++
|
||||
tools/usbredirect.c | 2 +-
|
||||
2 files changed, 7 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/tools/usbredirect.1 b/tools/usbredirect.1
|
||||
index d6b2a63..2be8be0 100644
|
||||
--- a/tools/usbredirect.1
|
||||
+++ b/tools/usbredirect.1
|
||||
@@ -4,6 +4,9 @@ usbredirect \- exporting an USB device for use from another (virtual) machine
|
||||
.SH SYNOPSIS
|
||||
.B usbredirect
|
||||
[\fI--device vendor:product\fR] [\fI--to addr:port\fR] [\fI--as addr:port\fR]
|
||||
+.br
|
||||
+.B usbredirect
|
||||
+[\fI--device bus-device\fR] [\fI--to addr:port\fR] [\fI--as addr:port\fR]
|
||||
.SH DESCRIPTION
|
||||
usbredirect is an usbredir client for exporting an USB device either as TCP
|
||||
client or server, for use from another (virtual) machine through the usbredir
|
||||
@@ -11,6 +14,9 @@ protocol.
|
||||
.PP
|
||||
You can specify the USB device to export by USB id in the form of
|
||||
\fI<vendorid>:<prodid>\fR.
|
||||
+.br
|
||||
+Or you can specify the USB device to export in the form of
|
||||
+\fI<busnum>-<devnum>\fR.
|
||||
.PP
|
||||
Notice that an instance of usbredirect can only be used to export a single USB
|
||||
device and it will close once the other side closes the connection. If you
|
||||
diff --git a/tools/usbredirect.c b/tools/usbredirect.c
|
||||
index b6a30ad..95f3580 100644
|
||||
--- a/tools/usbredirect.c
|
||||
+++ b/tools/usbredirect.c
|
||||
@@ -138,7 +138,7 @@ parse_opts(int *argc, char ***argv)
|
||||
redirect *self = NULL;
|
||||
|
||||
GOptionEntry entries[] = {
|
||||
- { "device", 0, 0, G_OPTION_ARG_STRING, &device, "Local USB device to be redirected", NULL },
|
||||
+ { "device", 0, 0, G_OPTION_ARG_STRING, &device, "Local USB device to be redirected identified as either VENDOR:PRODUCT \"0123:4567\" or BUS-DEVICE \"5-2\"", NULL },
|
||||
{ "to", 0, 0, G_OPTION_ARG_STRING, &remoteaddr, "Client URI to connect to", NULL },
|
||||
{ "as", 0, 0, G_OPTION_ARG_STRING, &localaddr, "Server URI to be run", NULL },
|
||||
{ "keepalive", 'k', 0, G_OPTION_ARG_NONE, &keepalive, "If we should set SO_KEEPALIVE flag on underlying socket", NULL },
|
||||
--
|
||||
2.39.0
|
||||
|
@ -0,0 +1,136 @@
|
||||
From 813afe206c8ff10cbbe715bf94980bf8ba6be70f Mon Sep 17 00:00:00 2001
|
||||
From: Victor Toso <victortoso@redhat.com>
|
||||
Date: Thu, 22 Dec 2022 16:13:08 +0100
|
||||
Subject: [PATCH 7/8] usbredirect: allow multiple devices by vendor:product
|
||||
|
||||
Currently, if an user tries to redirect two devices with the same
|
||||
vendor:product info, the second instance of usbredirect will not
|
||||
succeed, leading to a segmentation fault.
|
||||
|
||||
The core of the problem is that usbredirect is using
|
||||
libusb_open_device_with_vid_pid() which always returns the first
|
||||
instance of a given vendor:product, leading the second instance of
|
||||
usbredirect to give an usb device that is in use to usbredirhost.
|
||||
|
||||
This patch fixes the situation, making it possible to run usbredirect
|
||||
with --device $vendor:$product multiple times. We do a early check
|
||||
that we can claim the usb device, prior to handle it over to
|
||||
usbredirhost.
|
||||
|
||||
Related: https://gitlab.freedesktop.org/spice/usbredir/-/issues/29
|
||||
Signed-off-by: Victor Toso <victortoso@redhat.com>
|
||||
---
|
||||
tools/usbredirect.c | 90 ++++++++++++++++++++++++++++++++++++++++++---
|
||||
1 file changed, 85 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/tools/usbredirect.c b/tools/usbredirect.c
|
||||
index 95f3580..0b04418 100644
|
||||
--- a/tools/usbredirect.c
|
||||
+++ b/tools/usbredirect.c
|
||||
@@ -466,6 +466,90 @@ signal_handler(gpointer user_data)
|
||||
}
|
||||
#endif
|
||||
|
||||
+static bool
|
||||
+can_claim_usb_device(libusb_device *dev, libusb_device_handle **handle)
|
||||
+{
|
||||
+ int ret = libusb_open(dev, handle);
|
||||
+ if (ret != 0) {
|
||||
+ g_debug("Failed to open device");
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ /* Opening is not enough. We need to check if device can be claimed
|
||||
+ * for I/O operations */
|
||||
+ struct libusb_config_descriptor *config = NULL;
|
||||
+ ret = libusb_get_active_config_descriptor(dev, &config);
|
||||
+ if (ret != 0 || config == NULL) {
|
||||
+ g_debug("Failed to get active descriptor");
|
||||
+ *handle = NULL;
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+#if LIBUSBX_API_VERSION >= 0x01000102
|
||||
+ libusb_set_auto_detach_kernel_driver(*handle, 1);
|
||||
+#endif
|
||||
+
|
||||
+ int i;
|
||||
+ for (i = 0; i < config->bNumInterfaces; i++) {
|
||||
+ int interface_num = config->interface[i].altsetting[0].bInterfaceNumber;
|
||||
+#if LIBUSBX_API_VERSION < 0x01000102
|
||||
+ ret = libusb_detach_kernel_driver(handle, interface_num);
|
||||
+ if (ret != 0 && ret != LIBUSB_ERROR_NOT_FOUND
|
||||
+ && ret != LIBUSB_ERROR_NOT_SUPPORTED) {
|
||||
+ g_error("failed to detach driver from interface %d: %s",
|
||||
+ interface_num, libusb_error_name(ret));
|
||||
+ *handle = NULL;
|
||||
+ break
|
||||
+ }
|
||||
+#endif
|
||||
+ ret = libusb_claim_interface(*handle, interface_num);
|
||||
+ if (ret != 0) {
|
||||
+ g_debug("Could not claim interface");
|
||||
+ *handle = NULL;
|
||||
+ break;
|
||||
+ }
|
||||
+ ret = libusb_release_interface(*handle, interface_num);
|
||||
+ if (ret != 0) {
|
||||
+ g_debug("Could not release interface");
|
||||
+ *handle = NULL;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ libusb_free_config_descriptor(config);
|
||||
+ return *handle != NULL;
|
||||
+}
|
||||
+
|
||||
+static libusb_device_handle *
|
||||
+open_usb_device(redirect *self)
|
||||
+{
|
||||
+ struct libusb_device **devs;
|
||||
+ struct libusb_device_handle *dev_handle = NULL;
|
||||
+ size_t i, ndevices;
|
||||
+
|
||||
+ ndevices = libusb_get_device_list(NULL, &devs);
|
||||
+ for (i = 0; i < ndevices; i++) {
|
||||
+ struct libusb_device_descriptor desc;
|
||||
+ if (libusb_get_device_descriptor(devs[i], &desc) != 0) {
|
||||
+ g_warning("Failed to get descriptor");
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (self->device.vendor != desc.idVendor ||
|
||||
+ self->device.product != desc.idProduct) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (can_claim_usb_device(devs[i], &dev_handle)) {
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ libusb_free_device_list(devs, 1);
|
||||
+ return dev_handle;
|
||||
+}
|
||||
+
|
||||
+
|
||||
static gboolean
|
||||
connection_incoming_cb(GSocketService *service,
|
||||
GSocketConnection *client_connection,
|
||||
@@ -515,11 +599,7 @@ main(int argc, char *argv[])
|
||||
g_unix_signal_add(SIGTERM, signal_handler, self);
|
||||
#endif
|
||||
|
||||
- /* This is binary is not meant to support plugins so it is safe to pass
|
||||
- * NULL as libusb_context here and all subsequent calls */
|
||||
- libusb_device_handle *device_handle = libusb_open_device_with_vid_pid(NULL,
|
||||
- self->device.vendor,
|
||||
- self->device.product);
|
||||
+ libusb_device_handle *device_handle = open_usb_device(self);
|
||||
if (!device_handle) {
|
||||
g_printerr("Failed to open device!\n");
|
||||
goto err_init;
|
||||
--
|
||||
2.39.0
|
||||
|
@ -0,0 +1,153 @@
|
||||
From c32774c8a46aa04bf8f882ea552df8cb2d9f3a59 Mon Sep 17 00:00:00 2001
|
||||
From: Victor Toso <victortoso@redhat.com>
|
||||
Date: Thu, 22 Dec 2022 16:58:43 +0100
|
||||
Subject: [PATCH 8/8] usbredirect: use the correct bus-device
|
||||
|
||||
This patch is a continuation from:
|
||||
"usbredirect: allow multiple devices by vendor:product"
|
||||
|
||||
As we were using libusb_open_device_with_vid_pid(), if an user
|
||||
requested that device on 2-3 was redirected, we would instead get the
|
||||
vendor and product info of device on 2-3 and use that info to pick a
|
||||
usb device. This is wrong when multiple devices that shared
|
||||
vendor:product are plugged as libbusb_open_device_with_vid_pid()
|
||||
always return the same (first) device.
|
||||
|
||||
This commit now stores bus-device info and uses that to pick the usb
|
||||
device to redirect.
|
||||
|
||||
Related: https://gitlab.freedesktop.org/spice/usbredir/-/issues/29
|
||||
Signed-off-by: Victor Toso <victortoso@redhat.com>
|
||||
---
|
||||
tools/usbredirect.c | 63 ++++++++++++++++++++-------------------------
|
||||
1 file changed, 28 insertions(+), 35 deletions(-)
|
||||
|
||||
diff --git a/tools/usbredirect.c b/tools/usbredirect.c
|
||||
index 0b04418..cad9d23 100644
|
||||
--- a/tools/usbredirect.c
|
||||
+++ b/tools/usbredirect.c
|
||||
@@ -24,9 +24,14 @@
|
||||
|
||||
typedef struct redirect {
|
||||
struct {
|
||||
+ /* vendor:product */
|
||||
int vendor;
|
||||
int product;
|
||||
+ /* bus-device */
|
||||
+ int bus;
|
||||
+ int device_number;
|
||||
} device;
|
||||
+ bool by_bus;
|
||||
bool is_client;
|
||||
bool keepalive;
|
||||
bool watch_inout;
|
||||
@@ -46,7 +51,7 @@ typedef struct redirect {
|
||||
static void create_watch(redirect *self);
|
||||
|
||||
static bool
|
||||
-parse_opt_device(const char *device, int *vendor, int *product)
|
||||
+parse_opt_device(redirect *self, const char *device)
|
||||
{
|
||||
if (!device) {
|
||||
g_warning("No device to redirect. For testing only\n");
|
||||
@@ -54,37 +59,15 @@ parse_opt_device(const char *device, int *vendor, int *product)
|
||||
}
|
||||
|
||||
if (g_strrstr(device, "-") != NULL) {
|
||||
- /* Get vendor and product by bus and address number */
|
||||
+ self->by_bus = true;
|
||||
char **usbid = g_strsplit(device, "-", 2);
|
||||
if (usbid == NULL || usbid[0] == NULL || usbid[1] == NULL || usbid[2] != NULL) {
|
||||
g_strfreev(usbid);
|
||||
return false;
|
||||
}
|
||||
- gint64 bus = g_ascii_strtoll(usbid[0], NULL, 10);
|
||||
- gint64 addr = g_ascii_strtoll(usbid[1], NULL, 10);
|
||||
-
|
||||
- libusb_device **list = NULL;
|
||||
- ssize_t i, n;
|
||||
-
|
||||
- n = libusb_get_device_list(NULL, &list);
|
||||
- for (i = 0; i < n; i++) {
|
||||
- if (libusb_get_bus_number(list[i]) == bus &&
|
||||
- libusb_get_device_address(list[i]) == addr) {
|
||||
- break;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- if (i == n) {
|
||||
- libusb_free_device_list(list, true);
|
||||
- return false;
|
||||
- }
|
||||
-
|
||||
- struct libusb_device_descriptor desc;
|
||||
- libusb_get_device_descriptor(list[i], &desc);
|
||||
- *vendor = desc.idVendor;
|
||||
- *product = desc.idProduct;
|
||||
-
|
||||
- libusb_free_device_list(list, true);
|
||||
+ self->device.bus = g_ascii_strtoll(usbid[0], NULL, 10);
|
||||
+ self->device.device_number = g_ascii_strtoll(usbid[1], NULL, 10);
|
||||
+ g_strfreev(usbid);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -94,12 +77,14 @@ parse_opt_device(const char *device, int *vendor, int *product)
|
||||
return false;
|
||||
}
|
||||
|
||||
- *vendor = g_ascii_strtoll(usbid[0], NULL, 16);
|
||||
- *product = g_ascii_strtoll(usbid[1], NULL, 16);
|
||||
+ self->device.vendor = g_ascii_strtoll(usbid[0], NULL, 16);
|
||||
+ self->device.product = g_ascii_strtoll(usbid[1], NULL, 16);
|
||||
g_strfreev(usbid);
|
||||
|
||||
- if (*vendor <= 0 || *vendor > 0xffff || *product < 0 || *product > 0xffff) {
|
||||
- g_printerr("Bad vendor:product values %04x:%04x", *vendor, *product);
|
||||
+ if (self->device.vendor <= 0 || self->device.vendor > 0xffff ||
|
||||
+ self->device.product < 0 || self->device.product > 0xffff) {
|
||||
+ g_printerr("Bad vendor:product values %04x:%04x",
|
||||
+ self->device.vendor, self->device.product);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -166,7 +151,7 @@ parse_opts(int *argc, char ***argv)
|
||||
|
||||
self = g_new0(redirect, 1);
|
||||
self->watch_inout = true;
|
||||
- if (!parse_opt_device(device, &self->device.vendor, &self->device.product)) {
|
||||
+ if (!parse_opt_device(self, device)) {
|
||||
g_printerr("Failed to parse device: '%s' - expected: vendor:product or busnum-devnum\n", device);
|
||||
g_clear_pointer(&self, g_free);
|
||||
goto end;
|
||||
@@ -535,9 +520,16 @@ open_usb_device(redirect *self)
|
||||
continue;
|
||||
}
|
||||
|
||||
- if (self->device.vendor != desc.idVendor ||
|
||||
- self->device.product != desc.idProduct) {
|
||||
- continue;
|
||||
+ if (self->by_bus &&
|
||||
+ (self->device.bus != libusb_get_bus_number(devs[i]) ||
|
||||
+ self->device.device_number != libusb_get_device_address(devs[i]))) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (!self->by_bus &&
|
||||
+ (self->device.vendor != desc.idVendor ||
|
||||
+ self->device.product != desc.idProduct)) {
|
||||
+ continue;
|
||||
}
|
||||
|
||||
if (can_claim_usb_device(devs[i], &dev_handle)) {
|
||||
@@ -674,6 +666,7 @@ main(int argc, char *argv[])
|
||||
|
||||
socket_service = g_socket_service_new ();
|
||||
GInetAddress *iaddr = g_inet_address_new_loopback(G_SOCKET_FAMILY_IPV4);
|
||||
+
|
||||
GSocketAddress *saddr = g_inet_socket_address_new(iaddr, self->port);
|
||||
g_object_unref(iaddr);
|
||||
|
||||
--
|
||||
2.39.0
|
||||
|
@ -0,0 +1,207 @@
|
||||
Name: usbredir
|
||||
Version: 0.12.0
|
||||
Release: 4%{?dist}
|
||||
Summary: USB network redirection protocol libraries
|
||||
Group: System Environment/Libraries
|
||||
License: LGPLv2+
|
||||
URL: https://www.spice-space.org/usbredir.html
|
||||
Source0: http://spice-space.org/download/%{name}/%{name}-%{version}.tar.xz
|
||||
Patch0001: 0001-usbredirparser-Fix-unserialize-on-pristine-check.patch
|
||||
Patch0002: 0002-usbredirparser-reset-parser-s-fields-on-unserialize.patch
|
||||
Patch0003: 0003-Use-typedef-on-redirect-structure-to-simplify-some-s.patch
|
||||
Patch0004: 0004-Factor-out-a-function-to-create-watches.patch
|
||||
Patch0005: 0005-Recreate-watch-if-needed.patch
|
||||
Patch0006: 0006-Add-documentation-examples-for-using-bus-device-iden.patch
|
||||
Patch0007: 0007-usbredirect-allow-multiple-devices-by-vendor-product.patch
|
||||
Patch0008: 0008-usbredirect-use-the-correct-bus-device.patch
|
||||
BuildRequires: glib2-devel
|
||||
BuildRequires: libusb1-devel >= 1.0.9
|
||||
BuildRequires: git-core
|
||||
BuildRequires: meson
|
||||
|
||||
%description
|
||||
The usbredir libraries allow USB devices to be used on remote and/or virtual
|
||||
hosts over TCP. The following libraries are provided:
|
||||
|
||||
usbredirparser:
|
||||
A library containing the parser for the usbredir protocol
|
||||
|
||||
usbredirhost:
|
||||
A library implementing the USB host side of a usbredir connection.
|
||||
All that an application wishing to implement a USB host needs to do is:
|
||||
* Provide a libusb device handle for the device
|
||||
* Provide write and read callbacks for the actual transport of usbredir data
|
||||
* Monitor for usbredir and libusb read/write events and call their handlers
|
||||
|
||||
|
||||
%package devel
|
||||
Summary: Development files for %{name}
|
||||
Group: Development/Libraries
|
||||
Requires: %{name}%{?_isa} = %{version}-%{release}
|
||||
|
||||
%description devel
|
||||
The %{name}-devel package contains libraries and header files for
|
||||
developing applications that use %{name}.
|
||||
|
||||
|
||||
%package server
|
||||
Summary: Simple USB host TCP server
|
||||
Group: System Environment/Daemons
|
||||
License: GPLv2+
|
||||
Requires: %{name}%{?_isa} = %{version}-%{release}
|
||||
|
||||
%description server
|
||||
A simple USB host TCP server, using libusbredirhost.
|
||||
|
||||
|
||||
%prep
|
||||
%autosetup -S git_am
|
||||
|
||||
|
||||
%build
|
||||
%meson \
|
||||
-Dgit_werror=disabled \
|
||||
-Dtools=enabled \
|
||||
-Dfuzzing=disabled
|
||||
|
||||
%meson_build
|
||||
|
||||
|
||||
%install
|
||||
%meson_install
|
||||
|
||||
|
||||
%ldconfig_scriptlets
|
||||
|
||||
|
||||
%files
|
||||
%{!?_licensedir:%global license %%doc}
|
||||
%license COPYING.LIB
|
||||
%{_libdir}/libusbredir*.so.*
|
||||
|
||||
%files devel
|
||||
%doc docs/usb-redirection-protocol.md docs/multi-thread.md ChangeLog.md TODO
|
||||
%{_includedir}/usbredir*.h
|
||||
%{_libdir}/libusbredir*.so
|
||||
%{_libdir}/pkgconfig/libusbredir*.pc
|
||||
|
||||
%files server
|
||||
%{!?_licensedir:%global license %%doc}
|
||||
%license COPYING
|
||||
%{_bindir}/usbredirect
|
||||
%{_sbindir}/usbredirserver
|
||||
%{_mandir}/man1/usbredirect.1*
|
||||
%{_mandir}/man1/usbredirserver.1*
|
||||
|
||||
|
||||
%changelog
|
||||
* Wed Jan 25 2023 Victor Toso <victortoso@redhat.com> - 0.12.0-4
|
||||
- Rebuild to fix lack of elf sections
|
||||
Related: rhbz#2157521
|
||||
|
||||
* Thu Jan 05 2023 Victor Toso <victortoso@redhat.com> - 0.12.0-3
|
||||
- Fixes 100% CPU usage when usbredirect used as TCP server.
|
||||
Related: rhbz#2157521
|
||||
- Fixes USB redirection of identical devices.
|
||||
Resolves: rhbz#2157521
|
||||
|
||||
* Wed Jul 27 2022 Victor Toso <victortoso@redhat.com> - 0.12.0-2
|
||||
- Fixes unserialization on migration
|
||||
Resolves: rhbz#2111351
|
||||
|
||||
* Fri Nov 12 2021 Victor Toso <victortoso@redhat.com> - 0.12.0-1
|
||||
- Update to 0.12.0 release
|
||||
- Resolves: rhbz#2022751
|
||||
|
||||
* Thu Aug 23 2018 Victor Toso <victortoso@redhat.com> - 0.8.0-1
|
||||
- Update to 0.8.0 release
|
||||
- Resolves: rhbz#1620098
|
||||
|
||||
* Fri Feb 09 2018 Fedora Release Engineering <releng@fedoraproject.org> - 0.7.1-7
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild
|
||||
|
||||
* Mon Feb 05 2018 Igor Gnatenko <ignatenkobrain@fedoraproject.org> - 0.7.1-6
|
||||
- Switch to %%ldconfig_scriptlets
|
||||
|
||||
* Thu Aug 03 2017 Fedora Release Engineering <releng@fedoraproject.org> - 0.7.1-5
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild
|
||||
|
||||
* Thu Jul 27 2017 Fedora Release Engineering <releng@fedoraproject.org> - 0.7.1-4
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild
|
||||
|
||||
* Sat Feb 11 2017 Fedora Release Engineering <releng@fedoraproject.org> - 0.7.1-3
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild
|
||||
|
||||
* Fri Feb 05 2016 Fedora Release Engineering <releng@fedoraproject.org> - 0.7.1-2
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild
|
||||
|
||||
* Mon Nov 02 2015 Fabiano Fidêncio <fidencio@redhat.com> 0.7.1-1
|
||||
- Update to upstream 0.7.1 release
|
||||
|
||||
* Tue Jun 16 2015 Peter Robinson <pbrobinson@fedoraproject.org> 0.7-4
|
||||
- Use %%license
|
||||
|
||||
* Mon Aug 18 2014 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.7-3
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild
|
||||
|
||||
* Sun Jun 08 2014 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.7-2
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild
|
||||
|
||||
* Wed May 21 2014 Hans de Goede <hdegoede@redhat.com> - 0.7-1
|
||||
- Update to upstream 0.7 release
|
||||
|
||||
* Tue Sep 10 2013 Hans de Goede <hdegoede@redhat.com> - 0.6-5
|
||||
- Use the new libusb autodetach kernel driver functionality
|
||||
- Fix a usbredirparser bug which causes tcp/ip redir to not work (rhbz#1005015)
|
||||
|
||||
* Sun Aug 04 2013 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.6-4
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild
|
||||
|
||||
* Mon May 13 2013 Hans de Goede <hdegoede@redhat.com> - 0.6-3
|
||||
- Fix usbredirserver not listening for ipv6 connections (rhbz#957470)
|
||||
- Fix a few (harmless) coverity warnings
|
||||
|
||||
* Fri Feb 15 2013 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.6-2
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild
|
||||
|
||||
* Thu Dec 13 2012 Hans de Goede <hdegoede@redhat.com> - 0.6-1
|
||||
- Update to upstream 0.6 release
|
||||
|
||||
* Tue Sep 25 2012 Hans de Goede <hdegoede@redhat.com> - 0.5.2-1
|
||||
- Update to upstream 0.5.2 release
|
||||
|
||||
* Wed Sep 19 2012 Hans de Goede <hdegoede@redhat.com> - 0.5.1-1
|
||||
- Update to upstream 0.5.1 release
|
||||
|
||||
* Fri Sep 7 2012 Hans de Goede <hdegoede@redhat.com> - 0.5-1
|
||||
- Update to upstream 0.5 release
|
||||
|
||||
* Mon Jul 30 2012 Hans de Goede <hdegoede@redhat.com> - 0.4.3-3
|
||||
- Add 2 fixes from upstream fixing issues with some bulk devices (rhbz#842358)
|
||||
|
||||
* Sun Jul 22 2012 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.4.3-2
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild
|
||||
|
||||
* Mon Apr 2 2012 Hans de Goede <hdegoede@redhat.com> - 0.4.3-1
|
||||
- Update to upstream 0.4.3 release
|
||||
|
||||
* Tue Mar 6 2012 Hans de Goede <hdegoede@redhat.com> - 0.4.2-1
|
||||
- Update to upstream 0.4.2 release
|
||||
|
||||
* Sat Feb 25 2012 Hans de Goede <hdegoede@redhat.com> - 0.4.1-1
|
||||
- Update to upstream 0.4.1 release
|
||||
|
||||
* Thu Feb 23 2012 Hans de Goede <hdegoede@redhat.com> - 0.4-1
|
||||
- Update to upstream 0.4 release
|
||||
|
||||
* Thu Jan 12 2012 Hans de Goede <hdegoede@redhat.com> - 0.3.3-1
|
||||
- Update to upstream 0.3.3 release
|
||||
|
||||
* Tue Jan 3 2012 Hans de Goede <hdegoede@redhat.com> 0.3.2-1
|
||||
- Update to upstream 0.3.2 release
|
||||
|
||||
* Wed Aug 24 2011 Hans de Goede <hdegoede@redhat.com> 0.3.1-1
|
||||
- Update to upstream 0.3.1 release
|
||||
|
||||
* Thu Jul 14 2011 Hans de Goede <hdegoede@redhat.com> 0.3-1
|
||||
- Initial Fedora package
|
Loading…
Reference in new issue