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#include <Window.h>
20
21#include <TypeConstants.h>
22#include <syslog.h>
23
24#include <bluetoothserver_p.h>
25#include <bluetooth/HCI/btHCI_command.h>
26#include <bluetooth/L2CAP/btL2CAP.h>
27#include <bluetooth/bluetooth.h>
28
29#include "BluetoothServer.h"
30#include "DeskbarReplicant.h"
31#include "LocalDeviceImpl.h"
32#include "Debug.h"
33
34
35status_t
36DispatchEvent(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		TRACE_BT("BluetoothServer: Wrong type frame code\n");
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		TRACE_BT("BluetoothServer: LocalDevice could not be fetched\n");
50		return B_OK;
51	}
52
53	lDeviceImplementation->HandleEvent(header);
54
55	return B_OK;
56}
57
58
59BluetoothServer::BluetoothServer()
60	:
61	BApplication(BLUETOOTH_SIGNATURE),
62	fSDPThreadID(-1),
63	fIsShuttingDown(false)
64{
65	fDeviceManager = new DeviceManager();
66	fLocalDevicesList.MakeEmpty();
67
68	fEventListener2 = new BluetoothPortListener(BT_USERLAND_PORT_NAME,
69		(BluetoothPortListener::port_listener_func)&DispatchEvent);
70}
71
72
73bool BluetoothServer::QuitRequested(void)
74{
75	LocalDeviceImpl* lDeviceImpl = NULL;
76	while ((lDeviceImpl = (LocalDeviceImpl*)
77		fLocalDevicesList.RemoveItemAt(0)) != NULL)
78		delete lDeviceImpl;
79
80	_RemoveDeskbarIcon();
81
82	// stop the SDP server thread
83	fIsShuttingDown = true;
84
85	status_t threadReturnStatus;
86	wait_for_thread(fSDPThreadID, &threadReturnStatus);
87	TRACE_BT("BluetoothServer server thread exited with: %s\n",
88		strerror(threadReturnStatus));
89
90	delete fEventListener2;
91	TRACE_BT("Shutting down bluetooth_server.\n");
92
93	return BApplication::QuitRequested();
94}
95
96
97void BluetoothServer::ArgvReceived(int32 argc, char **argv)
98{
99	if (argc > 1) {
100		if (strcmp(argv[1], "--finish") == 0)
101			PostMessage(B_QUIT_REQUESTED);
102	}
103}
104
105
106void BluetoothServer::ReadyToRun(void)
107{
108	fDeviceManager->StartMonitoringDevice("bluetooth/h2");
109	fDeviceManager->StartMonitoringDevice("bluetooth/h3");
110	fDeviceManager->StartMonitoringDevice("bluetooth/h4");
111	fDeviceManager->StartMonitoringDevice("bluetooth/h5");
112
113	if (fEventListener2->Launch() != B_OK)
114		TRACE_BT("General: Bluetooth event listener failed\n");
115	else
116		TRACE_BT("General: Bluetooth event listener Ready\n");
117
118	_InstallDeskbarIcon();
119
120	// Spawn the SDP server thread
121	fSDPThreadID = spawn_thread(SDPServerThread, "SDP server thread",
122		B_NORMAL_PRIORITY, this);
123
124#define _USE_FAKE_SDP_SERVER
125#ifdef _USE_FAKE_SDP_SERVER
126	if (fSDPThreadID <= 0 || resume_thread(fSDPThreadID) != B_OK) {
127		TRACE_BT("BluetoothServer: Failed launching the SDP server thread\n");
128	}
129#endif
130}
131
132
133void BluetoothServer::AppActivated(bool act)
134{
135	printf("Activated %d\n",act);
136}
137
138
139void BluetoothServer::MessageReceived(BMessage* message)
140{
141	BMessage reply;
142	status_t status = B_WOULD_BLOCK; // mark somehow to do not reply anything
143
144	switch (message->what)
145	{
146		case BT_MSG_ADD_DEVICE:
147		{
148			BString str;
149			message->FindString("name", &str);
150
151			TRACE_BT("BluetoothServer: Requested LocalDevice %s\n", str.String());
152
153			BPath path(str.String());
154
155			LocalDeviceImpl* lDeviceImpl
156				= LocalDeviceImpl::CreateTransportAccessor(&path);
157
158			if (lDeviceImpl->GetID() >= 0) {
159				fLocalDevicesList.AddItem(lDeviceImpl);
160
161				TRACE_BT("LocalDevice %s id=%" B_PRId32 " added\n", str.String(),
162					lDeviceImpl->GetID());
163			} else {
164				TRACE_BT("BluetoothServer: Adding LocalDevice hci id invalid\n");
165			}
166
167			status = B_WOULD_BLOCK;
168			/* TODO: This should be by user request only! */
169			lDeviceImpl->Launch();
170			break;
171		}
172
173		case BT_MSG_REMOVE_DEVICE:
174		{
175			LocalDeviceImpl* lDeviceImpl = LocateDelegateFromMessage(message);
176			if (lDeviceImpl != NULL) {
177				fLocalDevicesList.RemoveItem(lDeviceImpl);
178				delete lDeviceImpl;
179			}
180			break;
181		}
182
183		case BT_MSG_COUNT_LOCAL_DEVICES:
184			status = HandleLocalDevicesCount(message, &reply);
185			break;
186
187		case BT_MSG_ACQUIRE_LOCAL_DEVICE:
188			status = HandleAcquireLocalDevice(message, &reply);
189			break;
190
191		case BT_MSG_HANDLE_SIMPLE_REQUEST:
192			status = HandleSimpleRequest(message, &reply);
193			break;
194
195		case BT_MSG_GET_PROPERTY:
196			status = HandleGetProperty(message, &reply);
197			break;
198
199		// Handle if the bluetooth preferences is running?
200		case B_SOME_APP_LAUNCHED:
201		{
202			const char* signature;
203
204			if (message->FindString("be:signature", &signature) == B_OK) {
205				printf("input_server : %s\n", signature);
206				if (strcmp(signature, "application/x-vnd.Be-TSKB") == 0) {
207
208				}
209			}
210			return;
211		}
212
213		default:
214			BApplication::MessageReceived(message);
215			break;
216	}
217
218	// Can we reply right now?
219	// TOD: review this condition
220	if (status != B_WOULD_BLOCK) {
221		reply.AddInt32("status", status);
222		message->SendReply(&reply);
223//		printf("Sending reply message for->\n");
224//		message->PrintToStream();
225	}
226}
227
228
229#if 0
230#pragma mark -
231#endif
232
233LocalDeviceImpl*
234BluetoothServer::LocateDelegateFromMessage(BMessage* message)
235{
236	LocalDeviceImpl* lDeviceImpl = NULL;
237	hci_id hid;
238
239	if (message->FindInt32("hci_id", &hid) == B_OK) {
240		// Try to find out when a ID was specified
241		int index;
242		for (index = 0; index < fLocalDevicesList.CountItems(); index ++) {
243			lDeviceImpl = fLocalDevicesList.ItemAt(index);
244			if (lDeviceImpl->GetID() == hid)
245				break;
246		}
247	}
248
249	return lDeviceImpl;
250
251}
252
253
254LocalDeviceImpl*
255BluetoothServer::LocateLocalDeviceImpl(hci_id hid)
256{
257	// Try to find out when a ID was specified
258	int index;
259
260	for (index = 0; index < fLocalDevicesList.CountItems(); index++) {
261		LocalDeviceImpl* lDeviceImpl = fLocalDevicesList.ItemAt(index);
262		if (lDeviceImpl->GetID() == hid)
263			return lDeviceImpl;
264	}
265
266	return NULL;
267}
268
269
270#if 0
271#pragma - Messages reply
272#endif
273
274status_t
275BluetoothServer::HandleLocalDevicesCount(BMessage* message, BMessage* reply)
276{
277	TRACE_BT("BluetoothServer: count requested\n");
278
279	return reply->AddInt32("count", fLocalDevicesList.CountItems());
280}
281
282
283status_t
284BluetoothServer::HandleAcquireLocalDevice(BMessage* message, BMessage* reply)
285{
286	hci_id hid;
287	ssize_t size;
288	bdaddr_t bdaddr;
289	LocalDeviceImpl* lDeviceImpl = NULL;
290	static int32 lastIndex = 0;
291
292	if (message->FindInt32("hci_id", &hid) == B_OK)	{
293		TRACE_BT("BluetoothServer: GetLocalDevice requested with id\n");
294		lDeviceImpl = LocateDelegateFromMessage(message);
295
296	} else if (message->FindData("bdaddr", B_ANY_TYPE,
297		(const void**)&bdaddr, &size) == B_OK) {
298
299		// Try to find out when the user specified the address
300		TRACE_BT("BluetoothServer: GetLocalDevice requested with bdaddr\n");
301		for (lastIndex = 0; lastIndex < fLocalDevicesList.CountItems();
302			lastIndex ++) {
303			// TODO: Only possible if the property is available
304			// bdaddr_t local;
305			// lDeviceImpl = fLocalDevicesList.ItemAt(lastIndex);
306			// if ((lDeviceImpl->GetAddress(&local, message) == B_OK)
307			// 	&& bacmp(&local, &bdaddr)) {
308			// 	break;
309			// }
310		}
311
312	} else {
313		// Careless, any device not performing operations will be fine
314		TRACE_BT("BluetoothServer: GetLocalDevice plain request\n");
315		// from last assigned till end
316		for (int index = lastIndex + 1;
317			index < fLocalDevicesList.CountItems();	index++) {
318			lDeviceImpl= fLocalDevicesList.ItemAt(index);
319			if (lDeviceImpl != NULL && lDeviceImpl->Available()) {
320				printf("Requested local device %" B_PRId32 "\n",
321					lDeviceImpl->GetID());
322				TRACE_BT("BluetoothServer: Device available: %" B_PRId32 "\n", lDeviceImpl->GetID());
323				lastIndex = index;
324				break;
325			}
326		}
327
328		// from starting till last assigned if not yet found
329		if (lDeviceImpl == NULL) {
330			for (int index = 0; index <= lastIndex ; index ++) {
331				lDeviceImpl = fLocalDevicesList.ItemAt(index);
332				if (lDeviceImpl != NULL && lDeviceImpl->Available()) {
333					printf("Requested local device %" B_PRId32 "\n",
334						lDeviceImpl->GetID());
335					TRACE_BT("BluetoothServer: Device available: %" B_PRId32 "\n", lDeviceImpl->GetID());
336					lastIndex = index;
337					break;
338				}
339			}
340		}
341	}
342
343	if (lastIndex <= fLocalDevicesList.CountItems() && lDeviceImpl != NULL
344		&& lDeviceImpl->Available()) {
345
346		hid = lDeviceImpl->GetID();
347		lDeviceImpl->Acquire();
348
349		TRACE_BT("BluetoothServer: Device acquired %" B_PRId32 "\n", hid);
350		return reply->AddInt32("hci_id", hid);
351	}
352
353	return B_ERROR;
354
355}
356
357
358status_t
359BluetoothServer::HandleSimpleRequest(BMessage* message, BMessage* reply)
360{
361	LocalDeviceImpl* lDeviceImpl = LocateDelegateFromMessage(message);
362	if (lDeviceImpl == NULL) {
363		return B_ERROR;
364	}
365
366	const char* propertyRequested;
367
368	// Find out if there is a property being requested,
369	if (message->FindString("property", &propertyRequested) == B_OK) {
370		// Check if the property has been already retrieved
371		if (lDeviceImpl->IsPropertyAvailable(propertyRequested)) {
372			// Dump everything
373			reply->AddMessage("properties", lDeviceImpl->GetPropertiesMessage());
374			return B_OK;
375		}
376	}
377
378	// we are gonna need issue the command ...
379	if (lDeviceImpl->ProcessSimpleRequest(DetachCurrentMessage()) == B_OK)
380		return B_WOULD_BLOCK;
381	else {
382		lDeviceImpl->Unregister();
383		return B_ERROR;
384	}
385
386}
387
388
389status_t
390BluetoothServer::HandleGetProperty(BMessage* message, BMessage* reply)
391{
392	// User side will look for the reply in a result field and will
393	// not care about status fields, therefore we return OK in all cases
394
395	LocalDeviceImpl* lDeviceImpl = LocateDelegateFromMessage(message);
396	if (lDeviceImpl == NULL) {
397		return B_ERROR;
398	}
399
400	const char* propertyRequested;
401
402	// Find out if there is a property being requested,
403	if (message->FindString("property", &propertyRequested) == B_OK) {
404
405		TRACE_BT("BluetoothServer: Searching %s property...\n", propertyRequested);
406
407		// Check if the property has been already retrieved
408		if (lDeviceImpl->IsPropertyAvailable(propertyRequested)) {
409
410			// 1 bytes requests
411			if (strcmp(propertyRequested, "hci_version") == 0
412				|| strcmp(propertyRequested, "lmp_version") == 0
413				|| strcmp(propertyRequested, "sco_mtu") == 0) {
414
415				uint8 result = lDeviceImpl->GetPropertiesMessage()->
416					FindInt8(propertyRequested);
417				reply->AddInt32("result", result);
418
419			// 2 bytes requests
420			} else if (strcmp(propertyRequested, "hci_revision") == 0
421					|| strcmp(propertyRequested, "lmp_subversion") == 0
422					|| strcmp(propertyRequested, "manufacturer") == 0
423					|| strcmp(propertyRequested, "acl_mtu") == 0
424					|| strcmp(propertyRequested, "acl_max_pkt") == 0
425					|| strcmp(propertyRequested, "sco_max_pkt") == 0
426					|| strcmp(propertyRequested, "packet_type") == 0 ) {
427
428				uint16 result = lDeviceImpl->GetPropertiesMessage()->
429					FindInt16(propertyRequested);
430				reply->AddInt32("result", result);
431
432			// 1 bit requests
433			} else if (strcmp(propertyRequested, "role_switch_capable") == 0
434					|| strcmp(propertyRequested, "encrypt_capable") == 0) {
435
436				bool result = lDeviceImpl->GetPropertiesMessage()->
437					FindBool(propertyRequested);
438
439				reply->AddInt32("result", result);
440
441
442
443			} else {
444				TRACE_BT("BluetoothServer: Property %s could not be satisfied\n", propertyRequested);
445			}
446		}
447	}
448
449	return B_OK;
450}
451
452
453#if 0
454#pragma mark -
455#endif
456
457int32
458BluetoothServer::SDPServerThread(void* data)
459{
460	const BluetoothServer* server = (BluetoothServer*)data;
461
462	// Set up the SDP socket
463	struct sockaddr_l2cap loc_addr = { 0 };
464	int socketServer;
465	int client;
466	status_t status;
467	char buffer[512] = "";
468
469	TRACE_BT("SDP: SDP server thread up...\n");
470
471	socketServer = socket(PF_BLUETOOTH, SOCK_STREAM, BLUETOOTH_PROTO_L2CAP);
472
473	if (socketServer < 0) {
474		TRACE_BT("SDP: Could not create server socket ...\n");
475		return B_ERROR;
476	}
477
478	// bind socket to port 0x1001 of the first available
479	// bluetooth adapter
480	loc_addr.l2cap_family = AF_BLUETOOTH;
481	loc_addr.l2cap_bdaddr = BDADDR_ANY;
482	loc_addr.l2cap_psm = B_HOST_TO_LENDIAN_INT16(1);
483	loc_addr.l2cap_len = sizeof(struct sockaddr_l2cap);
484
485	status = bind(socketServer, (struct sockaddr*)&loc_addr,
486		sizeof(struct sockaddr_l2cap));
487
488	if (status < 0) {
489		TRACE_BT("SDP: Could not bind server socket (%s)...\n", strerror(status));
490		return status;
491	}
492
493	// setsockopt(sock, SOL_L2CAP, SO_L2CAP_OMTU, &omtu, len );
494	// getsockopt(sock, SOL_L2CAP, SO_L2CAP_IMTU, &omtu, &len );
495
496	// Listen for up to 10 connections
497	status = listen(socketServer, 10);
498
499	if (status != B_OK) {
500		TRACE_BT("SDP: Could not listen server socket (%s)...\n", strerror(status));
501		return status;
502	}
503
504	while (!server->fIsShuttingDown) {
505
506		TRACE_BT("SDP: Waiting connection for socket (%s)...\n", strerror(status));
507
508		uint len = sizeof(struct sockaddr_l2cap);
509		client = accept(socketServer, (struct sockaddr*)&loc_addr, &len);
510
511		TRACE_BT("SDP: Incomming connection... %d\n", client);
512
513		ssize_t receivedSize;
514
515		do {
516			receivedSize = recv(client, buffer, 29 , 0);
517			if (receivedSize < 0)
518				TRACE_BT("SDP: Error reading client socket\n");
519			else {
520				TRACE_BT("SDP: Received from SDP client: %ld:\n", receivedSize);
521				for (int i = 0; i < receivedSize ; i++)
522					TRACE_BT("SDP: %x:", buffer[i]);
523
524				TRACE_BT("\n");
525			}
526		} while (receivedSize >= 0);
527
528		snooze(5000000);
529		TRACE_BT("SDP: Waiting for next connection...\n");
530	}
531
532	// Close the socket
533	close(socketServer);
534
535	return B_NO_ERROR;
536}
537
538
539void
540BluetoothServer::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
551void
552BluetoothServer::_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		TRACE_BT("Failed adding deskbar icon: %" B_PRId32 "\n", res);
566}
567
568
569void
570BluetoothServer::_RemoveDeskbarIcon()
571{
572	BDeskbar deskbar;
573	status_t res = deskbar.RemoveItem(kDeskbarItemName);
574	if (res != B_OK)
575		TRACE_BT("Failed removing Deskbar icon: %" B_PRId32 ": \n", res);
576}
577
578
579#if 0
580#pragma mark -
581#endif
582
583int
584main(int /*argc*/, char** /*argv*/)
585{
586	BluetoothServer* bluetoothServer = new BluetoothServer;
587
588	bluetoothServer->Run();
589	delete bluetoothServer;
590
591	return 0;
592}
593
594