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

Last change on this file since 5953 was 5953, checked in by Christoph Mayer, 15 years ago

more agressive sdp scan, sdp off when in spovnet, sdp on and agressive when not

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 connections, not searching");
308 //}
309
310 int nextscan = (rand() % 5) + 3;
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_debug("we have " << cl->conn_num << " active hci 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.