Issue23444
This issue tracker has been migrated to GitHub,
and is currently read-only.
For more information,
see the GitHub FAQs in the Python's Developer Guide.
Created on 2015-02-11 15:50 by Thomas.Chiroux, last changed 2022-04-11 14:58 by admin.
Files | ||||
---|---|---|---|---|
File name | Uploaded | Description | Edit | |
bluetooth_bind_arm.patch | Thomas.Chiroux, 2015-02-11 15:50 | patch file |
Messages (1) | |||
---|---|---|---|
msg235751 - (view) | Author: Thomas Chiroux (Thomas.Chiroux) * | Date: 2015-02-11 15:50 | |
This bug bellow occurs only on my crosscompiled environment on arm (marvell armada 166): arm-pxa168-linux-gnueabi It does not seems to be a cross-compile issue: python compiles without problem and all unittests pass on the target device. description and first clues --------------------------- The problem is easyly reproducted using this script: #!/usr/bin/python import socket sock = socket.socket(socket.AF_BLUETOOTH, socket.SOCK_RAW, socket.BTPROTO_HCI) sock.bind((0,)) which raises the following exception when run on the target device: Traceback (most recent call last): File "./test_bt.py", line 4, in <module> sock.bind((0,)) OSError: [Errno 22] Invalid argument This does not give much clues, but strace does (i've filtered to display the two significant parts of strace) socket(PF_BLUETOOTH, SOCK_RAW|SOCK_CLOEXEC, 1) = 3 bind(3, {sa_family=AF_UNSPEC, sa_data="\0\0\360\35\251\266s\316(U\3\0\0\0"}, 6) = -1 EINVAL (Invalid argument) (on a working environment, including arm, like a raspberry pi, strace gives the following result (and no traceback of course): socket(PF_BLUETOOTH, SOCK_RAW|SOCK_CLOEXEC, 1) = 3 bind(3, {sa_family=AF_BLUETOOTH, sa_data="\0\0\0\0\0\0X\352\243\266\0\24\265\266"}, 6) = 0 So, on the armada166, between the socket creation and the bind we lost the socket family (AF_UNSPEC instead of AF_BLUETOOTH). And That's why bind returns invalid argument. socketmodule and PyArg_ParseTuple --------------------------------- Now let's look at Modules/socketmodule.c: After some digging, i've found that the problem is in getsockaddrarg, in the AF_BLUETOOTH / BTPROTO_HCI case and more precisely on this line: https://hg.python.org/cpython/file/ab2c023a9432/Modules/socketmodule.c#l1449 reproducted here: if (!PyArg_ParseTuple(args, "i", &_BT_HCI_MEMB(addr, dev))) { When we execute the PyArg_ParseTuple, the addr->hci_family is crunched (by zeros with my previous python sample). At this same place, i've done the following test: char buffer[8]; memset(buffer, 0x55, 8); if (!PyArg_ParseTuple(args, "i", buffer) { PyErr_SetString(PyExc_OSError, "getsockaddrarg: " "wrong format"); return 0; } printf("CL: %d %d %d %d %d %d %d %d\n", buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], buffer[6], buffer[7]); memset(buffer, 0xAA, 8); if (!PyArg_ParseTuple(args, "i", buffer+1) { PyErr_SetString(PyExc_OSError, "getsockaddrarg: " "wrong format"); return 0; } printf("CL+1: %d %d %d %d %d %d %d %d\n", buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], buffer[6], buffer[7]); memset(buffer, 0xBB, 8); if (!PyArg_ParseTuple(args, "i", buffer+2) { PyErr_SetString(PyExc_OSError, "getsockaddrarg: " "wrong format"); return 0; } printf("CL+2: %d %d %d %d %d %d %d %d\n", buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], buffer[6], buffer[7]); memset(buffer, 0xcc, 8); if (!PyArg_ParseTuple(args, "i", buffer+3) { PyErr_SetString(PyExc_OSError, "getsockaddrarg: " "wrong format"); return 0; } printf("CL+3: %d %d %d %d %d %d %d %d\n", buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], buffer[6], buffer[7]); and the result is: CL: 0 0 0 0 85 85 85 85 CL+1: 0 0 0 0 170 170 170 170 CL+2: 0 0 0 0 187 187 187 187 CL+3: 0 0 0 0 204 204 204 204 (WTF ??) in a working environnement (tested on raspberry B+ / python 3.4.2 locally compiled) result is what we should expect: CL: 0 0 0 0 85 85 85 85 CL+1: 170 0 0 0 0 170 170 170 CL+2: 187 187 0 0 0 0 187 187 CL+3: 204 204 204 0 0 0 0 204 So on my box if PyArg_ParseTuple write on &addr->hci_dev if write 4 bytes from &addr->hci_family which is 2 bytes BEFORE &addr->hci_dev At this time I can not understand how it's possible. Remarks and patch ----------------- Now I have several remarks and a working patch. * remark/question 1: why does PyArg_ParseTuple parse an int when addr->hci_dev is an unsigned short ? even in normal situation, when it works, writing on &addr->hci_dev overflow on the next two bytes which are btw addr->channel (more on that later) * remark/question 2: i've tried to dig more deeply inside PyArg_ParseTuple and found another odd thing, but I did not try to change it without knowing what I do: in Python/getargs.c, in convertsimple, int parsing result is not casted before returned: here: https://hg.python.org/cpython/file/ab2c023a9432/Python/getargs.c#l690 (ival is a long). In all other cases (short, unsigned short, char, usigned char), they are casted before return. [disclosure: i've tested to add the cast and relaunched my bind test, it did not change anything, but it's still strange for me] * Now a working patch: here below and attached a working patch which results on a good socket bind, but now completely satisfiying: --- Python-3.4.2/Modules/socketmodule.c 2014-10-08 10:18:15.000000000 +0200 +++ CC_PYTHON/Python-3.4.2/Modules/socketmodule.c 2015-02-11 15:42:35.173455634 +0100 @@ -1446,11 +1446,12 @@ getsockaddrarg(PySocketSockObject *s, Py return 0; #else _BT_HCI_MEMB(addr, family) = AF_BLUETOOTH; - if (!PyArg_ParseTuple(args, "i", &_BT_HCI_MEMB(addr, dev))) { + if (!PyArg_ParseTuple(args, "H", &_BT_HCI_MEMB(addr, dev))) { PyErr_SetString(PyExc_OSError, "getsockaddrarg: " "wrong format"); return 0; } + _BT_HCI_MEMB(addr, channel) = HCI_CHANNEL_RAW; #endif *len_ret = sizeof *addr; return 1; in short: I parse now an unsigned short instead of parsing an int which gives me a two bytes long elements which is stored well on addr->hci_dev without overloading addr->hci_family. But this modification alone is not enough: addr->hci_channel needed a good value. that's why i added _BT_HCI_MEMB(addr, channel) = HCI_CHANNEL_RAW; which sets addr->hci_channel to zero. (without this line, any value could be here) And that led me to another question/problem: how is hci_channel normally handled ? It does not seems to be a valid parameter of bind; behaviour without the patch will erase hci_channel while storing int value in hci_dev, so theorically we can assign a well defined int value in our bind method to both assign the wanted value in hci_dev and hci_channel, but it does not seems to be a proper way to do it. |
History | |||
---|---|---|---|
Date | User | Action | Args |
2022-04-11 14:58:12 | admin | set | github: 67632 |
2015-02-11 16:05:05 | Thomas.Chiroux | set | title: HCI Bluetooth socket bind error on an arm crosscompiler environment -> HCI Bluetooth socket bind error on an arm crosscompiled environment |
2015-02-11 15:50:15 | Thomas.Chiroux | create |