Fixed urbdrc server notification of channel close

There was a recursion issue with usb device channel closing and
local redirected device removal.
If the local redirected device is removed due to hotplug events,
the device channel needs to be closed, which in turn checks if
the local device list contains the device. Ensure that the
channel close code is only executed when not called from the
channel side.
This commit is contained in:
Armin Novak
2020-08-10 13:30:41 +02:00
parent dbeaa614d6
commit 93ee13245c
4 changed files with 62 additions and 1 deletions

View File

@@ -1088,10 +1088,28 @@ static int libusb_udev_is_already_send(IUDEVICE* idev)
return (pdev->status & URBDRC_DEVICE_ALREADY_SEND) ? 1 : 0;
}
/* This is called from channel cleanup code.
* Avoid double free, just remove the device and mark the channel closed. */
static void libusb_udev_mark_channel_closed(IUDEVICE* idev)
{
UDEVICE* pdev = (UDEVICE*)idev;
if (pdev && ((pdev->status & URBDRC_DEVICE_CHANNEL_CLOSED) == 0))
{
URBDRC_PLUGIN* urbdrc = pdev->urbdrc;
const uint8_t busNr = idev->get_bus_number(idev);
const uint8_t devNr = idev->get_dev_number(idev);
pdev->status |= URBDRC_DEVICE_CHANNEL_CLOSED;
urbdrc->udevman->unregister_udevice(urbdrc->udevman, busNr, devNr);
}
}
/* This is called by local events where the device is removed or in an error
* state. Remove the device from redirection and close the channel. */
static void libusb_udev_channel_closed(IUDEVICE* idev)
{
UDEVICE* pdev = (UDEVICE*)idev;
if (pdev)
if (pdev && ((pdev->status & URBDRC_DEVICE_CHANNEL_CLOSED) == 0))
{
URBDRC_PLUGIN* urbdrc = pdev->urbdrc;
const uint8_t busNr = idev->get_bus_number(idev);
@@ -1104,6 +1122,9 @@ static void libusb_udev_channel_closed(IUDEVICE* idev)
pdev->status |= URBDRC_DEVICE_CHANNEL_CLOSED;
if (channel)
channel->Write(channel, 0, NULL, NULL);
urbdrc->udevman->unregister_udevice(urbdrc->udevman, busNr, devNr);
}
}
@@ -1481,6 +1502,7 @@ static void udev_load_interface(UDEVICE* pdev)
pdev->iface.isChannelClosed = libusb_udev_is_channel_closed;
pdev->iface.setAlreadySend = libusb_udev_set_already_send;
pdev->iface.setChannelClosed = libusb_udev_channel_closed;
pdev->iface.markChannelClosed = libusb_udev_mark_channel_closed;
pdev->iface.getPath = libusb_udev_get_path;
/* Transfer */
pdev->iface.isoch_transfer = libusb_udev_isoch_transfer;

View File

@@ -399,6 +399,36 @@ static IUDEVICE* udevman_get_udevice_by_UsbDevice(IUDEVMAN* idevman, UINT32 UsbD
return NULL;
}
static IUDEVICE* udevman_get_udevice_by_ChannelID(IUDEVMAN* idevman, UINT32 channelID)
{
UDEVICE* pdev;
URBDRC_PLUGIN* urbdrc;
if (!idevman || !idevman->plugin)
return NULL;
/* Mask highest 2 bits, must be ignored */
urbdrc = (URBDRC_PLUGIN*)idevman->plugin;
idevman->loading_lock(idevman);
idevman->rewind(idevman);
while (idevman->has_next(idevman))
{
pdev = (UDEVICE*)idevman->get_next(idevman);
if (pdev->channelID == channelID)
{
idevman->loading_unlock(idevman);
return (IUDEVICE*)pdev;
}
}
idevman->loading_unlock(idevman);
WLog_Print(urbdrc->log, WLOG_WARN, "Failed to find a USB device mapped to channelID=%08" PRIx32,
channelID);
return NULL;
}
static void udevman_loading_lock(IUDEVMAN* idevman)
{
UDEVMAN* udevman = (UDEVMAN*)idevman;
@@ -786,6 +816,7 @@ static void udevman_load_interface(UDEVMAN* udevman)
udevman->iface.register_udevice = udevman_register_udevice;
udevman->iface.unregister_udevice = udevman_unregister_udevice;
udevman->iface.get_udevice_by_UsbDevice = udevman_get_udevice_by_UsbDevice;
udevman->iface.get_udevice_by_ChannelID = udevman_get_udevice_by_ChannelID;
/* Extension */
udevman->iface.isAutoAdd = udevman_is_auto_add;
/* Basic state */

View File

@@ -621,6 +621,12 @@ static UINT urbdrc_on_close(IWTSVirtualChannelCallback* pChannelCallback)
UINT32 control = callback->channel_mgr->GetChannelId(callback->channel);
if (udevman->controlChannelId == control)
udevman->status |= URBDRC_DEVICE_CHANNEL_CLOSED;
else
{ /* Need to notify the local backend the device is gone */
IUDEVICE* pdev = udevman->get_udevice_by_ChannelID(udevman, control);
if (pdev)
pdev->markChannelClosed(pdev);
}
}
}
}

View File

@@ -174,6 +174,7 @@ struct _IUDEVICE
void (*setAlreadySend)(IUDEVICE* idev);
void (*setChannelClosed)(IUDEVICE* idev);
void (*markChannelClosed)(IUDEVICE* idev);
char* (*getPath)(IUDEVICE* idev);
void (*free)(IUDEVICE* idev);
@@ -205,6 +206,7 @@ struct _IUDEVMAN
UINT16 idProduct, UINT32 flag);
IUDEVICE* (*get_next)(IUDEVMAN* idevman);
IUDEVICE* (*get_udevice_by_UsbDevice)(IUDEVMAN* idevman, UINT32 UsbDevice);
IUDEVICE* (*get_udevice_by_ChannelID)(IUDEVMAN* idevman, UINT32 channelID);
/* Extension */
int (*isAutoAdd)(IUDEVMAN* idevman);