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 :
10 : #include "BluetoothServer.hxx"
11 :
12 : #include <iostream>
13 : #include <iomanip>
14 :
15 : #include <sal/log.hxx>
16 :
17 : #ifdef LINUX_BLUETOOTH
18 : #include <glib.h>
19 : #include <dbus/dbus.h>
20 : #include <errno.h>
21 : #include <fcntl.h>
22 : #include <sys/unistd.h>
23 : #include <sys/socket.h>
24 : #include <bluetooth/bluetooth.h>
25 : #include <bluetooth/rfcomm.h>
26 : #include "BluetoothServiceRecord.hxx"
27 : #include "BufferedStreamSocket.hxx"
28 : #endif
29 :
30 : #ifdef WIN32
31 : // LO vs WinAPI conflict
32 : #undef WB_LEFT
33 : #undef WB_RIGHT
34 : #include <winsock2.h>
35 : #include <ws2bth.h>
36 : #include "BufferedStreamSocket.hxx"
37 : #endif
38 :
39 : #ifdef MACOSX
40 : #include <osl/conditn.hxx> // Include this early to avoid error as check() gets defined by some SDK header to empty
41 : #include <premac.h>
42 : #if MACOSX_SDK_VERSION >= 1070
43 : #import <IOBluetooth/IOBluetooth.h>
44 : #else
45 : #import <CoreFoundation/CoreFoundation.h>
46 : #import <IOBluetooth/IOBluetoothUtilities.h>
47 : #import <IOBluetooth/objc/IOBluetoothSDPUUID.h>
48 : #import <IOBluetooth/objc/IOBluetoothSDPServiceRecord.h>
49 : #endif
50 : #include <postmac.h>
51 : #import "OSXBluetooth.h"
52 : #include "OSXBluetoothWrapper.hxx"
53 : #endif
54 :
55 : #ifdef __MINGW32__
56 : // Value taken from http://msdn.microsoft.com/en-us/library/windows/desktop/ms738518%28v=vs.85%29.aspx
57 : #define NS_BTH 16
58 : #endif
59 :
60 : #include "Communicator.hxx"
61 :
62 : using namespace sd;
63 :
64 : #ifdef LINUX_BLUETOOTH
65 :
66 11 : struct DBusObject {
67 : OString maBusName;
68 : OString maPath;
69 : OString maInterface;
70 :
71 0 : DBusObject() { }
72 11 : DBusObject( const char *pBusName, const char *pPath, const char *pInterface )
73 11 : : maBusName( pBusName ), maPath( pPath ), maInterface( pInterface ) { }
74 :
75 11 : DBusMessage *getMethodCall( const char *pName )
76 : {
77 : return dbus_message_new_method_call( maBusName.getStr(), maPath.getStr(),
78 11 : maInterface.getStr(), pName );
79 : }
80 0 : DBusObject *cloneForInterface( const char *pInterface )
81 : {
82 0 : DBusObject *pObject = new DBusObject();
83 :
84 0 : pObject->maBusName = maBusName;
85 0 : pObject->maPath = maPath;
86 0 : pObject->maInterface = pInterface;
87 :
88 0 : return pObject;
89 : }
90 : };
91 :
92 : struct sd::BluetoothServer::Impl {
93 : // the glib mainloop running in the thread
94 : GMainContext *mpContext;
95 : DBusConnection *mpConnection;
96 : DBusObject *mpService;
97 : volatile bool mbExitMainloop;
98 :
99 11 : Impl()
100 11 : : mpContext( g_main_context_new() )
101 : , mpConnection( NULL )
102 : , mpService( NULL )
103 11 : , mbExitMainloop( false )
104 11 : { }
105 :
106 0 : DBusObject *getAdapter()
107 : {
108 0 : if( !mpService )
109 0 : return NULL;
110 0 : return mpService->cloneForInterface( "org.bluez.Adapter" );
111 : }
112 : };
113 :
114 : static DBusConnection *
115 11 : dbusConnectToNameOnBus()
116 : {
117 : DBusError aError;
118 : DBusConnection *pConnection;
119 :
120 11 : dbus_error_init( &aError );
121 :
122 11 : pConnection = dbus_bus_get( DBUS_BUS_SYSTEM, &aError );
123 11 : if( !pConnection || dbus_error_is_set( &aError ))
124 : {
125 : SAL_WARN( "sdremote.bluetooth", "failed to get dbus system bus: " << aError.message );
126 0 : dbus_error_free( &aError );
127 0 : return NULL;
128 : }
129 :
130 11 : return pConnection;
131 : }
132 :
133 : static DBusMessage *
134 11 : sendUnrefAndWaitForReply( DBusConnection *pConnection, DBusMessage *pMsg )
135 : {
136 11 : DBusPendingCall *pPending = NULL;
137 :
138 22 : if( !pMsg || !dbus_connection_send_with_reply( pConnection, pMsg, &pPending,
139 11 : -1 /* default timeout */ ) )
140 : {
141 : SAL_WARN( "sdremote.bluetooth", "Memory allocation failed on message send" );
142 0 : dbus_message_unref( pMsg );
143 0 : return NULL;
144 : }
145 11 : dbus_connection_flush( pConnection );
146 11 : dbus_message_unref( pMsg );
147 :
148 11 : dbus_pending_call_block( pPending ); // block for reply
149 :
150 11 : pMsg = dbus_pending_call_steal_reply( pPending );
151 11 : if( !pMsg )
152 : SAL_WARN( "sdremote.bluetooth", "no valid reply / timeout" );
153 :
154 11 : dbus_pending_call_unref( pPending );
155 11 : return pMsg;
156 : }
157 :
158 : static DBusObject *
159 11 : bluezGetDefaultService( DBusConnection *pConnection )
160 : {
161 : DBusMessage *pMsg;
162 : DBusMessageIter it;
163 11 : const gchar* pInterfaceType = "org.bluez.Service";
164 :
165 11 : pMsg = DBusObject( "org.bluez", "/", "org.bluez.Manager" ).getMethodCall( "DefaultAdapter" );
166 11 : pMsg = sendUnrefAndWaitForReply( pConnection, pMsg );
167 :
168 11 : if(!pMsg || !dbus_message_iter_init( pMsg, &it ) )
169 0 : return NULL;
170 :
171 11 : if( DBUS_TYPE_OBJECT_PATH != dbus_message_iter_get_arg_type( &it ) )
172 : SAL_WARN( "sdremote.bluetooth", "invalid type of reply to DefaultAdapter: '"
173 : << dbus_message_iter_get_arg_type( &it ) << "'" );
174 : else
175 : {
176 0 : const char *pObjectPath = NULL;
177 0 : dbus_message_iter_get_basic( &it, &pObjectPath );
178 : SAL_INFO( "sdremote.bluetooth", "DefaultAdapter retrieved: '"
179 : << pObjectPath << "' '" << pInterfaceType << "'" );
180 0 : return new DBusObject( "org.bluez", pObjectPath, pInterfaceType );
181 : }
182 11 : dbus_message_unref( pMsg );
183 :
184 11 : return NULL;
185 : }
186 :
187 : static bool
188 0 : bluezRegisterServiceRecord( DBusConnection *pConnection, DBusObject *pAdapter,
189 : const char *pServiceRecord )
190 : {
191 : DBusMessage *pMsg;
192 : DBusMessageIter it;
193 :
194 0 : pMsg = pAdapter->getMethodCall( "AddRecord" );
195 0 : dbus_message_iter_init_append( pMsg, &it );
196 0 : dbus_message_iter_append_basic( &it, DBUS_TYPE_STRING, &pServiceRecord );
197 :
198 0 : pMsg = sendUnrefAndWaitForReply( pConnection, pMsg );
199 :
200 0 : if( !pMsg || !dbus_message_iter_init( pMsg, &it ) ||
201 0 : dbus_message_iter_get_arg_type( &it ) != DBUS_TYPE_UINT32 )
202 : {
203 : SAL_WARN( "sdremote.bluetooth", "SDP registration failed" );
204 0 : return false;
205 : }
206 :
207 : // We ignore the uint de-registration handle we get back:
208 : // bluez will clean us up automatically on exit
209 :
210 0 : return true;
211 : }
212 :
213 : static void
214 0 : bluezCreateAttachListeningSocket( GMainContext *pContext, GPollFD *pSocketFD )
215 : {
216 : int nSocket;
217 :
218 0 : pSocketFD->fd = -1;
219 :
220 0 : if( ( nSocket = socket( AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM ) ) < 0 )
221 : {
222 : SAL_WARN( "sdremote.bluetooth", "failed to open bluetooth socket with error " << nSocket );
223 0 : return;
224 : }
225 :
226 : sockaddr_rc aAddr;
227 : // Initialize whole structure. Mainly to appease valgrind, which
228 : // doesn't know about the padding at the end of sockaddr_rc which
229 : // it will dutifully check for definedness. But also the standard
230 : // definition of BDADDR_ANY is unusable in C++ code, so just use
231 : // memset to set aAddr.rc_bdaddr to 0.
232 0 : memset( &aAddr, 0, sizeof( aAddr ) );
233 0 : aAddr.rc_family = AF_BLUETOOTH;
234 0 : aAddr.rc_channel = 5;
235 :
236 : int a;
237 0 : if ( ( a = bind( nSocket, (sockaddr*) &aAddr, sizeof(aAddr) ) ) < 0 ) {
238 : SAL_WARN( "sdremote.bluetooth", "bind failed with error" << a );
239 0 : close( nSocket );
240 0 : return;
241 : }
242 :
243 0 : if ( ( a = listen( nSocket, 1 ) ) < 0 )
244 : {
245 : SAL_WARN( "sdremote.bluetooth", "listen failed with error" << a );
246 0 : close( nSocket );
247 0 : return;
248 : }
249 :
250 : // set non-blocking behaviour ...
251 0 : if( fcntl( nSocket, F_SETFL, O_NONBLOCK) < 0 )
252 : {
253 0 : close( nSocket );
254 0 : return;
255 : }
256 :
257 0 : pSocketFD->fd = nSocket;
258 0 : pSocketFD->events = G_IO_IN | G_IO_PRI;
259 0 : pSocketFD->revents = 0;
260 :
261 0 : g_main_context_add_poll( pContext, pSocketFD, G_PRIORITY_DEFAULT );
262 : }
263 :
264 : static void
265 0 : bluezDetachCloseSocket( GMainContext *pContext, GPollFD *pSocketFD )
266 : {
267 0 : if( pSocketFD->fd >= 0 )
268 : {
269 0 : close( pSocketFD->fd );
270 0 : g_main_context_remove_poll( pContext, pSocketFD );
271 0 : pSocketFD->fd = -1;
272 : }
273 0 : }
274 :
275 : #endif // LINUX_BLUETOOTH
276 :
277 : #if defined(MACOSX)
278 :
279 : OSXBluetoothWrapper::OSXBluetoothWrapper( IOBluetoothRFCOMMChannel* channel ) :
280 : mpChannel(channel),
281 : mnMTU(0),
282 : mHaveBytes(),
283 : mMutex(),
284 : mBuffer()
285 : {
286 : // silly enough, can't write more than mnMTU bytes at once
287 : mnMTU = [channel getMTU];
288 :
289 : SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::OSXBluetoothWrapper(): mnMTU=" << mnMTU );
290 : }
291 :
292 : sal_Int32 OSXBluetoothWrapper::readLine( OString& aLine )
293 : {
294 : SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::readLine()" );
295 :
296 : while( true )
297 : {
298 : {
299 : SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::readLine: entering mutex" );
300 : ::osl::MutexGuard aQueueGuard( mMutex );
301 : SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::readLine: entered mutex" );
302 :
303 : #ifdef SAL_LOG_INFO
304 : // We should have in the sal logging some standard way to
305 : // output char buffers with non-printables escaped.
306 : std::ostringstream s;
307 : if (mBuffer.size() > 0)
308 : {
309 : for (unsigned char *p = (unsigned char *) &mBuffer.front(); p != (unsigned char *) &mBuffer.front() + mBuffer.size(); p++)
310 : {
311 : if (*p == '\n')
312 : s << "\\n";
313 : else if (*p < ' ' || *p >= 0x7F)
314 : s << "\\0x" << std::hex << std::setw(2) << std::setfill('0') << (int) *p << std::setfill(' ') << std::setw(1) << std::dec;
315 : else
316 : s << *p;
317 : }
318 : }
319 : SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::readLine mBuffer: \"" << s.str() << "\"" );
320 : #endif
321 :
322 : // got enough bytes to return a line?
323 : std::vector<char>::iterator aIt;
324 : if ( (aIt = find( mBuffer.begin(), mBuffer.end(), '\n' ))
325 : != mBuffer.end() )
326 : {
327 : sal_uInt64 aLocation = aIt - mBuffer.begin();
328 :
329 : aLine = OString( &(*mBuffer.begin()), aLocation );
330 :
331 : mBuffer.erase( mBuffer.begin(), aIt + 1 ); // Also delete the empty line
332 :
333 : // yeps
334 : SAL_INFO( "sdremote.bluetooth", " returning, got \"" << OStringToOUString( aLine, RTL_TEXTENCODING_UTF8 ) << "\"" );
335 : return aLine.getLength() + 1;
336 : }
337 :
338 : // nope - wait some more (after releasing the mutex)
339 : SAL_INFO( "sdremote.bluetooth", " resetting mHaveBytes" );
340 : mHaveBytes.reset();
341 : SAL_INFO( "sdremote.bluetooth", " leaving mutex" );
342 : }
343 :
344 : SAL_INFO( "sdremote.bluetooth", " waiting for mHaveBytes" );
345 : mHaveBytes.wait();
346 : SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::readLine: got mHaveBytes" );
347 : }
348 : }
349 :
350 : sal_Int32 OSXBluetoothWrapper::write( const void* pBuffer, sal_uInt32 n )
351 : {
352 : SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::write(" << pBuffer << ", " << n << ") mpChannel=" << mpChannel );
353 :
354 : char* ptr = (char*)pBuffer;
355 : sal_uInt32 nBytesWritten = 0;
356 :
357 : if (mpChannel == nil)
358 : return 0;
359 :
360 : while( nBytesWritten < n )
361 : {
362 : int toWrite = n - nBytesWritten;
363 : toWrite = toWrite <= mnMTU ? toWrite : mnMTU;
364 : if ( [mpChannel writeSync:ptr length:toWrite] != kIOReturnSuccess )
365 : {
366 : SAL_INFO( "sdremote.bluetooth", " [mpChannel writeSync:" << (void *) ptr << " length:" << toWrite << "] returned error, total written " << nBytesWritten );
367 : return nBytesWritten;
368 : }
369 : ptr += toWrite;
370 : nBytesWritten += toWrite;
371 : }
372 : SAL_INFO( "sdremote.bluetooth", " total written " << nBytesWritten );
373 : return nBytesWritten;
374 : }
375 :
376 : void OSXBluetoothWrapper::appendData(void* pBuffer, size_t len)
377 : {
378 : SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::appendData(" << pBuffer << ", " << len << ")" );
379 :
380 : if( len )
381 : {
382 : SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::appendData: entering mutex" );
383 : ::osl::MutexGuard aQueueGuard( mMutex );
384 : SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::appendData: entered mutex" );
385 : mBuffer.insert(mBuffer.begin()+mBuffer.size(),
386 : (char*)pBuffer, (char *)pBuffer+len);
387 : SAL_INFO( "sdremote.bluetooth", " setting mHaveBytes" );
388 : mHaveBytes.set();
389 : SAL_INFO( "sdremote.bluetooth", " leaving mutex" );
390 : }
391 : }
392 :
393 : void OSXBluetoothWrapper::channelClosed()
394 : {
395 : SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::channelClosed()" );
396 :
397 : mpChannel = nil;
398 : }
399 :
400 : void incomingCallback( void *userRefCon,
401 : IOBluetoothUserNotificationRef inRef,
402 : IOBluetoothObjectRef objectRef )
403 : {
404 : (void) inRef;
405 :
406 : SAL_INFO( "sdremote.bluetooth", "incomingCallback()" );
407 :
408 : BluetoothServer* pServer = (BluetoothServer*)userRefCon;
409 :
410 : IOBluetoothRFCOMMChannel* channel = [IOBluetoothRFCOMMChannel withRFCOMMChannelRef:(IOBluetoothRFCOMMChannelRef)objectRef];
411 :
412 : OSXBluetoothWrapper* socket = new OSXBluetoothWrapper( channel);
413 : Communicator* pCommunicator = new Communicator( socket );
414 : pServer->addCommunicator( pCommunicator );
415 :
416 : ChannelDelegate* delegate = [[ChannelDelegate alloc] initWithCommunicatorAndSocket: pCommunicator socket: socket];
417 : [channel setDelegate: delegate];
418 : [delegate retain];
419 :
420 : pCommunicator->launch();
421 : }
422 :
423 : void BluetoothServer::addCommunicator( Communicator* pCommunicator )
424 : {
425 : mpCommunicators->push_back( pCommunicator );
426 : }
427 :
428 : #endif // MACOSX
429 :
430 : #ifdef LINUX_BLUETOOTH
431 :
432 : extern "C" {
433 0 : static gboolean ensureDiscoverable_cb(gpointer)
434 : {
435 0 : BluetoothServer::doEnsureDiscoverable();
436 0 : return FALSE; // remove source
437 : }
438 0 : static gboolean restoreDiscoverable_cb(gpointer)
439 : {
440 0 : BluetoothServer::doRestoreDiscoverable();
441 0 : return FALSE; // remove source
442 : }
443 : }
444 :
445 : static bool
446 0 : getBooleanProperty( DBusConnection *pConnection, DBusObject *pAdapter,
447 : const char *pPropertyName, bool *pBoolean )
448 : {
449 0 : *pBoolean = false;
450 :
451 0 : if( !pAdapter )
452 0 : return false;
453 :
454 : DBusMessage *pMsg;
455 : pMsg = sendUnrefAndWaitForReply( pConnection,
456 0 : pAdapter->getMethodCall( "GetProperties" ) );
457 :
458 : DBusMessageIter it;
459 0 : if( !pMsg || !dbus_message_iter_init( pMsg, &it ) )
460 : {
461 : SAL_WARN( "sdremote.bluetooth", "no valid reply / timeout" );
462 0 : return false;
463 : }
464 :
465 0 : if( DBUS_TYPE_ARRAY != dbus_message_iter_get_arg_type( &it ) )
466 : {
467 : SAL_WARN( "sdremote.bluetooth", "no valid reply / timeout" );
468 0 : return false;
469 : }
470 :
471 : DBusMessageIter arrayIt;
472 0 : dbus_message_iter_recurse( &it, &arrayIt );
473 :
474 0 : while( dbus_message_iter_get_arg_type( &arrayIt ) == DBUS_TYPE_DICT_ENTRY )
475 : {
476 : DBusMessageIter dictIt;
477 0 : dbus_message_iter_recurse( &arrayIt, &dictIt );
478 :
479 0 : const char *pName = NULL;
480 0 : if( dbus_message_iter_get_arg_type( &dictIt ) == DBUS_TYPE_STRING )
481 : {
482 0 : dbus_message_iter_get_basic( &dictIt, &pName );
483 0 : if( pName != NULL && !strcmp( pName, pPropertyName ) )
484 : {
485 : SAL_INFO( "sdremote.bluetooth", "hit " << pPropertyName << " property" );
486 0 : dbus_message_iter_next( &dictIt );
487 0 : dbus_bool_t bBool = false;
488 :
489 0 : if( dbus_message_iter_get_arg_type( &dictIt ) == DBUS_TYPE_VARIANT )
490 : {
491 : DBusMessageIter variantIt;
492 0 : dbus_message_iter_recurse( &dictIt, &variantIt );
493 :
494 0 : if( dbus_message_iter_get_arg_type( &variantIt ) == DBUS_TYPE_BOOLEAN )
495 : {
496 0 : dbus_message_iter_get_basic( &variantIt, &bBool );
497 : SAL_INFO( "sdremote.bluetooth", "" << pPropertyName << " is " << bBool );
498 0 : *pBoolean = bBool;
499 0 : return true;
500 : }
501 : else
502 : SAL_WARN( "sdremote.bluetooth", "" << pPropertyName << " type " <<
503 : dbus_message_iter_get_arg_type( &variantIt ) );
504 : }
505 : else
506 : SAL_WARN( "sdremote.bluetooth", "variant type ? " <<
507 0 : dbus_message_iter_get_arg_type( &dictIt ) );
508 : }
509 : else
510 : {
511 0 : const char *pStr = pName ? pName : "<null>";
512 : SAL_INFO( "sdremote.bluetooth", "property '" << pStr << "'" );
513 : }
514 : }
515 : else
516 : SAL_WARN( "sdremote.bluetooth", "unexpected property key type "
517 : << dbus_message_iter_get_arg_type( &dictIt ) );
518 0 : dbus_message_iter_next( &arrayIt );
519 : }
520 0 : dbus_message_unref( pMsg );
521 :
522 0 : return false;
523 : }
524 :
525 : static void
526 0 : setDiscoverable( DBusConnection *pConnection, DBusObject *pAdapter, bool bDiscoverable )
527 : {
528 : SAL_INFO( "sdremote.bluetooth", "setDiscoverable to " << bDiscoverable );
529 :
530 0 : bool bPowered = false;
531 0 : if( !getBooleanProperty( pConnection, pAdapter, "Powered", &bPowered ) || !bPowered )
532 0 : return; // nothing to do
533 :
534 : DBusMessage *pMsg;
535 : DBusMessageIter it, varIt;
536 :
537 : // set timeout to zero
538 0 : pMsg = pAdapter->getMethodCall( "SetProperty" );
539 0 : dbus_message_iter_init_append( pMsg, &it );
540 0 : const char *pTimeoutStr = "DiscoverableTimeout";
541 0 : dbus_message_iter_append_basic( &it, DBUS_TYPE_STRING, &pTimeoutStr );
542 : dbus_message_iter_open_container( &it, DBUS_TYPE_VARIANT,
543 0 : DBUS_TYPE_UINT32_AS_STRING, &varIt );
544 0 : dbus_uint32_t nTimeout = 0;
545 0 : dbus_message_iter_append_basic( &varIt, DBUS_TYPE_UINT32, &nTimeout );
546 0 : dbus_message_iter_close_container( &it, &varIt );
547 0 : dbus_connection_send( pConnection, pMsg, NULL ); // async send - why not ?
548 0 : dbus_message_unref( pMsg );
549 :
550 : // set discoverable value
551 0 : pMsg = pAdapter->getMethodCall( "SetProperty" );
552 0 : dbus_message_iter_init_append( pMsg, &it );
553 0 : const char *pDiscoverableStr = "Discoverable";
554 0 : dbus_message_iter_append_basic( &it, DBUS_TYPE_STRING, &pDiscoverableStr );
555 : dbus_message_iter_open_container( &it, DBUS_TYPE_VARIANT,
556 0 : DBUS_TYPE_BOOLEAN_AS_STRING, &varIt );
557 0 : dbus_bool_t bValue = bDiscoverable;
558 0 : dbus_message_iter_append_basic( &varIt, DBUS_TYPE_BOOLEAN, &bValue );
559 0 : dbus_message_iter_close_container( &it, &varIt ); // async send - why not ?
560 0 : dbus_connection_send( pConnection, pMsg, NULL );
561 0 : dbus_message_unref( pMsg );
562 : }
563 :
564 : static DBusObject *
565 11 : registerWithDefaultAdapter( DBusConnection *pConnection )
566 : {
567 : DBusObject *pService;
568 11 : pService = bluezGetDefaultService( pConnection );
569 11 : if( !pService )
570 11 : return NULL;
571 :
572 0 : if( !bluezRegisterServiceRecord( pConnection, pService,
573 0 : bluetooth_service_record ) )
574 : {
575 0 : delete pService;
576 0 : return NULL;
577 : }
578 :
579 0 : return pService;
580 : }
581 :
582 : #endif // LINUX_BLUETOOTH
583 :
584 11 : BluetoothServer::BluetoothServer( std::vector<Communicator*>* pCommunicators )
585 : : meWasDiscoverable( UNKNOWN ),
586 11 : mpCommunicators( pCommunicators )
587 : {
588 : #ifdef LINUX_BLUETOOTH
589 11 : mpImpl.reset(new BluetoothServer::Impl());
590 : #endif
591 11 : }
592 :
593 0 : BluetoothServer::~BluetoothServer()
594 : {
595 0 : }
596 :
597 0 : void BluetoothServer::ensureDiscoverable()
598 : {
599 : #ifdef LINUX_BLUETOOTH
600 : // Push it all across into our mainloop
601 0 : if( !spServer )
602 0 : return;
603 0 : GSource *pIdle = g_idle_source_new();
604 0 : g_source_set_callback( pIdle, ensureDiscoverable_cb, NULL, NULL );
605 0 : g_source_set_priority( pIdle, G_PRIORITY_DEFAULT );
606 0 : g_source_attach( pIdle, spServer->mpImpl->mpContext );
607 0 : g_source_unref( pIdle );
608 : #endif
609 : }
610 :
611 0 : void BluetoothServer::restoreDiscoverable()
612 : {
613 : #ifdef LINUX_BLUETOOTH
614 : // Push it all across into our mainloop
615 0 : if( !spServer )
616 0 : return;
617 0 : GSource *pIdle = g_idle_source_new();
618 0 : g_source_set_callback( pIdle, restoreDiscoverable_cb, NULL, NULL );
619 0 : g_source_set_priority( pIdle, G_PRIORITY_DEFAULT_IDLE );
620 0 : g_source_attach( pIdle, spServer->mpImpl->mpContext );
621 0 : g_source_unref( pIdle );
622 : #endif
623 : }
624 :
625 0 : void BluetoothServer::doEnsureDiscoverable()
626 : {
627 : #ifdef LINUX_BLUETOOTH
628 0 : if (!spServer->mpImpl->mpConnection ||
629 0 : spServer->meWasDiscoverable != UNKNOWN )
630 0 : return;
631 :
632 : // Find out if we are discoverable already ...
633 0 : DBusObject *pAdapter = spServer->mpImpl->getAdapter();
634 0 : if( !pAdapter )
635 0 : return;
636 :
637 : bool bDiscoverable;
638 0 : if( getBooleanProperty( spServer->mpImpl->mpConnection, pAdapter,
639 0 : "Discoverable", &bDiscoverable ) )
640 : {
641 0 : spServer->meWasDiscoverable = bDiscoverable ? DISCOVERABLE : NOT_DISCOVERABLE;
642 0 : if( !bDiscoverable )
643 0 : setDiscoverable( spServer->mpImpl->mpConnection, pAdapter, true );
644 : }
645 :
646 0 : delete pAdapter;
647 : #endif
648 : }
649 :
650 0 : void BluetoothServer::doRestoreDiscoverable()
651 : {
652 0 : if( spServer->meWasDiscoverable == NOT_DISCOVERABLE )
653 : {
654 : #ifdef LINUX_BLUETOOTH
655 0 : DBusObject *pAdapter = spServer->mpImpl->getAdapter();
656 0 : if( !pAdapter )
657 0 : return;
658 0 : setDiscoverable( spServer->mpImpl->mpConnection, pAdapter, false );
659 0 : delete pAdapter;
660 : #endif
661 : }
662 0 : spServer->meWasDiscoverable = UNKNOWN;
663 : }
664 :
665 : // We have to have all our clients shut otherwise we can't
666 : // re-bind to the same port number it appears.
667 0 : void BluetoothServer::cleanupCommunicators()
668 : {
669 0 : for (std::vector<Communicator *>::iterator it = mpCommunicators->begin();
670 0 : it != mpCommunicators->end(); ++it)
671 0 : (*it)->forceClose();
672 : // the hope is that all the threads then terminate cleanly and
673 : // clean themselves up.
674 0 : }
675 :
676 11 : void SAL_CALL BluetoothServer::run()
677 : {
678 : SAL_INFO( "sdremote.bluetooth", "BluetoothServer::run called" );
679 :
680 : #ifdef LINUX_BLUETOOTH
681 11 : DBusConnection *pConnection = dbusConnectToNameOnBus();
682 11 : if( !pConnection )
683 0 : return;
684 :
685 : // listen for connection state and power changes - we need to close
686 : // and re-create our socket code on suspend / resume, enable/disable
687 : DBusError aError;
688 11 : dbus_error_init( &aError );
689 11 : dbus_bus_add_match( pConnection, "type='signal',interface='org.bluez.Manager'", &aError );
690 11 : dbus_connection_flush( pConnection );
691 :
692 : // Try to setup the default adapter, otherwise wait for add/remove signal
693 11 : mpImpl->mpService = registerWithDefaultAdapter( pConnection );
694 :
695 : // poll on our bluetooth socket - if we can.
696 : GPollFD aSocketFD;
697 11 : if( mpImpl->mpService )
698 0 : bluezCreateAttachListeningSocket( mpImpl->mpContext, &aSocketFD );
699 :
700 : // also poll on our dbus connection
701 11 : int fd = -1;
702 : GPollFD aDBusFD;
703 11 : if( dbus_connection_get_unix_fd( pConnection, &fd ) && fd >= 0 )
704 : {
705 11 : aDBusFD.fd = fd;
706 11 : aDBusFD.events = G_IO_IN | G_IO_PRI;
707 11 : g_main_context_add_poll( mpImpl->mpContext, &aDBusFD, G_PRIORITY_DEFAULT );
708 : }
709 : else
710 : SAL_WARN( "sdremote.bluetooth", "failed to poll for incoming dbus signals" );
711 :
712 11 : mpImpl->mpConnection = pConnection;
713 :
714 44 : while( !mpImpl->mbExitMainloop )
715 : {
716 33 : aDBusFD.revents = 0;
717 33 : aSocketFD.revents = 0;
718 33 : g_main_context_iteration( mpImpl->mpContext, TRUE );
719 :
720 : SAL_INFO( "sdremote.bluetooth", "main-loop spin "
721 : << aDBusFD.revents << " " << aSocketFD.revents );
722 22 : if( aDBusFD.revents )
723 : {
724 0 : dbus_connection_read_write( pConnection, 0 );
725 0 : DBusMessage *pMsg = dbus_connection_pop_message( pConnection );
726 0 : if( pMsg )
727 : {
728 0 : if( dbus_message_is_signal( pMsg, "org.bluez.Manager", "AdapterRemoved" ) )
729 : {
730 : SAL_WARN( "sdremote.bluetooth", "lost adapter - cleaning up sockets" );
731 0 : bluezDetachCloseSocket( mpImpl->mpContext, &aSocketFD );
732 0 : cleanupCommunicators();
733 : }
734 0 : else if( dbus_message_is_signal( pMsg, "org.bluez.Manager", "AdapterAdded" ) ||
735 0 : dbus_message_is_signal( pMsg, "org.bluez.Manager", "DefaultAdapterChanged" ) )
736 : {
737 : SAL_WARN( "sdremote.bluetooth", "gained adapter - re-generating sockets" );
738 0 : bluezDetachCloseSocket( mpImpl->mpContext, &aSocketFD );
739 0 : cleanupCommunicators();
740 0 : mpImpl->mpService = registerWithDefaultAdapter( pConnection );
741 0 : if( mpImpl->mpService )
742 0 : bluezCreateAttachListeningSocket( mpImpl->mpContext, &aSocketFD );
743 : }
744 : else
745 : SAL_INFO( "sdremote.bluetooth", "unknown incoming dbus message, "
746 : << " type: " << dbus_message_get_type( pMsg )
747 : << " path: '" << dbus_message_get_path( pMsg )
748 : << "' interface: '" << dbus_message_get_interface( pMsg )
749 : << "' member: '" << dbus_message_get_member( pMsg ) );
750 : }
751 0 : dbus_message_unref( pMsg );
752 : }
753 :
754 22 : if( aSocketFD.revents )
755 : {
756 : sockaddr_rc aRemoteAddr;
757 0 : socklen_t aRemoteAddrLen = sizeof(aRemoteAddr);
758 :
759 : int nClient;
760 : SAL_INFO( "sdremote.bluetooth", "performing accept" );
761 0 : if ( ( nClient = accept( aSocketFD.fd, (sockaddr*) &aRemoteAddr, &aRemoteAddrLen)) < 0 &&
762 0 : errno != EAGAIN )
763 : {
764 : SAL_WARN( "sdremote.bluetooth", "accept failed with errno " << errno );
765 : } else {
766 : SAL_INFO( "sdremote.bluetooth", "connection accepted " << nClient );
767 0 : Communicator* pCommunicator = new Communicator( new BufferedStreamSocket( nClient ) );
768 0 : mpCommunicators->push_back( pCommunicator );
769 0 : pCommunicator->launch();
770 : }
771 : }
772 : }
773 :
774 0 : g_main_context_unref( mpImpl->mpContext );
775 0 : mpImpl->mpConnection = NULL;
776 0 : mpImpl->mpContext = NULL;
777 :
778 : #elif defined(WIN32)
779 : WORD wVersionRequested;
780 : WSADATA wsaData;
781 :
782 : wVersionRequested = MAKEWORD(2, 2);
783 :
784 : if ( WSAStartup(wVersionRequested, &wsaData) )
785 : {
786 : return; // winsock dll couldn't be loaded
787 : }
788 :
789 : int aSocket = socket( AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM );
790 : if ( !aSocket )
791 : {
792 : WSACleanup();
793 : return;
794 : }
795 : SOCKADDR_BTH aAddr;
796 : aAddr.addressFamily = AF_BTH;
797 : aAddr.btAddr = 0;
798 : aAddr.serviceClassId = GUID_NULL;
799 : aAddr.port = BT_PORT_ANY; // Select any free socket.
800 : if ( bind( aSocket, (SOCKADDR*) &aAddr, sizeof(aAddr) ) == SOCKET_ERROR )
801 : {
802 : closesocket( aSocket );
803 : WSACleanup();
804 : return;
805 : }
806 :
807 : SOCKADDR aName;
808 : int aNameSize = sizeof(aAddr);
809 : getsockname( aSocket, &aName, &aNameSize ); // Retrieve the local address and port
810 :
811 : CSADDR_INFO aAddrInfo;
812 : memset( &aAddrInfo, 0, sizeof(aAddrInfo) );
813 : aAddrInfo.LocalAddr.lpSockaddr = &aName;
814 : aAddrInfo.LocalAddr.iSockaddrLength = sizeof( SOCKADDR_BTH );
815 : aAddrInfo.RemoteAddr.lpSockaddr = &aName;
816 : aAddrInfo.RemoteAddr.iSockaddrLength = sizeof( SOCKADDR_BTH );
817 : aAddrInfo.iSocketType = SOCK_STREAM;
818 : aAddrInfo.iProtocol = BTHPROTO_RFCOMM;
819 :
820 : // To be used for setting a custom UUID once available.
821 : // GUID uuid;
822 : // uuid.Data1 = 0x00001101;
823 : // memset( &uuid, 0x1000 + UUID*2^96, sizeof( GUID ) );
824 : // uuid.Data2 = 0;
825 : // uuid.Data3 = 0x1000;
826 : // ULONGLONG aData4 = 0x800000805F9B34FB;
827 : // memcpy( uuid.Data4, &aData4, sizeof(uuid.Data4) );
828 :
829 : WSAQUERYSET aRecord;
830 : memset( &aRecord, 0, sizeof(aRecord));
831 : aRecord.dwSize = sizeof(aRecord);
832 : aRecord.lpszServiceInstanceName = (char *)"LibreOffice Impress Remote Control";
833 : aRecord.lpszComment = (char *)"Remote control of presentations over bluetooth.";
834 : aRecord.lpServiceClassId = (LPGUID) &SerialPortServiceClass_UUID;
835 : aRecord.dwNameSpace = NS_BTH;
836 : aRecord.dwNumberOfCsAddrs = 1;
837 : aRecord.lpcsaBuffer = &aAddrInfo;
838 :
839 : if ( WSASetService( &aRecord, RNRSERVICE_REGISTER, 0 ) == SOCKET_ERROR )
840 : {
841 : closesocket( aSocket );
842 : WSACleanup();
843 : return;
844 : }
845 :
846 : if ( listen( aSocket, 1 ) == SOCKET_ERROR )
847 : {
848 : closesocket( aSocket );
849 : WSACleanup();
850 : return;
851 : }
852 :
853 : SOCKADDR_BTH aRemoteAddr;
854 : int aRemoteAddrLen = sizeof(aRemoteAddr);
855 : while ( true )
856 : {
857 : SOCKET socket;
858 : if ( (socket = accept(aSocket, (sockaddr*) &aRemoteAddr, &aRemoteAddrLen)) == INVALID_SOCKET )
859 : {
860 : closesocket( aSocket );
861 : WSACleanup();
862 : return;
863 : } else {
864 : Communicator* pCommunicator = new Communicator( new BufferedStreamSocket( socket) );
865 : mpCommunicators->push_back( pCommunicator );
866 : pCommunicator->launch();
867 : }
868 : }
869 :
870 : #elif defined(MACOSX)
871 : // Build up dictionary at run-time instead of bothering with a
872 : // .plist file, using the Objective-C API
873 :
874 : // Compare to BluetoothServiceRecord.hxx
875 :
876 : NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
877 :
878 : NSDictionary *dict =
879 : [NSDictionary dictionaryWithObjectsAndKeys:
880 :
881 : // Service class ID list
882 : [NSArray arrayWithObject:
883 : [IOBluetoothSDPUUID uuid16: kBluetoothSDPUUID16ServiceClassSerialPort]],
884 : @"0001 - ServiceClassIDList",
885 :
886 : // Protocol descriptor list
887 : [NSArray arrayWithObjects:
888 : [NSArray arrayWithObject: [IOBluetoothSDPUUID uuid16: kBluetoothSDPUUID16L2CAP]],
889 : [NSArray arrayWithObjects:
890 : [IOBluetoothSDPUUID uuid16: kBluetoothL2CAPPSMRFCOMM],
891 : [NSDictionary dictionaryWithObjectsAndKeys:
892 : [NSNumber numberWithInt: 1],
893 : @"DataElementSize",
894 : [NSNumber numberWithInt: 1],
895 : @"DataElementType",
896 : [NSNumber numberWithInt: 5], // RFCOMM port number, will be replaced if necessary automatically
897 : @"DataElementValue",
898 : nil],
899 : nil],
900 : nil],
901 : @"0004 - Protocol descriptor list",
902 :
903 : // Browse group list
904 : [NSArray arrayWithObject:
905 : [IOBluetoothSDPUUID uuid16: kBluetoothSDPUUID16ServiceClassPublicBrowseGroup]],
906 : @"0005 - BrowseGroupList",
907 :
908 : // Language base attribute ID list
909 : [NSArray arrayWithObjects:
910 : [NSData dataWithBytes: "en" length: 2],
911 : [NSDictionary dictionaryWithObjectsAndKeys:
912 : [NSNumber numberWithInt: 2],
913 : @"DataElementSize",
914 : [NSNumber numberWithInt: 1],
915 : @"DataElementType",
916 : [NSNumber numberWithInt: 0x006a], // encoding
917 : @"DataElementValue",
918 : nil],
919 : [NSDictionary dictionaryWithObjectsAndKeys:
920 : [NSNumber numberWithInt: 2],
921 : @"DataElementSize",
922 : [NSNumber numberWithInt: 1],
923 : @"DataElementType",
924 : [NSNumber numberWithInt: 0x0100], // offset
925 : @"DataElementValue",
926 : nil],
927 : nil],
928 : @"0006 - LanguageBaseAttributeIDList",
929 :
930 : // Bluetooth profile descriptor list
931 : [NSArray arrayWithObject:
932 : [NSArray arrayWithObjects:
933 : [IOBluetoothSDPUUID uuid16: kBluetoothSDPUUID16ServiceClassSerialPort],
934 : [NSDictionary dictionaryWithObjectsAndKeys:
935 : [NSNumber numberWithInt: 2],
936 : @"DataElementSize",
937 : [NSNumber numberWithInt: 1],
938 : @"DataElementType",
939 : [NSNumber numberWithInt: 0x0100], // version number ?
940 : @"DataElementValue",
941 : nil],
942 : nil]],
943 : @"0009 - BluetoothProfileDescriptorList",
944 :
945 : // Attributes pointed to by the LanguageBaseAttributeIDList
946 : @"LibreOffice Impress Remote Control",
947 : @"0100 - ServiceName",
948 : @"The Document Foundation",
949 : @"0102 - ProviderName",
950 : nil];
951 :
952 : // Create service
953 : IOBluetoothSDPServiceRecordRef serviceRecordRef;
954 : IOReturn rc = IOBluetoothAddServiceDict((CFDictionaryRef) dict, &serviceRecordRef);
955 :
956 : SAL_INFO("sdremote.bluetooth", "IOBluetoothAddServiceDict returned " << rc);
957 :
958 : if (rc == kIOReturnSuccess)
959 : {
960 : IOBluetoothSDPServiceRecord *serviceRecord =
961 : [IOBluetoothSDPServiceRecord withSDPServiceRecordRef: serviceRecordRef];
962 :
963 : BluetoothRFCOMMChannelID channelID;
964 : [serviceRecord getRFCOMMChannelID: &channelID];
965 :
966 : BluetoothSDPServiceRecordHandle serviceRecordHandle;
967 : [serviceRecord getServiceRecordHandle: &serviceRecordHandle];
968 :
969 : // Register callback for incoming connections
970 : IOBluetoothUserNotificationRef callbackRef =
971 : IOBluetoothRegisterForFilteredRFCOMMChannelOpenNotifications(
972 : incomingCallback,
973 : this,
974 : channelID,
975 : kIOBluetoothUserNotificationChannelDirectionIncoming);
976 :
977 : (void) callbackRef;
978 :
979 : [serviceRecord release];
980 : }
981 :
982 : [pool release];
983 :
984 : (void) mpCommunicators;
985 : #else
986 : (void) mpCommunicators; // avoid warnings about unused member
987 : #endif
988 : }
989 :
990 : BluetoothServer *sd::BluetoothServer::spServer = NULL;
991 :
992 11 : void BluetoothServer::setup( std::vector<Communicator*>* pCommunicators )
993 : {
994 11 : if (spServer)
995 11 : return;
996 :
997 11 : spServer = new BluetoothServer( pCommunicators );
998 11 : spServer->create();
999 33 : }
1000 :
1001 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|