1 /* 2 * Copyright 2007-2009 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com 3 * Copyright 2008 Mika Lindqvist, monni1995_at_gmail.com 4 * All rights reserved. Distributed under the terms of the MIT License. 5 */ 6 7 #include <stdio.h> 8 #include <fcntl.h> 9 #include <unistd.h> 10 #include <sys/select.h> 11 12 #include <Entry.h> 13 #include <Deskbar.h> 14 #include <Directory.h> 15 #include <Message.h> 16 #include <Path.h> 17 #include <Roster.h> 18 #include <String.h> 19 20 #include <TypeConstants.h> 21 #include <syslog.h> 22 23 #include <bluetoothserver_p.h> 24 #include <bluetooth/HCI/btHCI_command.h> 25 #include <bluetooth/L2CAP/btL2CAP.h> 26 #include <bluetooth/bluetooth.h> 27 28 #include "BluetoothServer.h" 29 #include "DeskbarReplicant.h" 30 #include "LocalDeviceImpl.h" 31 #include "Output.h" 32 33 34 status_t 35 DispatchEvent(struct hci_event_header* header, int32 code, size_t size) 36 { 37 // we only handle events 38 if (GET_PORTCODE_TYPE(code)!= BT_EVENT) { 39 Output::Instance()->Post("Wrong type frame code", BLACKBOARD_KIT); 40 return B_OK; 41 } 42 43 // fetch the LocalDevice who belongs this event 44 LocalDeviceImpl* lDeviceImplementation = ((BluetoothServer*)be_app)-> 45 LocateLocalDeviceImpl(GET_PORTCODE_HID(code)); 46 47 if (lDeviceImplementation == NULL) { 48 Output::Instance()->Post("LocalDevice could not be fetched", BLACKBOARD_KIT); 49 return B_OK; 50 } 51 52 lDeviceImplementation->HandleEvent(header); 53 54 return B_OK; 55 } 56 57 58 BluetoothServer::BluetoothServer() 59 : BApplication(BLUETOOTH_SIGNATURE) 60 , fSDPThreadID(-1) 61 , fIsShuttingDown(false) 62 { 63 Output::Instance()->Run(); 64 Output::Instance()->SetTitle("Bluetooth message gathering"); 65 66 Output::Instance()->AddTab("General", BLACKBOARD_GENERAL); 67 Output::Instance()->AddTab("Device Manager", BLACKBOARD_DEVICEMANAGER); 68 Output::Instance()->AddTab("Kit", BLACKBOARD_KIT); 69 Output::Instance()->AddTab("SDP", BLACKBOARD_SDP); 70 71 fDeviceManager = new DeviceManager(); 72 fLocalDevicesList.MakeEmpty(); 73 74 fEventListener2 = new BluetoothPortListener(BT_USERLAND_PORT_NAME, 75 (BluetoothPortListener::port_listener_func)&DispatchEvent); 76 } 77 78 79 bool BluetoothServer::QuitRequested(void) 80 { 81 LocalDeviceImpl* lDeviceImpl = NULL; 82 while ((lDeviceImpl = (LocalDeviceImpl*) 83 fLocalDevicesList.RemoveItem((int32)0)) != NULL) 84 delete lDeviceImpl; 85 86 _RemoveDeskbarIcon(); 87 88 // stop the SDP server thread 89 fIsShuttingDown = true; 90 91 status_t threadReturnStatus; 92 wait_for_thread(fSDPThreadID, &threadReturnStatus); 93 printf("SDP server thread exited with: %s\n", strerror(threadReturnStatus)); 94 95 // Finish quitting 96 Output::Instance()->Lock(); 97 Output::Instance()->Quit(); 98 99 delete fEventListener2; 100 printf("Shutting down bluetooth_server.\n"); 101 102 return BApplication::QuitRequested(); 103 } 104 105 106 void BluetoothServer::ArgvReceived(int32 argc, char **argv) 107 { 108 if (argc > 1) { 109 if (strcmp(argv[1], "--finish") == 0) 110 PostMessage(B_QUIT_REQUESTED); 111 } 112 113 } 114 115 116 void BluetoothServer::ReadyToRun(void) 117 { 118 ShowWindow(Output::Instance()); 119 120 fDeviceManager->StartMonitoringDevice("bluetooth/h2"); 121 fDeviceManager->StartMonitoringDevice("bluetooth/h3"); 122 fDeviceManager->StartMonitoringDevice("bluetooth/h4"); 123 fDeviceManager->StartMonitoringDevice("bluetooth/h5"); 124 125 if (fEventListener2->Launch() != B_OK) 126 Output::Instance()->Post("Bluetooth event listener failed\n", 127 BLACKBOARD_GENERAL); 128 else 129 Output::Instance()->Post("Bluetooth event listener Ready\n", 130 BLACKBOARD_GENERAL); 131 132 _InstallDeskbarIcon(); 133 134 // Spawn the SDP server thread 135 fSDPThreadID = spawn_thread(SDPServerThread, "SDP server thread", 136 B_NORMAL_PRIORITY, this); 137 138 #define _USE_FAKE_SDP_SERVER 139 #ifdef _USE_FAKE_SDP_SERVER 140 if (fSDPThreadID <= 0 || resume_thread(fSDPThreadID) != B_OK) { 141 Output::Instance()->Postf(BLACKBOARD_SDP, 142 "Failed launching the SDP server thread: %x\n", fSDPThreadID); 143 } 144 #endif 145 } 146 147 148 void BluetoothServer::AppActivated(bool act) 149 { 150 printf("Activated %d\n",act); 151 } 152 153 154 void BluetoothServer::MessageReceived(BMessage* message) 155 { 156 BMessage reply; 157 status_t status = B_WOULD_BLOCK; // mark somehow to do not reply anything 158 159 switch (message->what) 160 { 161 case BT_MSG_ADD_DEVICE: 162 { 163 BString str; 164 165 message->FindString("name", &str); 166 167 Output::Instance()->Postf(BLACKBOARD_GENERAL, 168 "Requested LocalDevice %s\n", str.String()); 169 170 BPath path(str.String()); 171 172 LocalDeviceImpl* lDeviceImpl 173 = LocalDeviceImpl::CreateTransportAccessor(&path); 174 175 if (lDeviceImpl->GetID() >= 0) { 176 fLocalDevicesList.AddItem(lDeviceImpl); 177 178 Output::Instance()->AddTab("Local Device", 179 BLACKBOARD_LD(lDeviceImpl->GetID())); 180 Output::Instance()->Postf(BLACKBOARD_LD(lDeviceImpl->GetID()), 181 "LocalDevice %s id=%x added\n", str.String(), 182 lDeviceImpl->GetID()); 183 184 } else { 185 Output::Instance()->Post("Adding LocalDevice hci id invalid\n", 186 BLACKBOARD_GENERAL); 187 } 188 189 status = B_WOULD_BLOCK; 190 /* TODO: This should be by user request only! */ 191 lDeviceImpl->Launch(); 192 break; 193 } 194 195 case BT_MSG_REMOVE_DEVICE: 196 { 197 LocalDeviceImpl* lDeviceImpl = LocateDelegateFromMessage(message); 198 if (lDeviceImpl != NULL) { 199 fLocalDevicesList.RemoveItem(lDeviceImpl); 200 delete lDeviceImpl; 201 } 202 break; 203 } 204 205 case BT_MSG_COUNT_LOCAL_DEVICES: 206 status = HandleLocalDevicesCount(message, &reply); 207 break; 208 209 case BT_MSG_ACQUIRE_LOCAL_DEVICE: 210 status = HandleAcquireLocalDevice(message, &reply); 211 break; 212 213 case BT_MSG_HANDLE_SIMPLE_REQUEST: 214 status = HandleSimpleRequest(message, &reply); 215 break; 216 217 case BT_MSG_GET_PROPERTY: 218 status = HandleGetProperty(message, &reply); 219 break; 220 221 // Handle if the bluetooth preferences is running? 222 case B_SOME_APP_LAUNCHED: 223 { 224 const char* signature; 225 226 if (message->FindString("be:signature", &signature) == B_OK) { 227 printf("input_server : %s\n", signature); 228 if (strcmp(signature, "application/x-vnd.Be-TSKB") == 0) { 229 230 } 231 } 232 return; 233 } 234 235 case BT_MSG_SERVER_SHOW_CONSOLE: 236 ShowWindow(Output::Instance()); 237 break; 238 239 default: 240 BApplication::MessageReceived(message); 241 break; 242 } 243 244 // Can we reply right now? 245 // TOD: review this condition 246 if (status != B_WOULD_BLOCK) { 247 reply.AddInt32("status", status); 248 message->SendReply(&reply); 249 // printf("Sending reply message for->\n"); 250 // message->PrintToStream(); 251 } 252 } 253 254 255 #if 0 256 #pragma mark - 257 #endif 258 259 LocalDeviceImpl* 260 BluetoothServer::LocateDelegateFromMessage(BMessage* message) 261 { 262 LocalDeviceImpl* lDeviceImpl = NULL; 263 hci_id hid; 264 265 if (message->FindInt32("hci_id", &hid) == B_OK) { 266 // Try to find out when a ID was specified 267 int index; 268 for (index = 0; index < fLocalDevicesList.CountItems(); index ++) { 269 lDeviceImpl = fLocalDevicesList.ItemAt(index); 270 if (lDeviceImpl->GetID() == hid) 271 break; 272 } 273 } 274 275 return lDeviceImpl; 276 277 } 278 279 280 LocalDeviceImpl* 281 BluetoothServer::LocateLocalDeviceImpl(hci_id hid) 282 { 283 // Try to find out when a ID was specified 284 int index; 285 286 for (index = 0; index < fLocalDevicesList.CountItems(); index++) { 287 LocalDeviceImpl* lDeviceImpl = fLocalDevicesList.ItemAt(index); 288 if (lDeviceImpl->GetID() == hid) 289 return lDeviceImpl; 290 } 291 292 return NULL; 293 } 294 295 296 #if 0 297 #pragma - Messages reply 298 #endif 299 300 status_t 301 BluetoothServer::HandleLocalDevicesCount(BMessage* message, BMessage* reply) 302 { 303 Output::Instance()->Post("Count Requested\n", BLACKBOARD_KIT); 304 305 return reply->AddInt32("count", fLocalDevicesList.CountItems()); 306 } 307 308 309 status_t 310 BluetoothServer::HandleAcquireLocalDevice(BMessage* message, BMessage* reply) 311 { 312 hci_id hid; 313 ssize_t size; 314 bdaddr_t bdaddr; 315 LocalDeviceImpl* lDeviceImpl = NULL; 316 static int32 lastIndex = 0; 317 318 if (message->FindInt32("hci_id", &hid) == B_OK) { 319 Output::Instance()->Post("GetLocalDevice requested with id\n", 320 BLACKBOARD_KIT); 321 lDeviceImpl = LocateDelegateFromMessage(message); 322 323 } else if (message->FindData("bdaddr", B_ANY_TYPE, 324 (const void**)&bdaddr, &size) == B_OK) { 325 326 // Try to find out when the user specified the address 327 Output::Instance()->Post("GetLocalDevice requested with bdaddr\n", 328 BLACKBOARD_KIT); 329 for (lastIndex = 0; lastIndex < fLocalDevicesList.CountItems(); 330 lastIndex ++) { 331 // TODO: Only possible if the property is available 332 // bdaddr_t local; 333 // lDeviceImpl = fLocalDevicesList.ItemAt(lastIndex); 334 // if ((lDeviceImpl->GetAddress(&local, message) == B_OK) 335 // && bacmp(&local, &bdaddr)) { 336 // break; 337 // } 338 } 339 340 } else { 341 // Careless, any device not performing operations will be fine 342 Output::Instance()->Post("GetLocalDevice plain request\n", BLACKBOARD_KIT); 343 // from last assigned till end 344 for (int index = lastIndex + 1; 345 index < fLocalDevicesList.CountItems(); index++) { 346 lDeviceImpl= fLocalDevicesList.ItemAt(index); 347 printf("Requesting local device %" B_PRId32 "\n", 348 lDeviceImpl->GetID()); 349 if (lDeviceImpl != NULL && lDeviceImpl->Available()) { 350 Output::Instance()->Postf(BLACKBOARD_KIT, 351 "Device available: %lx\n", lDeviceImpl->GetID()); 352 lastIndex = index; 353 break; 354 } 355 } 356 357 // from starting till last assigned if not yet found 358 if (lDeviceImpl == NULL) { 359 for (int index = 0; index <= lastIndex ; index ++) { 360 lDeviceImpl = fLocalDevicesList.ItemAt(index); 361 printf("Requesting local device %" B_PRId32 "\n", 362 lDeviceImpl->GetID()); 363 if (lDeviceImpl != NULL && lDeviceImpl->Available()) { 364 Output::Instance()->Postf(BLACKBOARD_KIT, 365 "Device available: %lx\n", lDeviceImpl->GetID()); 366 lastIndex = index; 367 break; 368 } 369 } 370 } 371 } 372 373 if (lastIndex <= fLocalDevicesList.CountItems() && lDeviceImpl != NULL 374 && lDeviceImpl->Available()) { 375 376 hid = lDeviceImpl->GetID(); 377 lDeviceImpl->Acquire(); 378 379 Output::Instance()->Postf(BLACKBOARD_KIT, "Device acquired %lx\n", hid); 380 return reply->AddInt32("hci_id", hid); 381 } 382 383 return B_ERROR; 384 385 } 386 387 388 status_t 389 BluetoothServer::HandleSimpleRequest(BMessage* message, BMessage* reply) 390 { 391 LocalDeviceImpl* lDeviceImpl = LocateDelegateFromMessage(message); 392 if (lDeviceImpl == NULL) { 393 return B_ERROR; 394 } 395 396 const char* propertyRequested; 397 398 // Find out if there is a property being requested, 399 if (message->FindString("property", &propertyRequested) == B_OK) { 400 // Check if the property has been already retrieved 401 if (lDeviceImpl->IsPropertyAvailable(propertyRequested)) { 402 // Dump everything 403 reply->AddMessage("properties", lDeviceImpl->GetPropertiesMessage()); 404 return B_OK; 405 } 406 } 407 408 // we are gonna need issue the command ... 409 if (lDeviceImpl->ProcessSimpleRequest(DetachCurrentMessage()) == B_OK) 410 return B_WOULD_BLOCK; 411 else { 412 lDeviceImpl->Unregister(); 413 return B_ERROR; 414 } 415 416 } 417 418 419 status_t 420 BluetoothServer::HandleGetProperty(BMessage* message, BMessage* reply) 421 { 422 // User side will look for the reply in a result field and will 423 // not care about status fields, therefore we return OK in all cases 424 425 LocalDeviceImpl* lDeviceImpl = LocateDelegateFromMessage(message); 426 if (lDeviceImpl == NULL) { 427 return B_ERROR; 428 } 429 430 const char* propertyRequested; 431 432 // Find out if there is a property being requested, 433 if (message->FindString("property", &propertyRequested) == B_OK) { 434 435 Output::Instance()->Postf(BLACKBOARD_LD(lDeviceImpl->GetID()), 436 "Searching %s property...\n", propertyRequested); 437 438 // Check if the property has been already retrieved 439 if (lDeviceImpl->IsPropertyAvailable(propertyRequested)) { 440 441 // 1 bytes requests 442 if (strcmp(propertyRequested, "hci_version") == 0 443 || strcmp(propertyRequested, "lmp_version") == 0 444 || strcmp(propertyRequested, "sco_mtu") == 0) { 445 446 uint8 result = lDeviceImpl->GetPropertiesMessage()-> 447 FindInt8(propertyRequested); 448 reply->AddInt32("result", result); 449 450 // 2 bytes requests 451 } else if (strcmp(propertyRequested, "hci_revision") == 0 452 || strcmp(propertyRequested, "lmp_subversion") == 0 453 || strcmp(propertyRequested, "manufacturer") == 0 454 || strcmp(propertyRequested, "acl_mtu") == 0 455 || strcmp(propertyRequested, "acl_max_pkt") == 0 456 || strcmp(propertyRequested, "sco_max_pkt") == 0 457 || strcmp(propertyRequested, "packet_type") == 0 ) { 458 459 uint16 result = lDeviceImpl->GetPropertiesMessage()-> 460 FindInt16(propertyRequested); 461 reply->AddInt32("result", result); 462 463 // 1 bit requests 464 } else if (strcmp(propertyRequested, "role_switch_capable") == 0 465 || strcmp(propertyRequested, "encrypt_capable") == 0) { 466 467 bool result = lDeviceImpl->GetPropertiesMessage()-> 468 FindBool(propertyRequested); 469 470 reply->AddInt32("result", result); 471 472 473 474 } else { 475 Output::Instance()->Postf(BLACKBOARD_LD(lDeviceImpl->GetID()), 476 "Property %s could not be satisfied\n", propertyRequested); 477 } 478 } 479 } 480 481 return B_OK; 482 } 483 484 485 #if 0 486 #pragma mark - 487 #endif 488 489 int32 490 BluetoothServer::SDPServerThread(void* data) 491 { 492 const BluetoothServer* server = (BluetoothServer*)data; 493 494 // Set up the SDP socket 495 struct sockaddr_l2cap loc_addr = { 0 }; 496 int socketServer; 497 int client; 498 status_t status; 499 char buffer[512] = ""; 500 501 Output::Instance()->Postf(BLACKBOARD_SDP, "SDP server thread up...\n"); 502 503 socketServer = socket(PF_BLUETOOTH, SOCK_STREAM, BLUETOOTH_PROTO_L2CAP); 504 505 if (socketServer < 0) { 506 Output::Instance()->Post("Could not create server socket ...\n", 507 BLACKBOARD_SDP); 508 return B_ERROR; 509 } 510 511 // bind socket to port 0x1001 of the first available 512 // bluetooth adapter 513 loc_addr.l2cap_family = AF_BLUETOOTH; 514 loc_addr.l2cap_bdaddr = BDADDR_ANY; 515 loc_addr.l2cap_psm = B_HOST_TO_LENDIAN_INT16(1); 516 loc_addr.l2cap_len = sizeof(struct sockaddr_l2cap); 517 518 status = bind(socketServer, (struct sockaddr*)&loc_addr, 519 sizeof(struct sockaddr_l2cap)); 520 521 if (status < 0) { 522 Output::Instance()->Postf(BLACKBOARD_SDP, 523 "Could not bind server socket %d ...\n", status); 524 return status; 525 } 526 527 // setsockopt(sock, SOL_L2CAP, SO_L2CAP_OMTU, &omtu, len ); 528 // getsockopt(sock, SOL_L2CAP, SO_L2CAP_IMTU, &omtu, &len ); 529 530 // Listen for up to 10 connections 531 status = listen(socketServer, 10); 532 533 if (status != B_OK) { 534 Output::Instance()->Postf(BLACKBOARD_SDP, 535 "Could not listen server socket %d ...\n", status); 536 return status; 537 } 538 539 while (!server->fIsShuttingDown) { 540 541 Output::Instance()->Postf(BLACKBOARD_SDP, 542 "Waiting connection for socket %d ...\n", socketServer); 543 544 uint len = sizeof(struct sockaddr_l2cap); 545 client = accept(socketServer, (struct sockaddr*)&loc_addr, &len); 546 547 Output::Instance()->Postf(BLACKBOARD_SDP, 548 "Incomming connection... %ld\n", client); 549 550 ssize_t receivedSize; 551 552 do { 553 receivedSize = recv(client, buffer, 29 , 0); 554 if (receivedSize < 0) 555 Output::Instance()->Post("Error reading client socket\n", 556 BLACKBOARD_SDP); 557 else { 558 Output::Instance()->Postf(BLACKBOARD_SDP, 559 "Received from SDP client: %ld:\n", receivedSize); 560 for (int i = 0; i < receivedSize ; i++) 561 Output::Instance()->Postf(BLACKBOARD_SDP, "%x:", buffer[i]); 562 563 Output::Instance()->Post("\n", BLACKBOARD_SDP); 564 } 565 } while (receivedSize >= 0); 566 567 snooze(5000000); 568 Output::Instance()->Post("\nWaiting for next connection...\n", 569 BLACKBOARD_SDP); 570 } 571 572 // Close the socket 573 close(socketServer); 574 575 return B_NO_ERROR; 576 } 577 578 579 void 580 BluetoothServer::ShowWindow(BWindow* pWindow) 581 { 582 pWindow->Lock(); 583 if (pWindow->IsHidden()) 584 pWindow->Show(); 585 else 586 pWindow->Activate(); 587 pWindow->Unlock(); 588 } 589 590 591 void 592 BluetoothServer::_InstallDeskbarIcon() 593 { 594 app_info appInfo; 595 be_app->GetAppInfo(&appInfo); 596 597 BDeskbar deskbar; 598 599 if (deskbar.HasItem(kDeskbarItemName)) { 600 _RemoveDeskbarIcon(); 601 } 602 603 status_t res = deskbar.AddItem(&appInfo.ref); 604 if (res != B_OK) { 605 printf("Failed adding deskbar icon: %" B_PRId32 "\n", res); 606 } 607 } 608 609 610 void 611 BluetoothServer::_RemoveDeskbarIcon() 612 { 613 BDeskbar deskbar; 614 status_t res = deskbar.RemoveItem(kDeskbarItemName); 615 if (res != B_OK) { 616 printf("Failed removing Deskbar icon: %" B_PRId32 ": \n", res); 617 } 618 } 619 620 621 #if 0 622 #pragma mark - 623 #endif 624 625 int 626 main(int /*argc*/, char** /*argv*/) 627 { 628 setbuf(stdout, NULL); 629 630 BluetoothServer* bluetoothServer = new BluetoothServer; 631 632 bluetoothServer->Run(); 633 delete bluetoothServer; 634 635 return 0; 636 } 637 638