usbredir学习

文章目录

    • 背景
    • 典型场景
    • 编译
    • usbredirparser
      • usbredirfilter
      • usbredirparser/usbredirproto
    • usbredirhost
    • usbredirect/usbredirtestclient
    • 参考

背景

usbredir 是一种用于通过网络转发 USB 设备流量的网络协议。它也是一个软件包的名称,该软件包提供了一个解析库、一个 usbredirhost 库以及多个实现此协议的工具。
协议的具体内容可以参考usb-redirection-protocol,该文档还解释了 usbhost 和 usbguest 的含义。

usbredir 最初是为与 Spice 配合使用而创建的,但该协议和 usbredirhost 完全独立于 Spice,它们也可以用于创建 VNC 扩展,以便通过 VNC 连接将 USB 设备重定向到 QEMU 虚拟机。

usb guest 端目前仅在 QEMU 中实现,并作为 QEMU 的一部分发布(在 QEMU 中启用此功能需要在构建 QEMU 时提供 libusbredirparser 库)。

usbredir 支持通过过滤字符串配置 USB 设备过滤功能。

usbredir项目包含下面几个库/工具:

  1. usbredirparser
    一个包含 usbredir 协议解析器的库。

  2. usbredirhost
    一个实现 usbredir 连接中 usb-host端的库,这是实际usb设备所连接的一端。
    希望实现 usb-host 的应用程序需要实现:

  • 为设备提供一个 libusb 设备句柄
  • 为 usbredir 数据的实际传输提供写和读的回调函数
  • 监听 usbredir 和 libusb 的读/写事件,并调用其处理程序
  1. usbredirect
    usbredirect 二进制文件是一个 usbredir 客户端,用于将 USB 设备导出,以便通过 usbredir 协议从另一台(虚拟)机器使用。

  2. usbredirtestclient
    一个用于通过 TCP 使用 usbredir 协议 的小型测试客户端, 其使用usbredirparser库。

典型场景

一个典型场景:
在这里插入图片描述

  • usb device:usb设备。
  • client pc:usb设备直接连接的pc,一般是用户终端(pc或者VDI盒子)。
  • guest vm:连接到usb设备并使用它的桌面(一般是VM),就像直接连接到它一样。
  • usb host:使usb device可供usb guest使用的程序。

编译

  1. 下载源码
$ git clone https://gitlab.freedesktop.org/spice/usbredir.git
  1. 安装依赖
    参考.gitlab-ci.yml文件里的依赖
# debian环境
sudo apt install gcc clang meson ninja-build valgrind git bzip2 libglib2.0-dev libusb-1.0-0-dev
  1. 编译
$ meson . _build -Dfuzzing=disabled -Dtools=enabled
$ cd _build
$ meson compile

编译后,生成产物:
在这里插入图片描述

usbredirparser

usbredirparser/
├── meson.build
├── strtok_r.c
├── strtok_r.h
├── usbredirfilter.c
├── usbredirfilter.h
├── usbredirparser.c
├── usbredirparser.h
├── usbredirparser.map
├── usbredirproto-compat.h
└── usbredirproto.h	# redirection protocol的相关定义

其中:usbredirfilter.husbredirparser.husbredirproto.h 是提供的对外接口头文件。

usbredirfilter

首先定义了usbredir的规则:

struct usbredirfilter_rule {int device_class;       /* 0-255, -1 to match any class */int vendor_id;          /* 0-65535, -1 to match any id */int product_id;         /* 0-65535, -1 to match any id */int device_version_bcd; /* 0-65535, -1 to match any version */int allow;              /* 0: deny redir for this device, non 0: allow */
};

通过该规则可以过滤哪些usb设备可以重定向哪些不可以。
随后定义了规则的转换函数:

int usbredirfilter_string_to_rules(const char *filter_str, const char *token_sep, const char *rule_sep,struct usbredirfilter_rule **rules_ret, int *rules_count_ret);
char *usbredirfilter_rules_to_string(const struct usbredirfilter_rule *rules,int rules_count, const char *token_sep, const char *rule_sep);

通过这两个函数可以在字符串和规则之间转换。
下面是检查函数,用户检查一个设备是否允许重定向:

int usbredirfilter_check(const struct usbredirfilter_rule *rules, int rules_count,uint8_t device_class, uint8_t device_subclass, uint8_t device_protocol,uint8_t *interface_class, uint8_t *interface_subclass,uint8_t *interface_protocol, int interface_count,uint16_t vendor_id, uint16_t product_id, uint16_t device_version_bcd,int flags);

对传入的规则进行完整性检查:

int usbredirfilter_verify(const struct usbredirfilter_rule *rules, int rules_count);

将规则打印到文件中:

void usbredirfilter_print(const struct usbredirfilter_rule *rules, int rules_count, FILE *out);

最后,释放库所分配的内存:

void usbredirfilter_free(void *ptr);

usbredirparser/usbredirproto

一个usbredir protocol的解析器,用于协议解析,和usbredirproto.h一起。
关于协议这块,可以参考官方文档:usb-redirection-protocol或者其他人的总结:USB重定向协议。

usbredirhost

usbredirhost/
├── meson.build
├── usbredirhost.c
├── usbredirhost.h
└── usbredirhost.map

其中usbredirhost.h是提供的对外接口头文件。
usbredir的打开与关闭:

struct usbredirhost *usbredirhost_open(libusb_context *usb_ctx,libusb_device_handle *usb_dev_handle,usbredirparser_log log_func,usbredirparser_read  read_guest_data_func,usbredirparser_write write_guest_data_func,void *func_priv, const char *version, int verbose, int flags);/* See docs/multi-thread.md */
struct usbredirhost *usbredirhost_open_full(libusb_context *usb_ctx,libusb_device_handle *usb_dev_handle,usbredirparser_log log_func,usbredirparser_read  read_guest_data_func,usbredirparser_write write_guest_data_func,usbredirhost_flush_writes flush_writes_func,usbredirparser_alloc_lock alloc_lock_func,usbredirparser_lock lock_func,usbredirparser_unlock unlock_func,usbredirparser_free_lock free_lock_func,void *func_priv, const char *version, int verbose, int flags);
void usbredirhost_close(struct usbredirhost *host);

usbredirhost 获取设备/释放设备

int usbredirhost_set_device(struct usbredirhost *host,libusb_device_handle *usb_dev_handle);

设置usbredirhost的回调,在usbredirhost_fl_write_cb_owns_buffer标志位有效时,该回调负责返回应用程序的待写入缓冲区大小(以字节为单位)。

void usbredirhost_set_buffered_output_size_cb(struct usbredirhost *host,usbredirhost_buffered_output_size buffered_output_size_func);

数据处理相关:

int usbredirhost_read_guest_data(struct usbredirhost *host);
int usbredirhost_has_data_to_write(struct usbredirhost *host);
int usbredirhost_write_guest_data(struct usbredirhost *host);
void usbredirhost_free_write_buffer(struct usbredirhost *host, uint8_t *data);

获取usbredirfilter规则

void usbredirhost_get_guest_filter(struct usbredirhost *host,const struct usbredirfilter_rule **rules_ret, int *rules_count_ret);

检查usb设备是否允许重定向

int usbredirhost_check_device_filter(const struct usbredirfilter_rule *rules,int rules_count, libusb_device *dev, int flags);

usbredirect/usbredirtestclient

tools
├── meson.build
├── usbredirect.1
└── usbredirect.cusbredirtestclient/
├── meson.build
└── usbredirtestclient.c

运行参数:

$ ./usbredirect
./usbredirect need to act either as client (-to) or as server (-as)
Usage:usbredirect [OPTION?]Help Options:-h, --help          Show help optionsApplication Options:--device            Local USB device to be redirected identified as either VENDOR:PRODUCT "0123:4567" or BUS-DEVICE "5-2"--to                Client URI to connect to--as                Server URI to be run-k, --keepalive     If we should set SO_KEEPALIVE flag on underlying socket-v, --verbose       Set log level between 1-5 where 5 being the most verbose$ ./usbredirtestclient
Missing server argument
Usage: ./usbredirtestclient [-p|--port <port>] [-v|--verbose <0-3>] <server>

测试:

  1. usbredirect 作为server端将usb设备导出
$ sudo ./tools/usbredirect --as 0.0.0.0:5909 --device 058f:6387 --verbose 5

注意看此时系统日志:

[  601.361432] usb-storage 1-12.1:1.0: USB Mass Storage device detected
[  601.361930] scsi host6: usb-storage 1-12.1:1.0
[  601.617526] usb 1-12.1: reset high-speed USB device number 8 using xhci_hcd

被导出的设备被reset掉了,本地lsusb是看不到这个设备了,设备从本地导出了。

  1. usbredirtestclient 连接到server端
    连接到server端:
$ ./usbredirtestclient/usbredirtestclient -p 5909 192.168.0.26
usbredirparser: Peer version: usbredir 0.14.0, using 64-bits ids
interface 0 class  8 subclass  6 protocol 80
endpoint: 00, type: 0, interval: 0, interface: 0 max-packetsize: 0
endpoint: 01, type: 2, interval: 0, interface: 0 max-packetsize: 512
endpoint: 80, type: 0, interval: 0, interface: 0 max-packetsize: 0
endpoint: 82, type: 2, interval: 0, interface: 0 max-packetsize: 512
device info: speed: highclass  0 subclass  0 protocol  0vendor 0x058f product 6387
Get config: 1, status: 0
Set config: 1, status: 0
Get alt: 0, interface: 0, status: 0
interface 0 class  8 subclass  6 protocol 80
endpoint: 00, type: 0, interval: 0, interface: 0 max-packetsize: 0
endpoint: 01, type: 2, interval: 0, interface: 0 max-packetsize: 512
endpoint: 80, type: 0, interval: 0, interface: 0 max-packetsize: 0
endpoint: 82, type: 2, interval: 0, interface: 0 max-packetsize: 512
Set alt: 0, interface: 0, status: 0
> help
Available commands:
ctrl <endpoint> <request> <request_type> <value> <index> <length> [data]
quit
help
> quit

在客户端退出后,看下server端的系统日志:

[  733.420713] usb 1-12.1: reset high-speed USB device number 8 using xhci_hcd
[  733.628274] usb-storage 1-12.1:1.0: USB Mass Storage device detected
[  733.628954] scsi host6: usb-storage 1-12.1:1.0
[  734.654030] scsi 6:0:0:0: Direct-Access     Generic  Flash Disk       8.07 PQ: 0 ANSI: 4
[  734.654755] sd 6:0:0:0: Attached scsi generic sg5 type 0
[  734.657656] sd 6:0:0:0: [sdf] 15728640 512-byte logical blocks: (8.05 GB/7.50 GiB)
[  734.658392] sd 6:0:0:0: [sdf] Write Protect is off
[  734.658399] sd 6:0:0:0: [sdf] Mode Sense: 23 00 00 00
[  734.659086] sd 6:0:0:0: [sdf] Write cache: disabled, read cache: enabled, doesn't support DPO or FUA
[  734.725772]  sdf: sdf1
[  734.726165] sd 6:0:0:0: [sdf] Attached SCSI removable disk

可以发现,原来导出的设备重新被attach进去了,此时lsusb又可以看到该设备了,设备又回到本地了。

着两个工具对应的代码都很短,可以进去看看他们是怎么工作的,核心就是使用usbredirhost和usbredirparser这两个库。

参考

usbredir
usbredir
usbredir-0.7内容详解(一)
spice
USB重定向协议
USB虚拟化和虚拟桌面USB重定向
Spice Usbredirect 性能改进

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/65957.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ESXI 安装教程(3) ---​vCenter Server 安装

不涉及复杂的操作此项可不安装 1.镜像加载到虚拟光盘 对应的网盘文件 2.打开文件路径 双击运行文件installer.exe 3.调整安装语言 4.点击安装 5. 6. 证书,有效问题导致此提示,非专业网络管理人员,不知道如何处理,此处点是即可 证书有效开始时间是安装时间8小时 证书有效结束…

极客说|Azure AI Agent Service 结合 AutoGen/Semantic Kernel 构建多智能体解决⽅案

作者&#xff1a;卢建晖 - 微软高级云技术布道师 「极客说」 是一档专注 AI 时代开发者分享的专栏&#xff0c;我们邀请来自微软以及技术社区专家&#xff0c;带来最前沿的技术干货与实践经验。在这里&#xff0c;您将看到深度教程、最佳实践和创新解决方案。关注「极客说」&am…

【集成学习】Boosting算法详解

文章目录 1. 集成学习概述2. Boosting算法详解3. Gradient Boosting算法详解3.1 基本思想3.2 公式推导 4. Python实现 1. 集成学习概述 集成学习&#xff08;Ensemble Learning&#xff09;是一种通过结合多个模型的预测结果来提高整体预测性能的技术。相比于单个模型&#xf…

小米vela系统(基于开源nuttx内核)——如何使用信号量进行PV操作

如何使用信号量进行PV操作 前言信号量1. 信号量简介2. NuttX中信号量的创建与使用2.1 Nuttx信号量的初始化和销毁2.2 信号量的等待和发布 3. 信号量的实际应用&#xff1a;下载任务示例3.1 实际代码3.2 代码说明3.3 执行说明 4. 信号量的优势与应用场景5. 常见应用场景&#xf…

CMake学习笔记(2)

1. 嵌套的CMake 如果项目很大&#xff0c;或者项目中有很多的源码目录&#xff0c;在通过CMake管理项目的时候如果只使用一个CMakeLists.txt&#xff0c;那么这个文件相对会比较复杂&#xff0c;有一种化繁为简的方式就是给每个源码目录都添加一个CMakeLists.txt文件&#xff…

【C++】size_t究竟是什么?全面解析与深入拓展

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 &#x1f4af;前言&#x1f4af;一、什么是size_t&#xff1f;为什么需要size_t&#xff1f; &#x1f4af;二、size_t的特性与用途1. size_t是无符号类型示例&#xff1a; 2. size_t的跨平台适应性示例对…

【物流管理系统 - IDEAJavaSwingMySQL】基于Java实现的物流管理系统导入IDEA教程

有问题请留言或私信 步骤 下载项目源码&#xff1a;项目源码 解压项目源码到本地 打开IDEA 左上角&#xff1a;文件 → 新建 → 来自现有源代码的项目 找到解压在本地的项目源代码文件&#xff0c;点击确定&#xff0c;根据图示步骤继续导入项目 查看项目目录&#xff…

ssh2-sftp-client和ssh2配合使用js脚本快速部署项目到服务器

有时候因为服务器不能实现github或者gitlab的自动部署服务&#xff0c;所以就需要使用脚本来实现自动部署&#xff0c;可以省时省力&#xff0c;一劳永逸。这里就使用ssh2-sftp-client和ssh2来实现&#xff0c;即便是需要sudo权限&#xff0c;也是可以的。 1.先将本地打包后的…

深度解析Linux中的调试器gdb/cgdb的使用

Linux下我们编译好的代码&#xff0c;无法直接调试 gcc/g默认的工作模式是realse模式 程序要调试的话&#xff0c;必须是debug模式&#xff0c;也就是说编译的时候要加-g选项 gdb携带调试信息的exe 我们现在在文件夹里面创建一个文件lesson11 里面创建一个累加的代码&…

【Maui】动态菜单实现(绑定数据视图)

前言 .NET 多平台应用 UI (.NET MAUI) 是一个跨平台框架&#xff0c;用于使用 C# 和 XAML 创建本机移动和桌面应用。 使用 .NET MAUI&#xff0c;可从单个共享代码库开发可在 Android、iOS、macOS 和 Windows 上运行的应用。 .NET MAUI 是一款开放源代码应用&#xff0c;是 X…

RNN之:LSTM 长短期记忆模型-结构-理论详解-及实战(Matlab向)

0.前言 递归&#xff01;循环神经网络Recurrent Neural Network 循环神经网络&#xff08;又称递归神经网络&#xff0c;Recurrent Neural Network&#xff0c;RNN&#xff09;。是一种用于处理序列数据的神经网络结构&#xff0c;具有记忆功能&#xff0c;能够捕捉序列中的时…

泛目录和泛站有什么差别

啥是 SEO 泛目录&#xff1f; 咱先来说说 SEO 泛目录是啥。想象一下&#xff0c;你有一个巨大的图书馆&#xff0c;里面的书架上摆满了各种各样的书&#xff0c;每一本书都代表着一个网页。而 SEO 泛目录呢&#xff0c;就像是一个超级图书管理员&#xff0c;它的任务就是把这些…

【Vue】全局/局部组件使用流程(Vue2为例)

全局组件和局部组件区别 如何使用 全局组件&#xff1a;全局注册后&#xff0c;可以在任意页面中直接使用。局部组件&#xff1a;在页面中需要先导入子组件路径&#xff0c;注册组件才能使用。 适用场景 全局组件&#xff1a;适用于高频使用的组件&#xff0c;如导航栏、业…

【Pytorch实用教程】PyTorch 中如何输出模型参数:全面指南

文章目录 PyTorch 中如何输出模型参数:全面指南1. 为什么需要输出模型参数?2. PyTorch 中输出模型参数的方法2.1 使用 `model.parameters()` 输出所有参数2.2 使用 `model.named_parameters()` 输出参数名称和值2.3 使用 `model.state_dict()` 输出模型的参数字典2.4 输出特定…

1、docker概念和基本使用命令

docker概念 微服务&#xff1a;不再是以完整的物理机为基础的服务软件&#xff0c;而是借助于宿主机的性能。以小量的形式&#xff0c;单独部署的应用。 docker&#xff1a;是一个开源的应用容器引擎&#xff0c;基于go语言开发的&#xff0c;使用时apache2.0的协议。docker是…

Genymotion配套VirtualBox所在地址

在 Genymotion打开虚拟机前需要先打开VirtualBox中的虚拟机 C:\Program Files\Oracle\VirtualBox\VirtualBox.exe 再开启genymotion中的虚拟机开关

【Linux】深刻理解软硬链接

一.软硬链接操作 1.软连接 touch 创建一个文件file.txt &#xff0c;对该文件创建对应的软链接改怎么做呢&#xff1f; ln -s file.txt file-soft.link .给对应文件创建软连接。 软连接本质就是一个独立的文件&#xff0c;因为我们对应的软连接有独立的inode&#xff0c;他…

第三十六章 Spring之假如让你来写MVC——拦截器篇

Spring源码阅读目录 第一部分——IOC篇 第一章 Spring之最熟悉的陌生人——IOC 第二章 Spring之假如让你来写IOC容器——加载资源篇 第三章 Spring之假如让你来写IOC容器——解析配置文件篇 第四章 Spring之假如让你来写IOC容器——XML配置文件篇 第五章 Spring之假如让你来写…

快速上手 HarmonyOS 应用开发

一、DevEco Studio 安装与配置 1. DevEco Studio 简介 DevEco Studio 是 HarmonyOS 的一站式集成开发环境&#xff08;IDE&#xff09;&#xff0c;提供了丰富的工具和功能&#xff0c;支持 HarmonyOS 应用开发的全流程。 2. DevEco Studio 下载与安装 下载地址&#xff1a…

Java Web开发进阶——错误处理与日志管理

错误处理和日志管理是任何生产环境中不可或缺的一部分。在 Spring Boot 中&#xff0c;合理的错误处理机制不仅能够提升用户体验&#xff0c;还能帮助开发者快速定位问题&#xff1b;而有效的日志管理能够帮助团队监控应用运行状态&#xff0c;及时发现和解决问题。 1. 常见错误…