xref: /haiku/src/servers/bluetooth/BluetoothServer.cpp (revision 820dca4df6c7bf955c46e8f6521b9408f50b2900)
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 %ld\n", lDeviceImpl->GetID());
348 			if (lDeviceImpl != NULL && lDeviceImpl->Available()) {
349 				Output::Instance()->Postf(BLACKBOARD_KIT,
350 					"Device available: %lx\n", lDeviceImpl->GetID());
351 				lastIndex = index;
352 				break;
353 			}
354 		}
355 
356 		// from starting till last assigned if not yet found
357 		if (lDeviceImpl == NULL) {
358 			for (int index = 0; index <= lastIndex ; index ++) {
359 				lDeviceImpl = fLocalDevicesList.ItemAt(index);
360 				printf("Requesting local device %ld\n", lDeviceImpl->GetID());
361 				if (lDeviceImpl != NULL && lDeviceImpl->Available()) {
362 					Output::Instance()->Postf(BLACKBOARD_KIT,
363 						"Device available: %lx\n", lDeviceImpl->GetID());
364 					lastIndex = index;
365 					break;
366 				}
367 			}
368 		}
369 	}
370 
371 	if (lastIndex <= fLocalDevicesList.CountItems() && lDeviceImpl != NULL
372 		&& lDeviceImpl->Available()) {
373 
374 		hid = lDeviceImpl->GetID();
375 		lDeviceImpl->Acquire();
376 
377 		Output::Instance()->Postf(BLACKBOARD_KIT, "Device acquired %lx\n", hid);
378 		return reply->AddInt32("hci_id", hid);
379 	}
380 
381 	return B_ERROR;
382 
383 }
384 
385 
386 status_t
387 BluetoothServer::HandleSimpleRequest(BMessage* message, BMessage* reply)
388 {
389 	LocalDeviceImpl* lDeviceImpl = LocateDelegateFromMessage(message);
390 	if (lDeviceImpl == NULL) {
391 		return B_ERROR;
392 	}
393 
394 	const char* propertyRequested;
395 
396 	// Find out if there is a property being requested,
397 	if (message->FindString("property", &propertyRequested) == B_OK) {
398 		// Check if the property has been already retrieved
399 		if (lDeviceImpl->IsPropertyAvailable(propertyRequested)) {
400 			// Dump everything
401 			reply->AddMessage("properties", lDeviceImpl->GetPropertiesMessage());
402 			return B_OK;
403 		}
404 	}
405 
406 	// we are gonna need issue the command ...
407 	if (lDeviceImpl->ProcessSimpleRequest(DetachCurrentMessage()) == B_OK)
408 		return B_WOULD_BLOCK;
409 	else {
410 		lDeviceImpl->Unregister();
411 		return B_ERROR;
412 	}
413 
414 }
415 
416 
417 status_t
418 BluetoothServer::HandleGetProperty(BMessage* message, BMessage* reply)
419 {
420 	// User side will look for the reply in a result field and will
421 	// not care about status fields, therefore we return OK in all cases
422 
423 	LocalDeviceImpl* lDeviceImpl = LocateDelegateFromMessage(message);
424 	if (lDeviceImpl == NULL) {
425 		return B_ERROR;
426 	}
427 
428 	const char* propertyRequested;
429 
430 	// Find out if there is a property being requested,
431 	if (message->FindString("property", &propertyRequested) == B_OK) {
432 
433 		Output::Instance()->Postf(BLACKBOARD_LD(lDeviceImpl->GetID()),
434 			"Searching %s property...\n", propertyRequested);
435 
436 		// Check if the property has been already retrieved
437 		if (lDeviceImpl->IsPropertyAvailable(propertyRequested)) {
438 
439 			// 1 bytes requests
440 			if (strcmp(propertyRequested, "hci_version") == 0
441 				|| strcmp(propertyRequested, "lmp_version") == 0
442 				|| strcmp(propertyRequested, "sco_mtu") == 0) {
443 
444 				uint8 result = lDeviceImpl->GetPropertiesMessage()->
445 					FindInt8(propertyRequested);
446 				reply->AddInt32("result", result);
447 
448 			// 2 bytes requests
449 			} else if (strcmp(propertyRequested, "hci_revision") == 0
450 					|| strcmp(propertyRequested, "lmp_subversion") == 0
451 					|| strcmp(propertyRequested, "manufacturer") == 0
452 					|| strcmp(propertyRequested, "acl_mtu") == 0
453 					|| strcmp(propertyRequested, "acl_max_pkt") == 0
454 					|| strcmp(propertyRequested, "sco_max_pkt") == 0
455 					|| strcmp(propertyRequested, "packet_type") == 0 ) {
456 
457 				uint16 result = lDeviceImpl->GetPropertiesMessage()->
458 					FindInt16(propertyRequested);
459 				reply->AddInt32("result", result);
460 
461 			// 1 bit requests
462 			} else if (strcmp(propertyRequested, "role_switch_capable") == 0
463 					|| strcmp(propertyRequested, "encrypt_capable") == 0) {
464 
465 				bool result = lDeviceImpl->GetPropertiesMessage()->
466 					FindBool(propertyRequested);
467 
468 				reply->AddInt32("result", result);
469 
470 
471 
472 			} else {
473 				Output::Instance()->Postf(BLACKBOARD_LD(lDeviceImpl->GetID()),
474 					"Property %s could not be satisfied\n", propertyRequested);
475 			}
476 		}
477 	}
478 
479 	return B_OK;
480 }
481 
482 
483 #if 0
484 #pragma mark -
485 #endif
486 
487 int32
488 BluetoothServer::SDPServerThread(void* data)
489 {
490 	const BluetoothServer* server = (BluetoothServer*)data;
491 
492 	// Set up the SDP socket
493 	struct sockaddr_l2cap loc_addr = { 0 };
494 	int socketServer;
495 	int client;
496 	status_t status;
497 	char buffer[512] = "";
498 
499 	Output::Instance()->Postf(BLACKBOARD_SDP, "SDP server thread up...\n");
500 
501 	socketServer = socket(PF_BLUETOOTH, SOCK_STREAM, BLUETOOTH_PROTO_L2CAP);
502 
503 	if (socketServer < 0) {
504 		Output::Instance()->Post("Could not create server socket ...\n",
505 			BLACKBOARD_SDP);
506 		return B_ERROR;
507 	}
508 
509 	// bind socket to port 0x1001 of the first available
510 	// bluetooth adapter
511 	loc_addr.l2cap_family = AF_BLUETOOTH;
512 	loc_addr.l2cap_bdaddr = BDADDR_ANY;
513 	loc_addr.l2cap_psm = B_HOST_TO_LENDIAN_INT16(1);
514 	loc_addr.l2cap_len = sizeof(struct sockaddr_l2cap);
515 
516 	status = bind(socketServer, (struct sockaddr*)&loc_addr,
517 		sizeof(struct sockaddr_l2cap));
518 
519 	if (status < 0) {
520 		Output::Instance()->Postf(BLACKBOARD_SDP,
521 			"Could not bind server socket %d ...\n", status);
522 		return status;
523 	}
524 
525 	// setsockopt(sock, SOL_L2CAP, SO_L2CAP_OMTU, &omtu, len );
526 	// getsockopt(sock, SOL_L2CAP, SO_L2CAP_IMTU, &omtu, &len );
527 
528 	// Listen for up to 10 connections
529 	status = listen(socketServer, 10);
530 
531 	if (status != B_OK) {
532 		Output::Instance()->Postf(BLACKBOARD_SDP,
533 			"Could not listen server socket %d ...\n", status);
534 		return status;
535 	}
536 
537 	while (!server->fIsShuttingDown) {
538 
539 		Output::Instance()->Postf(BLACKBOARD_SDP,
540 			"Waiting connection for socket %d ...\n", socketServer);
541 
542 		uint len = sizeof(struct sockaddr_l2cap);
543 		client = accept(socketServer, (struct sockaddr*)&loc_addr, &len);
544 
545 		Output::Instance()->Postf(BLACKBOARD_SDP,
546 			"Incomming connection... %ld\n", client);
547 
548 		ssize_t receivedSize;
549 
550 		do {
551 			receivedSize = recv(client, buffer, 29 , 0);
552 			if (receivedSize < 0)
553 				Output::Instance()->Post("Error reading client socket\n",
554 					BLACKBOARD_SDP);
555 			else {
556 				Output::Instance()->Postf(BLACKBOARD_SDP,
557 					"Received from SDP client: %ld:\n", receivedSize);
558 				for (int i = 0; i < receivedSize ; i++)
559 					Output::Instance()->Postf(BLACKBOARD_SDP, "%x:", buffer[i]);
560 
561 				Output::Instance()->Post("\n", BLACKBOARD_SDP);
562 			}
563 		} while (receivedSize >= 0);
564 
565 		snooze(5000000);
566 		Output::Instance()->Post("\nWaiting for next connection...\n",
567 			BLACKBOARD_SDP);
568 	}
569 
570 	// Close the socket
571 	close(socketServer);
572 
573 	return B_NO_ERROR;
574 }
575 
576 
577 void
578 BluetoothServer::ShowWindow(BWindow* pWindow)
579 {
580 	pWindow->Lock();
581 	if (pWindow->IsHidden())
582 		pWindow->Show();
583 	else
584 		pWindow->Activate();
585 	pWindow->Unlock();
586 }
587 
588 
589 void
590 BluetoothServer::_InstallDeskbarIcon()
591 {
592 	app_info appInfo;
593 	be_app->GetAppInfo(&appInfo);
594 
595 	BDeskbar deskbar;
596 
597 	if (deskbar.HasItem(kDeskbarItemName)) {
598 		_RemoveDeskbarIcon();
599 	}
600 
601 	status_t res = deskbar.AddItem(&appInfo.ref);
602 	if (res != B_OK) {
603 		printf("Failed adding deskbar icon: %ld\n", res);
604 	}
605 }
606 
607 
608 void
609 BluetoothServer::_RemoveDeskbarIcon()
610 {
611 	BDeskbar deskbar;
612 	status_t res = deskbar.RemoveItem(kDeskbarItemName);
613 	if (res != B_OK) {
614 		printf("Failed removing Deskbar icon: %ld: \n", res);
615 	}
616 }
617 
618 
619 #if 0
620 #pragma mark -
621 #endif
622 
623 int
624 main(int /*argc*/, char** /*argv*/)
625 {
626 	setbuf(stdout, NULL);
627 
628 	BluetoothServer* bluetoothServer = new BluetoothServer;
629 
630 	bluetoothServer->Run();
631 	delete bluetoothServer;
632 
633 	return 0;
634 }
635 
636