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