An Overlay-based
Virtual Network Substrate
SpoVNet

source: source/ariba/utility/bootstrap/modules/bluetoothsdp/BluetoothSdp.cpp @ 5638

Last change on this file since 5638 was 5638, checked in by Christoph Mayer, 10 years ago

adress detection aufgeräumt, network info für bleutooth, data stream (hopeful crash fix), logging auf maemo nur warn, ...

File size: 12.9 KB
Line 
1// [License]
2// The Ariba-Underlay Copyright
3//
4// Copyright (c) 2008-2009, Institute of Telematics, UniversitÀt Karlsruhe (TH)
5//
6// Institute of Telematics
7// UniversitÀt Karlsruhe (TH)
8// Zirkel 2, 76128 Karlsruhe
9// Germany
10//
11// Redistribution and use in source and binary forms, with or without
12// modification, are permitted provided that the following conditions are
13// met:
14//
15// 1. Redistributions of source code must retain the above copyright
16// notice, this list of conditions and the following disclaimer.
17// 2. Redistributions in binary form must reproduce the above copyright
18// notice, this list of conditions and the following disclaimer in the
19// documentation and/or other materials provided with the distribution.
20//
21// THIS SOFTWARE IS PROVIDED BY THE INSTITUTE OF TELEMATICS ``AS IS'' AND
22// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ARIBA PROJECT OR
25// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32//
33// The views and conclusions contained in the software and documentation
34// are those of the authors and should not be interpreted as representing
35// official policies, either expressed or implied, of the Institute of
36// Telematics.
37// [License]
38
39#include "BluetoothSdp.h"
40
41#ifdef HAVE_BLUETOOTH_BLUETOOTH_H
42
43// Attribute descriptors for SDP
44// base was chosen randomly
45#define SDP_SPOVNET_BASE                        0x4000
46#define SDP_ATTR_SPOVNET_NAME           0x0000 + SDP_SPOVNET_BASE
47#define SDP_ATTR_SPOVNET_INFO1          0x0001 + SDP_SPOVNET_BASE
48#define SDP_ATTR_SPOVNET_INFO2          0x0002 + SDP_SPOVNET_BASE
49#define SDP_ATTR_SPOVNET_INFO3          0x0003 + SDP_SPOVNET_BASE
50
51// The SpoVNet unique identifier, this should be the same for all SpoVNet implementations
52const uint8_t svc_uuid_int[] = {0x59, 0x29, 0x24, 0x34, 0x69, 0x42, 0x11, 0xde, 0x94,
53                0x3e, 0x00, 0x21, 0x5d, 0xb4, 0xd8, 0x54};
54
55const char *service_name = "SpoVNet";
56const char *svc_dsc = "www.ariba-underlay.org";
57const char *service_prov = "ITM Uni Karlsruhe";
58
59#endif // HAVE_BLUETOOTH_BLUETOOTH_H
60
61
62namespace ariba {
63namespace utility {
64use_logging_cpp(BluetoothSdp);
65
66BluetoothSdp::BluetoothSdp(BootstrapInformationCallback* _callback) :
67        BootstrapModule(_callback), scan_timer_(io_service_) {
68        srand( time(NULL) );
69#ifdef HAVE_BLUETOOTH_BLUETOOTH_H
70
71        // This can be ignored, as the channel we really be saved in one
72        // of the info strings (as an attribute)
73        channel_ = 1;
74
75#endif // HAVE_BLUETOOTH_BLUETOOTH_H
76}
77
78BluetoothSdp::~BluetoothSdp() {
79}
80
81string BluetoothSdp::getName() {
82        return "BluetoothSdp";
83}
84
85string BluetoothSdp::getInformation() {
86        return "bootstrap module based on bluetooth service discovery protocol";
87}
88
89bool BluetoothSdp::isFunctional() {
90#ifdef HAVE_BLUETOOTH_BLUETOOTH_H
91        return true;
92#else
93        return false;
94#endif
95}
96
97void BluetoothSdp::start() {
98#ifdef HAVE_BLUETOOTH_BLUETOOTH_H
99
100        /*
101         * Initializes and forks the scanner.
102         */
103
104        io_service_.post(boost::bind(&BluetoothSdp::bt_scan, this));
105        t_ = boost::thread(boost::bind(&boost::asio::io_service::run, &io_service_));
106
107#endif // HAVE_BLUETOOTH_BLUETOOTH_H
108}
109
110void BluetoothSdp::stop() {
111#ifdef HAVE_BLUETOOTH_BLUETOOTH_H
112
113        /*
114         * Stops the scanner.
115         */
116
117        // not sure if this is thread safe
118        io_service_.stop();
119        t_.join();
120
121        if(sdp_session_ != NULL)
122                sdp_close(sdp_session_);
123
124#endif // HAVE_BLUETOOTH_BLUETOOTH_H
125}
126
127void BluetoothSdp::publishService(string name, string info1, string info2,
128                string info3) {
129#ifdef HAVE_BLUETOOTH_BLUETOOTH_H
130
131        /*
132         * Publishes an SpoVNet SDP Service and
133         * adds the arguments as info attributes.
134         */
135
136        logging_debug("registering SDP service");
137
138        uint8_t rfcomm_channel = channel_;
139
140        uuid_t root_uuid, l2cap_uuid, rfcomm_uuid, svc_uuid, svc_class_uuid;
141        sdp_list_t *l2cap_list = 0, *rfcomm_list = 0, *root_list = 0, *proto_list =
142                0, *access_proto_list = 0, *svc_class_list = 0, *profile_list = 0;
143        sdp_data_t *channel = 0;
144        sdp_profile_desc_t profile;
145        sdp_record_t record = {0};
146        sdp_session_ = 0;
147
148        if((name.length() > 256) || (info1.length() > 256) || (info2.length() > 256) || (info3.length() > 256)) {
149                logging_error("string argument too long, max size is 256");
150                return;
151        }
152
153        // prepare the info attribute buffers
154        //string namebuf, info1buf, info2buf, info3buf;
155        uint8_t namelen, info1len, info2len, info3len;
156
157        namelen = (uint8_t)name.length();
158        info1len = (uint8_t)info1.length();
159        info2len = (uint8_t)info2.length();
160        info3len = (uint8_t)info3.length();
161
162        // set the general service ID
163        sdp_uuid128_create(&svc_uuid, &svc_uuid_int);
164        sdp_set_service_id(&record, svc_uuid);
165
166        // set the service class
167        sdp_uuid16_create(&svc_class_uuid, SERIAL_PORT_SVCLASS_ID);
168        svc_class_list = sdp_list_append(0, &svc_class_uuid);
169        sdp_set_service_classes(&record, svc_class_list);
170
171        // set the Bluetooth profile information
172        sdp_uuid16_create(&profile.uuid, SERIAL_PORT_PROFILE_ID);
173        profile.version = 0x0100;
174        profile_list = sdp_list_append(0, &profile);
175        sdp_set_profile_descs(&record, profile_list);
176
177        // make the service record publicly browsable
178        sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
179        root_list = sdp_list_append(0, &root_uuid);
180        sdp_set_browse_groups(&record, root_list);
181
182        // set l2cap informatiint argc, char* argv[]on
183        sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
184        l2cap_list = sdp_list_append(0, &l2cap_uuid);
185        proto_list = sdp_list_append(0, l2cap_list);
186
187        // register the RFCOMM channel for RFCOMM sockets
188        sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
189        channel = sdp_data_alloc(SDP_UINT8, &rfcomm_channel);
190        rfcomm_list = sdp_list_append(0, &rfcomm_uuid);
191        sdp_list_append(rfcomm_list, channel);
192        sdp_list_append(proto_list, rfcomm_list);
193
194        access_proto_list = sdp_list_append(0, proto_list);
195        sdp_set_access_protos(&record, access_proto_list);
196
197        // set the name, provider, and description
198        sdp_set_info_attr(&record, service_name, service_prov, svc_dsc);
199
200        // add the spovnet attributes
201        sdp_attr_add_new(&record, SDP_ATTR_SPOVNET_NAME, SDP_TEXT_STR8,
202                        name.data());
203
204        sdp_attr_add_new(&record, SDP_ATTR_SPOVNET_INFO1, SDP_TEXT_STR8,
205                        info1.data());
206
207        sdp_attr_add_new(&record, SDP_ATTR_SPOVNET_INFO2, SDP_TEXT_STR8,
208                        info2.data());
209
210        sdp_attr_add_new(&record, SDP_ATTR_SPOVNET_INFO3, SDP_TEXT_STR8,
211                        info3.data());
212
213        // connect to the local SDP server, register the service record
214        if( sdp_session_ == NULL ){
215                sdp_session_ = sdp_connect(BDADDR_ANY, BDADDR_LOCAL, SDP_RETRY_IF_BUSY);
216        }
217
218        if (sdp_session_ == NULL) {
219                logging_error( "something is wrong with your SDP server, nothing registered: " << strerror(errno) );
220        } else {
221                int ret = sdp_record_register(sdp_session_, &record, 0);
222
223                if(ret < 0){
224                        logging_error("failed registering sdp record: " << strerror(errno));
225                }else{
226                        logging_debug("sdp record registered using session " << sdp_session_);
227                }
228        }
229
230        // cleanup
231        sdp_data_free(channel);
232        sdp_list_free(l2cap_list, 0);
233        sdp_list_free(rfcomm_list, 0);
234        sdp_list_free(root_list, 0);
235        sdp_list_free(access_proto_list, 0);
236        sdp_list_free(svc_class_list, 0);
237        sdp_list_free(profile_list, 0);
238
239#endif // HAVE_BLUETOOTH_BLUETOOTH_H
240}
241
242void BluetoothSdp::revokeService(string name) {
243#ifdef HAVE_BLUETOOTH_BLUETOOTH_H
244
245        logging_debug("unregistering SDP service");
246        sdp_close(sdp_session_);
247
248#endif // HAVE_BLUETOOTH_BLUETOOTH_H
249}
250
251#ifdef HAVE_BLUETOOTH_BLUETOOTH_H
252
253void BluetoothSdp::bt_scan() {
254
255        //
256        // scan for devices if we have no active rfcomm connections running.
257        // otherwise we would break existing connections due to chipping seq
258        //
259
260        if(!haveConnections()){
261
262                /*
263                 * Scans for other bluetooth devices and starts a SDP search on them.
264                 */
265
266                logging_debug("scanning for peers");
267
268                inquiry_info *ii = NULL;
269                int max_rsp, num_rsp;
270                int dev_id, sock, len, flags;
271                int i;
272
273                bdaddr_t address;
274                uint8_t channel;
275
276                dev_id = hci_get_route(NULL);
277                sock = hci_open_dev(dev_id);
278                if (dev_id < 0 || sock < 0) {
279                        logging_error("opening socket for device "
280                                        << dev_id << " failed. can not scan for peers: " << strerror(errno));
281                        return;
282                }
283
284                len = 8;
285                max_rsp = 255;
286                flags = IREQ_CACHE_FLUSH;
287                ii = (inquiry_info*) malloc(max_rsp * sizeof(inquiry_info));
288
289                num_rsp = hci_inquiry(dev_id, len, max_rsp, NULL, &ii, flags);
290                if (num_rsp < 0)
291                        logging_error("hci_inquiry failed with " << num_rsp << ": " << strerror(errno));
292
293                for (i = 0; i < num_rsp; i++) {
294                        address = (ii + i)->bdaddr;
295
296                        string saddress = ba2string(&address);
297                        string sname = ba2name(&address, sock);
298
299                        logging_debug("found peer [" << saddress << "] [" << sname << "]");
300                        sdp_search( address, sname );
301                }
302
303                free(ii);
304                close(sock);
305
306        } else {
307                logging_debug("have active rfcomm connectinos, not searching");
308        }
309
310        int nextscan = (rand() % 30) + 5;
311        logging_debug("next sdp scan try in " << nextscan << " seconds");
312
313        scan_timer_.expires_from_now( boost::posix_time::seconds(nextscan) );
314        scan_timer_.async_wait( boost::bind(&BluetoothSdp::bt_scan, this) );
315}
316
317void BluetoothSdp::sdp_search(bdaddr_t target, string devicename) {
318
319        /*
320         * Searches target for SDP records with the SpoVnet uuid
321         * and extracts its info attributes.
322         */
323
324        int status;
325        uuid_t svc_uuid;
326        sdp_list_t *response_list, *search_list, *attrid_list;
327        sdp_session_t *session = NULL;
328        uint32_t range = 0x0000ffff;
329        uint8_t port = 0;
330
331        // connect to the SDP server running on the remote machine
332        logging_debug("querying services from bt device ["
333                        << ba2string(&target) << "] [" << devicename << "]");
334
335        // prepare the buffers for the attributes
336        char name[256], info1[256], info2[256], info3[256];
337
338        session = sdp_connect(BDADDR_ANY, &target, SDP_RETRY_IF_BUSY);
339
340        if (session == NULL) {
341                logging_error("failed to connect to SDP server at "
342                                << ba2string(&target) << ": " << strerror(errno));
343                return;
344        }
345
346        sdp_uuid128_create(&svc_uuid, &svc_uuid_int);
347        search_list = sdp_list_append(0, &svc_uuid);
348        attrid_list = sdp_list_append(0, &range);
349
350        // get a list of service records that have UUID uuid_
351        response_list = NULL;
352        status = sdp_service_search_attr_req(session, search_list,
353                        SDP_ATTR_REQ_RANGE, attrid_list, &response_list);
354
355        if (status == 0) {
356                sdp_list_t *proto_list = NULL;
357                sdp_list_t *r = response_list;
358
359                // go through each of the service records
360                for ( ; r != NULL; r = r->next) {
361                        sdp_record_t *rec = (sdp_record_t*) r->data;
362
363                        // get a list of the protocol sequences
364                        if (sdp_get_access_protos(rec, &proto_list) == 0) {
365
366                                // get the RFCOMM port number
367                                port = sdp_get_proto_port(proto_list, RFCOMM_UUID);
368
369                                sdp_list_free(proto_list, 0);
370
371                                sdp_get_string_attr(rec, SDP_ATTR_SPOVNET_NAME, (char*)&name, 256);
372                                sdp_get_string_attr(rec, SDP_ATTR_SPOVNET_INFO1, (char*)&info1, 256);
373                                sdp_get_string_attr(rec, SDP_ATTR_SPOVNET_INFO2, (char*)&info2, 256);
374                                sdp_get_string_attr(rec, SDP_ATTR_SPOVNET_INFO3, (char*)&info3, 256);
375
376                                logging_info("Remote peer name is: " << name);
377                                logging_info("Remote peer info1 is: " << info1);
378                                logging_info("Remote peer info2 is: " << info2);
379                                logging_info("Remote peer info3 is: " << info3);
380
381                                // Callback
382                                callback->onBootstrapServiceFound(name, info1, info2, info3);
383                        }
384                        sdp_record_free(rec);
385                }
386        } else {
387                logging_error("sdp_service_search_attr_req failed with timeout: " << strerror(errno));
388        }
389
390        sdp_list_free(response_list, 0);
391        sdp_list_free(search_list, 0);
392        sdp_list_free(attrid_list, 0);
393        sdp_close(session);
394}
395
396string BluetoothSdp::ba2string(bdaddr_t* ba) {
397        /*
398         * Returns a string holding the bt adress in human readable form.
399         */
400        char addr[32] = { 0 };
401        char str[32] = { 0 };
402        ba2str(ba, str);
403        string result = str;
404        return result;
405}
406
407string BluetoothSdp::ba2name(bdaddr_t* ba, int sock){
408
409        char name[256] = {0};
410        memset(name, 0, sizeof(name));
411
412        if( hci_read_remote_name(sock, ba, sizeof(name), name, 0) < 0 )
413                strcpy(name, "unknown");
414
415        string result = name;
416        return result;
417}
418
419bool BluetoothSdp::haveConnections(){
420
421        struct hci_conn_list_req* cl = NULL;
422        struct hci_conn_info* ci = NULL;
423
424        int btsock = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
425        if(btsock <  0){
426                logging_error("failed getting bluetooth raw socket");
427                return true; // return true to be safe here and not perform sdp scan
428        }
429
430        cl = (struct hci_conn_list_req*)malloc(10 * sizeof(struct hci_conn_info) + sizeof(struct hci_conn_list_req));
431
432        cl->dev_id = hci_get_route(NULL);;
433        cl->conn_num = 10;
434        ci = cl->conn_info;
435
436        if(ioctl(btsock, HCIGETCONNLIST, (void*)cl)){
437                logging_warn("could not get active rfcomm connections");
438                return true; // return true to be safe here and not perform sdp scan
439        }
440
441        bool haveconn = (cl->conn_num > 0);
442        logging_error("we have " << cl->conn_num << " active connections");
443        free(cl);
444        close(btsock);
445
446        return haveconn;
447}
448
449#endif // HAVE_BLUETOOTH_BLUETOOTH_H
450
451}} //namespace ariba, utility
Note: See TracBrowser for help on using the repository browser.