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