Skip to content

GUACAMOLE-522: USB Device Redirection.#610

Open
aleitner wants to merge 1 commit intoapache:mainfrom
aleitner:GUACAMOLE-522-usb-redirection
Open

GUACAMOLE-522: USB Device Redirection.#610
aleitner wants to merge 1 commit intoapache:mainfrom
aleitner:GUACAMOLE-522-usb-redirection

Conversation

@aleitner
Copy link
Contributor

This PR implements the server-side protocol support for Web USB device redirection, complementing the client-side PR. This provides the infrastructure for Guacamole protocol plugins (RDP, VNC, etc.) to handle USB device redirection from browser clients.

Data Flow

  1. Server receives usbconnect with device descriptors and interface/endpoint data
  2. Protocol plugin's usbconnect_handler is invoked to establish redirection
  3. usbdata messages flow between client device and server handler
  4. Either side can initiate disconnection via usbdisconnect

New Protocol Instructions

  • Server → Client: Added usbdata and usbdisconnect instructions for sending data to USB devices and requesting disconnection
  • Client → Server: Added handlers for receiving usbconnect, usbdata, and usbdisconnect instructions

Handlers

  • guac_user_usbconnect_handler: Processes USB device connections with full device metadata (vendor/product IDs, interfaces, endpoints)
  • guac_user_usbdata_handler: Handles USB data transfer from the client with USB endpoint and transfer type information.
  • guac_user_usbdisconnect_handler: Manages USB device disconnection events.

@lokenorlinjohannessen
Copy link

Extremely interested in this PR, what is blocking it, since this is a awesome added feature :D

@necouchman
Copy link
Contributor

Extremely interested in this PR, what is blocking it, since this is a awesome added feature :D

Nothing is blocking it - just the time required to review the PR.

@coolkingh
Copy link

coolkingh commented Jan 8, 2026

@aleitner The usbconnect_handler is defined as a function pointer type and struct member, but there's no implementation assigned to it. It is incomplete same for other functions usbdata_handler and usbdisconnect_handler
It is given in comments but never defined.

/*** Handler for USB connect events sent by the Guacamole web-client.
  *
  * The handler takes the user that connected the device, the device ID,
  * vendor ID, product ID, device name, serial number, device class,
  * device subclass, device protocol, and interface data.
  *
  * Example:
  * @code
  *     int usbconnect_handler(guac_user* user, const char* device_id,
  *             int vendor_id, int product_id, const char* device_name,
  *             const char* serial_number, int device_class,
  *             int device_subclass, int device_protocol,
  *             const char* interface_data);
  *
  *     int guac_user_init(guac_user* user, int argc, char** argv) {
  *         user->usbconnect_handler = usbconnect_handler;
  *     }

@necouchman
Copy link
Contributor

@coolkingh Yes, this is the framework for it that provides methods for handling USB device redirection. This particular pull request does not implement it concretely for any of the protocols. Once this pull request is merged the changes can be made at the protocol level (RDP, SSH, etc.) that would actually enable this to function for a particular protocol.

@coolkingh
Copy link

@necouchman What's the point of merging if implementation is incomplete for any of the protocol.

@necouchman
Copy link
Contributor

@coolkingh The point is that the base components - the Guacamole protocol bits and hooks for the handler functions - are available in case someone wants to use them. The second sentence of this pull request says:

This provides the infrastructure for Guacamole protocol plugins (RDP, VNC, etc.) to handle USB device redirection from browser clients.

This indicates to me that @aleitner never intended this pull request to fully implement USB redirection support in any of the protocols, but only to provide these core components. There are several reasons why we might decide to merge only the core framework components and not the protocol-specific implementations. We often break complex implementations into multiple pull requests, where a more basic or foundational level of code is done prior to the detailed or specific implementations. It can make it easier to track down when bugs are introduced, it helps to break up work among people who have varying degrees of time and expertise, etc.

In the case of WebUSB support, I would imagine that this part - the addition of it to the Guacamole protocol and the implementation of the hooks - is the simpler part, whereas implementing the actual protocol-level of support will require a lot more time and effort to hook in these handlers to FreeRDP, libssh, libvncserver, etc. It makes sense to go ahead and get the framework/infrastructure out and available so that others who want to work on the protocol-level components can do so.

Copy link
Contributor

@necouchman necouchman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@aleitner Overall looks pretty good to me - my comments are mostly about documentation and not the actual implementation, aside from the one question about a protocol-level usbconnect function.

Copy link
Contributor

@necouchman necouchman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@aleitner One more comment, but, also, it looks like you added the RDP functionality, here - not sure if that was intended or not? Also, with that change, the check of the PR is failing, as the build has an issue.

Comment on lines +532 to +536
* @param interface_data
* Encoded string containing interface and endpoint information. Required.
* Format: "ifaceNum:class:subclass:protocol:ep1Num:ep1Dir:ep1Type:ep1Size;ep2...,iface2..."
* where multiple endpoints within an interface are separated by semicolons
* and multiple interfaces are separated by commas.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple of more question from me, here, regarding this...

First, are the format and fields of this interface_data parameter something standard an well-known/documented when dealing with USB devices? Is this data that will be provided automatically by the web browser, or something that it would be expected that someone would know how and what to assemble for it? I can kind of guess what each of the fields means, but a few are a bit obscure.

Somewhat related, it looks like some of the data in this interface_data field is the same as the other parameters to the function (class, subclass, protocol). How does that work out between the parameters provided in the function and the interface data? Should they always be identical? Or are there situations where the individual interfaces will differ from the overall "device" being connected?

I ask for two reasons:

  1. Curiosity, so I understand better how it works.
  2. To make sure we're not sending duplicate data, both for efficiency but also because of the risk that it'll be mis-matched.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The format ifaceNum:class:subclass:protocol:ep1Num:ep1Dir:ep1Type:ep1Size;ep2...,iface2... is not a USB standard. It's a custom encoding I set up for this Guacamole protocol.

The data itself comes from standard USB descriptors that the browser's WebUSB API provides automatically. We can see in ManagedUSB.js in our client PR that we're just reading properties that WebUSB gives us:

alt.interfaceClass              // Standard USB class code
alt.interfaceSubclass           // Standard USB subclass code  
alt.interfaceProtocol           // Standard USB protocol code
ep.endpointNumber               // Standard USB endpoint number
ep.direction                    // 'in' or 'out'
ep.type                         // 'bulk', 'interrupt', 'isochronous'
ep.packetSize                   // Max packet size in bytes

These are all standard USB descriptor fields defined in the USB specification. We're just encoding them into a string format for sending over the Guacamole protocol.

As you pointed out thoguh we can see that USB has class/subclass/protocol at two levels.

These describe the overall device and are often set to 0 for composite devices:

  • device_class, device_subclass, device_protocol

Composite devices like webcams with microphones commonly use:

  • Device class 0xEF (Miscellaneous Device)
  • Device subclass 0x02 (Common Class)
  • Device protocol 0x01 (Interface Association Descriptor)

These describe each individual interface and is where the actual functionality is usually defined:

  • interfaceClass, interfaceSubclass, interfaceProtocol

HID devices like keyboards/mice commonly have:

  • Device class 0x00 (defined at interface level)
  • Interface class 0x03 (HID)
  • Interface subclass 0x01 (Boot Interface)
  • Interface protocol 0x01 (Keyboard) or 0x02 (Mouse)
  • Interface 0: class=0x03 (HID), subclass=0x01 (Boot), protocol=0x01 (Keyboard)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay - I'd suggest this all of this - both the encoding of the fields for Guacamole, and the way composite devices are handled - get documented somewhere - I'm not really sure if the code is the best place, or the manual, but I think it'd be useful for folks looking to implement USB functionality with Guacamole to know how we're handling this data.

@aleitner aleitner force-pushed the GUACAMOLE-522-usb-redirection branch from f9df463 to 73b5861 Compare January 12, 2026 16:58
@aleitner
Copy link
Contributor Author

@aleitner One more comment, but, also, it looks like you added the RDP functionality, here - not sure if that was intended or not? Also, with that change, the check of the PR is failing, as the build has an issue.

Whoops, didn't mean to push the rdp code as that has a good bit of work that needs to be done

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants