Repository navigation
HCI Bluetooth socket bind error on an arm crosscompiled environment #67632
Description
Activity
thomaschiroux commented
on Feb 11, 2015 thomaschirouxmannequinMannequinAuthorMore actionsThis 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 argumentThis 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) = 0So, 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#l1449reproducted 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 204So 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.-
- addedextension-modulesC modules in the Modules dirC modules in the Modules dirtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
on Feb 11, 2015 - changed the title
[-]HCI Bluetooth socket bind error on an arm crosscompiler environment[/-][+]HCI Bluetooth socket bind error on an arm crosscompiled environment[/+]on Feb 11, 2015 It should be fixed by #131668.
Reacted by Victor Stinner and Thomas Chiroux
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields: