/msbt/_msbt.c

http://pybluez.googlecode.com/ · C · 969 lines · 760 code · 174 blank · 35 comment · 136 complexity · 4e924db89adcef9cd8f687d9f18d9856 MD5 · raw file

  1. #include <winsock2.h>
  2. #include <ws2bth.h>
  3. #include <BluetoothAPIs.h>
  4. #include <Python.h>
  5. #include <initguid.h>
  6. #include <port3.h>
  7. #if 1
  8. static void dbg(const char *fmt, ...)
  9. {
  10. }
  11. #else
  12. static void dbg(const char *fmt, ...)
  13. {
  14. va_list ap;
  15. va_start (ap, fmt);
  16. vprintf (fmt, ap);
  17. va_end (ap);
  18. }
  19. #endif
  20. static void Err_SetFromWSALastError(PyObject *exc)
  21. {
  22. LPVOID lpMsgBuf;
  23. FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
  24. NULL, WSAGetLastError(), 0, (LPTSTR) &lpMsgBuf, 0, NULL );
  25. PyErr_SetString( exc, lpMsgBuf );
  26. LocalFree(lpMsgBuf);
  27. }
  28. #define _CHECK_OR_RAISE_WSA(cond) \
  29. if( !(cond) ) { Err_SetFromWSALastError( PyExc_IOError ); return 0; }
  30. static void
  31. ba2str( BTH_ADDR ba, char *addr )
  32. {
  33. int i;
  34. unsigned char bytes[6];
  35. for( i=0; i<6; i++ ) {
  36. bytes[5-i] = (unsigned char) ((ba >> (i*8)) & 0xff);
  37. }
  38. sprintf(addr, "%02X:%02X:%02X:%02X:%02X:%02X",
  39. bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5] );
  40. }
  41. static PyObject *
  42. msbt_initwinsock(PyObject *self)
  43. {
  44. WORD wVersionRequested;
  45. WSADATA wsaData;
  46. int status;
  47. wVersionRequested = MAKEWORD( 2, 0 );
  48. status = WSAStartup( wVersionRequested, &wsaData );
  49. if( 0 != status ) {
  50. Err_SetFromWSALastError( PyExc_RuntimeError );
  51. return 0;
  52. }
  53. Py_INCREF( Py_None );
  54. return Py_None;
  55. }
  56. PyDoc_STRVAR(msbt_initwinsock_doc, "TODO");
  57. static void
  58. dict_set_str_pyobj(PyObject *dict, const char *key, PyObject *valobj)
  59. {
  60. PyObject *keyobj;
  61. keyobj = PyString_FromString( key );
  62. PyDict_SetItem( dict, keyobj, valobj );
  63. Py_DECREF( keyobj );
  64. }
  65. static void
  66. dict_set_strings(PyObject *dict, const char *key, const char *val)
  67. {
  68. PyObject *keyobj, *valobj;
  69. keyobj = PyString_FromString( key );
  70. valobj = PyString_FromString( val );
  71. PyDict_SetItem( dict, keyobj, valobj );
  72. Py_DECREF( keyobj );
  73. Py_DECREF( valobj );
  74. }
  75. static void
  76. dict_set_str_long(PyObject *dict, const char *key, long val)
  77. {
  78. PyObject *keyobj, *valobj;
  79. keyobj = PyString_FromString( key );
  80. valobj = PyInt_FromLong(val);
  81. PyDict_SetItem( dict, keyobj, valobj );
  82. Py_DECREF( keyobj );
  83. Py_DECREF( valobj );
  84. }
  85. static int
  86. str2uuid( const char *uuid_str, GUID *uuid)
  87. {
  88. // Parse uuid128 standard format: 12345678-9012-3456-7890-123456789012
  89. int i;
  90. char buf[20] = { 0 };
  91. strncpy(buf, uuid_str, 8);
  92. uuid->Data1 = strtoul( buf, NULL, 16 );
  93. memset(buf, 0, sizeof(buf));
  94. strncpy(buf, uuid_str+9, 4);
  95. uuid->Data2 = (unsigned short) strtoul( buf, NULL, 16 );
  96. memset(buf, 0, sizeof(buf));
  97. strncpy(buf, uuid_str+14, 4);
  98. uuid->Data3 = (unsigned short) strtoul( buf, NULL, 16 );
  99. memset(buf, 0, sizeof(buf));
  100. strncpy(buf, uuid_str+19, 4);
  101. strncpy(buf+4, uuid_str+24, 12);
  102. for( i=0; i<8; i++ ) {
  103. char buf2[3] = { buf[2*i], buf[2*i+1], 0 };
  104. uuid->Data4[i] = (unsigned char)strtoul( buf2, NULL, 16 );
  105. }
  106. return 0;
  107. }
  108. // ====================== SOCKET FUNCTIONS ========================
  109. static PyObject *
  110. msbt_socket(PyObject *self, PyObject *args)
  111. {
  112. int family = AF_BTH;
  113. int type;
  114. int proto;
  115. int sockfd = -1;
  116. if(!PyArg_ParseTuple(args, "ii", &type, &proto)) return 0;
  117. Py_BEGIN_ALLOW_THREADS;
  118. sockfd = socket( AF_BTH, type, proto );
  119. Py_END_ALLOW_THREADS;
  120. _CHECK_OR_RAISE_WSA( SOCKET_ERROR != sockfd );
  121. return PyInt_FromLong( sockfd );
  122. };
  123. PyDoc_STRVAR(msbt_socket_doc, "TODO");
  124. static PyObject *
  125. msbt_bind(PyObject *self, PyObject *args)
  126. {
  127. char *addrstr = NULL;
  128. int addrstrlen = -1;
  129. int sockfd = -1;
  130. int port = -1;
  131. char buf[100] = { 0 };
  132. int buf_len = sizeof( buf );
  133. int status;
  134. SOCKADDR_BTH sa = { 0 };
  135. int sa_len = sizeof(sa);
  136. if(!PyArg_ParseTuple(args, "is#i", &sockfd, &addrstr, &addrstrlen, &port))
  137. return 0;
  138. if( addrstrlen == 0 ) {
  139. sa.btAddr = 0;
  140. } else {
  141. _CHECK_OR_RAISE_WSA( NO_ERROR == WSAStringToAddress( addrstr, \
  142. AF_BTH, NULL, (LPSOCKADDR)&sa, &sa_len ) );
  143. }
  144. sa.addressFamily = AF_BTH;
  145. sa.port = port;
  146. Py_BEGIN_ALLOW_THREADS;
  147. status = bind( sockfd, (LPSOCKADDR)&sa, sa_len );
  148. Py_END_ALLOW_THREADS;
  149. _CHECK_OR_RAISE_WSA( NO_ERROR == status );
  150. Py_INCREF(Py_None);
  151. return Py_None;
  152. };
  153. PyDoc_STRVAR(msbt_bind_doc, "TODO");
  154. static PyObject *
  155. msbt_listen(PyObject *self, PyObject *args)
  156. {
  157. int sockfd = -1;
  158. int backlog = -1;
  159. DWORD status;
  160. if(!PyArg_ParseTuple(args, "ii", &sockfd, &backlog)) return 0;
  161. Py_BEGIN_ALLOW_THREADS;
  162. status = listen(sockfd, backlog);
  163. Py_END_ALLOW_THREADS;
  164. _CHECK_OR_RAISE_WSA( NO_ERROR == status );
  165. Py_INCREF(Py_None);
  166. return Py_None;
  167. };
  168. PyDoc_STRVAR(msbt_listen_doc, "TODO");
  169. static PyObject *
  170. msbt_accept(PyObject *self, PyObject *args)
  171. {
  172. int sockfd = -1;
  173. int clientfd = -1;
  174. SOCKADDR_BTH ca = { 0 };
  175. int ca_len = sizeof(ca);
  176. PyObject *result = NULL;
  177. char buf[100] = { 0 };
  178. int buf_len = sizeof(buf);
  179. if(!PyArg_ParseTuple(args, "i", &sockfd)) return 0;
  180. Py_BEGIN_ALLOW_THREADS;
  181. clientfd = accept(sockfd, (LPSOCKADDR)&ca, &ca_len);
  182. Py_END_ALLOW_THREADS;
  183. _CHECK_OR_RAISE_WSA( SOCKET_ERROR != clientfd );
  184. ba2str(ca.btAddr, buf);
  185. result = Py_BuildValue( "isi", clientfd, buf, ca.port );
  186. return result;
  187. };
  188. PyDoc_STRVAR(msbt_accept_doc, "TODO");
  189. static PyObject *
  190. msbt_connect(PyObject *self, PyObject *args)
  191. {
  192. int sockfd = -1;
  193. char *addrstr = NULL;
  194. int port = -1;
  195. SOCKADDR_BTH sa = { 0 };
  196. int sa_len = sizeof(sa);
  197. DWORD status;
  198. if(!PyArg_ParseTuple(args, "isi", &sockfd, &addrstr, &port)) return 0;
  199. if( SOCKET_ERROR == WSAStringToAddress( addrstr, AF_BTH, NULL,
  200. (LPSOCKADDR)&sa, &sa_len ) ) {
  201. Err_SetFromWSALastError(PyExc_IOError);
  202. return 0;
  203. }
  204. sa.addressFamily = AF_BTH;
  205. sa.port = port;
  206. Py_BEGIN_ALLOW_THREADS;
  207. status = connect(sockfd, (LPSOCKADDR)&sa, sizeof(sa));
  208. Py_END_ALLOW_THREADS;
  209. _CHECK_OR_RAISE_WSA( NO_ERROR == status );
  210. Py_INCREF(Py_None);
  211. return Py_None;
  212. };
  213. PyDoc_STRVAR(msbt_connect_doc, "TODO");
  214. static PyObject *
  215. msbt_send(PyObject *self, PyObject *args)
  216. {
  217. int sockfd = -1;
  218. char *data = NULL;
  219. int datalen = -1;
  220. int flags = 0;
  221. int sent = 0;
  222. if(!PyArg_ParseTuple(args, "is#|i", &sockfd, &data, &datalen, &flags))
  223. return 0;
  224. Py_BEGIN_ALLOW_THREADS;
  225. sent = send(sockfd, data, datalen, flags);
  226. Py_END_ALLOW_THREADS;
  227. if (WSAGetLastError() == WSAEWOULDBLOCK ||
  228. WSAGetLastError() == WSAETIMEDOUT ) {
  229. return PyInt_FromLong ( 0 );
  230. }
  231. _CHECK_OR_RAISE_WSA( SOCKET_ERROR != sent );
  232. return PyInt_FromLong( sent );
  233. };
  234. PyDoc_STRVAR(msbt_send_doc, "TODO");
  235. static PyObject *
  236. msbt_recv(PyObject *self, PyObject *args)
  237. {
  238. int sockfd = -1;
  239. PyObject *buf = NULL;
  240. int datalen = -1;
  241. int flags = 0;
  242. int received = 0;
  243. if(!PyArg_ParseTuple(args, "ii|i", &sockfd, &datalen, &flags))
  244. return 0;
  245. buf = PyString_FromStringAndSize((char*)0, datalen);
  246. Py_BEGIN_ALLOW_THREADS;
  247. received = recv(sockfd, PyString_AS_STRING(buf), datalen, flags);
  248. Py_END_ALLOW_THREADS;
  249. if (WSAGetLastError() == WSAEWOULDBLOCK ||
  250. WSAGetLastError() == WSAETIMEDOUT ) {
  251. _PyString_Resize(&buf, 0); // XXX is this necessary? -albert
  252. return buf;
  253. }
  254. if( SOCKET_ERROR == received ){
  255. Py_DECREF(buf);
  256. return 0;
  257. }
  258. if( received != datalen ) _PyString_Resize(&buf, received);
  259. return buf;
  260. };
  261. PyDoc_STRVAR(msbt_recv_doc, "TODO");
  262. static PyObject *
  263. msbt_close(PyObject *self, PyObject *args)
  264. {
  265. int sockfd = -1;
  266. int status;
  267. if(!PyArg_ParseTuple( args, "i", &sockfd )) return 0;
  268. Py_BEGIN_ALLOW_THREADS;
  269. status = closesocket(sockfd);
  270. Py_END_ALLOW_THREADS;
  271. Py_INCREF(Py_None);
  272. return Py_None;
  273. };
  274. PyDoc_STRVAR(msbt_close_doc, "TODO");
  275. static PyObject *
  276. msbt_getsockname(PyObject *self, PyObject *args)
  277. {
  278. int sockfd = -1;
  279. SOCKADDR_BTH sa = { 0 };
  280. int sa_len = sizeof(sa);
  281. char buf[100] = { 0 };
  282. int buf_len = sizeof(buf);
  283. int status;
  284. if(!PyArg_ParseTuple( args, "i", &sockfd )) return 0;
  285. sa.addressFamily = AF_BTH;
  286. Py_BEGIN_ALLOW_THREADS;
  287. status = getsockname( sockfd, (LPSOCKADDR)&sa, &sa_len );
  288. Py_END_ALLOW_THREADS;
  289. _CHECK_OR_RAISE_WSA( NO_ERROR == status );
  290. ba2str( sa.btAddr, buf );
  291. return Py_BuildValue( "si", buf, sa.port );
  292. };
  293. PyDoc_STRVAR(msbt_getsockname_doc, "TODO");
  294. static PyObject *
  295. msbt_dup(PyObject *self, PyObject *args)
  296. {
  297. int sockfd = -1;
  298. int newsockfd = -1;
  299. int status;
  300. DWORD pid;
  301. WSAPROTOCOL_INFO pi = { 0 };
  302. if(!PyArg_ParseTuple( args, "i", &sockfd )) return 0;
  303. // prepare to duplicate
  304. pid = GetCurrentProcessId();
  305. status = WSADuplicateSocket( sockfd, pid, &pi );
  306. _CHECK_OR_RAISE_WSA( NO_ERROR == status );
  307. // duplicate!
  308. newsockfd = WSASocket( FROM_PROTOCOL_INFO,
  309. FROM_PROTOCOL_INFO,
  310. FROM_PROTOCOL_INFO,
  311. &pi, 0, 0 );
  312. _CHECK_OR_RAISE_WSA( INVALID_SOCKET != newsockfd );
  313. return PyInt_FromLong( newsockfd );
  314. }
  315. PyDoc_STRVAR(msbt_dup_doc, "TODO");
  316. // ====================
  317. static PyObject *
  318. msbt_discover_devices(PyObject *self, PyObject *args)
  319. {
  320. int flushcache = 0;
  321. int lookupnames = 0;
  322. int lookupclass = 0;
  323. // inquiry data structure
  324. DWORD qs_len = sizeof( WSAQUERYSET );
  325. WSAQUERYSET *qs = (WSAQUERYSET*) malloc( qs_len );
  326. DWORD flags = LUP_CONTAINERS;
  327. HANDLE h;
  328. int done = 0;
  329. PyObject *toreturn = NULL;
  330. int status = 0;
  331. dbg("msbt_discover_devices\n");
  332. if(!PyArg_ParseTuple(args, "iii", &flushcache, &lookupnames, &lookupclass)) {
  333. free( qs );
  334. return 0;
  335. }
  336. if (flushcache) flushcache = LUP_FLUSHCACHE;
  337. if (lookupnames) lookupnames = LUP_RETURN_NAME;
  338. if (lookupclass) lookupclass = LUP_RETURN_TYPE;
  339. ZeroMemory( qs, qs_len );
  340. qs->dwSize = sizeof(WSAQUERYSET);
  341. qs->dwNameSpace = NS_BTH;
  342. flags |= flushcache | lookupnames | lookupclass | LUP_RETURN_ADDR;
  343. Py_BEGIN_ALLOW_THREADS;
  344. // start the device inquiry
  345. status = WSALookupServiceBegin (qs, flags, &h);
  346. Py_END_ALLOW_THREADS;
  347. if (SOCKET_ERROR == status) {
  348. int error = WSAGetLastError();
  349. if( error == WSASERVICE_NOT_FOUND ) {
  350. dbg("No devices detected\n");
  351. // no devices detected.
  352. WSALookupServiceEnd( h );
  353. free( qs );
  354. PyErr_SetString (PyExc_IOError, "No Bluetooth adapter detected");
  355. return NULL;
  356. } else {
  357. Err_SetFromWSALastError( PyExc_IOError );
  358. free(qs);
  359. return 0;
  360. }
  361. }
  362. toreturn = PyList_New(0);
  363. // iterate through the inquiry results
  364. while(! done) {
  365. Py_BEGIN_ALLOW_THREADS;
  366. status = WSALookupServiceNext (h, flags, &qs_len, qs);
  367. Py_END_ALLOW_THREADS;
  368. if (NO_ERROR == status) {
  369. char buf[40] = {0};
  370. PyObject *tup = NULL;
  371. BTH_ADDR result =
  372. ((SOCKADDR_BTH*)qs->lpcsaBuffer->RemoteAddr.lpSockaddr)->btAddr;
  373. ba2str( result, buf );
  374. if( lookupnames && lookupclass ) {
  375. tup = Py_BuildValue( "ssl", buf, qs->lpszServiceInstanceName, qs->lpServiceClassId->Data1 );
  376. } else if( lookupnames ) {
  377. tup = Py_BuildValue( "ss", buf, qs->lpszServiceInstanceName );
  378. } else if (lookupclass) {
  379. tup = Py_BuildValue( "sl", buf, qs->lpServiceClassId->Data1 );
  380. } else {
  381. tup = PyString_FromString (buf);
  382. }
  383. PyList_Append( toreturn, tup );
  384. Py_DECREF( tup );
  385. } else {
  386. int error = WSAGetLastError();
  387. if( error == WSAEFAULT ) {
  388. // the qs data structure is too small. allocate a bigger
  389. // buffer and try again.
  390. free( qs );
  391. qs = (WSAQUERYSET*) malloc( qs_len );
  392. } else if( error == WSA_E_NO_MORE ) {
  393. // no more results.
  394. done = 1;
  395. } else {
  396. // unexpected error. raise an exception.
  397. Err_SetFromWSALastError( PyExc_IOError );
  398. Py_DECREF( toreturn );
  399. return 0;
  400. }
  401. }
  402. }
  403. Py_BEGIN_ALLOW_THREADS;
  404. WSALookupServiceEnd( h );
  405. Py_END_ALLOW_THREADS;
  406. free( qs );
  407. return toreturn;
  408. }
  409. PyDoc_STRVAR(msbt_discover_devices_doc, "TODO");
  410. static PyObject *
  411. msbt_lookup_name(PyObject *self, PyObject *args)
  412. {
  413. HANDLE rhandle = NULL;
  414. BLUETOOTH_FIND_RADIO_PARAMS p = { sizeof(p) };
  415. HBLUETOOTH_RADIO_FIND fhandle = NULL;
  416. BLUETOOTH_DEVICE_INFO dinfo = { 0 };
  417. char *addrstr = NULL;
  418. SOCKADDR_BTH sa = { 0 };
  419. int sa_len = sizeof(sa);
  420. DWORD status;
  421. if(!PyArg_ParseTuple(args,"s",&addrstr)) return 0;
  422. _CHECK_OR_RAISE_WSA( NO_ERROR == WSAStringToAddress( addrstr, \
  423. AF_BTH, NULL, (LPSOCKADDR)&sa, &sa_len ) );
  424. // printf("looking for first radio\n");
  425. fhandle = BluetoothFindFirstRadio(&p, &rhandle);
  426. _CHECK_OR_RAISE_WSA( NULL != fhandle );
  427. // printf("found radio 0x%p\n", rhandle );
  428. dinfo.dwSize = sizeof( dinfo );
  429. dinfo.Address.ullLong = sa.btAddr;
  430. status = BluetoothGetDeviceInfo( rhandle, &dinfo );
  431. _CHECK_OR_RAISE_WSA( status == ERROR_SUCCESS );
  432. // printf("name: %s\n", dinfo.szName );
  433. _CHECK_OR_RAISE_WSA( TRUE == BluetoothFindRadioClose( fhandle ) );
  434. return PyUnicode_FromWideChar( dinfo.szName, wcslen( dinfo.szName ) );
  435. }
  436. PyDoc_STRVAR(msbt_lookup_name_doc, "TODO");
  437. // ======================= SDP FUNCTIONS ======================
  438. static PyObject *
  439. msbt_find_service(PyObject *self, PyObject *args)
  440. {
  441. char *addrstr = NULL;
  442. char *uuidstr = NULL;
  443. // inquiry data structure
  444. DWORD qs_len = sizeof( WSAQUERYSET );
  445. WSAQUERYSET *qs = (WSAQUERYSET*) malloc( qs_len );
  446. DWORD flags = LUP_FLUSHCACHE | LUP_RETURN_ALL;
  447. HANDLE h;
  448. int done = 0;
  449. int status = 0;
  450. PyObject *record = NULL;
  451. PyObject *toreturn = NULL;
  452. GUID uuid = { 0 };
  453. char localAddressBuf[20] = { 0 };
  454. if(!PyArg_ParseTuple(args,"ss", &addrstr, &uuidstr))
  455. return 0;
  456. ZeroMemory( qs, qs_len );
  457. qs->dwSize = sizeof(WSAQUERYSET);
  458. qs->dwNameSpace = NS_BTH;
  459. qs->dwNumberOfCsAddrs = 0;
  460. qs->lpszContext = (LPSTR) localAddressBuf;
  461. if( 0 == strcmp( addrstr, "localhost" ) ) {
  462. // find the Bluetooth address of the first local adapter.
  463. #if 0
  464. HANDLE rhandle = NULL;
  465. BLUETOOTH_RADIO_INFO info;
  466. BLUETOOTH_FIND_RADIO_PARAMS p = { sizeof(p) };
  467. HBLUETOOTH_RADIO_FIND fhandle = NULL;
  468. printf("looking for first radio\n");
  469. fhandle = BluetoothFindFirstRadio(&p, &rhandle);
  470. _CHECK_OR_RAISE_WSA( NULL != fhandle );
  471. printf("first radio: 0x%p\n", rhandle);
  472. _CHECK_OR_RAISE_WSA( \
  473. TRUE == BluetoothFindRadioClose( fhandle ) );
  474. printf("retrieving radio info on handle 0x%p\n", rhandle);
  475. info.dwSize = sizeof(info);
  476. // XXX why doesn't this work???
  477. _CHECK_OR_RAISE_WSA( \
  478. ERROR_SUCCESS != BluetoothGetRadioInfo( rhandle, &info ) );
  479. ba2str( info.address.ullLong, localAddressBuf );
  480. #else
  481. // bind a temporary socket and get its Bluetooth address
  482. SOCKADDR_BTH sa = { 0 };
  483. int sa_len = sizeof(sa);
  484. int tmpfd = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM);
  485. _CHECK_OR_RAISE_WSA( tmpfd >= 0 );
  486. sa.addressFamily = AF_BTH;
  487. sa.port = BT_PORT_ANY;
  488. _CHECK_OR_RAISE_WSA(NO_ERROR == bind(tmpfd,(LPSOCKADDR)&sa,sa_len) );
  489. _CHECK_OR_RAISE_WSA(NO_ERROR == getsockname(tmpfd, (LPSOCKADDR)&sa,\
  490. &sa_len ) );
  491. ba2str(sa.btAddr, localAddressBuf );
  492. close(tmpfd);
  493. #endif
  494. flags |= LUP_RES_SERVICE;
  495. } else {
  496. strcpy( localAddressBuf, addrstr );
  497. }
  498. if( strlen(uuidstr) != 36 || uuidstr[8] != '-' || uuidstr[13] != '-'
  499. || uuidstr[18] != '-' || uuidstr[23] != '-' ) {
  500. PyErr_SetString( PyExc_ValueError, "Invalid UUID!");
  501. return 0;
  502. }
  503. str2uuid( uuidstr, &uuid );
  504. qs->lpServiceClassId = &uuid;
  505. Py_BEGIN_ALLOW_THREADS;
  506. status = WSALookupServiceBegin( qs, flags, &h );
  507. Py_END_ALLOW_THREADS;
  508. if( SOCKET_ERROR == status) {
  509. int err_code = WSAGetLastError();
  510. if( WSASERVICE_NOT_FOUND == err_code ) {
  511. // this device does not advertise any services. return an
  512. // empty list
  513. free( qs );
  514. return PyList_New(0);
  515. } else {
  516. // unexpected error. raise an exception
  517. Err_SetFromWSALastError( PyExc_IOError );
  518. free(qs);
  519. return 0;
  520. }
  521. }
  522. toreturn = PyList_New(0);
  523. // iterate through the inquiry results
  524. while(! done) {
  525. Py_BEGIN_ALLOW_THREADS;
  526. status = WSALookupServiceNext( h, flags, &qs_len, qs );
  527. Py_END_ALLOW_THREADS;
  528. if (NO_ERROR == status) {
  529. int proto;
  530. int port;
  531. PyObject *rawrecord = NULL;
  532. CSADDR_INFO *csinfo = NULL;
  533. record = PyDict_New();
  534. // set host name
  535. dict_set_strings( record, "host", localAddressBuf );
  536. // set service name
  537. dict_set_strings( record, "name", qs->lpszServiceInstanceName );
  538. // set description
  539. dict_set_strings( record, "description", qs->lpszComment );
  540. // set protocol and port
  541. csinfo = qs->lpcsaBuffer;
  542. if( csinfo != NULL ) {
  543. proto = csinfo->iProtocol;
  544. port = ((SOCKADDR_BTH*)csinfo->RemoteAddr.lpSockaddr)->port;
  545. dict_set_str_long(record, "port", port);
  546. if( proto == BTHPROTO_RFCOMM ) {
  547. dict_set_strings(record, "protocol", "RFCOMM");
  548. } else if( proto == BTHPROTO_L2CAP ) {
  549. dict_set_strings(record, "protocol", "L2CAP");
  550. } else {
  551. dict_set_strings(record, "protocol", "UNKNOWN");
  552. dict_set_str_pyobj(record, "port", Py_None);
  553. }
  554. } else {
  555. dict_set_str_pyobj(record, "port", Py_None);
  556. dict_set_strings(record, "protocol", "UNKNOWN");
  557. }
  558. // add the raw service record to be parsed in python
  559. rawrecord = PyString_FromStringAndSize( qs->lpBlob->pBlobData,
  560. qs->lpBlob->cbSize );
  561. dict_set_str_pyobj(record, "rawrecord", rawrecord);
  562. Py_DECREF(rawrecord);
  563. PyList_Append( toreturn, record );
  564. Py_DECREF( record );
  565. } else {
  566. int error = WSAGetLastError();
  567. if( error == WSAEFAULT ) {
  568. // the qs data structure is too small. allocate a bigger
  569. // buffer and try again.
  570. free( qs );
  571. qs = (WSAQUERYSET*) malloc( qs_len );
  572. } else if( error == WSA_E_NO_MORE ) {
  573. // no more results.
  574. done = 1;
  575. } else {
  576. // unexpected error. raise an exception.
  577. Err_SetFromWSALastError( PyExc_IOError );
  578. Py_DECREF( toreturn );
  579. return 0;
  580. }
  581. }
  582. }
  583. Py_BEGIN_ALLOW_THREADS;
  584. WSALookupServiceEnd( h );
  585. Py_END_ALLOW_THREADS;
  586. free( qs );
  587. return toreturn;
  588. }
  589. PyDoc_STRVAR(msbt_find_service_doc, "TODO");
  590. static PyObject *
  591. msbt_set_service_raw(PyObject *self, PyObject *args)
  592. {
  593. int advertise = 0;
  594. WSAQUERYSET qs = { 0 };
  595. WSAESETSERVICEOP op;
  596. char *record = NULL;
  597. int reclen = -1;
  598. BTH_SET_SERVICE *si = NULL;
  599. int silen = -1;
  600. ULONG sdpVersion = BTH_SDP_VERSION;
  601. BLOB blob = { 0 };
  602. int status = -1;
  603. PyObject *result = NULL;
  604. HANDLE rh = 0;
  605. if(!PyArg_ParseTuple(args, "s#i|i", &record, &reclen, &advertise, &rh))
  606. return 0;
  607. silen = sizeof(BTH_SET_SERVICE) + reclen - 1;
  608. si = (BTH_SET_SERVICE*) malloc(silen);
  609. ZeroMemory( si, silen );
  610. si->pSdpVersion = &sdpVersion;
  611. si->pRecordHandle = &rh;
  612. si->fCodService = 0;
  613. si->Reserved;
  614. si->ulRecordLength = reclen;
  615. memcpy( si->pRecord, record, reclen );
  616. op = advertise ? RNRSERVICE_REGISTER : RNRSERVICE_DELETE;
  617. qs.dwSize = sizeof(qs);
  618. qs.lpBlob = &blob;
  619. qs.dwNameSpace = NS_BTH;
  620. blob.cbSize = silen;
  621. blob.pBlobData = (BYTE*)si;
  622. status = WSASetService( &qs, op, 0 );
  623. free( si );
  624. if( SOCKET_ERROR == status ) {
  625. Err_SetFromWSALastError( PyExc_IOError );
  626. return 0;
  627. }
  628. return PyInt_FromLong( (unsigned long) rh );
  629. }
  630. PyDoc_STRVAR(msbt_set_service_raw_doc, "");
  631. static PyObject *
  632. msbt_set_service(PyObject *self, PyObject *args)
  633. {
  634. int advertise = 0;
  635. WSAQUERYSET qs = { 0 };
  636. WSAESETSERVICEOP op;
  637. SOCKADDR_BTH sa = { 0 };
  638. int sa_len = sizeof(sa);
  639. char *service_name = NULL;
  640. char *service_desc = NULL;
  641. char *service_class_id_str = NULL;
  642. CSADDR_INFO sockInfo = { 0 };
  643. GUID uuid = { 0 };
  644. int sockfd;
  645. if(!PyArg_ParseTuple(args, "iisss", &sockfd, &advertise, &service_name,
  646. &service_desc, &service_class_id_str))
  647. return 0;
  648. op = advertise ? RNRSERVICE_REGISTER : RNRSERVICE_DELETE;
  649. if( SOCKET_ERROR == getsockname( sockfd, (SOCKADDR*) &sa, &sa_len ) ) {
  650. Err_SetFromWSALastError( PyExc_IOError );
  651. return 0;
  652. }
  653. sockInfo.iProtocol = BTHPROTO_RFCOMM;
  654. sockInfo.iSocketType = SOCK_STREAM;
  655. sockInfo.LocalAddr.lpSockaddr = (LPSOCKADDR) &sa;
  656. sockInfo.LocalAddr.iSockaddrLength = sizeof(sa);
  657. sockInfo.RemoteAddr.lpSockaddr = (LPSOCKADDR) &sa;
  658. sockInfo.RemoteAddr.iSockaddrLength = sizeof(sa);
  659. qs.dwSize = sizeof(qs);
  660. qs.dwNameSpace = NS_BTH;
  661. qs.lpcsaBuffer = &sockInfo;
  662. qs.lpszServiceInstanceName = service_name;
  663. qs.lpszComment = service_desc;
  664. str2uuid( service_class_id_str, &uuid );
  665. qs.lpServiceClassId = (LPGUID) &uuid;
  666. qs.dwNumberOfCsAddrs = 1;
  667. if( SOCKET_ERROR == WSASetService( &qs, op, 0 ) ) {
  668. Err_SetFromWSALastError( PyExc_IOError );
  669. return 0;
  670. }
  671. Py_INCREF( Py_None );
  672. return Py_None;
  673. }
  674. PyDoc_STRVAR(msbt_set_service_doc, "");
  675. static PyObject *
  676. msbt_setblocking(PyObject *self, PyObject *args)
  677. {
  678. int sockfd = -1;
  679. int block = -1;
  680. PyObject* blockingArg;
  681. if(!PyArg_ParseTuple(args, "iO", &sockfd, &blockingArg)) return 0;
  682. block = PyInt_AsLong(blockingArg);
  683. if (block == -1 && PyErr_Occurred())
  684. return NULL;
  685. if (block) {
  686. block = 0;
  687. ioctlsocket( sockfd, FIONBIO, &block);
  688. } else {
  689. block = 1;
  690. ioctlsocket( sockfd, FIONBIO, &block);
  691. }
  692. Py_INCREF(Py_None);
  693. return Py_None;
  694. }
  695. PyDoc_STRVAR(msbt_setblocking_doc, "");
  696. static PyObject *
  697. msbt_settimeout(PyObject *self, PyObject *args)
  698. {
  699. int sockfd = -1;
  700. double secondTimeout = -1;
  701. DWORD timeout = -1;
  702. int timeoutLen = sizeof(DWORD);
  703. if(!PyArg_ParseTuple(args, "id", &sockfd, &secondTimeout)) return 0;
  704. timeout = (DWORD) (secondTimeout * 1000);
  705. if(setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout,
  706. timeoutLen) != 0) {
  707. Err_SetFromWSALastError( PyExc_IOError );
  708. return 0;
  709. }
  710. if(setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout,
  711. timeoutLen) != 0) {
  712. Err_SetFromWSALastError( PyExc_IOError );
  713. return 0;
  714. }
  715. Py_INCREF(Py_None);
  716. return Py_None;
  717. }
  718. PyDoc_STRVAR(msbt_settimeout_doc, "");
  719. static PyObject *
  720. msbt_gettimeout(PyObject *self, PyObject *args)
  721. {
  722. int sockfd = -1;
  723. DWORD recv_timeout = -1;
  724. int recv_timeoutLen = sizeof(DWORD);
  725. double timeout = -1;
  726. if(!PyArg_ParseTuple(args, "i", &sockfd)) return 0;
  727. if(getsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char*)&recv_timeout,
  728. &recv_timeoutLen) != 0) {
  729. Err_SetFromWSALastError( PyExc_IOError );
  730. return 0;
  731. }
  732. timeout = (double)recv_timeout / 1000;
  733. return PyFloat_FromDouble(timeout);
  734. }
  735. PyDoc_STRVAR(msbt_gettimeout_doc, "");
  736. // ======================= ADMINISTRATIVE =========================
  737. static PyMethodDef msbt_methods[] = {
  738. { "initwinsock", (PyCFunction)msbt_initwinsock, METH_NOARGS,
  739. msbt_initwinsock_doc },
  740. { "socket", (PyCFunction)msbt_socket, METH_VARARGS, msbt_socket_doc },
  741. { "bind", (PyCFunction)msbt_bind, METH_VARARGS, msbt_bind_doc },
  742. { "listen", (PyCFunction)msbt_listen, METH_VARARGS, msbt_listen_doc },
  743. { "accept", (PyCFunction)msbt_accept, METH_VARARGS, msbt_accept_doc },
  744. { "connect", (PyCFunction)msbt_connect, METH_VARARGS, msbt_connect_doc },
  745. { "send", (PyCFunction)msbt_send, METH_VARARGS, msbt_send_doc },
  746. { "recv", (PyCFunction)msbt_recv, METH_VARARGS, msbt_recv_doc },
  747. { "close", (PyCFunction)msbt_close, METH_VARARGS, msbt_close_doc },
  748. { "getsockname", (PyCFunction)msbt_getsockname, METH_VARARGS,
  749. msbt_getsockname_doc },
  750. { "dup", (PyCFunction)msbt_dup, METH_VARARGS, msbt_dup_doc },
  751. { "discover_devices", (PyCFunction)msbt_discover_devices, METH_VARARGS, msbt_discover_devices_doc },
  752. { "lookup_name", (PyCFunction)msbt_lookup_name, METH_VARARGS, msbt_lookup_name_doc },
  753. { "find_service", (PyCFunction)msbt_find_service, METH_VARARGS, msbt_find_service_doc },
  754. { "set_service", (PyCFunction)msbt_set_service, METH_VARARGS, msbt_set_service_doc },
  755. { "set_service_raw", (PyCFunction)msbt_set_service_raw, METH_VARARGS, msbt_set_service_raw_doc },
  756. { "setblocking", (PyCFunction)msbt_setblocking, METH_VARARGS, msbt_setblocking_doc },
  757. { "settimeout", (PyCFunction)msbt_settimeout, METH_VARARGS, msbt_settimeout_doc },
  758. { "gettimeout", (PyCFunction)msbt_gettimeout, METH_VARARGS, msbt_gettimeout_doc },
  759. { NULL, NULL }
  760. };
  761. PyDoc_STRVAR(msbt_doc, "TODO\n");
  762. #define ADD_INT_CONSTANT(m,a) PyModule_AddIntConstant(m, #a, a)
  763. #if PY_MAJOR_VERSION < 3
  764. PyMODINIT_FUNC
  765. init_msbt(void)
  766. {
  767. PyObject * m = Py_InitModule3("_msbt", msbt_methods, msbt_doc);
  768. ADD_INT_CONSTANT(m, SOCK_STREAM);
  769. ADD_INT_CONSTANT(m, BTHPROTO_RFCOMM);
  770. ADD_INT_CONSTANT(m, BT_PORT_ANY);
  771. }
  772. #else
  773. PyMODINIT_FUNC
  774. PyInit__msbt(void)
  775. {
  776. PyObject *m;
  777. static struct PyModuleDef moduledef = {
  778. PyModuleDef_HEAD_INIT,
  779. "_msbt",
  780. NULL,
  781. -1,
  782. msbt_methods,
  783. NULL,
  784. NULL,
  785. NULL,
  786. NULL
  787. };
  788. m = PyModule_Create(&moduledef);
  789. #define ADD_INT_CONSTANT(m,a) PyModule_AddIntConstant(m, #a, a)
  790. ADD_INT_CONSTANT(m, SOCK_STREAM);
  791. ADD_INT_CONSTANT(m, BTHPROTO_RFCOMM);
  792. ADD_INT_CONSTANT(m, BT_PORT_ANY);
  793. return m;
  794. }
  795. #endif