VirtualHere Server Event System

The VirtualHere server can make callbacks to scripts on certain events. Sometimes USB devices need certain commands to be sent to them to workaround their in-built differences (or quirks). Most USB devices will work with VirtualHere without having to set anything special in the configuration.

You can also use the event system for special logging e.g bind/unbind of devices for time based usage.

The way the VirtualHere server handles this is to provide a callback mechanism to enable a bash script (Linux/OSX servers) or Batch file(Windows) to be executed to issue commands. The callback mechanism is specified in the server configuration. The event type is specified and a dot, then vendor id and optionally a dot and product id that the quirk is specified for. If no product id is specified, all products from that vendor have the quirk script executed against. If no qualification is made it applies to all devices.

For example the default iPad scripts are as follows (written inside the server config.ini)

onEnumeration.05ac=cat $DEVPATH$/bNumConfigurations > $DEVPATH$/bConfigurationValue
onBind.05ac=cat $DEVPATH$/bNumConfigurations > $DEVPATH$/bConfigurationValue

VirtualHere will replace $DEVPATH$ with the kernel device path at runtime. What these lines do, is set the iPad configuration to the maximum configuration number supported by the device when its first plugged in and when it is "used" by a remote client. This allows proper operation of the iDevice.

For each event you can pass at least the following arguments:

$ADDRESS$ Address of the device on the server
$PRODUCT_ID$ The USB product id of the device
$VENDOR_ID$ The USB Vendor id of the device
$DEVPATH$ The USB path of the device the Operating System uses to represent the device

There are 15 events that the VirtualHere server provides callbacks to. (Some events have extra arguments that can be passed and these are noted below. [ ] means optional qualifier)

onBind[.<vendor_id>[.<product_id>]] - Occurs when the user selects "Use" on the client. You can also use , $CLIENT_IP$ and $CONNECTION_ID$ arguments.

onEnumeration[.<vendor_id>[.<product_id>]] - Occurs when the USB device goes through "enumeration" when it is first plugged into the server. You can also pass $NICKNAME$ for the device nickname, $SERIAL$ for the device serial, and $PRODUCT$ for the product name of the device being enumerated

onDeviceUnplug[.<vendor_id>[.<product_id>]] - Occurs when the USB device is physically unplugged from the server. You can also pass $NICKNAME$ for the device nickname, $SERIAL$ for the device serial, and $PRODUCT$ for the product name of the device being unplugged.

onReset[.<vendor_id>[.<product_id>]] - Occurs when a device is required to be "reset"

onPassToKernel[.<vendor_id>[.<product_id>]] - Occurs when a device control is passed from VirtualHere (for example if the device or bus is ignored) to the Linux Kernel (host).

onClearHalt[.<vendor_id>[.<product_id>]] - Occurs when a device endpoint has the USB "clear halt" applied to it

onResetEp[.<vendor_id>[.<product_id>]] - Occurs when a device has the linux "reset endpoint" operation applied to it

onUnbind[.<vendor_id>[.<product_id>]] - Occurs when a device is unbound from a user, e.g the User selects "Stop Using". You can use the $SURPRISE_UNBOUND$ statement in the arguments to the script. That will return 1 if the device was pulled from the server while it was in use by the client. You can also use , $CLIENT_IP$ and $CONNECTION_ID$ arguments.

onServerRename - This event is called when the user attempts to rename the server. You can pass $NEW_NAME$ as an argument to the script call. If you return 1 from the script the rename occurs, anything else (or nothing) and the rename will not occur. You can also use $CLIENT_ID$, $CLIENT_IP$ and $CONNECTION_ID$ arguments

onChangeNickname - This event is called when the user clicks on a device and selects "Rename". If you return 0 the nickname will be accepted, anything else and the nickname will not be accepted. You can use the string $NICKNAME$ and $NEW_NICKNAME$ in the script call to get the old/new nickname for use in your script. You can pass $CLIENT_ID$ and $CLIENT_IP$ as arguments to the script call for information about the client making the call.

onDeviceIgnore - This event is called when the user clicks on a device and selects "Ignore". If you return 0 the ignore will be silently rejected, if you return 1 the ignore will be accepted, if you return 2 the ignore will be rejected and a message sent to the client saying "Unauthorized operation". You can pass $CLIENT_ID$ and $CLIENT_IP$ and $CLIENT_HOSTNAME$ as arguments to the script call for information about the client making the call. You can also use $VENDOR_ID$ and $PRODUCT_ID$ to get information about the device being ignored

onDeviceUnignore - This event is called when the user tries to unignore a device. If you return 0 the unignore will be silently rejected, if you return 1 the unignore will be accepted, if you return 2 the unignore will be rejected and a message sent to the client saying "Unauthorized operation". You can pass $CLIENT_ID$ and $CLIENT_IP$ and $CLIENT_HOSTNAME$ as arguments to the script for information about the client making the call.You can also use the $UNIGNORE$ argument to see what the user is trying to unignore.

onAddReverseClient - This event is called when the user tries to add a reverse client to the server via the Client. If you return 1 the reverse client will be added, anything else and it will not be added. You can pass $CLIENT_ID$ and $CLIENT_IP$ as arguments to the script call for information about the client making the call.

onRemoveReverseClient - This event is called when the user tries to remove a reverse client from the server via the Client. If you return 1 the reverse client will be removed, anything else and it will not be removed. You can pass $CLIENT_ID$ and $CLIENT_IP$ as arguments to the script call for information about the client making the call.

onClientConnect - This event is called when a new client connects to the server. You can pass $CLIENT_IP$ (for the IP address of the client) and $CONNECTION_ID$ for the unique id number assigned to the client connection. You can use this id to match the disconnect at a later time.

onClientDisconnect - This event is called when a client disconnects from the server. You can pass $CONNECTION_ID$ (for the id number of the client) and $REASON$ for the reason why there was a disconnection (e.g "timeout" or "server shutdown") and $CLIENT_ID$ for the username of the client that just disconnected

There are a few more authorization/authentication events here here

Example:

In the server config.ini file:

...
...
onUnbind.4ca.3911=/home/vh/onUnbind.sh "$DEVPATH$" "$ADDRESS$" "$VENDOR_ID$" "$PRODUCT_ID$"
...

In the onUnbind.sh file:

#!/bin/sh
logger onUnbind "$1" "$2" "$3" "$4"

Output in syslog:

onUnbind "/sys/bus/usb/devices/2-2" "22" "4ca" "3911"