1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
10 #include "BluetoothServer.hxx"
16 #include <boost/scoped_ptr.hpp>
18 #include <sal/log.hxx>
20 #ifdef LINUX_BLUETOOTH
22 #include <dbus/dbus.h>
25 #include <sys/unistd.h>
26 #include <sys/socket.h>
27 #include <bluetooth/bluetooth.h>
28 #include <bluetooth/rfcomm.h>
29 #include "BluetoothServiceRecord.hxx"
30 #include "BufferedStreamSocket.hxx"
34 // LO vs WinAPI conflict
39 #include "BufferedStreamSocket.hxx"
43 #include <osl/conditn.hxx>
45 #if MACOSX_SDK_VERSION == 1080
46 #import <IOBluetooth/IOBluetooth.h>
48 #import <CoreFoundation/CoreFoundation.h>
49 #import <IOBluetooth/IOBluetoothUtilities.h>
50 #import <IOBluetooth/objc/IOBluetoothSDPUUID.h>
51 #import <IOBluetooth/objc/IOBluetoothSDPServiceRecord.h>
54 #import "OSXBluetooth.h"
55 #include "OSXBluetoothWrapper.hxx"
59 // Value taken from http://msdn.microsoft.com/en-us/library/windows/desktop/ms738518%28v=vs.85%29.aspx
63 #include "Communicator.hxx"
67 #ifdef LINUX_BLUETOOTH
75 DBusObject( const char *pBusName
, const char *pPath
, const char *pInterface
)
76 : maBusName( pBusName
), maPath( pPath
), maInterface( pInterface
) { }
78 DBusMessage
*getMethodCall( const char *pName
)
80 return dbus_message_new_method_call( maBusName
.getStr(), maPath
.getStr(),
81 maInterface
.getStr(), pName
);
83 DBusObject
*cloneForInterface( const char *pInterface
)
85 DBusObject
*pObject
= new DBusObject();
87 pObject
->maBusName
= maBusName
;
88 pObject
->maPath
= maPath
;
89 pObject
->maInterface
= pInterface
;
95 static DBusObject
* getBluez5Adapter(DBusConnection
*pConnection
);
97 struct sd::BluetoothServer::Impl
{
98 // the glib mainloop running in the thread
99 GMainContext
*mpContext
;
100 DBusConnection
*mpConnection
;
101 DBusObject
*mpService
;
102 volatile bool mbExitMainloop
;
103 enum BluezVersion
{ BLUEZ4
, BLUEZ5
, UNKNOWN
};
104 BluezVersion maBluezVersion
;
107 : mpContext( g_main_context_new() )
108 , mpConnection( NULL
)
110 , mbExitMainloop( false )
111 , maBluezVersion( UNKNOWN
)
114 DBusObject
*getAdapter()
118 DBusObject
* pAdapter
= mpService
->cloneForInterface( "org.bluez.Adapter" );
121 else if (spServer
->mpImpl
->maBluezVersion
== BLUEZ5
)
123 return getBluez5Adapter(mpConnection
);
132 static DBusConnection
*
133 dbusConnectToNameOnBus()
136 DBusConnection
*pConnection
;
138 dbus_error_init( &aError
);
140 pConnection
= dbus_bus_get( DBUS_BUS_SYSTEM
, &aError
);
141 if( !pConnection
|| dbus_error_is_set( &aError
))
143 SAL_WARN( "sdremote.bluetooth", "failed to get dbus system bus: " << aError
.message
);
144 dbus_error_free( &aError
);
152 sendUnrefAndWaitForReply( DBusConnection
*pConnection
, DBusMessage
*pMsg
)
154 DBusPendingCall
*pPending
= NULL
;
156 if( !pMsg
|| !dbus_connection_send_with_reply( pConnection
, pMsg
, &pPending
,
157 -1 /* default timeout */ ) )
159 SAL_WARN( "sdremote.bluetooth", "Memory allocation failed on message send" );
160 dbus_message_unref( pMsg
);
163 dbus_connection_flush( pConnection
);
164 dbus_message_unref( pMsg
);
166 dbus_pending_call_block( pPending
); // block for reply
168 pMsg
= dbus_pending_call_steal_reply( pPending
);
170 SAL_WARN( "sdremote.bluetooth", "no valid reply / timeout" );
172 dbus_pending_call_unref( pPending
);
177 isBluez5Available(DBusConnection
*pConnection
)
181 // Simplest wasy to check whether we have Bluez 5+ is to check
182 // that we can obtain adapters using the new interfaces.
183 // The first two error checks however don't tell us anything as they should
184 // succeed as long as dbus is working correctly.
185 pMsg
= DBusObject( "org.bluez", "/", "org.freedesktop.DBus.ObjectManager" ).getMethodCall( "GetManagedObjects" );
188 SAL_INFO("sdremote.bluetooth", "No GetManagedObjects call created");
192 pMsg
= sendUnrefAndWaitForReply( pConnection
, pMsg
);
195 SAL_INFO("sdremote.bluetooth", "No reply received");
199 // If dbus is working correctly and we aren't on bluez 5 this is where we
200 // should actually get the error.
201 if (dbus_message_get_error_name( pMsg
))
203 SAL_INFO( "sdremote.bluetooth", "GetManagedObjects call failed with \""
204 << dbus_message_get_error_name( pMsg
)
205 << "\" -- we don't seem to have Bluez 5 available");
208 SAL_INFO("sdremote.bluetooth", "GetManagedObjects call seems to have succeeded -- we must be on Bluez 5");
209 dbus_message_unref(pMsg
);
214 getBluez5Adapter(DBusConnection
*pConnection
)
217 // This returns a list of objects where we need to find the first
218 // org.bluez.Adapter1 .
219 pMsg
= DBusObject( "org.bluez", "/", "org.freedesktop.DBus.ObjectManager" ).getMethodCall( "GetManagedObjects" );
223 const gchar
* pInterfaceType
= "org.bluez.Adapter1";
225 pMsg
= sendUnrefAndWaitForReply( pConnection
, pMsg
);
227 DBusMessageIter aObjectIterator
;
228 if (pMsg
&& dbus_message_iter_init(pMsg
, &aObjectIterator
))
230 if (DBUS_TYPE_ARRAY
== dbus_message_iter_get_arg_type(&aObjectIterator
))
232 DBusMessageIter aObject
;
233 dbus_message_iter_recurse(&aObjectIterator
, &aObject
);
236 if (DBUS_TYPE_DICT_ENTRY
== dbus_message_iter_get_arg_type(&aObject
))
238 DBusMessageIter aContainerIter
;
239 dbus_message_iter_recurse(&aObject
, &aContainerIter
);
243 if (DBUS_TYPE_OBJECT_PATH
== dbus_message_iter_get_arg_type(&aContainerIter
))
245 dbus_message_iter_get_basic(&aContainerIter
, &pPath
);
246 SAL_INFO( "sdremote.bluetooth", "Something retrieved: '"
249 else if (DBUS_TYPE_ARRAY
== dbus_message_iter_get_arg_type(&aContainerIter
))
251 DBusMessageIter aInnerIter
;
252 dbus_message_iter_recurse(&aContainerIter
, &aInnerIter
);
255 if (DBUS_TYPE_DICT_ENTRY
== dbus_message_iter_get_arg_type(&aInnerIter
))
257 DBusMessageIter aInnerInnerIter
;
258 dbus_message_iter_recurse(&aInnerIter
, &aInnerInnerIter
);
261 if (DBUS_TYPE_STRING
== dbus_message_iter_get_arg_type(&aInnerInnerIter
))
265 dbus_message_iter_get_basic(&aInnerInnerIter
, &pMessage
);
266 if (OString(pMessage
) == "org.bluez.Adapter1")
268 dbus_message_unref(pMsg
);
271 return new DBusObject( "org.bluez", pPath
, pInterfaceType
);
273 assert(false); // We should already have pPath provided for us.
277 while (dbus_message_iter_next(&aInnerInnerIter
));
280 while (dbus_message_iter_next(&aInnerIter
));
283 while (dbus_message_iter_next(&aContainerIter
));
286 while (dbus_message_iter_next(&aObject
));
288 dbus_message_unref(pMsg
);
295 bluez4GetDefaultService( DBusConnection
*pConnection
)
299 const gchar
* pInterfaceType
= "org.bluez.Service";
301 // org.bluez.manager only exists for bluez 4.
302 // getMethodCall should return NULL if there is any issue e.g. the
303 // if org.bluez.manager doesn't exist.
304 pMsg
= DBusObject( "org.bluez", "/", "org.bluez.Manager" ).getMethodCall( "DefaultAdapter" );
308 SAL_WARN("sdremote.bluetooth", "Couldn't retrieve DBusObject for DefaultAdapter");
312 SAL_INFO("sdremote.bluetooth", "successfully retrieved org.bluez.Manager.DefaultAdapter, attempting to use.");
313 pMsg
= sendUnrefAndWaitForReply( pConnection
, pMsg
);
315 if(!pMsg
|| !dbus_message_iter_init( pMsg
, &it
) )
320 // This works for Bluez 4
321 if( DBUS_TYPE_OBJECT_PATH
== dbus_message_iter_get_arg_type( &it
) )
323 const char *pObjectPath
= NULL
;
324 dbus_message_iter_get_basic( &it
, &pObjectPath
);
325 SAL_INFO( "sdremote.bluetooth", "DefaultAdapter retrieved: '"
326 << pObjectPath
<< "' '" << pInterfaceType
<< "'" );
327 dbus_message_unref( pMsg
);
328 return new DBusObject( "org.bluez", pObjectPath
, pInterfaceType
);
330 // Some form of error, e.g. if we have bluez 5 we get a message that
331 // this method doesn't exist.
332 else if ( DBUS_TYPE_STRING
== dbus_message_iter_get_arg_type( &it
) )
334 const char *pMessage
= NULL
;
335 dbus_message_iter_get_basic( &it
, &pMessage
);
336 SAL_INFO( "sdremote.bluetooth", "Error message: '"
337 << pMessage
<< "' '" << pInterfaceType
<< "'" );
341 SAL_INFO( "sdremote.bluetooth", "invalid type of reply to DefaultAdapter: '"
342 << (const char) dbus_message_iter_get_arg_type( &it
) << "'" );
344 dbus_message_unref(pMsg
);
349 bluez4RegisterServiceRecord( DBusConnection
*pConnection
, DBusObject
*pAdapter
,
350 const char *pServiceRecord
)
355 pMsg
= pAdapter
->getMethodCall( "AddRecord" );
356 dbus_message_iter_init_append( pMsg
, &it
);
357 dbus_message_iter_append_basic( &it
, DBUS_TYPE_STRING
, &pServiceRecord
);
359 pMsg
= sendUnrefAndWaitForReply( pConnection
, pMsg
);
361 if( !pMsg
|| !dbus_message_iter_init( pMsg
, &it
) ||
362 dbus_message_iter_get_arg_type( &it
) != DBUS_TYPE_UINT32
)
364 SAL_WARN( "sdremote.bluetooth", "SDP registration failed" );
368 // We ignore the uint de-registration handle we get back:
369 // bluez will clean us up automatically on exit
375 bluezCreateAttachListeningSocket( GMainContext
*pContext
, GPollFD
*pSocketFD
)
381 if( ( nSocket
= socket( AF_BLUETOOTH
, SOCK_STREAM
, BTPROTO_RFCOMM
) ) < 0 )
383 SAL_WARN( "sdremote.bluetooth", "failed to open bluetooth socket with error " << nSocket
);
388 // Initialize whole structure. Mainly to appease valgrind, which
389 // doesn't know about the padding at the end of sockaddr_rc which
390 // it will dutifully check for definedness. But also the standard
391 // definition of BDADDR_ANY is unusable in C++ code, so just use
392 // memset to set aAddr.rc_bdaddr to 0.
393 memset( &aAddr
, 0, sizeof( aAddr
) );
394 aAddr
.rc_family
= AF_BLUETOOTH
;
395 aAddr
.rc_channel
= 5;
398 if ( ( a
= bind( nSocket
, reinterpret_cast<sockaddr
*>(&aAddr
), sizeof(aAddr
) ) ) < 0 ) {
399 SAL_WARN( "sdremote.bluetooth", "bind failed with error" << a
);
404 if ( ( a
= listen( nSocket
, 1 ) ) < 0 )
406 SAL_WARN( "sdremote.bluetooth", "listen failed with error" << a
);
411 // set non-blocking behaviour ...
412 if( fcntl( nSocket
, F_SETFL
, O_NONBLOCK
) < 0 )
418 pSocketFD
->fd
= nSocket
;
419 pSocketFD
->events
= G_IO_IN
| G_IO_PRI
;
420 pSocketFD
->revents
= 0;
422 g_main_context_add_poll( pContext
, pSocketFD
, G_PRIORITY_DEFAULT
);
426 bluezDetachCloseSocket( GMainContext
*pContext
, GPollFD
*pSocketFD
)
428 if( pSocketFD
->fd
>= 0 )
430 close( pSocketFD
->fd
);
431 g_main_context_remove_poll( pContext
, pSocketFD
);
436 #endif // LINUX_BLUETOOTH
440 OSXBluetoothWrapper::OSXBluetoothWrapper( IOBluetoothRFCOMMChannel
* channel
) :
447 // silly enough, can't write more than mnMTU bytes at once
448 mnMTU
= [channel getMTU
];
450 SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::OSXBluetoothWrapper(): mnMTU=" << mnMTU
);
453 sal_Int32
OSXBluetoothWrapper::readLine( OString
& aLine
)
455 SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::readLine()" );
460 SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::readLine: entering mutex" );
461 ::osl::MutexGuard
aQueueGuard( mMutex
);
462 SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::readLine: entered mutex" );
465 // We should have in the sal logging some standard way to
466 // output char buffers with non-printables escaped.
467 std::ostringstream s
;
468 if (mBuffer
.size() > 0)
470 for (unsigned char *p
= reinterpret_cast<unsigned char *>(&mBuffer
.front()); p
!= reinterpret_cast<unsigned char *>(&mBuffer
.front()) + mBuffer
.size(); p
++)
474 else if (*p
< ' ' || *p
>= 0x7F)
475 s
<< "\\0x" << std::hex
<< std::setw(2) << std::setfill('0') << (int) *p
<< std::setfill(' ') << std::setw(1) << std::dec
;
480 SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::readLine mBuffer: \"" << s
.str() << "\"" );
483 // got enough bytes to return a line?
484 std::vector
<char>::iterator aIt
;
485 if ( (aIt
= find( mBuffer
.begin(), mBuffer
.end(), '\n' ))
488 sal_uInt64 aLocation
= aIt
- mBuffer
.begin();
490 aLine
= OString( &(*mBuffer
.begin()), aLocation
);
492 mBuffer
.erase( mBuffer
.begin(), aIt
+ 1 ); // Also delete the empty line
495 SAL_INFO( "sdremote.bluetooth", " returning, got \"" << OStringToOUString( aLine
, RTL_TEXTENCODING_UTF8
) << "\"" );
496 return aLine
.getLength() + 1;
499 // nope - wait some more (after releasing the mutex)
500 SAL_INFO( "sdremote.bluetooth", " resetting mHaveBytes" );
502 SAL_INFO( "sdremote.bluetooth", " leaving mutex" );
505 SAL_INFO( "sdremote.bluetooth", " waiting for mHaveBytes" );
507 SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::readLine: got mHaveBytes" );
511 sal_Int32
OSXBluetoothWrapper::write( const void* pBuffer
, sal_uInt32 n
)
513 SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::write(" << pBuffer
<< ", " << n
<< ") mpChannel=" << mpChannel
);
515 char const * ptr
= static_cast<char const *>(pBuffer
);
516 sal_uInt32 nBytesWritten
= 0;
518 if (mpChannel
== nil
)
521 while( nBytesWritten
< n
)
523 int toWrite
= n
- nBytesWritten
;
524 toWrite
= toWrite
<= mnMTU
? toWrite
: mnMTU
;
525 if ( [mpChannel writeSync
:const_cast<char *>(ptr
) length
:toWrite
] != kIOReturnSuccess
)
527 SAL_INFO( "sdremote.bluetooth", " [mpChannel writeSync:" << (void *) ptr
<< " length:" << toWrite
<< "] returned error, total written " << nBytesWritten
);
528 return nBytesWritten
;
531 nBytesWritten
+= toWrite
;
533 SAL_INFO( "sdremote.bluetooth", " total written " << nBytesWritten
);
534 return nBytesWritten
;
537 void OSXBluetoothWrapper::appendData(void* pBuffer
, size_t len
)
539 SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::appendData(" << pBuffer
<< ", " << len
<< ")" );
543 SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::appendData: entering mutex" );
544 ::osl::MutexGuard
aQueueGuard( mMutex
);
545 SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::appendData: entered mutex" );
546 mBuffer
.insert(mBuffer
.begin()+mBuffer
.size(),
547 static_cast<char*>(pBuffer
), static_cast<char *>(pBuffer
)+len
);
548 SAL_INFO( "sdremote.bluetooth", " setting mHaveBytes" );
550 SAL_INFO( "sdremote.bluetooth", " leaving mutex" );
554 void OSXBluetoothWrapper::channelClosed()
556 SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::channelClosed()" );
561 void incomingCallback( void *userRefCon
,
562 IOBluetoothUserNotificationRef inRef
,
563 IOBluetoothObjectRef objectRef
)
567 SAL_INFO( "sdremote.bluetooth", "incomingCallback()" );
569 BluetoothServer
* pServer
= static_cast<BluetoothServer
*>(userRefCon
);
571 IOBluetoothRFCOMMChannel
* channel
= [IOBluetoothRFCOMMChannel withRFCOMMChannelRef
:(IOBluetoothRFCOMMChannelRef
)objectRef
];
573 OSXBluetoothWrapper
* socket
= new OSXBluetoothWrapper( channel
);
574 Communicator
* pCommunicator
= new Communicator( socket
);
575 pServer
->addCommunicator( pCommunicator
);
577 ChannelDelegate
* delegate
= [[ChannelDelegate alloc
] initWithCommunicatorAndSocket
: pCommunicator socket
: socket
];
578 [channel setDelegate
: delegate
];
581 pCommunicator
->launch();
584 void BluetoothServer::addCommunicator( Communicator
* pCommunicator
)
586 mpCommunicators
->push_back( pCommunicator
);
591 #ifdef LINUX_BLUETOOTH
594 static gboolean
ensureDiscoverable_cb(gpointer
)
596 BluetoothServer::doEnsureDiscoverable();
597 return FALSE
; // remove source
599 static gboolean
restoreDiscoverable_cb(gpointer
)
601 BluetoothServer::doRestoreDiscoverable();
602 return FALSE
; // remove source
607 * Bluez 4 uses custom methods for setting properties, whereas Bluez 5+
608 * implements properties using the generic "org.freedesktop.DBus.Properties"
609 * interface -- hence we have a specific Bluez 4 function to deal with the
610 * old style of reading properties.
613 getBluez4BooleanProperty( DBusConnection
*pConnection
, DBusObject
*pAdapter
,
614 const char *pPropertyName
, bool *pBoolean
)
622 pMsg
= sendUnrefAndWaitForReply( pConnection
,
623 pAdapter
->getMethodCall( "GetProperties" ) );
626 if( !pMsg
|| !dbus_message_iter_init( pMsg
, &it
) )
628 SAL_WARN( "sdremote.bluetooth", "no valid reply / timeout" );
632 if( DBUS_TYPE_ARRAY
!= dbus_message_iter_get_arg_type( &it
) )
634 SAL_WARN( "sdremote.bluetooth", "no valid reply / timeout" );
638 DBusMessageIter arrayIt
;
639 dbus_message_iter_recurse( &it
, &arrayIt
);
641 while( dbus_message_iter_get_arg_type( &arrayIt
) == DBUS_TYPE_DICT_ENTRY
)
643 DBusMessageIter dictIt
;
644 dbus_message_iter_recurse( &arrayIt
, &dictIt
);
646 const char *pName
= NULL
;
647 if( dbus_message_iter_get_arg_type( &dictIt
) == DBUS_TYPE_STRING
)
649 dbus_message_iter_get_basic( &dictIt
, &pName
);
650 if( pName
!= NULL
&& !strcmp( pName
, pPropertyName
) )
652 SAL_INFO( "sdremote.bluetooth", "hit " << pPropertyName
<< " property" );
653 dbus_message_iter_next( &dictIt
);
654 dbus_bool_t bBool
= false;
656 if( dbus_message_iter_get_arg_type( &dictIt
) == DBUS_TYPE_VARIANT
)
658 DBusMessageIter variantIt
;
659 dbus_message_iter_recurse( &dictIt
, &variantIt
);
661 if( dbus_message_iter_get_arg_type( &variantIt
) == DBUS_TYPE_BOOLEAN
)
663 dbus_message_iter_get_basic( &variantIt
, &bBool
);
664 SAL_INFO( "sdremote.bluetooth", "" << pPropertyName
<< " is " << bBool
);
669 SAL_WARN( "sdremote.bluetooth", "" << pPropertyName
<< " type " <<
670 dbus_message_iter_get_arg_type( &variantIt
) );
673 SAL_WARN( "sdremote.bluetooth", "variant type ? " <<
674 dbus_message_iter_get_arg_type( &dictIt
) );
678 const char *pStr
= pName
? pName
: "<null>";
679 SAL_INFO( "sdremote.bluetooth", "property '" << pStr
<< "'" );
683 SAL_WARN( "sdremote.bluetooth", "unexpected property key type "
684 << dbus_message_iter_get_arg_type( &dictIt
) );
685 dbus_message_iter_next( &arrayIt
);
687 dbus_message_unref( pMsg
);
693 * This gets an org.freedesktop.DBus.Properties boolean
694 * (as opposed to the old Bluez 4 custom properties methods as visible above).
697 getDBusBooleanProperty( DBusConnection
*pConnection
, DBusObject
*pAdapter
,
698 const char *pPropertyName
, bool *pBoolean
)
705 ::boost::scoped_ptr
< DBusObject
> pProperties (
706 pAdapter
->cloneForInterface( "org.freedesktop.DBus.Properties" ) );
708 DBusMessage
*pMsg
= pProperties
->getMethodCall( "Get" );
710 DBusMessageIter itIn
;
711 dbus_message_iter_init_append( pMsg
, &itIn
);
712 const char* pInterface
= "org.bluez.Adapter1";
713 dbus_message_iter_append_basic( &itIn
, DBUS_TYPE_STRING
, &pInterface
);
714 dbus_message_iter_append_basic( &itIn
, DBUS_TYPE_STRING
, &pPropertyName
);
715 pMsg
= sendUnrefAndWaitForReply( pConnection
, pMsg
);
718 if( !pMsg
|| !dbus_message_iter_init( pMsg
, &it
) )
720 SAL_WARN( "sdremote.bluetooth", "no valid reply / timeout" );
724 if( DBUS_TYPE_VARIANT
!= dbus_message_iter_get_arg_type( &it
) )
726 SAL_WARN( "sdremote.bluetooth", "invalid return type" );
730 DBusMessageIter variantIt
;
731 dbus_message_iter_recurse( &it
, &variantIt
);
733 if( dbus_message_iter_get_arg_type( &variantIt
) == DBUS_TYPE_BOOLEAN
)
735 dbus_bool_t bBool
= false;
736 dbus_message_iter_get_basic( &variantIt
, &bBool
);
737 SAL_INFO( "sdremote.bluetooth", "" << pPropertyName
<< " is " << bBool
);
743 SAL_WARN( "sdremote.bluetooth", "" << pPropertyName
<< " type " <<
744 dbus_message_iter_get_arg_type( &variantIt
) );
747 const char* pError
= dbus_message_get_error_name( pMsg
);
750 SAL_WARN( "sdremote.bluetooth",
751 "Get failed for " << pPropertyName
<< " on " <<
752 pAdapter
->maPath
<< " with error: " << pError
);
755 dbus_message_unref( pMsg
);
761 setDBusBooleanProperty( DBusConnection
*pConnection
, DBusObject
*pAdapter
,
762 const char *pPropertyName
, bool bBoolean
)
766 ::boost::scoped_ptr
< DBusObject
> pProperties(
767 pAdapter
->cloneForInterface( "org.freedesktop.DBus.Properties" ) );
769 DBusMessage
*pMsg
= pProperties
->getMethodCall( "Set" );
771 DBusMessageIter itIn
;
772 dbus_message_iter_init_append( pMsg
, &itIn
);
773 const char* pInterface
= "org.bluez.Adapter1";
774 dbus_message_iter_append_basic( &itIn
, DBUS_TYPE_STRING
, &pInterface
);
775 dbus_message_iter_append_basic( &itIn
, DBUS_TYPE_STRING
, &pPropertyName
);
778 DBusMessageIter varIt
;
779 dbus_message_iter_open_container( &itIn
, DBUS_TYPE_VARIANT
,
780 DBUS_TYPE_BOOLEAN_AS_STRING
, &varIt
);
781 dbus_bool_t bDBusBoolean
= bBoolean
;
782 dbus_message_iter_append_basic( &varIt
, DBUS_TYPE_BOOLEAN
, &bDBusBoolean
);
783 dbus_message_iter_close_container( &itIn
, &varIt
);
786 pMsg
= sendUnrefAndWaitForReply( pConnection
, pMsg
);
790 SAL_WARN( "sdremote.bluetooth", "no valid reply / timeout" );
794 const char* pError
= dbus_message_get_error_name( pMsg
);
797 SAL_WARN( "sdremote.bluetooth",
798 "Set failed for " << pPropertyName
<< " on " <<
799 pAdapter
->maPath
<< " with error: " << pError
);
801 dbus_message_unref( pMsg
);
806 getDiscoverable( DBusConnection
*pConnection
, DBusObject
*pAdapter
)
808 if (pAdapter
->maInterface
== "org.bluez.Adapter") // Bluez 4
811 if( getBluez4BooleanProperty(pConnection
, pAdapter
, "Discoverable", &bDiscoverable
) )
812 return bDiscoverable
;
814 else if (pAdapter
->maInterface
== "org.bluez.Adapter1") // Bluez 5
817 if ( getDBusBooleanProperty(pConnection
, pAdapter
, "Discoverable", &bDiscoverable
) )
818 return bDiscoverable
;
824 setDiscoverable( DBusConnection
*pConnection
, DBusObject
*pAdapter
, bool bDiscoverable
)
826 SAL_INFO( "sdremote.bluetooth", "setDiscoverable to " << bDiscoverable
);
828 if (pAdapter
->maInterface
== "org.bluez.Adapter") // Bluez 4
830 bool bPowered
= false;
831 if( !getBluez4BooleanProperty( pConnection
, pAdapter
, "Powered", &bPowered
) || !bPowered
)
832 return; // nothing to do
835 DBusMessageIter it
, varIt
;
837 // set timeout to zero
838 pMsg
= pAdapter
->getMethodCall( "SetProperty" );
839 dbus_message_iter_init_append( pMsg
, &it
);
840 const char *pTimeoutStr
= "DiscoverableTimeout";
841 dbus_message_iter_append_basic( &it
, DBUS_TYPE_STRING
, &pTimeoutStr
);
842 dbus_message_iter_open_container( &it
, DBUS_TYPE_VARIANT
,
843 DBUS_TYPE_UINT32_AS_STRING
, &varIt
);
844 dbus_uint32_t nTimeout
= 0;
845 dbus_message_iter_append_basic( &varIt
, DBUS_TYPE_UINT32
, &nTimeout
);
846 dbus_message_iter_close_container( &it
, &varIt
);
847 dbus_connection_send( pConnection
, pMsg
, NULL
); // async send - why not ?
848 dbus_message_unref( pMsg
);
850 // set discoverable value
851 pMsg
= pAdapter
->getMethodCall( "SetProperty" );
852 dbus_message_iter_init_append( pMsg
, &it
);
853 const char *pDiscoverableStr
= "Discoverable";
854 dbus_message_iter_append_basic( &it
, DBUS_TYPE_STRING
, &pDiscoverableStr
);
855 dbus_message_iter_open_container( &it
, DBUS_TYPE_VARIANT
,
856 DBUS_TYPE_BOOLEAN_AS_STRING
, &varIt
);
857 dbus_bool_t bValue
= bDiscoverable
;
858 dbus_message_iter_append_basic( &varIt
, DBUS_TYPE_BOOLEAN
, &bValue
);
859 dbus_message_iter_close_container( &it
, &varIt
); // async send - why not ?
860 dbus_connection_send( pConnection
, pMsg
, NULL
);
861 dbus_message_unref( pMsg
);
863 else if (pAdapter
->maInterface
== "org.bluez.Adapter1") // Bluez 5
865 setDBusBooleanProperty(pConnection
, pAdapter
, "Discoverable", bDiscoverable
);
870 registerWithDefaultAdapter( DBusConnection
*pConnection
)
872 DBusObject
*pService
;
873 pService
= bluez4GetDefaultService( pConnection
);
876 if( !bluez4RegisterServiceRecord( pConnection
, pService
,
877 bluetooth_service_record
) )
887 void ProfileUnregisterFunction
888 (DBusConnection
*connection
, void *user_data
)
890 // We specifically don't need to do anything here.
895 DBusHandlerResult ProfileMessageFunction
896 (DBusConnection
*pConnection
, DBusMessage
*pMessage
, void *user_data
)
898 SAL_INFO("sdremote.bluetooth", "ProfileMessageFunction||" << dbus_message_get_interface(pMessage
) << "||" << dbus_message_get_member(pMessage
));
899 DBusHandlerResult aRet
= DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
901 if (OString(dbus_message_get_interface(pMessage
)).equals("org.bluez.Profile1"))
903 if (OString(dbus_message_get_member(pMessage
)).equals("Release"))
905 return DBUS_HANDLER_RESULT_HANDLED
;
907 else if (OString(dbus_message_get_member(pMessage
)).equals("NewConnection"))
909 if (!dbus_message_has_signature(pMessage
, "oha{sv}"))
911 SAL_WARN("sdremote.bluetooth", "wrong signature for NewConnection");
915 if (!dbus_message_iter_init(pMessage
, &it
))
916 SAL_WARN( "sdremote.bluetooth", "error init dbus" );
920 dbus_message_iter_get_basic(&it
, &pPath
);
921 SAL_INFO("sdremote.bluetooth", "Adapter path:" << pPath
);
923 if (!dbus_message_iter_next(&it
))
924 SAL_WARN("sdremote.bluetooth", "not enough parameters passed");
926 // DBUS_TYPE_UNIX_FD == 'h' -- doesn't exist in older versions
927 // of dbus (< 1.3?) hence defined manually for now
928 if ('h' == dbus_message_iter_get_arg_type(&it
))
932 dbus_message_iter_get_basic(&it
, &nDescriptor
);
933 std::vector
<Communicator
*>* pCommunicators
= static_cast<std::vector
<Communicator
*>*>(user_data
);
935 // Bluez gives us non-blocking sockets, but our code relies
936 // on blocking behaviour.
937 (void)fcntl(nDescriptor
, F_SETFL
, fcntl(nDescriptor
, F_GETFL
) & ~O_NONBLOCK
);
939 SAL_INFO( "sdremote.bluetooth", "connection accepted " << nDescriptor
);
940 Communicator
* pCommunicator
= new Communicator( new BufferedStreamSocket( nDescriptor
) );
941 pCommunicators
->push_back( pCommunicator
);
942 pCommunicator
->launch();
945 // For some reason an (empty?) reply is expected.
946 DBusMessage
* pRet
= dbus_message_new_method_return(pMessage
);
947 dbus_connection_send(pConnection
, pRet
, NULL
);
948 dbus_message_unref(pRet
);
950 // We could read the remote profile version and features here
951 // (i.e. they are provided as part of the DBusMessage),
952 // however for us they are irrelevant (as our protocol handles
953 // equivalent functionality independently of whether we're on
954 // bluetooth or normal network connection).
955 return DBUS_HANDLER_RESULT_HANDLED
;
958 else if (OString(dbus_message_get_member(pMessage
)).equals("RequestDisconnection"))
960 return DBUS_HANDLER_RESULT_HANDLED
;
963 SAL_WARN("sdremote.bluetooth", "Couldn't handle message correctly.");
969 setupBluez5Profile1(DBusConnection
* pConnection
, std::vector
<Communicator
*>* pCommunicators
)
973 SAL_INFO("sdremote.bluetooth", "Attempting to register our org.bluez.Profile1");
974 static DBusObjectPathVTable aVTable
;
975 aVTable
.unregister_function
= ProfileUnregisterFunction
;
976 aVTable
.message_function
= ProfileMessageFunction
;
978 // dbus_connection_try_register_object_path could be used but only exists for
979 // dbus-glib >= 1.2 -- we really shouldn't be trying this twice in any case.
980 // (dbus_connection_try_register_object_path also returns an error with more
981 // information which could be useful for debugging purposes.)
982 bErr
= !dbus_connection_register_object_path(pConnection
, "/org/libreoffice/bluez/profile1", &aVTable
, pCommunicators
);
986 SAL_WARN("sdremote.bluetooth", "Failed to register Bluez 5 Profile1 callback, bluetooth won't work.");
989 dbus_connection_flush( pConnection
);
993 unregisterBluez5Profile(DBusConnection
* pConnection
)
995 DBusMessage
* pMsg
= dbus_message_new_method_call("org.bluez", "/org/bluez",
996 "org.bluez.ProfileManager1", "UnregisterProfile");
998 dbus_message_iter_init_append(pMsg
, &it
);
1000 const char *pPath
= "/org/libreoffice/bluez/profile1";
1001 dbus_message_iter_append_basic(&it
, DBUS_TYPE_OBJECT_PATH
, &pPath
);
1003 pMsg
= sendUnrefAndWaitForReply( pConnection
, pMsg
);
1006 dbus_message_unref(pMsg
);
1008 dbus_connection_unregister_object_path( pConnection
, "/org/libreoffice/bluez/profile1");
1010 dbus_connection_flush(pConnection
);
1014 registerBluez5Profile(DBusConnection
* pConnection
, std::vector
<Communicator
*>* pCommunicators
)
1016 setupBluez5Profile1(pConnection
, pCommunicators
);
1021 pMsg
= dbus_message_new_method_call("org.bluez", "/org/bluez",
1022 "org.bluez.ProfileManager1", "RegisterProfile");
1023 dbus_message_iter_init_append(pMsg
, &it
);
1025 const char *pPath
= "/org/libreoffice/bluez/profile1";
1026 dbus_message_iter_append_basic(&it
, DBUS_TYPE_OBJECT_PATH
, &pPath
);
1027 const char *pUUID
= "spp"; // Bluez translates this to 0x1101 for spp
1028 dbus_message_iter_append_basic(&it
, DBUS_TYPE_STRING
, &pUUID
);
1030 DBusMessageIter aOptionsIter
;
1031 dbus_message_iter_open_container(&it
, DBUS_TYPE_ARRAY
, "{sv}", &aOptionsIter
);
1033 DBusMessageIter aEntry
;
1036 dbus_message_iter_open_container(&aOptionsIter
, DBUS_TYPE_DICT_ENTRY
, NULL
, &aEntry
);
1038 const char *pString
= "Name";
1039 dbus_message_iter_append_basic(&aEntry
, DBUS_TYPE_STRING
, &pString
);
1041 const char *pValue
= "LibreOffice Impress Remote";
1042 DBusMessageIter aValue
;
1043 dbus_message_iter_open_container(&aEntry
, DBUS_TYPE_VARIANT
, "s", &aValue
);
1044 dbus_message_iter_append_basic(&aValue
, DBUS_TYPE_STRING
, &pValue
);
1045 dbus_message_iter_close_container(&aEntry
, &aValue
);
1046 dbus_message_iter_close_container(&aOptionsIter
, &aEntry
);
1049 dbus_message_iter_close_container(&it
, &aOptionsIter
);
1051 // Other properties that we could set (but don't, since they appear
1052 // to be useless for us):
1053 // "Service": "0x1101" (not needed, but we used to have it in the manually defined profile).
1054 // "Role": setting this to "server" breaks things, although we think we're a server?
1055 // "Channel": seems to be dealt with automatically (but we used to use 5 in the manual profile).
1057 bool bSuccess
= true;
1059 pMsg
= sendUnrefAndWaitForReply( pConnection
, pMsg
);
1062 dbus_error_init(&aError
);
1063 if (pMsg
&& dbus_set_error_from_message( &aError
, pMsg
))
1066 SAL_WARN("sdremote.bluetooth",
1067 "Failed to register our Profile1 with bluez ProfileManager "
1068 << (aError
.message
? aError
.message
: "<null>"));
1071 dbus_error_free(&aError
);
1073 dbus_message_unref(pMsg
);
1075 dbus_connection_flush(pConnection
);
1080 #endif // LINUX_BLUETOOTH
1082 BluetoothServer::BluetoothServer( std::vector
<Communicator
*>* pCommunicators
)
1083 : meWasDiscoverable( UNKNOWN
),
1084 mpCommunicators( pCommunicators
)
1086 #ifdef LINUX_BLUETOOTH
1087 // D-Bus requires the following in order to be thread-safe (and we
1088 // potentially access D-Bus from different threads in different places of
1090 if (!dbus_threads_init_default()) {
1091 throw std::bad_alloc();
1094 mpImpl
.reset(new BluetoothServer::Impl());
1098 BluetoothServer::~BluetoothServer()
1102 void BluetoothServer::ensureDiscoverable()
1104 #ifdef LINUX_BLUETOOTH
1105 // Push it all across into our mainloop
1108 GSource
*pIdle
= g_idle_source_new();
1109 g_source_set_callback( pIdle
, ensureDiscoverable_cb
, NULL
, NULL
);
1110 g_source_set_priority( pIdle
, G_PRIORITY_DEFAULT
);
1111 g_source_attach( pIdle
, spServer
->mpImpl
->mpContext
);
1112 g_source_unref( pIdle
);
1116 void BluetoothServer::restoreDiscoverable()
1118 #ifdef LINUX_BLUETOOTH
1119 // Push it all across into our mainloop
1122 GSource
*pIdle
= g_idle_source_new();
1123 g_source_set_callback( pIdle
, restoreDiscoverable_cb
, NULL
, NULL
);
1124 g_source_set_priority( pIdle
, G_PRIORITY_DEFAULT_IDLE
);
1125 g_source_attach( pIdle
, spServer
->mpImpl
->mpContext
);
1126 g_source_unref( pIdle
);
1130 void BluetoothServer::doEnsureDiscoverable()
1132 #ifdef LINUX_BLUETOOTH
1133 if (!spServer
->mpImpl
->mpConnection
||
1134 spServer
->meWasDiscoverable
!= UNKNOWN
)
1137 // Find out if we are discoverable already ...
1138 DBusObject
*pAdapter
= spServer
->mpImpl
->getAdapter();
1142 bool bDiscoverable
= getDiscoverable(spServer
->mpImpl
->mpConnection
, pAdapter
);
1144 spServer
->meWasDiscoverable
= bDiscoverable
? DISCOVERABLE
: NOT_DISCOVERABLE
;
1145 if( !bDiscoverable
)
1146 setDiscoverable( spServer
->mpImpl
->mpConnection
, pAdapter
, true );
1152 void BluetoothServer::doRestoreDiscoverable()
1154 if( spServer
->meWasDiscoverable
== NOT_DISCOVERABLE
)
1156 #ifdef LINUX_BLUETOOTH
1157 DBusObject
*pAdapter
= spServer
->mpImpl
->getAdapter();
1160 setDiscoverable( spServer
->mpImpl
->mpConnection
, pAdapter
, false );
1164 spServer
->meWasDiscoverable
= UNKNOWN
;
1167 // We have to have all our clients shut otherwise we can't
1168 // re-bind to the same port number it appears.
1169 void BluetoothServer::cleanupCommunicators()
1171 for (std::vector
<Communicator
*>::iterator it
= mpCommunicators
->begin();
1172 it
!= mpCommunicators
->end(); ++it
)
1173 (*it
)->forceClose();
1174 // the hope is that all the threads then terminate cleanly and
1175 // clean themselves up.
1178 void SAL_CALL
BluetoothServer::run()
1180 SAL_INFO( "sdremote.bluetooth", "BluetoothServer::run called" );
1181 osl::Thread::setName("BluetoothServer");
1182 #ifdef LINUX_BLUETOOTH
1183 DBusConnection
*pConnection
= dbusConnectToNameOnBus();
1187 // For either implementation we need to poll the dbus fd
1190 if( dbus_connection_get_unix_fd( pConnection
, &fd
) && fd
>= 0 )
1193 aDBusFD
.events
= G_IO_IN
| G_IO_PRI
;
1194 g_main_context_add_poll( mpImpl
->mpContext
, &aDBusFD
, G_PRIORITY_DEFAULT
);
1197 SAL_WARN( "sdremote.bluetooth", "failed to poll for incoming dbus signals" );
1199 if (isBluez5Available(pConnection
))
1201 SAL_INFO("sdremote.bluetooth", "Using Bluez 5");
1202 registerBluez5Profile(pConnection
, mpCommunicators
);
1203 mpImpl
->mpConnection
= pConnection
;
1204 mpImpl
->maBluezVersion
= Impl::BLUEZ5
;
1206 // We don't need to listen to adapter changes anymore -- profile
1207 // registration is done globally for the entirety of bluez, so we only
1208 // need adapters when setting discovereability, which can be done
1209 // dyanmically without the need to listen for changes.
1211 // TODO: exit on SD deinit
1212 // Probably best to do that in SdModule::~SdModule?
1213 while (!mpImpl
->mbExitMainloop
)
1215 aDBusFD
.revents
= 0;
1216 g_main_context_iteration( mpImpl
->mpContext
, TRUE
);
1217 if( aDBusFD
.revents
)
1219 dbus_connection_read_write( pConnection
, 0 );
1220 while (DBUS_DISPATCH_DATA_REMAINS
== dbus_connection_get_dispatch_status( pConnection
))
1221 dbus_connection_dispatch( pConnection
);
1224 unregisterBluez5Profile( pConnection
);
1225 g_main_context_unref( mpImpl
->mpContext
);
1226 mpImpl
->mpConnection
= NULL
;
1227 mpImpl
->mpContext
= NULL
;
1231 // Otherwise we could be on Bluez 4 and continue as usual.
1232 mpImpl
->maBluezVersion
= Impl::BLUEZ4
;
1234 // Try to setup the default adapter, otherwise wait for add/remove signal
1235 mpImpl
->mpService
= registerWithDefaultAdapter( pConnection
);
1236 // listen for connection state and power changes - we need to close
1237 // and re-create our socket code on suspend / resume, enable/disable
1239 dbus_error_init( &aError
);
1240 dbus_bus_add_match( pConnection
, "type='signal',interface='org.bluez.Manager'", &aError
);
1241 dbus_connection_flush( pConnection
);
1243 // Try to setup the default adapter, otherwise wait for add/remove signal
1244 mpImpl
->mpService
= registerWithDefaultAdapter( pConnection
);
1246 // poll on our bluetooth socket - if we can.
1248 if( mpImpl
->mpService
)
1249 bluezCreateAttachListeningSocket( mpImpl
->mpContext
, &aSocketFD
);
1251 mpImpl
->mpConnection
= pConnection
;
1253 while( !mpImpl
->mbExitMainloop
)
1255 aDBusFD
.revents
= 0;
1256 aSocketFD
.revents
= 0;
1257 g_main_context_iteration( mpImpl
->mpContext
, TRUE
);
1259 SAL_INFO( "sdremote.bluetooth", "main-loop spin "
1260 << aDBusFD
.revents
<< " " << aSocketFD
.revents
);
1261 if( aDBusFD
.revents
)
1263 dbus_connection_read_write( pConnection
, 0 );
1264 DBusMessage
*pMsg
= dbus_connection_pop_message( pConnection
);
1267 if( dbus_message_is_signal( pMsg
, "org.bluez.Manager", "AdapterRemoved" ) )
1269 SAL_WARN( "sdremote.bluetooth", "lost adapter - cleaning up sockets" );
1270 bluezDetachCloseSocket( mpImpl
->mpContext
, &aSocketFD
);
1271 cleanupCommunicators();
1273 else if( dbus_message_is_signal( pMsg
, "org.bluez.Manager", "AdapterAdded" ) ||
1274 dbus_message_is_signal( pMsg
, "org.bluez.Manager", "DefaultAdapterChanged" ) )
1276 SAL_WARN( "sdremote.bluetooth", "gained adapter - re-generating sockets" );
1277 bluezDetachCloseSocket( mpImpl
->mpContext
, &aSocketFD
);
1278 cleanupCommunicators();
1279 mpImpl
->mpService
= registerWithDefaultAdapter( pConnection
);
1280 if( mpImpl
->mpService
)
1281 bluezCreateAttachListeningSocket( mpImpl
->mpContext
, &aSocketFD
);
1284 SAL_INFO( "sdremote.bluetooth", "unknown incoming dbus message, "
1285 " type: " << dbus_message_get_type( pMsg
)
1286 << " path: '" << dbus_message_get_path( pMsg
)
1287 << "' interface: '" << dbus_message_get_interface( pMsg
)
1288 << "' member: '" << dbus_message_get_member( pMsg
) );
1290 dbus_message_unref( pMsg
);
1293 if( aSocketFD
.revents
)
1295 sockaddr_rc aRemoteAddr
;
1296 socklen_t aRemoteAddrLen
= sizeof(aRemoteAddr
);
1299 SAL_INFO( "sdremote.bluetooth", "performing accept" );
1300 if ( ( nClient
= accept( aSocketFD
.fd
, reinterpret_cast<sockaddr
*>(&aRemoteAddr
), &aRemoteAddrLen
)) < 0 &&
1303 SAL_WARN( "sdremote.bluetooth", "accept failed with errno " << errno
);
1305 SAL_INFO( "sdremote.bluetooth", "connection accepted " << nClient
);
1306 Communicator
* pCommunicator
= new Communicator( new BufferedStreamSocket( nClient
) );
1307 mpCommunicators
->push_back( pCommunicator
);
1308 pCommunicator
->launch();
1313 unregisterBluez5Profile( pConnection
);
1314 g_main_context_unref( mpImpl
->mpContext
);
1315 mpImpl
->mpConnection
= NULL
;
1316 mpImpl
->mpContext
= NULL
;
1318 #elif defined(WIN32)
1319 WORD wVersionRequested
;
1322 wVersionRequested
= MAKEWORD(2, 2);
1324 if ( WSAStartup(wVersionRequested
, &wsaData
) )
1326 return; // winsock dll couldn't be loaded
1329 int aSocket
= socket( AF_BTH
, SOCK_STREAM
, BTHPROTO_RFCOMM
);
1336 aAddr
.addressFamily
= AF_BTH
;
1338 aAddr
.serviceClassId
= GUID_NULL
;
1339 aAddr
.port
= BT_PORT_ANY
; // Select any free socket.
1340 if ( bind( aSocket
, (SOCKADDR
*) &aAddr
, sizeof(aAddr
) ) == SOCKET_ERROR
)
1342 closesocket( aSocket
);
1348 int aNameSize
= sizeof(aName
);
1349 getsockname( aSocket
, &aName
, &aNameSize
); // Retrieve the local address and port
1351 CSADDR_INFO aAddrInfo
;
1352 memset( &aAddrInfo
, 0, sizeof(aAddrInfo
) );
1353 aAddrInfo
.LocalAddr
.lpSockaddr
= &aName
;
1354 aAddrInfo
.LocalAddr
.iSockaddrLength
= sizeof( SOCKADDR_BTH
);
1355 aAddrInfo
.RemoteAddr
.lpSockaddr
= &aName
;
1356 aAddrInfo
.RemoteAddr
.iSockaddrLength
= sizeof( SOCKADDR_BTH
);
1357 aAddrInfo
.iSocketType
= SOCK_STREAM
;
1358 aAddrInfo
.iProtocol
= BTHPROTO_RFCOMM
;
1360 // To be used for setting a custom UUID once available.
1362 // uuid.Data1 = 0x00001101;
1363 // memset( &uuid, 0x1000 + UUID*2^96, sizeof( GUID ) );
1365 // uuid.Data3 = 0x1000;
1366 // ULONGLONG aData4 = 0x800000805F9B34FB;
1367 // memcpy( uuid.Data4, &aData4, sizeof(uuid.Data4) );
1369 WSAQUERYSETW aRecord
;
1370 memset( &aRecord
, 0, sizeof(aRecord
));
1371 aRecord
.dwSize
= sizeof(aRecord
);
1372 aRecord
.lpszServiceInstanceName
= L
"LibreOffice Impress Remote Control";
1373 aRecord
.lpszComment
= L
"Remote control of presentations over bluetooth.";
1374 aRecord
.lpServiceClassId
= (LPGUID
) &SerialPortServiceClass_UUID
;
1375 aRecord
.dwNameSpace
= NS_BTH
;
1376 aRecord
.dwNumberOfCsAddrs
= 1;
1377 aRecord
.lpcsaBuffer
= &aAddrInfo
;
1379 if (WSASetServiceW( &aRecord
, RNRSERVICE_REGISTER
, 0 ) == SOCKET_ERROR
)
1381 closesocket( aSocket
);
1386 if ( listen( aSocket
, 1 ) == SOCKET_ERROR
)
1388 closesocket( aSocket
);
1393 SOCKADDR_BTH aRemoteAddr
;
1394 int aRemoteAddrLen
= sizeof(aRemoteAddr
);
1398 if ( (socket
= accept(aSocket
, (sockaddr
*) &aRemoteAddr
, &aRemoteAddrLen
)) == INVALID_SOCKET
)
1400 closesocket( aSocket
);
1404 Communicator
* pCommunicator
= new Communicator( new BufferedStreamSocket( socket
) );
1405 mpCommunicators
->push_back( pCommunicator
);
1406 pCommunicator
->launch();
1410 #elif defined(MACOSX)
1411 // Build up dictionary at run-time instead of bothering with a
1412 // .plist file, using the Objective-C API
1414 // Compare to BluetoothServiceRecord.hxx
1416 NSAutoreleasePool
* pool
= [[NSAutoreleasePool alloc
] init
];
1418 NSDictionary
*dict
=
1419 [NSDictionary dictionaryWithObjectsAndKeys
:
1421 // Service class ID list
1422 [NSArray arrayWithObject
:
1423 [IOBluetoothSDPUUID uuid16
: kBluetoothSDPUUID16ServiceClassSerialPort
]],
1424 @
"0001 - ServiceClassIDList",
1426 // Protocol descriptor list
1427 [NSArray arrayWithObjects
:
1428 [NSArray arrayWithObject
: [IOBluetoothSDPUUID uuid16
: kBluetoothSDPUUID16L2CAP
]],
1429 [NSArray arrayWithObjects
:
1430 [IOBluetoothSDPUUID uuid16
: kBluetoothL2CAPPSMRFCOMM
],
1431 [NSDictionary dictionaryWithObjectsAndKeys
:
1432 [NSNumber numberWithInt
: 1],
1434 [NSNumber numberWithInt
: 1],
1436 [NSNumber numberWithInt
: 5], // RFCOMM port number, will be replaced if necessary automatically
1437 @
"DataElementValue",
1441 @
"0004 - Protocol descriptor list",
1443 // Browse group list
1444 [NSArray arrayWithObject
:
1445 [IOBluetoothSDPUUID uuid16
: kBluetoothSDPUUID16ServiceClassPublicBrowseGroup
]],
1446 @
"0005 - BrowseGroupList",
1448 // Language base attribute ID list
1449 [NSArray arrayWithObjects
:
1450 [NSData dataWithBytes
: "en" length
: 2],
1451 [NSDictionary dictionaryWithObjectsAndKeys
:
1452 [NSNumber numberWithInt
: 2],
1454 [NSNumber numberWithInt
: 1],
1456 [NSNumber numberWithInt
: 0x006a], // encoding
1457 @
"DataElementValue",
1459 [NSDictionary dictionaryWithObjectsAndKeys
:
1460 [NSNumber numberWithInt
: 2],
1462 [NSNumber numberWithInt
: 1],
1464 [NSNumber numberWithInt
: 0x0100], // offset
1465 @
"DataElementValue",
1468 @
"0006 - LanguageBaseAttributeIDList",
1470 // Bluetooth profile descriptor list
1471 [NSArray arrayWithObject
:
1472 [NSArray arrayWithObjects
:
1473 [IOBluetoothSDPUUID uuid16
: kBluetoothSDPUUID16ServiceClassSerialPort
],
1474 [NSDictionary dictionaryWithObjectsAndKeys
:
1475 [NSNumber numberWithInt
: 2],
1477 [NSNumber numberWithInt
: 1],
1479 [NSNumber numberWithInt
: 0x0100], // version number ?
1480 @
"DataElementValue",
1483 @
"0009 - BluetoothProfileDescriptorList",
1485 // Attributes pointed to by the LanguageBaseAttributeIDList
1486 @
"LibreOffice Impress Remote Control",
1487 @
"0100 - ServiceName",
1488 @
"The Document Foundation",
1489 @
"0102 - ProviderName",
1493 IOBluetoothSDPServiceRecordRef serviceRecordRef
;
1494 SAL_WNODEPRECATED_DECLARATIONS_PUSH
//TODO: 10.9 IOBluetoothAddServiceDict
1495 IOReturn rc
= IOBluetoothAddServiceDict(reinterpret_cast<CFDictionaryRef
>(dict
), &serviceRecordRef
);
1496 SAL_WNODEPRECATED_DECLARATIONS_POP
1498 SAL_INFO("sdremote.bluetooth", "IOBluetoothAddServiceDict returned " << rc
);
1500 if (rc
== kIOReturnSuccess
)
1502 IOBluetoothSDPServiceRecord
*serviceRecord
=
1503 [IOBluetoothSDPServiceRecord withSDPServiceRecordRef
: serviceRecordRef
];
1505 BluetoothRFCOMMChannelID channelID
;
1506 [serviceRecord getRFCOMMChannelID
: &channelID
];
1508 BluetoothSDPServiceRecordHandle serviceRecordHandle
;
1509 [serviceRecord getServiceRecordHandle
: &serviceRecordHandle
];
1511 // Register callback for incoming connections
1512 IOBluetoothUserNotificationRef callbackRef
=
1513 IOBluetoothRegisterForFilteredRFCOMMChannelOpenNotifications(
1517 kIOBluetoothUserNotificationChannelDirectionIncoming
);
1521 [serviceRecord release
];
1526 (void) mpCommunicators
;
1528 (void) mpCommunicators
; // avoid warnings about unused member
1532 BluetoothServer
*sd::BluetoothServer::spServer
= NULL
;
1534 void BluetoothServer::setup( std::vector
<Communicator
*>* pCommunicators
)
1539 spServer
= new BluetoothServer( pCommunicators
);
1543 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */