Skip to content

Commit 8bbfc8b

Browse files
authored
More robust handling of socket opening and closing (#2)
Fix for #1 * Change how socket is created from: socket.fromfd to using socket.socket * Output from btmgmt_socket.open() is a single socket object rather than two references to the same object
1 parent 2273895 commit 8bbfc8b

File tree

3 files changed

+29
-24
lines changed

3 files changed

+29
-24
lines changed

btsocket/btmgmt_callback.py

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class Mgmt:
1515

1616
def __init__(self):
1717
# Setup read and write sockets
18-
self.rsock, self.wsock = btmgmt_socket.btmgmt_socket()
18+
self.sock = btmgmt_socket.open()
1919
self.loop = asyncio.get_event_loop()
2020
# Store for event callbacks
2121
self._event_callbacks = dict()
@@ -42,7 +42,7 @@ def reader(self):
4242
to events.
4343
"""
4444
logger.debug('Reader callback')
45-
data = self.rsock.recv(100)
45+
data = self.sock.recv(100)
4646
pkt = btmgmt_protocol.reader(data)
4747
logger.info('pkt: [%s]', pkt)
4848
if pkt.header.event_code in self._event_callbacks:
@@ -59,7 +59,7 @@ def writer(self):
5959
if len(self.cmd_queue) > 0:
6060
this_cmd = self.cmd_queue.popleft()
6161
logger.info('sending pkt [%s]', tools.format_pkt(this_cmd))
62-
self.wsock.send(this_cmd)
62+
self.sock.send(this_cmd)
6363
if not self.running and len(self.cmd_queue) == 0:
6464
self.loop.stop()
6565
# Do one more read to get the response from the last command
@@ -95,24 +95,23 @@ def stop(self):
9595
"""
9696
self.running = False
9797

98-
self.loop.remove_writer(self.wsock)
99-
self.loop.remove_reader(self.rsock)
98+
self.loop.remove_writer(self.sock)
99+
self.loop.remove_reader(self.sock)
100100
self.loop.stop()
101101

102102
def close(self):
103103
"""
104104
Stop the event loop and close sockets etc.
105105
"""
106-
self.rsock.close()
107-
# self.wsock.close()
106+
btmgmt_socket.close(self.sock)
108107
# Stop the event loop
109108
self.loop.close()
110109

111110
def start(self):
112111
self.running = True
113112
# Setup reader and writer for socket streams
114-
self.loop.add_reader(self.rsock, self.reader)
115-
self.loop.add_writer(self.wsock, self.writer)
113+
self.loop.add_reader(self.sock, self.reader)
114+
self.loop.add_writer(self.sock, self.writer)
116115
logger.debug('Starting event loop...')
117116
try:
118117
# Run the event loop

btsocket/btmgmt_socket.py

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class SocketAddr(ctypes.Structure):
2929
]
3030

3131

32-
def btmgmt_socket():
32+
def open():
3333
"""
3434
Because of the following issue with Python the Bluetooth User socket
3535
on linux needs to be done with lower level calls.
@@ -53,6 +53,7 @@ def btmgmt_socket():
5353
# fd = libc_socket(PF_BLUETOOTH, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK,
5454
# BTPROTO_HCI)
5555
fd = libc_socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)
56+
5657
if fd < 0:
5758
raise BluetoothSocketError("Unable to open PF_BLUETOOTH socket")
5859

@@ -64,40 +65,45 @@ def btmgmt_socket():
6465
if r < 0:
6566
raise BluetoothSocketError("Unable to bind %s", r)
6667

67-
ins = outs = socket.fromfd(fd, AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)
68-
return ins, outs
68+
sock_fd = socket.socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI, fileno=fd)
69+
return sock_fd
70+
71+
72+
def close(bt_socket):
73+
"""Close the open socket"""
74+
fd = bt_socket.detach()
75+
socket.close(fd)
6976

7077

7178
def test_asyncio_usage():
72-
rsock, wsock = btmgmt_socket()
79+
sock = open()
7380

7481
loop = asyncio.get_event_loop()
7582

7683
def reader():
77-
data = rsock.recv(100)
84+
data = sock.recv(100)
7885
print("Received:", data)
7986

8087
# We are done: unregister the file descriptor
81-
loop.remove_reader(rsock)
88+
loop.remove_reader(sock)
8289

8390
# Stop the event loop
8491
loop.stop()
8592

8693
# Register the file descriptor for read event
87-
loop.add_reader(rsock, reader)
94+
loop.add_reader(sock, reader)
8895

8996
# Write a command to the socket
9097
# Read Management Version Information Command
9198
# b'\x01\x00\xff\xff\x00\x00'
92-
loop.call_soon(wsock.send, b'\x01\x00\xff\xff\x00\x00')
99+
loop.call_soon(sock.send, b'\x01\x00\xff\xff\x00\x00')
93100

94101
try:
95102
# Run the event loop
96103
loop.run_forever()
97104
finally:
98105
# We are done. Close sockets and the event loop.
99-
rsock.close()
100-
wsock.close()
106+
close(sock)
101107
loop.close()
102108

103109

btsocket/btmgmt_sync.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,18 @@ def send(*args):
1919
logger.debug('Sending btmgmt frames %s', pkt_objs)
2020
cmd_pkt = _as_packet(pkt_objs)
2121
# print('cmd pkt', [f'{octets:x}' for octets in cmd_pkt])
22-
rsock, wsock = btmgmt_socket.btmgmt_socket()
22+
sock = btmgmt_socket.open()
2323
logger.debug('Sending bytes: %s', cmd_pkt)
24-
wsock.send(cmd_pkt)
24+
sock.send(cmd_pkt)
2525
while not response_recvd:
26-
raw_data = rsock.recv(100)
26+
raw_data = sock.recv(100)
2727
logger.debug('Received: %s', raw_data)
2828
data = btmgmt_protocol.reader(raw_data)
2929
logger.debug('Received btmgmt frames: %s', data)
3030
if data.cmd_response_frame:
3131
response_recvd = True
32-
rsock.close()
33-
wsock.close()
32+
33+
btmgmt_socket.close(sock)
3434
if data.event_frame.status != btmgmt_protocol.ErrorCodes.Success:
3535
raise NameError(f'btmgmt Error: '
3636
f'{data.event_frame.command_opcode} '

0 commit comments

Comments
 (0)