xref: /haiku/src/servers/bluetooth/BluetoothServer.cpp (revision 4b7e219688450694efc9d1890f83f816758c16d3)
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