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