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