This patch adds utilities transmit packets via WebSocket protocol. WebSocket version of utilities as following. usbws : command usbwsa : application-side daemon usbwsd : device-side daemon The command supports all sub-command (ie. list, connect, disconnect, port, bind, unbind, attach and detach). It uses --url option to specify remote address and port number. Implementation of this patch depends on Poco C++ (http://pocoproject.org/). The tree is shown below. tools +--usb +--usbip +--src : command, daemons and their core libraries +--libsrc : common library for command and daemon +--websocket : new! WebSocket implementations +--poco : new! implementation with Poco C++ Signed-off-by: Nobuo Iwata <nobuo.iwata@xxxxxxxxxxxxxxx> --- tools/usb/usbip/websocket/INSTALL | 237 ++++++++++ tools/usb/usbip/websocket/Makefile.am | 3 + tools/usb/usbip/websocket/README | 184 ++++++++ tools/usb/usbip/websocket/autogen.sh | 9 + tools/usb/usbip/websocket/cleanup.sh | 12 + tools/usb/usbip/websocket/configure.ac | 55 +++ tools/usb/usbip/websocket/doc/usbws.8 | 192 ++++++++ tools/usb/usbip/websocket/doc/usbwsa.8 | 101 +++++ tools/usb/usbip/websocket/doc/usbwsd.8 | 109 +++++ tools/usb/usbip/websocket/poco/Makefile.am | 18 + .../usb/usbip/websocket/poco/USBWSCommand.cpp | 410 ++++++++++++++++++ tools/usb/usbip/websocket/poco/USBWSCommand.h | 99 +++++ .../usb/usbip/websocket/poco/USBWSDaemon.cpp | 228 ++++++++++ tools/usb/usbip/websocket/poco/USBWSDaemon.h | 80 ++++ .../websocket/poco/USBWSRequestHandler.cpp | 90 ++++ .../websocket/poco/USBWSRequestHandler.h | 49 +++ .../poco/USBWSRequestHandlerFactory.cpp | 49 +++ .../poco/USBWSRequestHandlerFactory.h | 48 ++ tools/usb/usbip/websocket/poco/USBWSUtil.h | 52 +++ .../usbip/websocket/poco/USBWSWebSocket.cpp | 204 +++++++++ .../usb/usbip/websocket/poco/USBWSWebSocket.h | 69 +++ 21 files changed, 2298 insertions(+) diff --git a/tools/usb/usbip/websocket/INSTALL b/tools/usb/usbip/websocket/INSTALL new file mode 100644 index 0000000..d3c5b40 --- /dev/null +++ b/tools/usb/usbip/websocket/INSTALL @@ -0,0 +1,237 @@ +Installation Instructions +************************* + +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, +2006, 2007 Free Software Foundation, Inc. + +This file is free documentation; the Free Software Foundation gives +unlimited permission to copy, distribute and modify it. + +Basic Installation +================== + +Briefly, the shell commands `./configure; make; make install' should +configure, build, and install this package. The following +more-detailed instructions are generic; see the `README' file for +instructions specific to this package. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. Caching is +disabled by default to prevent problems with accidental use of stale +cache files. + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You need `configure.ac' if +you want to change it or regenerate `configure' using a newer version +of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. + + Running `configure' might take a while. While running, it prints + some messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + + 6. Often, you can also type `make uninstall' to remove the installed + files again. + +Compilers and Options +===================== + +Some systems require unusual options for compilation or linking that the +`configure' script does not know about. Run `./configure --help' for +details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c99 CFLAGS=-g LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + +You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you can use GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + With a non-GNU `make', it is safer to compile the package for one +architecture at a time in the source code directory. After you have +installed the package for one architecture, use `make distclean' before +reconfiguring for another architecture. + +Installation Names +================== + +By default, `make install' installs the package's commands under +`/usr/local/bin', include files under `/usr/local/include', etc. You +can specify an installation prefix other than `/usr/local' by giving +`configure' the option `--prefix=PREFIX'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +pass the option `--exec-prefix=PREFIX' to `configure', the package uses +PREFIX as the prefix for installing programs and libraries. +Documentation and other data files still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=DIR' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + +Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + +There may be some features `configure' cannot figure out automatically, +but needs to determine by the type of machine the package will run on. +Usually, assuming the package is built to be run on the _same_ +architectures, `configure' can figure that out, but if it prints a +message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the option `--target=TYPE' to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + +If you want to set default values for `configure' scripts to share, you +can create a site shell script called `config.site' that gives default +values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + +Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +causes the specified `gcc' to be used as the C compiler (unless it is +overridden in the site shell script). + +Unfortunately, this technique does not work for `CONFIG_SHELL' due to +an Autoconf bug. Until the bug is fixed you can use this workaround: + + CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash + +`configure' Invocation +====================== + +`configure' recognizes the following options to control how it operates. + +`--help' +`-h' + Print a summary of the options to `configure', and exit. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. + diff --git a/tools/usb/usbip/websocket/Makefile.am b/tools/usb/usbip/websocket/Makefile.am new file mode 100644 index 0000000..008c817 --- /dev/null +++ b/tools/usb/usbip/websocket/Makefile.am @@ -0,0 +1,3 @@ +SUBDIRS := poco + +dist_man_MANS := $(addprefix doc/, usbws.8 usbwsa.8 usbwsd.8) diff --git a/tools/usb/usbip/websocket/README b/tools/usb/usbip/websocket/README new file mode 100644 index 0000000..94d48a0 --- /dev/null +++ b/tools/usb/usbip/websocket/README @@ -0,0 +1,184 @@ +# +# README for usbip-utils WebSocket extension sample. +# +# Copyright (C) 2015 Nobuo Iwata +# + +1) Goal of this sample + + To give a sample application of userspace transmission of USB/IP and it's + utilities. + +2) Requirement + +2-1) POCO C++ implementation + + Install C++ package. + + > sudo yum install gcc-c++ + + Install openssl-devel or openssl-dev package. + + > sodo yum install openssl-devel + + Get complete edition source code from http://pocoproject.org/. + + > ./configure --omit=Data/ODBC,Data/MySQL + + > make + + > sudo make install + +3) Make + +3-1) POCO C++ implementation + + Compile drivers. + + > cd usbip + > make + + Compile libraries. + + > cd tools/usb/usbip + > make + + Compile WebSocket utilities. + + > cd tools/usb/usbip/websocket + > make + +4) Usage of WebSocket utilities + + usbwsa [options] - daemon for application side + + usbwsd [options] - daemon for device side + + -d, --debug + Enable debug messages. + -t, --tcp=PORT-NUMBER + Serving TCP port number. Default is 80 or 443 for non-SSL and SSL + respectively. + -p, --path=PATH + Serving path portion of URL. Default is /usbip. + -i, --interval=INTERVAL + Noncommunication time period to send ping-pong in seconds. + Default is 60. 0 denotes not to use ping-pong. + -s, -ssl + SSL mode, ie. wss. + -k, --key=KEY-FILE + Private key file. Default is cert/server.key. + -c, --cert=CERT-FILE + Certificate file. Default is cert/server.crt. + -r, --root-cert=ROOT-CERT-FILE + Certificate file of root CA. Not used as default. + -V, --verification=VERIFICATION-MODE + none(default), relaxed, strict or once. + -h, --help + Print help. + -v, --version + Show version. + + usbws <command> [options] - command for both device and application side + + command + connect - export a device to remote. (at device side) + disconnect - unexport a device from remote. (at device side) + + list - list local devices. (at device side) + list importable devices. (at application side) + port - list imported devices. (at application side) + + bind - make a device importable. (at device side) + attach - import a device. (at application side) + detach - cancel import. (at application side) + unbind - make a device not importable. (at device side) + + -d, --debug + Enable debug messages. + -u, --url=URL + URL of WebSocket server. ex) ws://<host>/usbip or wss://<host>/usbip + Default port number is 80 or 443 for ws and wsss respectively. + -p, --proxy=URL + URL of http proxy server. ex) http://<proxy-addr>:8080 + No proxy is used as default. + Proxy user and password can be specified in URL. + ex) http://<user>:<pwd>@<proxy-host>:8080 + -b, --busid=BUS-ID + Bus ID of a device to export or unexport. + -o, --timeout + Connect timeout in seconds. Default is 5. + -i, --interval=INTERVAL + Noncommunication time period to send ping-pong in seconds. + Default is 60. 0 denotes not to use ping-pong. + -k, --key=KEY-FILE + Private key file. Default is cert/server.key. + -c, --cert=CERT-FILE + Certificate file. Default is cert/server.crt. + -r, --root-cert=ROOT-CERT-FILE + Certificate file of root CA. Not used as default. + -V, --verification=VERIFICATION-MODE + none(default), relaxed. + +5) Execution + +5-1) POCO C++ implementation + + Insert drivers. + + a) Application side computer + # cd usbip + # insmod usbip-core.ko + # insmod usbip-ux.ko + # insmod vhci-hcd.ko + + b) Device side computer + # cd usbip + # insmod usbip-core.ko + # insmod usbip-ux.ko + # insmod usbip-host.ko + + Execute utilities. + + a) Application side computer + # cd usbip/userspace + # websocket/poco/usbwsa --tcp-port 3240 --ssl + + b) Device side computer + --- START --- + # cd usbip/userspace + # websocket/poco/usbws connect \ + --url wss://111.222.333.444:3240/usbip -b 1-2 + NOTE: it will running while normal operation. + + --- END ... in another window --- + # cd usbip/userspace + # websocket/poco/usbws disconnect \ + --url wss://111.222.333.444:3240/usbip -b 1-2 + +Usage via HTTP proxy + + Example below shows usage pass through squid proxy. + + a) Summary of /etc/squid/squid.conf + acl SSL_ports port 443 + acl CONNECT method CONNECT + http_access deny CONNECT !SSL_ports + http_port 3128 + + b) Application side + # cd usbip/userspace + # websocket/poco/usbwsa --ssl + + c) Device side + --- START --- + # cd usbip/userspace + # websocket/poco/usbws connect -proxy http://proxy.example.com:3128 \ + --url wss://111.222.333.444/usbip -b 1-2 + NOTE: it will running while normal operation. + + --- END ... in another window --- + # cd usbip/userspace + # websocket/poco/usbws disconnect -proxy http://proxy.example.com:3128 \ + --url wss://111.222.333.444/usbip -b 1-2 + diff --git a/tools/usb/usbip/websocket/autogen.sh b/tools/usb/usbip/websocket/autogen.sh new file mode 100755 index 0000000..e1112d3 --- /dev/null +++ b/tools/usb/usbip/websocket/autogen.sh @@ -0,0 +1,9 @@ +#!/bin/sh -x + +#aclocal +#autoheader +#libtoolize --copy --force +#automake-1.9 -acf +#autoconf + +autoreconf -i -f -v diff --git a/tools/usb/usbip/websocket/cleanup.sh b/tools/usb/usbip/websocket/cleanup.sh new file mode 100755 index 0000000..810f99c --- /dev/null +++ b/tools/usb/usbip/websocket/cleanup.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +if [ -r Makefile ]; then + make distclean +fi + +FILES="aclocal.m4 autom4te.cache compile config.guess config.h.in config.log \ + config.status config.sub configure cscope.out depcomp install-sh \ + poco/Makefile poco/Makefile.in libtool ltmain.sh Makefile \ + Makefile.in missing" + +rm -vRf $FILES diff --git a/tools/usb/usbip/websocket/configure.ac b/tools/usb/usbip/websocket/configure.ac new file mode 100644 index 0000000..39ea211 --- /dev/null +++ b/tools/usb/usbip/websocket/configure.ac @@ -0,0 +1,55 @@ +dnl Process this file with autoconf to produce a configure script. + +AC_PREREQ(2.59) +AC_INIT([usbws-utils], [0.1.0], [linux-usb@xxxxxxxxxxxxxxx]) + +AC_CONFIG_HEADERS([config.h]) + +AM_INIT_AUTOMAKE([foreign]) +LT_INIT + +# Silent build for automake >= 1.11 +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + +AC_SUBST([EXTRA_CFLAGS], ["-Wall -Werror -Wextra -std=gnu99"]) + +# Checks for programs. +AC_PROG_CC +AC_PROG_CXX +AC_PROG_INSTALL +AC_PROG_MAKE_SET + +# Set language to C++ +AC_LANG_CPLUSPLUS + +# Checks for header files. +AC_HEADER_DIRENT +AC_HEADER_STDC +AC_CHECK_HEADERS([fcntl.h unistd.h]) + +# Checks for typedefs, structures, and compiler characteristics. +AC_TYPE_SIZE_T +AC_TYPE_SSIZE_T + +# Checks for library functions. +AC_CHECK_FUNCS([fcntl.h unistd.h]) + +AC_CHECK_HEADER(Poco/Logger.h,, + AC_MSG_ERROR([Missing Poco/Logger.h])) +AC_CHECK_HEADER(Poco/Util/ServerApplication.h,, + AC_MSG_ERROR([Missing Poco/Util/ServerApplication.h])) +AC_CHECK_HEADER(Poco/Net/WebSocket.h,, + AC_MSG_ERROR([Missing Poco/Net/WebSocket.h])) +AC_CHECK_HEADER(Poco/Net/Context.h,, + AC_MSG_ERROR([Missing Poco/Net/Context.h])) +AC_CHECK_LIB(PocoFoundation,main,LIBS="$LIBS -lPocoFoundation", + AC_MSG_ERROR([libPocoFoundation not found!])) +AC_CHECK_LIB(PocoUtil,main,LIBS="$LIBS -lPocoUtil", + AC_MSG_ERROR([libPocoUtil not found!])) +AC_CHECK_LIB(PocoNet,main,LIBS="$LIBS -lPocoNet", + AC_MSG_ERROR([libPocNet not found!])) +AC_CHECK_LIB(PocoNetSSL,main,LIBS="$LIBS -lPocoNetSSL", + AC_MSG_ERROR([libPocNetSSL not found!])) + +AC_CONFIG_FILES([Makefile poco/Makefile]) +AC_OUTPUT diff --git a/tools/usb/usbip/websocket/doc/usbws.8 b/tools/usb/usbip/websocket/doc/usbws.8 new file mode 100644 index 0000000..cc9f8ad --- /dev/null +++ b/tools/usb/usbip/websocket/doc/usbws.8 @@ -0,0 +1,192 @@ +.TH USBWS "8" "March 2015" "usbws" "System Administration Utilities" +.SH NAME +usbws \- manage USB/IP devices via WebSocket +.SH SYNOPSIS +.B usbws +<\fIcommand\fR> [\fIoptions\fR] + +.SH DESCRIPTION +On a USB/IP device side computer, +lists local devices, makes a device importable, makes not importable, +export and unexport. +On a USB/IP application side computer, +lists importable devices from device side, import device and unimport device. +Connect and attach command will not return +and they transmit USB packets between a daemon +until disconnect or detach command is executed respectively. + +.SH COMMANDS +.HP +\fBversion\fR +.IP +Show version and exit. +.PP + +.HP +\fBhelp\fR +.IP +Print the program help message, or help on a specific command, and +then exit. +.PP + +.HP +\fBattach\fR \-\-url <\fIurl\fR> \-\-busid <\fIbus_id\fR> [\fIoptions\fR] +.IP +Attach a importable USB device from remote computer. +.PP + +.HP +\fBdetach\fR \-\-port <\fIport\fR> [\fIoptions\fR] +.IP +Detach an imported USB device. +.PP + +.HP +\fBbind\fR \-\-busid <\fIbusid\fR> [\fIoptions\fR] +.IP +Make a USB device importable from remote computer. +.PP + +.HP +\fBunbind\fR \-\-busid <\fIbusid\fR> [\fIoptions\fR] +.IP +Make a USB device not importable so it can be used by a local driver. +.PP + +.HP +\fBlist\fR \-\-url <\fIurl\fR> [\fIoptions\fR] +.IP +List importable USB devices from a remote computer. +.PP + +.HP +\fBlist\fR \-\-local [\fIoptions\fR] +.IP +List local USB devices. +.PP + +.HP +\fBport\fR +.IP +List imported USB devices. +.PP + + +.SH OPTIONS +.HP +\fB\-d\fR, \fB\-\-debug\fR +.IP +Print debugging information. +.PP + +.HP +\fB\-uURL\fR, \fB\-\-url URL\fR +.IP +URL served by remote usbip daemon. Scheme must be \fBws\fR or \fBwss\fR. +.PP + +.HP +\fB\-xURL\fR, \fB\-\-proxy URL\fR +.IP +URL of HTTP proxy server. +.PP + +.HP +\fB\-bBUS-ID\fR, \fB\-\-busid BUS-ID\fR +.IP +Bus ID of a USB device. +.PP + +.HP +\fB\-oCONN-TOUT\fR, \fB\-\-timeout CONN-TIMEOUT\fR +.IP +Connect timeout in seconds. Defult is 5. +.PP + +.HP +\fB\-iINTERVAL\fR, \fB\-\-interval INTERVAL\fR +.IP +Noncommunication time period to send ping-pong in seconds. +Default is 60. 0 denotes not to use ping-pong. +.PP + +.HP +\fB\-tPORT\fR, \fB\-\-port PORT\fR +.IP +Port number to detach. +.PP + +.HP +\fB\-l\fR, \fB\-\-local\fR +.IP +List local devices. +.PP + +.HP +\fB\-P\fR, \fB\-\-parsable\fR +.IP +Use parsable list format. +.PP + +.HP +\fB\-cCERT-FILE\fR, \fB\-\-cert CERT-FILE\fR +.IP +Certificate file for SSL in PEM format. Default is ./cert/clinet.crt. +.PP + +.HP +\fB\-kKEY-FILE\fR, \fB\-\-key KEY-FILE\fR +.IP +Private key file for SSL in PEM format. Default is ./cert/clinet.key. +.PP + +.HP +\fB\-Vverification-mode\fR, \fB\-\-verification verification-mode\fR +.IP +Verification mode for SSL from 'none' or 'relaxed'. Default is 'none'. +.PP + +.HP +\fB\-rROOT-CERT-FILE\fR, \fB\-\-root ROOT-CERT-FILE\fR +.IP +Root CA certificate file for SSL in PEM format. Default is none. +.PP + + +.SH EXAMPLES + + dev: - at device side computer. + app: - at application side computer. + +Import from application side computer. + dev:# usbwsd + - Start daemon. + dev:# usbws list + - List local USB devices. + dev:# usbws bind --busid 1-2 + - Make a USB device importable from a remote computer. + app:# usbws list --url ws://172.1.2.3/usbip + - List importable USB devices from the computer. + app:# usbws attach --url ws://172.1.2.3/usbip --busid 1-2 + - Import the remote USB device. + app:# usbws port + - List imported USB devices. + app:# usbws detach --port 0 + - Detach a USB device. + dev:# usbws unbind --busid 1-2 + - Make the USB device not importable, then release to local. + +Export from device side computer. + app:# usbwsa + - Start daemon. + dev:# usbws list + - List local USB devices. + dev:# usbws connect --url ws://172.4.5.6 --busid 1-2 + - Export a USB device to a remote computer. + dev:# usbws disconnect --url ws://172.4.5.6 --busid 1-2 + - Unxport the USB device from a remote computer. + + +.SH "SEE ALSO" +\fBusbwsd\fP\fB(8)\fB\fP +\fBusbwsa\fP\fB(8)\fB\fP diff --git a/tools/usb/usbip/websocket/doc/usbwsa.8 b/tools/usb/usbip/websocket/doc/usbwsa.8 new file mode 100644 index 0000000..3cb8783 --- /dev/null +++ b/tools/usb/usbip/websocket/doc/usbwsa.8 @@ -0,0 +1,101 @@ +.TH USBWS "8" "March 2015" "usbwsa" "System Administration Utilities" +.SH NAME +usbwsa \- USB/IP application side WebSocket daemon +.SH SYNOPSIS +.B usbwsa +[\fIoptions\fR] + +.SH DESCRIPTION +.B usbwsa +runs on application side computer and services exported USB devices from +device side computer. + +Devices are exported using +.B usbws connect +at device side computer. + + +.SH OPTIONS +.HP +\fB\-d\fR, \fB\-\-debug\fR +.IP +Print debugging information. +.PP + +\fB\-tPORT\fR, \fB\-\-tcp\-port PORT\fR +.IP +Listen on TCP/IP port PORT. Default is 443 if --ssl option is specified, otherwise 443. +.PP + +\fB\-pPATH\fR, \fB\-\-path PATH\fR +.IP +Path in URL served by daemon. Default is 'usbip'. +.PP + +.HP +\fB\-iINTERVAL\fR, \fB\-\-interval INTERVAL\fR +.IP +Noncommunication time period to send ping-pong in seconds. +Default is 60. 0 denotes not to use ping-pong. +.PP + +\fB\-s\fR, \fB\-\-ssl\fR +.IP +Enable SSL. +.PP + +.HP +\fB\-cCERT-FILE\fR, \fB\-\-cert CERT-FILE\fR +.IP +Certificate file for SSL in PEM format. Default is ./cert/server.crt. +.PP + +.HP +\fB\-kKEY-FILE\fR, \fB\-\-key KEY-FILE\fR +.IP +Private key file for SSL in PEM format. Default is ./cert/server.key. +.PP + +.HP +\fB\-Vverification-mode\fR, \fB\-\-verification verification-mode\fR +.IP +Verification mode for SSL from 'none', 'relaxed', 'strict' or 'once'. Default is 'none'. +.PP + +.HP +\fB\-rROOT-CERT-FILE\fR, \fB\-\-root ROOT-CERT-FILE\fR +.IP +Root CA certificate file for SSL in PEM format. Default is none. +.PP + +\fB\-h\fR, \fB\-\-help\fR +.IP +Print the program help message and exit. +.PP + +.HP +\fB\-v\fR, \fB\-\-version\fR +.IP +Show version. +.PP + + +.SH EXAMPLES + + app: - at application side computer. + dev: - at device side computer. + + app:# usbwsa + - Start daemon. + dev:# usbws list + - List local USB devices. + dev:# usbws connect --url ws://172.4.5.6 --busid 1-2 + - Export a USB device to a remote computer. + dev:# usbws disconnect --url ws://172.4.5.6 --busid 1-2 + - Unxport the USB device from a remote computer. + + +.SH "SEE ALSO" +\fBusbws\fP\fB(8)\fB\fP +\fBusbwsd\fP\fB(8)\fB\fP + diff --git a/tools/usb/usbip/websocket/doc/usbwsd.8 b/tools/usb/usbip/websocket/doc/usbwsd.8 new file mode 100644 index 0000000..b5c1ae1 --- /dev/null +++ b/tools/usb/usbip/websocket/doc/usbwsd.8 @@ -0,0 +1,109 @@ +.TH USBWS "8" "March 2015" "usbwsd" "System Administration Utilities" +.SH NAME +usbwsd \- USB/IP device side WebSocket daemon +.SH SYNOPSIS +.B usbwsd +[\fIoptions\fR] + +.SH DESCRIPTION +.B usbwsd +runs on divice side computer and provides USB/IP application side computer +to import USB devices. + +Devices have to explicitly be importable from remote computer using +.B usbip bind +before usbipd makes them available. + + +.SH OPTIONS +.HP +\fB\-d\fR, \fB\-\-debug\fR +.IP +Print debugging information. +.PP + +\fB\-tPORT\fR, \fB\-\-tcp\-port PORT\fR +.IP +Listen on TCP/IP port PORT. Default is 443 if --ssl option is specified, otherwise 443. +.PP + +\fB\-pPATH\fR, \fB\-\-path PATH\fR +.IP +Path in URL served by daemon. Default is 'usbip'. +.PP + +.HP +\fB\-iINTERVAL\fR, \fB\-\-interval INTERVAL\fR +.IP +Noncommunication time period to send ping-pong in seconds. +Default is 60. 0 denotes not to use ping-pong. +.PP + +\fB\-s\fR, \fB\-\-ssl\fR +.IP +Enable SSL. +.PP + +.HP +\fB\-cCERT-FILE\fR, \fB\-\-cert CERT-FILE\fR +.IP +Certificate file for SSL in PEM format. Default is ./cert/server.crt. +.PP + +.HP +\fB\-kKEY-FILE\fR, \fB\-\-key KEY-FILE\fR +.IP +Private key file for SSL in PEM format. Default is ./cert/server.key. +.PP + +.HP +\fB\-Vverification-mode\fR, \fB\-\-verification verification-mode\fR +.IP +Verification mode for SSL from 'none', 'relaxed', 'strict' or 'once'. Default is 'none'. +.PP + +.HP +\fB\-rROOT-CERT-FILE\fR, \fB\-\-root ROOT-CERT-FILE\fR +.IP +Root CA certificate file for SSL in PEM format. Default is none. +.PP + +\fB\-h\fR, \fB\-\-help\fR +.IP +Print the program help message and exit. +.PP + +.HP +\fB\-v\fR, \fB\-\-version\fR +.IP +Show version. +.PP + + +.SH EXAMPLES + + dev: - at device side computer. + app: - at application side computer. + + dev:# usbwsd + - Start daemon. + dev:# usbws list + - List local USB devices. + dev:# usbws bind --busid 1-2 + - Make a USB device importable from a remote computer. + app:# usbws list --url ws://172.1.2.3/usbip + - List importable USB devices from the computer. + app:# usbws attach --url ws://172.1.2.3/usbip --busid 1-2 + - Import the remote USB device. + app:# usbws port + - List imported USB devices. + app:# usbws detach --port 0 + - Detach a USB device. + dev:# usbws unbind --busid 1-2 + - Make the USB device not importable, then release to local. + + +.SH "SEE ALSO" +\fBusbws\fP\fB(8)\fB\fP +\fBusbwsa\fP\fB(8)\fB\fP + diff --git a/tools/usb/usbip/websocket/poco/Makefile.am b/tools/usb/usbip/websocket/poco/Makefile.am new file mode 100644 index 0000000..5ecf53e --- /dev/null +++ b/tools/usb/usbip/websocket/poco/Makefile.am @@ -0,0 +1,18 @@ +AM_CPPFLAGS = -I$(top_srcdir)/../libsrc -I$(top_srcdir)/../src + +bin_PROGRAMS = usbws usbwsa usbwsd + +usbws_LDFLAGS = -lPocoFoundation -lPocoUtil -lPocoNet -lPocoNetSSL -lstdc++ +usbws_LDADD = $(top_builddir)/../libsrc/libusbiplib.la $(top_builddir)/../src/libusbip.la +usbws_SOURCES = USBWSCommand.cpp USBWSWebSocket.cpp + +usbwsa_LDFLAGS = -lPocoFoundation -lPocoUtil -lPocoNet -lPocoNetSSL -lstdc++ +usbwsa_LDADD = $(top_builddir)/../libsrc/libusbiplib.la $(top_builddir)/../src/libusbipa.la +usbwsa_SOURCES = USBWSDaemon.cpp USBWSWebSocket.cpp \ + USBWSRequestHandlerFactory.cpp USBWSRequestHandler.cpp + +usbwsd_LDFLAGS = -lPocoFoundation -lPocoUtil -lPocoNet -lPocoNetSSL -lstdc++ +usbwsd_LDADD = $(top_builddir)/../libsrc/libusbiplib.la $(top_builddir)/../src/libusbipd.la +usbwsd_SOURCES = USBWSDaemon.cpp USBWSWebSocket.cpp \ + USBWSRequestHandlerFactory.cpp USBWSRequestHandler.cpp + diff --git a/tools/usb/usbip/websocket/poco/USBWSCommand.cpp b/tools/usb/usbip/websocket/poco/USBWSCommand.cpp new file mode 100644 index 0000000..9f8cb9f --- /dev/null +++ b/tools/usb/usbip/websocket/poco/USBWSCommand.cpp @@ -0,0 +1,410 @@ +/* + * Copyright (C) 2015 Nobuo IWata + * + * This 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 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 program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#include "USBWSCommand.h" +#include "USBWSWebSocket.h" +#include "USBWSUtil.h" +#include "Poco/Net/HTTPClientSession.h" +#include "Poco/Net/HTTPSClientSession.h" +#include "Poco/Net/HTTPRequest.h" +#include "Poco/Net/HTTPResponse.h" +#include "Poco/Net/NetException.h" +#include "Poco/Util/HelpFormatter.h" +#include "Poco/StringTokenizer.h" +#include "Poco/Exception.h" +#include <iostream> + +extern "C" { +#include "usbip_common.h" +#include "usbip_host_driver.h" +#include "usbip.h" +} + +using namespace ::Poco; +using namespace ::Poco::Net; +using namespace ::Poco::Util; +using namespace ::Usbip::WebSock::Poco; + +const std::string USBWSCommand::kDefaultKey("cert/client.key"); +const std::string USBWSCommand::kDefaultCert("cert/client.crt"); +const int USBWSCommand::kMajorVersion(0); +const int USBWSCommand::kMinorVersion(0); +const int USBWSCommand::kRevision(1); + +USBWSCommand::USBWSCommand() : + fDebug(false), + fURL(), + fProxy(), + fBusID(), + fConnTimeout(5), + fPingPong(60), + fPort(), + fLocal(false), + fParsable(false), + fKey(kDefaultKey), + fCert(kDefaultCert), + fRootCert(), + fVerificationStr(), + fVerification(Context::VERIFY_NONE), + fSSL(false), + fHost(), + fTcpPort(0), + fPath(), + fProxyHost(), + fProxyPort(), + fProxyUser(), + fProxyPwd(), + fHelp(false), + fVersion(false), + fClientSession(0) +{ +} + +USBWSCommand::~USBWSCommand() +{ +} + +void USBWSCommand::initialize(Application& self) +{ + Application::initialize(self); +} + +void USBWSCommand::uninitialize(void) +{ + Application::uninitialize(); +} + +void USBWSCommand::defineOptions(OptionSet& options) +{ + Application::defineOptions(options); + options.addOption(Option("debug", "d", "Print debug information.")); + options.addOption(Option("url", "u", "WebSocket URL for USB/IP." + ).argument("url")); + options.addOption(Option("proxy", "x", "Proxy URL if used." + ).argument("proxy")); + options.addOption(Option("busid", "b", "Bus ID of a device to export." + ).argument("busid")); + options.addOption(Option("timeout", "o", + "Connect timeout in seconds. Default is 5." + ).argument("timeout-sec")); + options.addOption(Option("interval", "i", + "Noncommunication time period to send ping-pong in seconds." + " Default is 60. 0 denotes not to use ping-pong." + ).argument("interval-sec")); + options.addOption(Option("port", "p", "Attached port to detach." + ).argument("port")); + options.addOption(Option("local", "l", "List local devices.")); + options.addOption(Option("parsable", "P", "Parsable list output.")); + options.addOption(Option("key", "k", + "Private key file. Default is " + kDefaultKey + "." + ).argument("key-file")); + options.addOption(Option("cert", "c", + "Certificate file. Default is " + kDefaultCert + "." + ).argument("cert-file")); + options.addOption(Option("root-cert", "r", + "Certificate file of root CA." + ).argument("root-cert-file")); + options.addOption(Option("verification", "V", + "Certificate verification mode - none(default) or relaxed." + ).argument("verification-mode")); + options.addOption(Option("help", "h", "Print this help.")); + options.addOption(Option("version", "v", "Show version.")); +} + +void USBWSCommand::handleOption(const std::string& name, const std::string & value) +{ + Application::handleOption(name, value); + + if (name == "debug") { + fDebug = true; + usbip_use_debug = 1; + } else if (name == "url") { + fURL = value; + } else if (name == "proxy") { + fProxy = value; + } else if (name == "busid") { + fBusID = value; + } else if (name == "timeout") { + fConnTimeout = USBWSUtil::s2i(value); + } else if (name == "interval") { + fPingPong = USBWSUtil::s2i(value); + } else if (name == "port") { + fPort = value; + } else if (name == "local") { + fLocal = true; + } else if (name == "parsable") { + fParsable = true; + } else if (name == "key") { + fKey = value; + } else if (name == "cert") { + fCert = value; + } else if (name == "root-cert") { + fRootCert = value; + } else if (name == "verification") { + fVerificationStr = value; + } else if (name == "help") { + fHelp = true; + } else if (name == "version") { + fVersion = true; + } +} + +void USBWSCommand::help() +{ + HelpFormatter helpFormatter(options()); + helpFormatter.setCommand(commandName() + + " <connect | disconnect | list | port | bind |" + " attach | detach | unbind> [options]"); + helpFormatter.format(std::cout); +} + +void USBWSCommand::version() +{ + std::cout << kMajorVersion << "." << kMinorVersion << "." << kRevision << std::endl; +} + +void USBWSCommand::getProxyCredentials(const URI &url) +{ + std::string info = url.getUserInfo(); + if (info.size() > 0) { + StringTokenizer t(info, ":"); + try { + fProxyUser = t[0]; + fProxyPwd = t[1]; + } catch (RangeException& e) { + } + } +} + +int USBWSCommand::main(const std::vector<std::string>& args) +{ + usbip_use_stderr = 1; + std::string cmd(args[0]); + if (fHelp || cmd == "help") { + help(); + return Application::EXIT_OK; + } else if (fVersion || cmd == "version") { + version(); + return Application::EXIT_OK; + } + if (fURL.size() > 0) { + try { + URI url(fURL); + std::string scheme = url.getScheme(); + if (scheme == "wss") { + fSSL = true; + } else if (scheme != "ws") { + std::cerr << "Unsupported scheme in URL." + << std::endl; + return Application::EXIT_USAGE; + } + fHost = url.getHost(); + fTcpPort = url.getPort(); + fPath = url.getPath(); + } catch (SyntaxException& e) { + std::cerr << "URL syntax error." << std::endl; + return Application::EXIT_USAGE; + } + } + if (fTcpPort == 0) { + if (fSSL) { + fTcpPort = 443; + } else { + fTcpPort = 80; + } + dbg("TCP port has been set to %d", fTcpPort); + } + if ((cmd == "connect" || cmd == "disconnect" || cmd == "attach" || + (cmd == "list" && fURL.size() > 0)) && + fHost.size() <= 0) { + std::cerr << "Missing host." << std::endl; + return Application::EXIT_USAGE; + } + if ((cmd == "connect" || cmd == "disconnect" || cmd == "attach" || + cmd == "bind" || cmd == "unbind") && + fBusID.size() <= 0) { + std::cerr << "Missing bus ID." << std::endl; + return Application::EXIT_USAGE; + } + if (cmd == "detach" && fPort.size() <= 0) { + std::cerr << "Missing port." << std::endl; + return Application::EXIT_USAGE; + } + if (fVerificationStr.size() > 0) { + if (fVerificationStr == "none") { + fVerification = Context::VERIFY_NONE; + } else if (fVerificationStr == "relaxed") { + fVerification = Context::VERIFY_RELAXED; + } else { + std::cerr << "Unsupported verification mode." << std::endl; + return Application::EXIT_USAGE; + } + } + if (fProxy.size() > 0) { + try { + URI url(fProxy); + fProxyHost = url.getHost(); + fProxyPort = url.getPort(); + getProxyCredentials(url); + dbg("Using proxy host:%s port:%d user:%s pwd:%s", + fProxyHost.c_str(), fProxyPort, + fProxyUser.c_str(), fProxyPwd.c_str()); + } catch (SyntaxException& e) { + std::cerr << "Proxy syntax error." << std::endl; + return Application::EXIT_USAGE; + } + } + + std::string tcpPortStr = USBWSUtil::i2s(fTcpPort); + + usbip_conn_init(USBWSCommand::connect, USBWSCommand::close); + + if (cmd == "connect") { + if (usbip_connect_device( + fHost.c_str(), tcpPortStr.c_str(), fBusID.c_str())) { + return Application::EXIT_SOFTWARE; + } + } else if (cmd == "disconnect") { + if (usbip_disconnect_device( + fHost.c_str(), tcpPortStr.c_str(), fBusID.c_str())) { + return Application::EXIT_SOFTWARE; + } + } else if (cmd == "attach") { + if (usbip_attach_device( + fHost.c_str(), tcpPortStr.c_str(), fBusID.c_str())) { + return Application::EXIT_SOFTWARE; + } + } else if (cmd == "detach") { + if (usbip_detach_port(fPort.c_str())) { + return Application::EXIT_SOFTWARE; + } + } else if (cmd == "port") { + if (usbip_list_imported_devices()) { + return Application::EXIT_SOFTWARE; + } + } else if (cmd == "list" && fURL.size() > 0) { + if (usbip_list_importable_devices( + fHost.c_str(), tcpPortStr.c_str())) { + return Application::EXIT_SOFTWARE; + } + } else if (cmd == "list") { + if (usbip_list_devices(fParsable)) { + return Application::EXIT_SOFTWARE; + } + } else if (cmd == "bind") { + if (usbip_bind_device(fBusID.c_str())) { + return Application::EXIT_SOFTWARE; + } + } else if (cmd == "unbind") { + if (usbip_unbind_device(fBusID.c_str())) { + return Application::EXIT_SOFTWARE; + } + } else { + help(); + return Application::EXIT_USAGE; + } + return Application::EXIT_OK; +} + +POCO_APP_MAIN(USBWSCommand) + +int USBWSCommand::openSession() +{ + if (fSSL) { + Context* ctx = new Context(Context::CLIENT_USE, fKey, fCert, fRootCert, fVerification); + // TODO: manipulate other params. + fClientSession = new HTTPSClientSession(fHost, fTcpPort, ctx); + } else { + fClientSession = new HTTPClientSession(fHost, fTcpPort); + } + if (fClientSession == NULL) { + return -1; + } + if (fProxy.size() > 0) { + fClientSession->setProxy(fProxyHost, fProxyPort); + if (fProxyUser.size() > 0) { + fClientSession->setProxyCredentials(fProxyUser, fProxyPwd); + } + } + fClientSession->setKeepAlive(true); + fClientSession->setTimeout(Timespan(fConnTimeout, 0)); + return 0; +} + +void USBWSCommand::closeSession() +{ + if (fClientSession) { + delete fClientSession; + fClientSession = 0; + } +} + +usbip_sock_t *USBWSCommand::connect(const char *host, const char *port) +{ + USBWSCommand& app = (USBWSCommand&)instance(); + + usbip_sock_t* sock = (usbip_sock_t*)malloc(sizeof(usbip_sock_t)); + if (sock == NULL) { + app.logger().error("Fail to alloc sock."); + return NULL; + } + + try { + if (app.openSession()) { + app.logger().error("Fail to open session."); + free(sock); + return NULL; + } + + USBWSWebSocket* ws; + HTTPRequest req(HTTPRequest::HTTP_GET, app.fPath); + HTTPResponse rsp; + ws = new USBWSWebSocket(*app.fClientSession, req, rsp, + app.fPingPong); + ws->setApp(&app); + usbip_sock_init(sock, ws->getSockfd(), ws, + USBWSWebSocket::send, USBWSWebSocket::recv, + USBWSWebSocket::shutdown); + return sock; + } catch (WebSocketException& e) { + app.logger().log(e); + } catch (::Poco::IOException& e) { + app.logger().log(e); + } + free(sock); + return NULL; +} + +void USBWSCommand::close(usbip_sock_t *sock) +{ + if (sock) { + USBWSWebSocket* ws = (USBWSWebSocket*)sock->arg; + if (ws) { + USBWSCommand* app = (USBWSCommand*)ws->getApp(); + try { + app->closeSession(); + } catch (::Poco::IOException& e) { + app->logger().log(e); + } + delete ws; + } + free(sock); + } +} + diff --git a/tools/usb/usbip/websocket/poco/USBWSCommand.h b/tools/usb/usbip/websocket/poco/USBWSCommand.h new file mode 100644 index 0000000..edf7c2f --- /dev/null +++ b/tools/usb/usbip/websocket/poco/USBWSCommand.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2015 Nobuo Iwata + * + * This 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 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 program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifndef _USBIP_WEBSOCK_POCO_USBWS_COMMAND_H +#define _USBIP_WEBSOCK_POCO_USBWS_COMMAND_H + +#include "Poco/Net/HTTPClientSession.h" +#include "Poco/Net/Context.h" +#include "Poco/Util/Application.h" +#include "Poco/Util/Option.h" +#include "Poco/Util/OptionSet.h" +#include "Poco/URI.h" + +extern "C" { +#include "usbip_common.h" +} + +namespace Usbip { namespace WebSock { namespace Poco { + +using namespace ::Poco; +using namespace ::Poco::Net; +using namespace ::Poco::Util; + +class USBWSCommand : + public ::Poco::Util::Application +{ +public: + USBWSCommand(); + ~USBWSCommand(); +protected: + // For Application + void initialize(Application& self); + void uninitialize(void); + void defineOptions(OptionSet& options); + void handleOption(const std::string& name, const std::string & value); + int main(const std::vector<std::string>& args); +public: + static usbip_sock_t *connect(const char *host, const char *port); + static void close(usbip_sock_t *sock); +private: + void help(); + void version(); + void getProxyCredentials(const URI &url); + int openSession(); + void closeSession(); + + bool fDebug; + std::string fURL; + std::string fProxy; + std::string fBusID; + std::string fPort; + int fConnTimeout; + int fPingPong; + bool fLocal; + bool fParsable; + std::string fKey; + std::string fCert; + std::string fRootCert; + std::string fVerificationStr; + Context::VerificationMode fVerification; + bool fSSL; + std::string fHost; + int fTcpPort; + std::string fPath; + std::string fProxyHost; + int fProxyPort; + std::string fProxyUser; + std::string fProxyPwd; + bool fHelp; + bool fVersion; + HTTPClientSession* fClientSession; + + static const std::string kDefaultKey; + static const std::string kDefaultCert; + static const int kMajorVersion; + static const int kMinorVersion; + static const int kRevision; +}; + +}}} + +#endif /* !_USBIP_WEBSOCK_POCO_USBWS_COMMAND_H */ + diff --git a/tools/usb/usbip/websocket/poco/USBWSDaemon.cpp b/tools/usb/usbip/websocket/poco/USBWSDaemon.cpp new file mode 100644 index 0000000..bf46fb0 --- /dev/null +++ b/tools/usb/usbip/websocket/poco/USBWSDaemon.cpp @@ -0,0 +1,228 @@ +/* + * Copyright (C) 2015 Nobuo Iwata + * + * This 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 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 program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#include "USBWSDaemon.h" +#include "USBWSRequestHandlerFactory.h" +#include "USBWSUtil.h" +#include "Poco/Net/HTTPServer.h" +#include "Poco/Net/HTTPServerParams.h" +#include "Poco/Net/ServerSocket.h" +#include "Poco/Net/SecureServerSocket.h" +#include "Poco/Util/HelpFormatter.h" +#include <iostream> + +extern "C" { +#include "usbip_common.h" +#include "usbipd.h" +} + +using namespace ::Poco; +using namespace ::Poco::Net; +using namespace ::Poco::Util; +using namespace ::Usbip::WebSock::Poco; + +const std::string USBWSDaemon::kDefaultPath("/usbip"); +const std::string USBWSDaemon::kDefaultKey("cert/server.key"); +const std::string USBWSDaemon::kDefaultCert("cert/server.crt"); +const int USBWSDaemon::kMajorVersion(0); +const int USBWSDaemon::kMinorVersion(0); +const int USBWSDaemon::kRevision(1); + +USBWSDaemon::USBWSDaemon() : + fDebug(false), + fTcpPort(0), + fPath(kDefaultPath), + fPingPong(60), + fSSL(false), + fKey(kDefaultKey), + fCert(kDefaultCert), + fRootCert(), + fVerificationStr(), + fVerification(Context::VERIFY_NONE), + fHelp(false), + fVersion(false), + fSocket(0) +{ +} + +USBWSDaemon::~USBWSDaemon() +{ +} + +void USBWSDaemon::initialize(Application& self) +{ + ServerApplication::initialize(self); +} + +void USBWSDaemon::uninitialize(void) +{ + ServerApplication::uninitialize(); +} + +void USBWSDaemon::defineOptions(OptionSet& options) +{ + ServerApplication::defineOptions(options); + options.addOption(Option("debug", "d", "Print debug information.")); + options.addOption(Option("tcp-port", "t", "Port number to listen." + ).argument("port-number")); + options.addOption(Option("path", "p", + "WebSocket path to serve USBIP/IP. Default is " + + kDefaultPath + "." + ).argument("path")); + options.addOption(Option("interval", "i", + "Noncommunication time period to send ping-pong in seconds." + " Default is 60. 0 denotes not to use ping-pong." + ).argument("interval-sec")); + options.addOption(Option("ssl", "s", "Enable SSL.")); + options.addOption(Option("key", "k", + "Private key file. Default is " + kDefaultKey + "." + ).argument("cert-file")); + options.addOption(Option("cert", "c", + "Certificate file. Default is " + kDefaultCert + "." + ).argument("key-file")); + options.addOption(Option("root-cert", "r", + "Certificate file of root CA." + ).argument("root-cert-file")); + options.addOption(Option("verification", "V", + "Certificate verification mode -" + " none(default), relaxed, strict or once." + ).argument("verification-mode")); + options.addOption(Option("help", "h", "Print this help.")); + options.addOption(Option("version", "v", "Show version.")); +} + +void USBWSDaemon::handleOption(const std::string& name, const std::string & value) +{ + ServerApplication::handleOption(name, value); + + if (name == "debug") { + fDebug = true; + usbip_use_debug = 1; + } else if (name == "tcp-port") { + fTcpPort = USBWSUtil::s2i(value); + } else if (name == "path") { + fPath = value; + } else if (name == "interval") { + fPingPong = USBWSUtil::s2i(value); + } else if (name == "ssl") { + fSSL = true; + } else if (name == "key") { + fKey = value; + } else if (name == "cert") { + fCert = value; + } else if (name == "root-cert") { + fRootCert = value; + } else if (name == "verification") { + fVerificationStr = value; + } else if (name == "help") { + fHelp = true; + } else if (name == "version") { + fVersion = true; + } +} + +void USBWSDaemon::help() +{ + HelpFormatter helpFormatter(options()); + helpFormatter.setCommand(commandName()); + helpFormatter.format(std::cout); +} + +void USBWSDaemon::version() +{ + std::cout << kMajorVersion << "." << kMinorVersion << "." << kRevision << std::endl; +} + +int USBWSDaemon::main(const std::vector<std::string>& args) +{ + usbip_use_stderr = 1; + if (fHelp) { + help(); + return Application::EXIT_OK; + } + if (fVersion) { + version(); + return Application::EXIT_OK; + } + if (fTcpPort == 0) { + if (fSSL) { + fTcpPort = 443; + } else { + fTcpPort = 80; + } + } + if (fVerificationStr.size() > 0) { + if (fVerificationStr == "none") { + fVerification = Context::VERIFY_NONE; + } else if (fVerificationStr == "relaxed") { + fVerification = Context::VERIFY_RELAXED; + } else if (fVerificationStr == "strict") { + fVerification = Context::VERIFY_STRICT; + } else if (fVerificationStr == "once") { + fVerification = Context::VERIFY_ONCE; + } else { + std::cerr << "Unsupported verification mode." << std::endl; + return Application::EXIT_USAGE; + } + } + if (usbip_driver_open()) { + logger().error("Fail to open vhci driver."); + return Application::EXIT_IOERR; + } + if (openSocket()) { + logger().error("Fail to open socket."); + return Application::EXIT_IOERR; + } + HTTPServer svr( + new USBWSRequestHandlerFactory(fPath, fPingPong, logger()), + *fSocket, new HTTPServerParams()); + svr.start(); + dbg("Waiting at %d:%s %s", + fTcpPort, fPath.c_str(), fSSL? "with SSL" : ""); + waitForTerminationRequest(); + logger().information("Stopping server."); + usbip_break_connections(); + svr.stop(); + closeSocket(); + usbip_driver_close(); + return Application::EXIT_OK; +} + +POCO_SERVER_MAIN(USBWSDaemon) + +int USBWSDaemon::openSocket() +{ + if (fSSL) { + Context *ctx = new Context(Context::SERVER_USE, fKey, fCert, fRootCert, fVerification); + // TODO: manipulate other params. + fSocket = new SecureServerSocket(fTcpPort, 64, ctx); + } else { + fSocket = new ServerSocket(fTcpPort, 64); + } + return 0; +} + +void USBWSDaemon::closeSocket() +{ + if (fSocket) { + delete fSocket; + } + fSocket = 0; +} + diff --git a/tools/usb/usbip/websocket/poco/USBWSDaemon.h b/tools/usb/usbip/websocket/poco/USBWSDaemon.h new file mode 100644 index 0000000..84a5a85 --- /dev/null +++ b/tools/usb/usbip/websocket/poco/USBWSDaemon.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2015 Nobuo Iwata + * + * This 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 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 program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifndef _USBIP_WEBSOCK_POCO_USBWS_DAEMON_H +#define _USBIP_WEBSOCK_POCO_USBWS_DAEMON_H + +#include "Poco/Net/ServerSocket.h" +#include "Poco/Net/Context.h" +#include "Poco/Util/ServerApplication.h" +#include "Poco/Util/Option.h" +#include "Poco/Util/OptionSet.h" + +namespace Usbip { namespace WebSock { namespace Poco { + +using namespace ::Poco; +using namespace ::Poco::Net; +using namespace ::Poco::Util; + +class USBWSDaemon: + public ::Poco::Util::ServerApplication +{ +public: + USBWSDaemon(); + ~USBWSDaemon(); +protected: + // For ServerApplication + void initialize(Application& self); + void uninitialize(void); + void defineOptions(OptionSet& options); + void handleOption(const std::string& name, const std::string & value); + int main(const std::vector<std::string>& args); +private: + void help(void); + void version(void); + int openSocket(void); + void closeSocket(void); + + bool fDebug; + int fTcpPort; + std::string fPath; + int fPingPong; + bool fSSL; + std::string fKey; + std::string fCert; + std::string fRootCert; + std::string fVerificationStr; + Context::VerificationMode fVerification; + bool fHelp; + bool fVersion; + ServerSocket* fSocket; + + static const int kDefaultTcpPort; + static const std::string kDefaultPath; + static const std::string kDefaultKey; + static const std::string kDefaultCert; + static const int kMajorVersion; + static const int kMinorVersion; + static const int kRevision; +}; + +}}} + +#endif /* !_USBIP_WEBSOCK_POCO_USBWS_DAEMON_H */ + diff --git a/tools/usb/usbip/websocket/poco/USBWSRequestHandler.cpp b/tools/usb/usbip/websocket/poco/USBWSRequestHandler.cpp new file mode 100644 index 0000000..e0e3023 --- /dev/null +++ b/tools/usb/usbip/websocket/poco/USBWSRequestHandler.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2015 Nobuo Iwata + * + * This 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 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 program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#include "USBWSRequestHandler.h" +#include "USBWSWebSocket.h" +#include "USBWSUtil.h" +#include "Poco/Net/Socket.h" +#include "Poco/Net/NetException.h" +extern "C" { +#include "usbip_common.h" +#include "usbipd.h" +} + +using namespace ::Poco; +using namespace ::Poco::Net; +using namespace ::Usbip::WebSock::Poco; + +USBWSRequestHandler::USBWSRequestHandler(int pingPong, Logger& logger) : + HTTPRequestHandler(), + fPingPong(pingPong), + fLogger(logger) +{ +} + +USBWSRequestHandler::~USBWSRequestHandler() +{ +} + +void USBWSRequestHandler::handleRequest( + HTTPServerRequest& req, + HTTPServerResponse& rsp) +{ + int interrupted = 0; + fLogger.information("WebSocket connection established."); + try { + USBWSWebSocket ws(req, rsp, fPingPong); + + usbip_sock_t sock; + usbip_sock_init(&sock, ws.getSockfd(), &ws, + USBWSWebSocket::send, USBWSWebSocket::recv, + USBWSWebSocket::shutdown); + + SocketAddress addr = ws.address(); + std::string port = USBWSUtil::i2s(addr.port()); + + fLogger.information("Entering to usbip_recv_pdu()."); + usbip_recv_pdu(&sock, + addr.host().toString().c_str(), + port.c_str()); + fLogger.information("Exited from usbip_recv_pdu()."); + } catch (WebSocketException& e) { + fLogger.information("WebSocketexception."); + fLogger.log(e); + switch(e.code()) { + case WebSocket::WS_ERR_HANDSHAKE_UNSUPPORTED_VERSION: + rsp.set("Sec-WebSocket-Version", WebSocket::WEBSOCKET_VERSION); + // fallthrough + case WebSocket::WS_ERR_NO_HANDSHAKE: + case WebSocket::WS_ERR_HANDSHAKE_NO_VERSION: + case WebSocket::WS_ERR_HANDSHAKE_NO_KEY: + rsp.setContentLength(0); + rsp.send(); + break; + case WebSocket::WS_ERR_HANDSHAKE_ACCEPT: + case WebSocket::WS_ERR_UNAUTHORIZED: + case WebSocket::WS_ERR_PAYLOAD_TOO_BIG: + case WebSocket::WS_ERR_INCOMPLETE_FRAME: + default: + break; + } + } + fLogger.information("WebSocket connection terminated."); +} + diff --git a/tools/usb/usbip/websocket/poco/USBWSRequestHandler.h b/tools/usb/usbip/websocket/poco/USBWSRequestHandler.h new file mode 100644 index 0000000..fa8f8ba --- /dev/null +++ b/tools/usb/usbip/websocket/poco/USBWSRequestHandler.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2015 Nobuo Iwata + * + * This 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 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 program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifndef _USBIP_WEBSOCK_POCO_USBWS_REQUEST_HANDLER_H +#define _USBIP_WEBSOCK_POCO_USBWS_REQUEST_HANDLER_H + +#include "Poco/Net/HTTPRequestHandler.h" +#include "Poco/Net/HTTPServerRequest.h" +#include "Poco/Net/HTTPServerResponse.h" +#include "Poco/Logger.h" + +namespace Usbip { namespace WebSock { namespace Poco { + +using namespace ::Poco; +using namespace ::Poco::Net; + +class USBWSRequestHandler: + public ::Poco::Net::HTTPRequestHandler +{ +public: + USBWSRequestHandler(int pingPong, Logger& logger); + ~USBWSRequestHandler(); + bool hasError(); + void handleRequest(HTTPServerRequest& req, HTTPServerResponse& rsp); +private: + int fPingPong; + Logger &fLogger; +}; + +}}} + +#endif /* !_USBIP_WS_POCO_USBWS_REQUEST_HANDLER_H */ + diff --git a/tools/usb/usbip/websocket/poco/USBWSRequestHandlerFactory.cpp b/tools/usb/usbip/websocket/poco/USBWSRequestHandlerFactory.cpp new file mode 100644 index 0000000..f4ea39f --- /dev/null +++ b/tools/usb/usbip/websocket/poco/USBWSRequestHandlerFactory.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2015 Nobuo Iwata + * + * This 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 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 program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#include "USBWSRequestHandlerFactory.h" +#include "USBWSRequestHandler.h" +#include "Poco/URI.h" + +using namespace ::Poco::Net; +using namespace ::Usbip::WebSock::Poco; + +USBWSRequestHandlerFactory::USBWSRequestHandlerFactory( + std::string& path, int pingPong, Logger& logger) : + fPath(path), + fPingPong(pingPong), + fLogger(logger) +{ +} + +USBWSRequestHandlerFactory::~USBWSRequestHandlerFactory() +{ +} + +HTTPRequestHandler* USBWSRequestHandlerFactory::createRequestHandler(const HTTPServerRequest& req) +{ + URI uri(req.getURI()); + const std::string& path = uri.getPath(); + fLogger.information("Handling path:" + path); + if (path == fPath) { + return new USBWSRequestHandler(fPingPong, fLogger); + } + return 0; +} + diff --git a/tools/usb/usbip/websocket/poco/USBWSRequestHandlerFactory.h b/tools/usb/usbip/websocket/poco/USBWSRequestHandlerFactory.h new file mode 100644 index 0000000..ae5aacd --- /dev/null +++ b/tools/usb/usbip/websocket/poco/USBWSRequestHandlerFactory.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2015 Nobuo Iwata + * + * This 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 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 program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifndef _USBIP_WEBSOCK_POCO_USBWS_REQUEST_HANDLER_FACTORY_H +#define _USBIP_WEBSOCK_POCO_USBWS_REQUEST_HANDLER_FACTORY_H + +#include "Poco/Net/HTTPRequestHandlerFactory.h" +#include "Poco/Net/HTTPServerRequest.h" +#include "Poco/Logger.h" + +namespace Usbip { namespace WebSock { namespace Poco { + +using namespace ::Poco; +using namespace ::Poco::Net; + +class USBWSRequestHandlerFactory: + public ::Poco::Net::HTTPRequestHandlerFactory +{ +public: + USBWSRequestHandlerFactory(std::string& path, int pingPong, Logger& logger); + ~USBWSRequestHandlerFactory(); + HTTPRequestHandler* createRequestHandler(const HTTPServerRequest& req); +private: + std::string& fPath; + int fPingPong; + Logger& fLogger; +}; + +}}} + +#endif /* !_USBIP_WEBSOCK_POCO_USBWS_REQUEST_HANDLER_FACTORY_H */ + diff --git a/tools/usb/usbip/websocket/poco/USBWSUtil.h b/tools/usb/usbip/websocket/poco/USBWSUtil.h new file mode 100644 index 0000000..fe95270 --- /dev/null +++ b/tools/usb/usbip/websocket/poco/USBWSUtil.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2015 Nobuo Iwata + * + * This 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 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 program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifndef _USBIP_WEBSOCK_POCO_USBWS_UTIL_H +#define _USBIP_WEBSOCK_POCO_USBWS_UTIL_H + +#include <sstream> + +namespace Usbip { namespace WebSock { namespace Poco { + +using namespace ::Poco::Net; + +class USBWSUtil +{ +public: + static int s2i(const std::string& s) { + int i; + std::stringstream ss(s); + ss >> i; + return i; + }; + static int c2i(const char* c) { + std::string s(c); + return USBWSUtil::s2i(s); + }; + static std::string i2s(int i) { + std::stringstream ss; + ss << i; + return ss.str(); + }; +}; + +}}} + +#endif /* !_USBIP_WEBSOCK_POCO_USBWS_UTIL_H */ + diff --git a/tools/usb/usbip/websocket/poco/USBWSWebSocket.cpp b/tools/usb/usbip/websocket/poco/USBWSWebSocket.cpp new file mode 100644 index 0000000..cccd984 --- /dev/null +++ b/tools/usb/usbip/websocket/poco/USBWSWebSocket.cpp @@ -0,0 +1,204 @@ +/* + * Copyright (C) 2015 Nobuo Iwata + * + * This 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 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 program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#include "USBWSWebSocket.h" +#include "USBWSUtil.h" +#include "Poco/Exception.h" +#include "Poco/Net/NetException.h" + +extern "C" { +#include "usbip_common.h" +} + +using namespace ::Poco::Net; +using namespace ::Usbip::WebSock::Poco; + +USBWSWebSocket::USBWSWebSocket( + HTTPServerRequest& req, + HTTPServerResponse& rsp, + int pingPong) : + WebSocket(req, rsp), + Timer(0, pingPong * 1000), + fApp(0), + fPingPongStarted(false), + fFirstTimeout(true), + fSendLock() +{ + setKeepAlive(true); + if (pingPong > 0) { + setReceiveTimeout(Timespan(pingPong + 60, 0)); + startPingPong(); + fPingPongStarted = true; + } +} + +USBWSWebSocket::USBWSWebSocket( + HTTPClientSession& cs, + HTTPRequest& req, + HTTPResponse& rsp, + int pingPong) : + WebSocket(cs, req, rsp), + Timer(0, 0), + fApp(0), + fPingPongStarted(false), + fFirstTimeout(true), + fSendLock() +{ + setKeepAlive(true); + if (pingPong > 0) { + setReceiveTimeout(Timespan(pingPong + 60, 0)); + } +} + +ssize_t USBWSWebSocket::send(void *arg, void *buf, size_t len) +{ + USBWSWebSocket *ws = (USBWSWebSocket*)arg; + return ws->send(buf, len); +} + +ssize_t USBWSWebSocket::recv(void *arg, void *buf, size_t len, int all) +{ + USBWSWebSocket *ws = (USBWSWebSocket*)arg; + return ws->recv(buf, len, all); +} + +void USBWSWebSocket::shutdown(void *arg) +{ + USBWSWebSocket *ws = (USBWSWebSocket*)arg; + ws->shutdown(); +} + +ssize_t USBWSWebSocket::send(void *buf, size_t len) +{ + ssize_t ret; + fSendLock.lock(); + try { + ret = sendFrame(buf, len, WebSocket::FRAME_OP_BINARY); + } catch (::Poco::IOException& e) { + dbg("Send IOException %s", e.message().c_str()); + ret = -1; + errno = EIO; + } + fSendLock.unlock(); + return ret; +} + +ssize_t USBWSWebSocket::recv(void *buf, size_t len, int all) +{ + char *p = (char*)buf; + try { + ssize_t received = 0; + int op, flags; + do { + ssize_t bytes = + receiveFrame(p+received, len-received, flags); + op = flags & WebSocket::FRAME_OP_BITMASK; + if (op == WebSocket::FRAME_OP_BINARY) { + if (bytes == 0) { + return received; + } + received += bytes; + } else if (op == WebSocket::FRAME_OP_PING) { + sendPong(); + } else if (op == WebSocket::FRAME_OP_PONG) { + restartPingPong(); + } else if (op == WebSocket::FRAME_OP_CLOSE) { + throw ::Poco::IOException( + "Recieved close frame"); + } else { + throw ::Poco::Net::WebSocketException( + "Unsupported op code:" + + USBWSUtil::i2s(op)); + } + } while((all && received < len) || + op != WebSocket::FRAME_OP_BINARY); + restartPingPong(); + return received; + } catch (::Poco::Net::WebSocketException& e) { + dbg("Recv WebSocketException %s", e.message().c_str()); + errno = EINVAL; + } catch (::Poco::TimeoutException& e) { + dbg("Recv TimeoutException %s", e.message().c_str()); + errno = ETIMEDOUT; + } catch (::Poco::Net::NetException& e) { + dbg("Recv NetException %s", e.message().c_str()); + errno = EIO; + } catch (::Poco::IOException& e) { + dbg("Recv IOException %s", e.message().c_str()); + errno = EIO; + } + return -1; +} + +void USBWSWebSocket::shutdown(void) +{ + dbg("Shutting down websocket."); + fPingPongStarted = false; + shutdownReceive(); + close(); +} + +void USBWSWebSocket::startPingPong(void) +{ + TimerCallback<USBWSWebSocket> callback(*this, &USBWSWebSocket::onTimer); + start(callback); +} + +void USBWSWebSocket::restartPingPong(void) +{ + if (fPingPongStarted) { + restart(); + } +} + +void USBWSWebSocket::onTimer(Timer& timer) +{ + USBWSWebSocket& ws = (USBWSWebSocket&)timer; + if (ws.fFirstTimeout) { + ws.fFirstTimeout = false; + } else { + ws.sendPing(); + } +} + +void USBWSWebSocket::sendPing() +{ + if (fPingPongStarted) { + dbg("Ping"); + sendPingPong(WebSocket::FRAME_OP_PING); + } +} + +void USBWSWebSocket::sendPong(void) +{ + dbg("Pong"); + sendPingPong(WebSocket::FRAME_OP_PONG); +} + +void USBWSWebSocket::sendPingPong(int op) +{ + fSendLock.lock(); + try { + sendFrame(NULL, 0, op); + } catch (::Poco::IOException& e) { + dbg("Send IOException %s", e.message().c_str()); + } + fSendLock.unlock(); +} + diff --git a/tools/usb/usbip/websocket/poco/USBWSWebSocket.h b/tools/usb/usbip/websocket/poco/USBWSWebSocket.h new file mode 100644 index 0000000..d6bae0b --- /dev/null +++ b/tools/usb/usbip/websocket/poco/USBWSWebSocket.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2015 Nobuo Iwata + * + * This 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 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 program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifndef _USBIP_WEBSOCK_POCO_USBWS_WEBSOCKET_H +#define _USBIP_WEBSOCK_POCO_USBWS_WEBSOCKET_H + +#include "Poco/Net/WebSocket.h" +#include "Poco/Util/Application.h" +#include "Poco/Timer.h" +#include "Poco/Mutex.h" + +namespace Usbip { namespace WebSock { namespace Poco { + +using namespace ::Poco; +using namespace ::Poco::Net; +using namespace ::Poco::Util; + +class USBWSWebSocket : + public ::Poco::Net::WebSocket, + public ::Poco::Timer +{ +public: + USBWSWebSocket(HTTPServerRequest& req, HTTPServerResponse& rsp, + int pingPong); + USBWSWebSocket(HTTPClientSession& cs, + HTTPRequest& req, HTTPResponse& rsp, int pingPong); + static ssize_t send(void *arg, void *buf, size_t len); + static ssize_t recv(void *arg, void *buf, size_t len, int wait_all); + static void shutdown(void *arg); + int getSockfd(void) { return sockfd(); }; + void setApp(Application* app) { fApp = app; }; + Application* getApp(void) { return fApp; }; +private: + Application* fApp; + bool fPingPongStarted; + bool fFirstTimeout; + Mutex fSendLock; + + ssize_t send(void *buf, size_t len); + ssize_t recv(void *buf, size_t len, int wait_all); + void shutdown(void); + void startPingPong(void); + void restartPingPong(void); + void onTimer(Timer& timer); + void sendPing(void); + void sendPong(void); + void sendPingPong(int op); +}; + +}}} + +#endif /* !_USBIP_WEBSOCK_POCO_USBWS_WEBSOCKET_H */ + -- 2.1.0 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html