vpelletier / python-libusb1

Python ctype-based wrapper around libusb1
GNU Lesser General Public License v2.1
168 stars 65 forks source link

Libusb1 Async Control Buffer Null #27

Closed jdkeenan closed 7 years ago

jdkeenan commented 7 years ago

I've been using libusb1 for around 9 months for multiple usb devices and found out ew 1.6.0 versions and later cause problems with my devices. I'm pretty sure it's tied to this issue (https://github.com/vpelletier/python-libusb1/issues/21) and using the getBuffer() command to get the most recent data sent when preforming a setControl call. After some further inspection I couldn't find where the buffer is actually updated during a 0xC1 request. Any help would be much appreciated.

Here is some example code. I'm awaiting asyncControlTransfer which is calling setControl. This works perfectly fine with 1.5.3

transfer = await asyncusb.asyncControlTransfer(
            self.handle, 0xC1,
            0x20,
            0, 0, 8, timeout = self.CT_TIMEOUT)
result = transfer.getUserData()

def asyncControlTransfer(handle, *args, **kwargs):
    ct = handle.getTransfer()
    ct.setControl(*args, **kwargs)
    return asyncTransfer(ct)

def asyncTransfer(transfer):
    fut = asyncio.Future()
    def callback(t):
        try:
            result = t.getStatus()
            if result != TRANSFER_COMPLETED:
                raise USBTransferError(result)
            if not fut.cancelled():
                fut.set_result(t)
        except Exception as e:
            fut.set_exception(e)
    transfer.setCallback(callback)
    result = transfer.submit()
    return fut
vpelletier commented 7 years ago

The idea behind the change in #21 is that __transfer_py_buffer gets modified when the memory behind __transfer_buffer is modified inside the C library, to avoid copies.

But I broke this with this line in setControl, which is likely the cause of this bug:

self.__transfer_py_buffer = transfer_py_buffer[CONTROL_SETUP_SIZE:]

Could you change this line to the following and report if it fixes the problem ?

self.__transfer_py_buffer = memoryview(transfer_py_buffer)[CONTROL_SETUP_SIZE:]

The problem with this fix is that, while python3's bytearray only accepts integers for item assignment, python2's memoryview rejects integers (I'm surprised to be apparently the first to report this on python's bugtracker given the number of google hits this issue has...). So if I apply it, I force the user of my module to be actively incompatible... Gah.

jdkeenan commented 7 years ago

Awesome, this solved the problem. Yeah, this is a pretty amazing package and has been incredible useful in my work, so keep up the great work! Also thanks for the quick response!

vpelletier commented 7 years ago

Thanks for the warm words, and happy my work is useful to you !

I reopen this issue, as the bug is still present in master - just so I do not forget to push the fix once I know what to expect from python 2.7.

vpelletier commented 7 years ago

Now fixed in master, and released on pypi as 1.6.4, closing.