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