/bluetooth/widcomm.py

http://pybluez.googlecode.com/ · Python · 790 lines · 612 code · 128 blank · 50 comment · 148 complexity · 7c7d4dc88c78f9fb8b53a2ad18a3f8fb MD5 · raw file

  1. from .btcommon import *
  2. import socket
  3. import struct
  4. import threading
  5. import os
  6. import _widcomm
  7. DEFAULT_MTU = 672
  8. def dbg (*args):
  9. return
  10. sys.stdout.write (*args)
  11. sys.stdout.write ("\n")
  12. def BD_ADDR_to_str (bda):
  13. return "%02X:%02X:%02X:%02X:%02X:%02X" % \
  14. (ord(bda[0]), ord(bda[1]), ord(bda[2]),
  15. ord(bda[3]), ord(bda[4]), ord(bda[5]))
  16. def str_to_BD_ADDR (s):
  17. digits = [ int (c, 16) for c in s.split(":") ]
  18. return struct.pack ("6B", *digits)
  19. class WCInquirer:
  20. DEVST_DOWN = 0
  21. DEVST_UP = 1
  22. DEVST_ERROR = 2
  23. DEVST_UNLOADED = 3
  24. DEVST_RELOADED = 4
  25. def __init__ (self):
  26. self._wcinq = _widcomm._WCInquirer ()
  27. port = self._wcinq.get_sockport ()
  28. self.readsock = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
  29. self.readsock.connect (("127.0.0.1", port))
  30. self._wcinq.accept_client ()
  31. self.recently_discovered = []
  32. self.inquiry_in_progress = False
  33. self.sdp_query_in_progress = False
  34. def fileno ():
  35. return self.readsock.fileno ()
  36. def start_inquiry (self):
  37. self.recently_discovered = []
  38. self.inquiry_in_progress = self._wcinq.start_inquiry ()
  39. def read_msg (self):
  40. intsize = struct.calcsize ("=i")
  41. msg_type = struct.unpack ("=i", self.readsock.recv (intsize))[0]
  42. if msg_type == _widcomm.INQ_DEVICE_RESPONDED:
  43. fmt = "=6s3s248si"
  44. data = self.readsock.recv (struct.calcsize (fmt))
  45. bda, devclass, bdname, connected = struct.unpack (fmt, data)
  46. bdaddr = BD_ADDR_to_str (bda)
  47. bdname = bdname.strip ("\0")
  48. self.recently_discovered.append ((bdaddr, devclass, bdname,
  49. connected))
  50. elif msg_type == _widcomm.INQ_INQUIRY_COMPLETE:
  51. fmt = "=ih"
  52. data = self.readsock.recv (struct.calcsize (fmt))
  53. success, num_responses = struct.unpack (fmt, data)
  54. self.inquiry_in_progress = False
  55. elif msg_type == _widcomm.INQ_DISCOVERY_COMPLETE:
  56. self.sdp_query_in_progress = False
  57. elif msg_type == _widcomm.INQ_STACK_STATUS_CHANGE:
  58. fmt = "=i"
  59. data = self.readsock.recv (struct.calcsize (fmt))
  60. new_status = struct.unpack (fmt, data)[0]
  61. def start_discovery (self, addr, uuid = None):
  62. bd_addr = str_to_BD_ADDR (addr)
  63. if uuid is not None:
  64. self.sdp_query_in_progress = \
  65. self._wcinq.start_discovery (bd_addr, to_full_uuid (uuid))
  66. else:
  67. self.sdp_query_in_progress = \
  68. self._wcinq.start_discovery (bd_addr)
  69. self.sdp_query_in_progress = True
  70. def read_discovery_records (self, addr, uuid = None):
  71. if not is_valid_address (addr):
  72. raise ValueError ("invalid Bluetooth address")
  73. bd_addr = str_to_BD_ADDR (addr)
  74. if uuid is not None:
  75. dbg ("read_discovery_records (%s, %s)" % (addr, uuid))
  76. return self._wcinq.read_discovery_records (bd_addr,
  77. to_full_uuid (uuid))
  78. else:
  79. return self._wcinq.read_discovery_records (bd_addr)
  80. def is_device_ready (self):
  81. return self._wcinq.is_device_ready ()
  82. def get_local_device_address (self):
  83. return self._wcinq.get_local_device_address ()
  84. inquirer = WCInquirer ()
  85. def discover_devices (duration=8, flush_cache=True, lookup_names=False, lookup_class=False):
  86. inquirer.start_inquiry ()
  87. while inquirer.inquiry_in_progress:
  88. inquirer.read_msg ()
  89. discovered = inquirer.recently_discovered[:]
  90. if not lookup_names and not lookup_class:
  91. return [ tup[0] for tup in discovered ]
  92. if lookup_names and not lookup_class:
  93. result = []
  94. for bdaddr, devClass, bdName, bConnected in discovered:
  95. if bdName:
  96. result.append ((bdaddr, bdName))
  97. else:
  98. result.append ((bdAddr, None))
  99. return result
  100. if not lookup_names and lookup_class:
  101. result = []
  102. for bdaddr, devClass, bdName, bConnected in discovered:
  103. hex = "%02X%02X%02X" % (ord(devClass[0]), ord(devClass[1]), ord(devClass[2]))
  104. devClass = int(hex, 16)
  105. result.append ((bdAddr, devClass))
  106. return result
  107. if lookup_names and lookup_class:
  108. result = []
  109. for bdaddr, devClass, bdName, bConnected in discovered:
  110. hex = "%02X%02X%02X" % (ord(devClass[0]), ord(devClass[1]), ord(devClass[2]))
  111. devClass = int(hex, 16)
  112. if bdName:
  113. result.append ((bdaddr, bdName, devClass))
  114. else:
  115. result.append ((bdAddr, None, devClass))
  116. return result
  117. def lookup_name (address, timeout=10):
  118. discover_devices ()
  119. for bdaddr, devClass, bdName, bConnected in inquirer.recently_discovered:
  120. if bdaddr == address:
  121. return bdName
  122. def advertise_service (sock, name, service_id = "", service_classes = [], \
  123. profiles = [], provider = "", description = "", protocols = []):
  124. sock._advertise_service (name, service_id, service_classes,
  125. profiles, provider, description, protocols)
  126. def stop_advertising (sock):
  127. sock._stop_advertising ()
  128. def find_service (name = None, uuid = None, address = None):
  129. if address:
  130. if address == "localhost": raise NotImplementedError
  131. if not is_valid_address (address):
  132. raise ValueError ("invalid Bluetooth address")
  133. addresses = [ address ]
  134. else:
  135. addresses = discover_devices ()
  136. if uuid and not is_valid_uuid (uuid):
  137. raise ValueError ("invalid uuid ", uuid)
  138. results = []
  139. for addr in addresses:
  140. inquirer.start_discovery (addr, uuid)
  141. while inquirer.sdp_query_in_progress:
  142. inquirer.read_msg ()
  143. results.extend (inquirer.read_discovery_records (addr, uuid))
  144. return results
  145. def _port_return_code_to_str (code):
  146. k = { _widcomm.RFCOMM_SUCCESS : "Success",
  147. _widcomm.RFCOMM_ALREADY_OPENED : "Port already opened",
  148. _widcomm.RFCOMM_NOT_OPENED : "Connection not open",
  149. _widcomm.RFCOMM_HANDLE_ERROR: "This error should never occur " \
  150. "(HANDLE_ERROR) and is a stack bug",
  151. _widcomm.RFCOMM_LINE_ERR: "Line error",
  152. _widcomm.RFCOMM_START_FAILED: "Connection attempt failed",
  153. _widcomm.RFCOMM_PAR_NEG_FAILED: "Parameter negotion (MTU) failed",
  154. _widcomm.RFCOMM_PORT_NEG_FAILED: "Port negotiation failed",
  155. _widcomm.RFCOMM_PEER_CONNECTION_FAILED: "Connection ended by remote "\
  156. "side",
  157. _widcomm.RFCOMM_PEER_TIMEOUT: "Timeout by remote side",
  158. _widcomm.RFCOMM_INVALID_PARAMETER: "Invalid parameter",
  159. _widcomm.RFCOMM_UNKNOWN_ERROR: "Unknown error" }
  160. if code in k:
  161. return k[code]
  162. else:
  163. return "Invalid RFCOMM error code %s" % str (code)
  164. def _port_ev_code_to_str (code):
  165. d = { _widcomm.PORT_EV_RXFLAG : "Received certain character",
  166. _widcomm.PORT_EV_TXEMPTY : "Transmit Queue Empty",
  167. _widcomm.PORT_EV_CTS : "CTS changed state",
  168. _widcomm.PORT_EV_DSR : "DSR changed state",
  169. _widcomm.PORT_EV_RLSD : "RLSD changed state",
  170. _widcomm.PORT_EV_BREAK : "BREAK received",
  171. _widcomm.PORT_EV_ERR : "Line status error occurred",
  172. _widcomm.PORT_EV_RING : "Ring signal detected",
  173. _widcomm.PORT_EV_CTSS : "CTS state",
  174. _widcomm.PORT_EV_DSRS : "DSR state",
  175. _widcomm.PORT_EV_RLSDS : "RLSD state",
  176. _widcomm.PORT_EV_OVERRUN : "Receiver buffer overrun",
  177. _widcomm.PORT_EV_TXCHAR : "Any character transmitted",
  178. _widcomm.PORT_EV_CONNECTED : "RFCOMM connection established",
  179. _widcomm.PORT_EV_CONNECT_ERR : "Was not able to establish " \
  180. "connection or disconnected",
  181. _widcomm.PORT_EV_FC : "Flow control enabled flag changed by remote",
  182. _widcomm.PORT_EV_FCS : "Flow control status true = enabled" }
  183. result = []
  184. for k, v in list(d.items ()):
  185. if code & k:
  186. result.append (v)
  187. if len (result) == 0:
  188. return "Invalid event code %d" % code
  189. else:
  190. return "\n".join (result)
  191. def _sdp_checkraise (code):
  192. if code == _widcomm.SDP_OK: return
  193. elif code == _widcomm.SDP_COULD_NOT_ADD_RECORD:
  194. raise BluetoothError ("Could not add SDP record")
  195. elif code == _widcomm.SDP_INVALID_RECORD:
  196. raise BluetoothError ("Invalid SDP record")
  197. elif code == _widcomm.SDP_INVALID_PARAMETERS:
  198. raise BluetoothError ("SDP: invalid parameters")
  199. raise RuntimeError ("unknown SDP status code %s" % code)
  200. class BluetoothSocket:
  201. def __init__ (self, proto = RFCOMM, _sockdata = None):
  202. if not proto in [ RFCOMM, L2CAP ]:
  203. raise ValueError ("invalid protocol")
  204. self.proto = proto
  205. if proto == RFCOMM:
  206. self.bind = self.rfcomm_bind
  207. self.listen = self.rfcomm_listen
  208. self.accept = self.rfcomm_accept
  209. self.connect = self.rfcomm_connect
  210. self.send = self.rfcomm_send
  211. self.recv = self.rfcomm_recv
  212. self.close = self.rfcomm_close
  213. self.getsockname = self.rfcomm_getsockname
  214. self.setblocking = self.rfcomm_setblocking
  215. self.settimeout = self.rfcomm_settimeout
  216. self.gettimeout = self.rfcomm_gettimeout
  217. self.dup = self.rfcomm_dup
  218. self.makefile = self.rfcomm_makefile
  219. self.fileno = self.rfcomm_fileno
  220. self.__make_cobjects = self.__rfcomm_make_cobjects
  221. self._advertise_service = self.__rfcomm_advertise_service
  222. if _sockdata:
  223. self._wc, self._if, self.readsock = _sockdata
  224. else:
  225. self.__make_cobjects ()
  226. self.connected = self._wc.is_connected ()
  227. elif proto == L2CAP:
  228. dbg ("creating l2cap socket")
  229. self.bind = self.l2cap_bind
  230. self.listen = self.l2cap_listen
  231. self.accept = self.l2cap_accept
  232. self.connect = self.l2cap_connect
  233. self.send = self.l2cap_send
  234. self.recv = self.l2cap_recv
  235. self.close = self.l2cap_close
  236. self.getsockname = self.l2cap_getsockname
  237. self.setblocking = self.l2cap_setblocking
  238. self.settimeout = self.l2cap_settimeout
  239. self.gettimeout = self.l2cap_gettimeout
  240. self.dup = self.l2cap_dup
  241. self.makefile = self.l2cap_makefile
  242. self.fileno = self.l2cap_fileno
  243. self.__make_cobjects = self.__l2cap_make_cobjects
  244. self._advertise_service = self.__l2cap_advertise_service
  245. if _sockdata:
  246. self._wc, self._if, self.readsock = _sockdata
  247. self.connected = True
  248. else:
  249. self.__make_cobjects ()
  250. self.connected = False
  251. else:
  252. raise NotImplementedError ()
  253. self.nonblocking = False
  254. self.connecting = False
  255. self.listening = False
  256. self.bound = False
  257. self.received_data = []
  258. self.last_event_code = None
  259. self.port = 0
  260. self._sdpservice = None
  261. def _stop_advertising (self):
  262. if not self._sdpservice:
  263. raise BluetoothError ("not advertising any services")
  264. self._sdpservice = None
  265. def __rfcomm_make_cobjects (self):
  266. self._wc = _widcomm._WCRfCommPort ()
  267. self._if = _widcomm._WCRfCommIf ()
  268. self.readsock = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
  269. self.readsock.connect (("127.0.0.1", self._wc.get_sockport ()))
  270. self._wc.accept_client ()
  271. def rfcomm_read_msg (self):
  272. intsize = struct.calcsize ("=i")
  273. msg_type_data = self.readsock.recv (intsize)
  274. msg_type = struct.unpack ("=i", msg_type_data)[0]
  275. if msg_type == _widcomm.RFCOMM_DATA_RECEIVED:
  276. datalen_fmt = "=i"
  277. datalen_data = self.readsock.recv (struct.calcsize (datalen_fmt))
  278. datalen = struct.unpack (datalen_fmt, datalen_data)[0]
  279. self.received_data.append (self.readsock.recv (datalen))
  280. elif msg_type == _widcomm.RFCOMM_EVENT_RECEIVED:
  281. fmt = "=I"
  282. data = self.readsock.recv (struct.calcsize (fmt))
  283. code = struct.unpack (fmt, data)[0]
  284. dbg ("event %X received" % code)
  285. if code & _widcomm.PORT_EV_CONNECTED:
  286. self.connecting = False
  287. self.listening = False
  288. self.connected = True
  289. if code & _widcomm.PORT_EV_CONNECT_ERR:
  290. self.connecting = False
  291. self.listening = False
  292. self.connected = False
  293. raise BluetoothError ("Connection failed")
  294. if code & _widcomm.PORT_EV_RXFLAG:
  295. dbg ("Rx flag")
  296. if code & _widcomm.PORT_EV_TXEMPTY:
  297. dbg ("Tx queue empty")
  298. if code & _widcomm.PORT_EV_CTS:
  299. dbg ("CTS changed state")
  300. if code & _widcomm.PORT_EV_DSR:
  301. dbg ("DSR changed state")
  302. if code & _widcomm.PORT_EV_RLSD:
  303. dbg ("RLSD changed state")
  304. if code & _widcomm.PORT_EV_BREAK:
  305. dbg ("BREAK received")
  306. if code & _widcomm.PORT_EV_ERR:
  307. dbg ("Line status error")
  308. if code & _widcomm.PORT_EV_RING:
  309. dbg ("Ring")
  310. if code & _widcomm.PORT_EV_CTSS:
  311. dbg ("CTS state")
  312. if code & _widcomm.PORT_EV_DSRS:
  313. dbg ("DSR state")
  314. if code & _widcomm.PORT_EV_RLSDS:
  315. dbg ("RLSD state")
  316. if code & _widcomm.PORT_EV_OVERRUN:
  317. dbg ("Receive buffer overrun")
  318. if code & _widcomm.PORT_EV_TXCHAR:
  319. dbg ("Data transmitted")
  320. if code & _widcomm.PORT_EV_FC:
  321. dbg ("Flow control changed by remote")
  322. if code & _widcomm.PORT_EV_FCS:
  323. dbg ("Flow control status true = enabled")
  324. self.last_event_code = code
  325. def rfcomm_bind (self, addrport):
  326. addr, port = addrport
  327. if len (addr):
  328. raise ValueError ("Widcomm stack can't bind to " \
  329. "user-specified adapter")
  330. result = self._if.assign_scn_value (RFCOMM_UUID, port)
  331. if not result:
  332. raise BluetoothError ("unable to bind to port")
  333. self.bound = True
  334. self.port = self._if.get_scn ()
  335. def rfcomm_listen (self, backlog):
  336. if self.connected:
  337. raise BluetoothError ("already connected")
  338. if self.listening:
  339. raise BluetoothError ("already listening/connecting")
  340. if backlog != 1:
  341. raise ValueError ("Widcomm stack requires backlog == 1")
  342. port = self._if.get_scn ()
  343. self._if.set_security_level ("", _widcomm.BTM_SEC_NONE, True)
  344. if not port:
  345. raise BluetoothError ("not bound to a port")
  346. result = self._wc.open_server (port, DEFAULT_MTU)
  347. if result != _widcomm.RFCOMM_SUCCESS:
  348. raise BluetoothError (_port_return_code_to_str (result))
  349. self.listening = True
  350. def rfcomm_accept (self):
  351. if self.connected:
  352. raise BluetoothError ("already connected")
  353. while self.listening and not self.connected:
  354. dbg ("waiting for connection")
  355. self.rfcomm_read_msg ()
  356. if self.connected:
  357. port = self._if.get_scn ()
  358. client_bdaddr = BD_ADDR_to_str (self._wc.is_connected ())
  359. # XXX widcomm API doesn't provide a way to determine the RFCOMM
  360. # channel number of the client
  361. client_port = 0
  362. # create a new socket object and give it ownership of the
  363. # wrapped C++ objects, since those are the ones actually connected
  364. _sockdata = self._wc, self._if, self.readsock
  365. clientsock = BluetoothSocket (RFCOMM, _sockdata)
  366. # now create new C++ objects
  367. self.__rfcomm_make_cobjects ()
  368. # self.bind (("", port))
  369. # self.listen (1)
  370. return clientsock, (client_bdaddr, client_port)
  371. def rfcomm_connect (self, addrport):
  372. addr, port = addrport
  373. dbg ("connecting to %s port %d" % (addr, port))
  374. if not is_valid_address (addr):
  375. raise ValueError ("invalid address %s" % addr)
  376. self._if.assign_scn_value (RFCOMM_UUID, port)
  377. self._if.set_security_level ("", _widcomm.BTM_SEC_NONE, False)
  378. result = self._wc.open_client (port, str_to_BD_ADDR (addr), DEFAULT_MTU)
  379. if result != _widcomm.RFCOMM_SUCCESS:
  380. raise BluetoothError (_port_return_code_to_str (result))
  381. self.connecting = True
  382. while self.connecting:
  383. self.rfcomm_read_msg ()
  384. if not self._wc.is_connected ():
  385. raise BluetoothError ("connection failed")
  386. def rfcomm_send (self, data):
  387. dbg ("sending: [%s]" % data)
  388. status, written = self._wc.write (data)
  389. if status == _widcomm.RFCOMM_SUCCESS:
  390. dbg ("sent okay")
  391. return written
  392. else:
  393. raise BluetoothError (_port_return_code_to_str (status))
  394. def rfcomm_recv (self, numbytes):
  395. if self.nonblocking and not self.received_data:
  396. # XXX are we supposed to raise an exception, or just return None?
  397. return None
  398. while not self.received_data and self._wc.is_connected ():
  399. self.rfcomm_read_msg ()
  400. if self.received_data:
  401. data = self.received_data.pop (0)
  402. if len(data) > numbytes:
  403. self.received_data.insert (0, data[numbytes:])
  404. return data[:numbytes]
  405. else:
  406. return data
  407. def rfcomm_close (self):
  408. self._wc.close ()
  409. self._wc = None
  410. self.bound = False
  411. self.connecting = False
  412. self.listening = False
  413. self.connected = False
  414. # return bt.close (self._sockfd)
  415. def rfcomm_getsockname (self):
  416. if not self.bound:
  417. raise BluetoothError ("Socket not bound")
  418. addr = inquirer.get_local_device_address ()
  419. port = self._if.get_scn ()
  420. return addr, port
  421. def rfcomm_setblocking (self, blocking):
  422. self.nonblocking = not blocking
  423. self.readsock.setblocking (blocking)
  424. def rfcomm_settimeout (self, timeout):
  425. raise NotImplementedError
  426. pass
  427. # if timeout < 0: raise ValueError ("invalid timeout")
  428. #
  429. # if timeout == 0:
  430. # self.setblocking (False)
  431. # else:
  432. # self.setblocking (True)
  433. # # XXX this doesn't look correct
  434. # timeout = 0 # winsock timeout still needs to be set 0
  435. #
  436. # s = bt.settimeout (self._sockfd, timeout)
  437. # self._timeout = timeout
  438. def rfcomm_gettimeout (self):
  439. raise NotImplementedError
  440. # if self._blocking and not self._timeout: return None
  441. # return bt.gettimeout (self._sockfd)
  442. def rfcomm_fileno (self):
  443. return self.readsock.fileno ()
  444. def rfcomm_dup (self):
  445. raise NotImplementedError
  446. def rfcomm_makefile (self):
  447. raise NotImplementedError
  448. def __rfcomm_advertise_service (self, name, service_id,
  449. service_classes, profiles, provider, description,
  450. protocols):
  451. if self._sdpservice is not None:
  452. raise BluetoothError ("Service already advertised")
  453. if not self.listening:
  454. raise BluetoothError ("Socket must be listening before advertised")
  455. if protocols:
  456. raise NotImplementedError ("extra protocols not yet supported in Widcomm stack")
  457. self._sdpservice = _widcomm._WCSdpService ()
  458. if service_classes:
  459. service_classes = [ to_full_uuid (s) for s in service_classes ]
  460. _sdp_checkraise (self._sdpservice.add_service_class_id_list ( \
  461. service_classes))
  462. # self._if.set_security_level (name, _widcomm.BTM_SEC_NONE, True)
  463. _sdp_checkraise (self._sdpservice.add_rfcomm_protocol_descriptor ( \
  464. self.port))
  465. if profiles:
  466. for uuid, version in profiles:
  467. uuid = to_full_uuid (uuid)
  468. _sdp_checkraise (self._sdpservice.add_profile_descriptor_list (\
  469. uuid, version))
  470. _sdp_checkraise (self._sdpservice.add_service_name (name))
  471. _sdp_checkraise (self._sdpservice.make_public_browseable ())
  472. def __l2cap_make_cobjects (self):
  473. dbg ("__l2cap_make_cobjects")
  474. self._wc = _widcomm._WCL2CapConn ()
  475. self._if = _widcomm._WCL2CapIf ()
  476. self.readsock = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
  477. self.readsock.connect (("127.0.0.1", self._wc.get_sockport ()))
  478. self._wc.accept_client ()
  479. def l2cap_read_msg (self):
  480. intsize = struct.calcsize ("=i")
  481. msg_type_data = self.readsock.recv (intsize)
  482. msg_type = struct.unpack ("=i", msg_type_data)[0]
  483. if msg_type == _widcomm.L2CAP_DATA_RECEIVED:
  484. datalen_fmt = "=i"
  485. datalen_data = self.readsock.recv (struct.calcsize (datalen_fmt))
  486. datalen = struct.unpack (datalen_fmt, datalen_data)[0]
  487. self.received_data.append (self.readsock.recv (datalen))
  488. elif msg_type == _widcomm.L2CAP_INCOMING_CONNECTION:
  489. result = self._wc.accept ()
  490. if not result: raise BluetoothError ("accept() failed")
  491. elif msg_type == _widcomm.L2CAP_REMOTE_DISCONNECTED:
  492. dbg ("L2CAP_REMOTE_DISCONNECTED")
  493. self.connecting = False
  494. self.listening = False
  495. self.connected = False
  496. elif msg_type == _widcomm.L2CAP_CONNECTED:
  497. self.connecting = False
  498. self.listening = False
  499. self.connected = True
  500. # elif msg_type == _widcomm.PORT_EV_CONNECT_ERR:
  501. # self.connecting = False
  502. # self.listening = False
  503. # raise BluetoothError ("Connection failed")
  504. def l2cap_bind (self, addrport):
  505. dbg ("l2cap_bind %s" % str(addrport))
  506. addr, port = addrport
  507. if len (addr):
  508. raise ValueError ("Widcomm stack can't bind to " \
  509. "user-specified adapter")
  510. result = self._if.assign_psm_value (L2CAP_UUID, port)
  511. if not result:
  512. raise BluetoothError ("unable to bind to port")
  513. self.bound = True
  514. self.port = self._if.get_psm ()
  515. result = self._if.register ()
  516. if not result:
  517. raise BluetoothError ("register() failed")
  518. def l2cap_listen (self, backlog):
  519. dbg ("l2cap_listen %s" % backlog)
  520. if self.connected:
  521. raise BluetoothError ("already connected")
  522. if self.listening:
  523. raise BluetoothError ("already listening/connecting")
  524. if backlog != 1:
  525. raise ValueError ("Widcomm stack requires backlog == 1")
  526. port = self._if.get_psm ()
  527. self._if.set_security_level ("", _widcomm.BTM_SEC_NONE, True)
  528. if not port:
  529. raise BluetoothError ("not bound to a port")
  530. result = self._wc.listen (self._if)
  531. if not result:
  532. raise BluetoothError ("listen() failed. don't know why")
  533. self.listening = True
  534. def l2cap_accept (self):
  535. dbg ("l2cap_accept")
  536. if self.connected:
  537. raise BluetoothError ("already connected")
  538. while self.listening and not self.connected:
  539. dbg ("waiting for connection")
  540. self.l2cap_read_msg ()
  541. if self.connected:
  542. port = self._if.get_psm ()
  543. client_bdaddr = BD_ADDR_to_str (self._wc.remote_bd_addr ())
  544. # XXX widcomm API doesn't provide a way to determine the L2CAP
  545. # PSM of the client
  546. client_port = 0
  547. # create a new socket object and give it ownership of the
  548. # wrapped C++ objects, since those are the ones actually connected
  549. _sockdata = self._wc, self._if, self.readsock
  550. clientsock = BluetoothSocket (L2CAP, _sockdata)
  551. # now create new C++ objects
  552. self.__l2cap_make_cobjects ()
  553. # self.bind (("", port))
  554. # self.listen (1)
  555. return clientsock, (client_bdaddr, client_port)
  556. def l2cap_connect (self, addrport):
  557. addr, port = addrport
  558. dbg ("connecting to %s port %d" % (addr, port))
  559. if not is_valid_address (addr):
  560. raise ValueError ("invalid address %s" % addr)
  561. if not self._if.assign_psm_value (L2CAP_UUID, port):
  562. raise BluetoothError ("Failed to assign PSM %d" % port)
  563. if not self._if.set_security_level ("", _widcomm.BTM_SEC_NONE, False):
  564. raise BluetoothError ("Failed to set security level")
  565. if not self._if.register ():
  566. raise BluetoothError ("Failed to register PSM")
  567. self.connecting = True
  568. if not self._wc.connect (self._if, str_to_BD_ADDR (addr)):
  569. raise BluetoothError ("Connect failed")
  570. while self.connecting:
  571. self.l2cap_read_msg ()
  572. if not self.connected:
  573. raise BluetoothError ("connection failed")
  574. def l2cap_send (self, data):
  575. dbg ("sending: [%s]" % data)
  576. status, written = self._wc.write (data)
  577. if status:
  578. dbg ("sent okay")
  579. return written
  580. else:
  581. raise BluetoothError (_port_return_code_to_str (status))
  582. def l2cap_recv (self, numbytes):
  583. if self.nonblocking and not self.received_data:
  584. # XXX are we supposed to raise an exception, or just return None?
  585. return None
  586. while not self.received_data and self.connected:
  587. self.l2cap_read_msg ()
  588. if self.received_data:
  589. data = self.received_data.pop (0)
  590. if len(data) > numbytes:
  591. self.received_data.insert (0, data[numbytes:])
  592. return data[:numbytes]
  593. else:
  594. return data
  595. def l2cap_close (self):
  596. self._wc.disconnect ()
  597. self._if.deregister ()
  598. self._wc = None
  599. self.bound = False
  600. self.connecting = False
  601. self.listening = False
  602. self.connected = False
  603. # return bt.close (self._sockfd)
  604. def l2cap_getsockname (self):
  605. if not self.bound:
  606. raise BluetoothError ("Socket not bound")
  607. addr = inquirer.get_local_device_address ()
  608. port = self._if.get_psm ()
  609. return addr, port
  610. def l2cap_setblocking (self, blocking):
  611. self.nonblocking = not blocking
  612. self.readsock.setblocking (blocking)
  613. def l2cap_settimeout (self, timeout):
  614. raise NotImplementedError
  615. # if timeout < 0: raise ValueError ("invalid timeout")
  616. #
  617. # if timeout == 0:
  618. # self.setblocking (False)
  619. # else:
  620. # self.setblocking (True)
  621. # # XXX this doesn't look correct
  622. # timeout = 0 # winsock timeout still needs to be set 0
  623. #
  624. # s = bt.settimeout (self._sockfd, timeout)
  625. # self._timeout = timeout
  626. def l2cap_gettimeout (self):
  627. raise NotImplementedError
  628. # if self._blocking and not self._timeout: return None
  629. # return bt.gettimeout (self._sockfd)
  630. def l2cap_fileno (self):
  631. return self.readsock.fileno ()
  632. def l2cap_dup (self):
  633. raise NotImplementedError
  634. # return BluetoothSocket (self._proto, sockfd=bt.dup (self._sockfd))
  635. def l2cap_makefile (self):
  636. raise NotImplementedError
  637. def __l2cap_advertise_service (self, name, service_id,
  638. service_classes, profiles, provider, description,
  639. protocols):
  640. if self._sdpservice is not None:
  641. raise BluetoothError ("Service already advertised")
  642. if not self.listening:
  643. raise BluetoothError ("Socket must be listening before advertised")
  644. if protocols:
  645. raise NotImplementedError ("extra protocols not yet supported in Widcomm stack")
  646. self._sdpservice = _widcomm._WCSdpService ()
  647. if service_classes:
  648. service_classes = [ to_full_uuid (s) for s in service_classes ]
  649. _sdp_checkraise (self._sdpservice.add_service_class_id_list ( \
  650. service_classes))
  651. _sdp_checkraise (self._sdpservice.add_l2cap_protocol_descriptor ( \
  652. self.port))
  653. if profiles:
  654. for uuid, version in profiles:
  655. uuid = to_full_uuid (uuid)
  656. _sdp_checkraise (self._sdpservice.add_profile_descriptor_list (\
  657. uuid, version))
  658. _sdp_checkraise (self._sdpservice.add_service_name (name))
  659. _sdp_checkraise (self._sdpservice.make_public_browseable ())
  660. class DeviceDiscoverer:
  661. def __init__ (self):
  662. raise NotImplementedError