Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : */
9 : #include "BluetoothServer.hxx"
10 : #include <stdio.h>
11 :
12 : #include <sal/log.hxx>
13 :
14 : #if (defined(LINUX) && !defined(__FreeBSD_kernel__)) && defined(ENABLE_DBUS)
15 : #include <glib.h>
16 : #include <dbus/dbus-glib.h>
17 : #include <errno.h>
18 : #include <sys/unistd.h>
19 : #include <sys/socket.h>
20 : #include <bluetooth/bluetooth.h>
21 : #include <bluetooth/rfcomm.h>
22 : #define DBUS_TYPE_G_STRING_ANY_HASHTABLE (dbus_g_type_get_map( "GHashTable", G_TYPE_STRING, G_TYPE_VALUE ))
23 : #ifndef G_VALUE_INIT
24 : #define G_VALUE_INIT {0,{{0}}} // G_VALUE_INIT only present in glib >= 2.30
25 : #endif
26 : #ifndef DBusGObjectPath
27 : #define DBusGObjectPath char // DBusGObjectPath is only present in newer version of dbus-glib
28 : #endif
29 : #endif
30 :
31 : #ifdef WIN32
32 : // LO vs WinAPI conflict
33 : #undef WB_LEFT
34 : #undef WB_RIGHT
35 :
36 : #include <winsock2.h>
37 : #include <ws2bth.h>
38 : #endif
39 :
40 : #ifdef __MINGW32__
41 : // Value taken from http://msdn.microsoft.com/en-us/library/windows/desktop/ms738518%28v=vs.85%29.aspx
42 : #define NS_BTH 16
43 : #endif
44 :
45 : // FIXME: move this into an external file and look at sharing definitions
46 : // across OS's (i.e. UUID and port ).
47 : // Also look at determining which ports are available.
48 : // Alternatively use the binary sdp record
49 : #define BLUETOOTH_SERVICE_RECORD "<?xml version='1.0' encoding= 'UTF-8' ?><record><attribute id='0x0001'><sequence><uuid value='0x1101' /></sequence></attribute><attribute id='0x0004'><sequence><sequence><uuid value='0x0100' /></sequence><sequence><uuid value='0x0003' /><uint8 value='0x05' /></sequence></sequence></attribute><attribute id='0x0005'><sequence><uuid value='0x1002' /></sequence></attribute><attribute id='0x0006'><sequence><uint16 value='0x656e' /><uint16 value='0x006a' /><uint16 value='0x0100' /></sequence></attribute><attribute id='0x0009'><sequence><sequence><uuid value='0x1101' /><uint16 value='0x0100' /></sequence></sequence></attribute><attribute id='0x0100'><text value='Serial Port' /></attribute><attribute id='0x0101'><text value='COM Port' /></attribute></record>"
50 :
51 : #include "Communicator.hxx"
52 :
53 : using namespace sd;
54 :
55 : #if (defined(LINUX) && !defined(__FreeBSD_kernel__)) && defined(ENABLE_DBUS)
56 0 : DBusGProxy* bluezGetDefaultAdapter( DBusGConnection* aConnection,
57 : const gchar* aInterfaceType = "org.bluez.Adapter" )
58 : {
59 0 : GError *aError = NULL;
60 :
61 0 : DBusGProxy *aManager = NULL;
62 : aManager = dbus_g_proxy_new_for_name( aConnection, "org.bluez", "/",
63 0 : "org.bluez.Manager" );
64 :
65 0 : if ( aManager == NULL )
66 : {
67 : SAL_WARN( "sdremote.bluetooth", "getting org.bluez.Manager failed" );
68 0 : dbus_g_connection_unref( aConnection );
69 0 : return NULL;
70 : }
71 :
72 : gboolean aResult;
73 0 : DBusGObjectPath* aAdapterPath = NULL;
74 : aResult = dbus_g_proxy_call( aManager, "DefaultAdapter", &aError,
75 : G_TYPE_INVALID,
76 : DBUS_TYPE_G_OBJECT_PATH, &aAdapterPath,
77 0 : G_TYPE_INVALID);
78 :
79 0 : g_object_unref( G_OBJECT( aManager ));
80 0 : if ( !aResult || aError )
81 : {
82 : SAL_WARN( "sdremote.bluetooth", "getting DefaultAdapter path failed" );
83 0 : if ( aError )
84 0 : g_error_free( aError );
85 0 : return NULL;
86 : }
87 :
88 0 : DBusGProxy *aAdapter = NULL;
89 : aAdapter = dbus_g_proxy_new_for_name( aConnection, "org.bluez",
90 0 : aAdapterPath, aInterfaceType );
91 0 : g_free( aAdapterPath );
92 :
93 : SAL_INFO( "sdremote.bluetooth", "DefaultAdapter retrieved" );
94 0 : return aAdapter;
95 : }
96 : #endif // defined(LINUX) && defined(ENABLE_DBUS)
97 :
98 0 : BluetoothServer::BluetoothServer( std::vector<Communicator*>* pCommunicators )
99 0 : : mpCommunicators( pCommunicators )
100 : {
101 0 : }
102 :
103 0 : BluetoothServer::~BluetoothServer()
104 : {
105 0 : }
106 :
107 0 : bool BluetoothServer::isDiscoverable()
108 : {
109 : #if (defined(LINUX) && !defined(__FreeBSD_kernel__)) && defined(ENABLE_DBUS)
110 : SAL_INFO( "sdremote.bluetooth", "BluetoothServer::isDiscoverable called" );
111 0 : g_type_init();
112 : gboolean aResult;
113 :
114 0 : GError *aError = NULL;
115 :
116 0 : DBusGConnection *aConnection = NULL;
117 0 : aConnection = dbus_g_bus_get( DBUS_BUS_SYSTEM, &aError );
118 :
119 0 : if ( aError != NULL ) {
120 0 : g_error_free (aError);
121 0 : return false;
122 : }
123 :
124 0 : DBusGProxy* aAdapter = bluezGetDefaultAdapter( aConnection );
125 0 : if ( aAdapter == NULL )
126 : {
127 0 : dbus_g_connection_unref( aConnection );
128 0 : return false;
129 : }
130 :
131 : GHashTable* aProperties;
132 : aResult = dbus_g_proxy_call( aAdapter, "GetProperties", &aError,
133 : G_TYPE_INVALID,
134 : DBUS_TYPE_G_STRING_ANY_HASHTABLE, &aProperties,
135 0 : G_TYPE_INVALID);
136 0 : g_object_unref( G_OBJECT( aAdapter ));
137 0 : dbus_g_connection_unref( aConnection );
138 0 : if ( !aResult || aError )
139 : {
140 0 : if ( aError )
141 0 : g_error_free( aError );
142 0 : return false;
143 : }
144 :
145 : gboolean aIsDiscoverable = g_value_get_boolean( (GValue*) g_hash_table_lookup(
146 0 : aProperties, "Discoverable" ) );
147 :
148 0 : g_free( aProperties );
149 0 : return aIsDiscoverable;
150 : #else // defined(LINUX) && defined(ENABLE_DBUS)
151 : return false;
152 : #endif
153 : }
154 :
155 0 : void BluetoothServer::setDiscoverable( bool aDiscoverable )
156 : {
157 : #if (defined(LINUX) && !defined(__FreeBSD_kernel__)) && defined(ENABLE_DBUS)
158 : SAL_INFO( "sdremote.bluetooth", "BluetoothServer::setDiscoverable called" );
159 0 : g_type_init();
160 : gboolean aResult;
161 :
162 0 : GError *aError = NULL;
163 :
164 0 : DBusGConnection *aConnection = NULL;
165 0 : aConnection = dbus_g_bus_get( DBUS_BUS_SYSTEM, &aError );
166 :
167 0 : if ( aError != NULL )
168 : {
169 0 : g_error_free (aError);
170 : return;
171 : }
172 :
173 0 : DBusGProxy* aAdapter = bluezGetDefaultAdapter( aConnection );
174 0 : if ( aAdapter == NULL )
175 : {
176 0 : dbus_g_connection_unref( aConnection );
177 : return;
178 : }
179 :
180 : GHashTable* aProperties;
181 : aResult = dbus_g_proxy_call( aAdapter, "GetProperties", &aError,
182 : G_TYPE_INVALID,
183 : DBUS_TYPE_G_STRING_ANY_HASHTABLE, &aProperties,
184 0 : G_TYPE_INVALID);
185 :
186 0 : if ( !aResult || aError )
187 : {
188 : SAL_WARN( "sdremote.bluetooth", "GetProperties failed" );
189 0 : if ( aError )
190 : {
191 0 : g_error_free( aError );
192 : SAL_WARN( "sdremote.bluetooth", "with error " << aError->message );
193 : }
194 : return;
195 : }
196 :
197 : gboolean aPowered = g_value_get_boolean( (GValue*) g_hash_table_lookup(
198 0 : aProperties, "Powered" ) );
199 :
200 0 : g_free( aProperties );
201 0 : if ( !aPowered )
202 : {
203 : SAL_INFO( "sdremote.bluetooth", "Bluetooth adapter not powered, returning" );
204 0 : g_object_unref( G_OBJECT( aAdapter ));
205 : return;
206 : }
207 :
208 0 : GValue aTimeout = G_VALUE_INIT;
209 0 : g_value_init( &aTimeout, G_TYPE_UINT );
210 0 : g_value_set_uint( &aTimeout, 0 );
211 : aResult = dbus_g_proxy_call( aAdapter, "SetProperty", &aError,
212 : G_TYPE_STRING, "DiscoverableTimeout",
213 0 : G_TYPE_VALUE, &aTimeout, G_TYPE_INVALID, G_TYPE_INVALID);
214 0 : if ( !aResult || aError )
215 : {
216 : SAL_WARN( "sdremote.bluetooth", "SetProperty(DiscoverableTimeout) failed" );
217 0 : if ( aError )
218 : {
219 0 : g_error_free( aError );
220 : SAL_WARN( "sdremote.bluetooth", "with error " << aError->message );
221 : }
222 : return;
223 : }
224 :
225 0 : GValue aDiscoverableGValue = G_VALUE_INIT;
226 0 : g_value_init( &aDiscoverableGValue, G_TYPE_BOOLEAN );
227 0 : g_value_set_boolean( &aDiscoverableGValue, aDiscoverable );
228 : aResult = dbus_g_proxy_call( aAdapter, "SetProperty", &aError,
229 : G_TYPE_STRING, "Discoverable",
230 0 : G_TYPE_VALUE, &aDiscoverableGValue, G_TYPE_INVALID, G_TYPE_INVALID);
231 0 : if ( !aResult || aError )
232 : {
233 : SAL_WARN( "sdremote.bluetooth", "SetProperty(Discoverable) failed" );
234 0 : if ( aError )
235 : {
236 0 : g_error_free( aError );
237 : SAL_WARN( "sdremote.bluetooth", "with error " << aError->message );
238 : }
239 : return;
240 : }
241 :
242 0 : g_object_unref( G_OBJECT( aAdapter ));
243 0 : dbus_g_connection_unref( aConnection );
244 : #else // defined(LINUX) && defined(ENABLE_DBUS)
245 : (void) aDiscoverable; // avoid warnings
246 : return;
247 : #endif
248 : }
249 :
250 0 : void SAL_CALL BluetoothServer::run()
251 : {
252 : SAL_INFO( "sdremote.bluetooth", "BluetoothServer::run called" );
253 : #if (defined(LINUX) && !defined(__FreeBSD_kernel__)) && defined(ENABLE_DBUS)
254 0 : g_type_init();
255 :
256 0 : GError *aError = NULL;
257 :
258 0 : DBusGConnection *aConnection = NULL;
259 0 : aConnection = dbus_g_bus_get( DBUS_BUS_SYSTEM, &aError );
260 :
261 0 : if ( aError != NULL ) {
262 : SAL_WARN( "sdremote.bluetooth", "failed to get dbus system bus" );
263 0 : g_error_free (aError);
264 : return;
265 : }
266 :
267 0 : DBusGProxy* aAdapter = bluezGetDefaultAdapter( aConnection, "org.bluez.Service" );
268 0 : if ( aAdapter == NULL )
269 : {
270 : SAL_WARN( "sdremote.bluetooth", "failed to retrieve default adapter" );
271 0 : dbus_g_connection_unref( aConnection );
272 : return;
273 : }
274 :
275 : // Add the record -- the handle can be used to release it again, but we
276 : // don't bother as the record is automatically released when LO exits.
277 : guint aHandle;
278 : gboolean aResult = dbus_g_proxy_call( aAdapter, "AddRecord", &aError,
279 : G_TYPE_STRING, BLUETOOTH_SERVICE_RECORD ,
280 : G_TYPE_INVALID,
281 : G_TYPE_UINT, &aHandle,
282 0 : G_TYPE_INVALID);
283 :
284 0 : g_object_unref( G_OBJECT( aAdapter ));
285 0 : dbus_g_connection_unref( aConnection );
286 0 : if ( !aResult)
287 : {
288 : SAL_WARN( "sdremote.bluetooth", "SDP registration failed" );
289 : return;
290 : }
291 :
292 : // ---------------- Socket code
293 : int aSocket;
294 0 : if ( (aSocket = socket( AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM )) < 0 )
295 : {
296 : SAL_WARN( "sdremote.bluetooth", "failed to open bluetooth socket with error " << aSocket );
297 : return;
298 : }
299 :
300 : sockaddr_rc aAddr;
301 0 : aAddr.rc_family = AF_BLUETOOTH;
302 : // BDADDR_ANY is broken, so use memset to set to 0.
303 0 : memset( &aAddr.rc_bdaddr, 0, sizeof( aAddr.rc_bdaddr ) );
304 0 : aAddr.rc_channel = 5;
305 :
306 : int a;
307 0 : if ( ( a = bind( aSocket, (sockaddr*) &aAddr, sizeof(aAddr) ) ) < 0 ) {
308 : SAL_WARN( "sdremote.bluetooth", "bind failed with error" << a );
309 0 : close( aSocket );
310 : return;
311 : }
312 :
313 0 : if ( ( a = listen( aSocket, 1 ) ) < 0 )
314 : {
315 : SAL_WARN( "sdremote.bluetooth", "listen failed with error" << a );
316 0 : close( aSocket );
317 : return;
318 : }
319 :
320 : sockaddr_rc aRemoteAddr;
321 0 : socklen_t aRemoteAddrLen = sizeof(aRemoteAddr);
322 0 : while ( true )
323 : {
324 : int bSocket;
325 : SAL_INFO( "sdremote.bluetooth", "waiting on accept" );
326 0 : if ( (bSocket = accept(aSocket, (sockaddr*) &aRemoteAddr, &aRemoteAddrLen)) < 0 )
327 : {
328 0 : int err = errno;
329 : SAL_WARN( "sdremote.bluetooth", "accept failed with errno " << err );
330 0 : close( aSocket );
331 : return;
332 : } else {
333 : SAL_INFO( "sdremote.bluetooth", "connection accepted" );
334 0 : Communicator* pCommunicator = new Communicator( new BufferedStreamSocket( bSocket ) );
335 0 : mpCommunicators->push_back( pCommunicator );
336 0 : pCommunicator->launch();
337 : }
338 : }
339 :
340 : // LINUX && ENABLE_DBUS
341 : #elif defined(WIN32)
342 : WORD wVersionRequested;
343 : WSADATA wsaData;
344 :
345 : wVersionRequested = MAKEWORD(2, 2);
346 :
347 : if ( WSAStartup(wVersionRequested, &wsaData) )
348 : {
349 : return; // winsock dll couldn't be loaded
350 : }
351 :
352 : int aSocket = socket( AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM );
353 : if ( !aSocket )
354 : {
355 : WSACleanup();
356 : return;
357 : }
358 : SOCKADDR_BTH aAddr;
359 : aAddr.addressFamily = AF_BTH;
360 : aAddr.btAddr = 0;
361 : aAddr.serviceClassId = GUID_NULL;
362 : aAddr.port = BT_PORT_ANY; // Select any free socket.
363 : if ( bind( aSocket, (SOCKADDR*) &aAddr, sizeof(aAddr) ) == SOCKET_ERROR )
364 : {
365 : closesocket( aSocket );
366 : WSACleanup();
367 : return;
368 : }
369 :
370 : SOCKADDR aName;
371 : int aNameSize = sizeof(aAddr);
372 : getsockname( aSocket, &aName, &aNameSize ); // Retrieve the local address and port
373 :
374 : CSADDR_INFO aAddrInfo;
375 : memset( &aAddrInfo, 0, sizeof(aAddrInfo) );
376 : aAddrInfo.LocalAddr.lpSockaddr = &aName;
377 : aAddrInfo.LocalAddr.iSockaddrLength = sizeof( SOCKADDR_BTH );
378 : aAddrInfo.RemoteAddr.lpSockaddr = &aName;
379 : aAddrInfo.RemoteAddr.iSockaddrLength = sizeof( SOCKADDR_BTH );
380 : aAddrInfo.iSocketType = SOCK_STREAM;
381 : aAddrInfo.iProtocol = BTHPROTO_RFCOMM;
382 :
383 : // To be used for setting a custom UUID once available.
384 : // GUID uuid;
385 : // uuid.Data1 = 0x00001101;
386 : // memset( &uuid, 0x1000 + UUID*2^96, sizeof( GUID ) );
387 : // uuid.Data2 = 0;
388 : // uuid.Data3 = 0x1000;
389 : // ULONGLONG aData4 = 0x800000805F9B34FB;
390 : // memcpy( uuid.Data4, &aData4, sizeof(uuid.Data4) );
391 :
392 : WSAQUERYSET aRecord;
393 : memset( &aRecord, 0, sizeof(aRecord));
394 : aRecord.dwSize = sizeof(aRecord);
395 : aRecord.lpszServiceInstanceName = "LibreOffice-SDRemote"; // Optional
396 : aRecord.lpszComment = "Remote control of presentations over bluetooth.";
397 : aRecord.lpServiceClassId = (LPGUID) &SerialPortServiceClass_UUID;
398 : aRecord.dwNameSpace = NS_BTH;
399 : aRecord.dwNumberOfCsAddrs = 1;
400 : aRecord.lpcsaBuffer = &aAddrInfo;
401 :
402 : if ( WSASetService( &aRecord, RNRSERVICE_REGISTER, 0 ) == SOCKET_ERROR )
403 : {
404 : closesocket( aSocket );
405 : WSACleanup();
406 : return;
407 : }
408 :
409 : if ( listen( aSocket, 1 ) == SOCKET_ERROR )
410 : {
411 : closesocket( aSocket );
412 : WSACleanup();
413 : return;
414 : }
415 :
416 : SOCKADDR_BTH aRemoteAddr;
417 : int aRemoteAddrLen = sizeof(aRemoteAddr);
418 : while ( true )
419 : {
420 : SOCKET socket;
421 : if ( (socket = accept(aSocket, (sockaddr*) &aRemoteAddr, &aRemoteAddrLen)) == INVALID_SOCKET )
422 : {
423 : closesocket( aSocket );
424 : WSACleanup();
425 : return;
426 : } else {
427 : Communicator* pCommunicator = new Communicator( new BufferedStreamSocket( socket) );
428 : mpCommunicators->push_back( pCommunicator );
429 : pCommunicator->launch();
430 : }
431 : }
432 :
433 : // WIN32
434 : #else // !((defined(LINUX) && !defined(__FreeBSD_kernel__)) && defined(ENABLE_DBUS)) && !defined(WIN32)
435 : (void) mpCommunicators; // avoid warnings about unused member
436 : #endif
437 : }
438 :
439 :
440 : BluetoothServer *sd::BluetoothServer::spServer = NULL;
441 :
442 0 : void BluetoothServer::setup( std::vector<Communicator*>* pCommunicators )
443 : {
444 0 : if (spServer)
445 0 : return;
446 :
447 0 : spServer = new BluetoothServer( pCommunicators );
448 0 : spServer->create();
449 : }
450 :
451 :
452 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|