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