PageRenderTime 83ms CodeModel.GetById 19ms app.highlight 56ms RepoModel.GetById 1ms app.codeStats 1ms

/msbt/_msbt.c

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