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"
15 #include <boost/scoped_ptr.hpp>
17 #include <sal/log.hxx>
19 #ifdef LINUX_BLUETOOTH
21 #include <dbus/dbus.h>
24 #include <sys/unistd.h>
25 #include <sys/socket.h>
26 #include <bluetooth/bluetooth.h>
27 #include <bluetooth/rfcomm.h>
28 #include "BluetoothServiceRecord.hxx"
29 #include "BufferedStreamSocket.hxx"
33 // LO vs WinAPI conflict
38 #include "BufferedStreamSocket.hxx"
42 #include <osl/conditn.hxx> // Include this early to avoid error as check() gets defined by some SDK header to empty
44 #if MACOSX_SDK_VERSION >= 1070
45 #import <IOBluetooth/IOBluetooth.h>
47 #import <CoreFoundation/CoreFoundation.h>
48 #import <IOBluetooth/IOBluetoothUtilities.h>
49 #import <IOBluetooth/objc/IOBluetoothSDPUUID.h>
50 #import <IOBluetooth/objc/IOBluetoothSDPServiceRecord.h>
53 #import "OSXBluetooth.h"
54 #include "OSXBluetoothWrapper.hxx"
58 // Value taken from http://msdn.microsoft.com/en-us/library/windows/desktop/ms738518%28v=vs.85%29.aspx
62 #include "Communicator.hxx"
66 #ifdef LINUX_BLUETOOTH
74 DBusObject( const char *pBusName
, const char *pPath
, const char *pInterface
)
75 : maBusName( pBusName
), maPath( pPath
), maInterface( pInterface
) { }
77 DBusMessage
*getMethodCall( const char *pName
)
79 return dbus_message_new_method_call( maBusName
.getStr(), maPath
.getStr(),
80 maInterface
.getStr(), pName
);
82 DBusObject
*cloneForInterface( const char *pInterface
)
84 DBusObject
*pObject
= new DBusObject();
86 pObject
->maBusName
= maBusName
;
87 pObject
->maPath
= maPath
;
88 pObject
->maInterface
= pInterface
;
94 static DBusObject
* getBluez5Adapter(DBusConnection
*pConnection
);
96 struct sd::BluetoothServer::Impl
{
97 // the glib mainloop running in the thread
98 GMainContext
*mpContext
;
99 DBusConnection
*mpConnection
;
100 DBusObject
*mpService
;
101 volatile bool mbExitMainloop
;
102 enum BluezVersion
{ BLUEZ4
, BLUEZ5
, UNKNOWN
};
103 BluezVersion maBluezVersion
;
106 : mpContext( g_main_context_new() )
107 , mpConnection( NULL
)
109 , mbExitMainloop( false )
110 , maBluezVersion( UNKNOWN
)
113 DBusObject
*getAdapter()
117 DBusObject
* pAdapter
= mpService
->cloneForInterface( "org.bluez.Adapter" );
120 else if (spServer
->mpImpl
->maBluezVersion
== BLUEZ5
)
122 return getBluez5Adapter(mpConnection
);
131 static DBusConnection
*
132 dbusConnectToNameOnBus()
135 DBusConnection
*pConnection
;
137 dbus_error_init( &aError
);
139 pConnection
= dbus_bus_get( DBUS_BUS_SYSTEM
, &aError
);
140 if( !pConnection
|| dbus_error_is_set( &aError
))
142 SAL_WARN( "sdremote.bluetooth", "failed to get dbus system bus: " << aError
.message
);
143 dbus_error_free( &aError
);
151 sendUnrefAndWaitForReply( DBusConnection
*pConnection
, DBusMessage
*pMsg
)
153 DBusPendingCall
*pPending
= NULL
;
155 if( !pMsg
|| !dbus_connection_send_with_reply( pConnection
, pMsg
, &pPending
,
156 -1 /* default timeout */ ) )
158 SAL_WARN( "sdremote.bluetooth", "Memory allocation failed on message send" );
159 dbus_message_unref( pMsg
);
162 dbus_connection_flush( pConnection
);
163 dbus_message_unref( pMsg
);
165 dbus_pending_call_block( pPending
); // block for reply
167 pMsg
= dbus_pending_call_steal_reply( pPending
);
169 SAL_WARN( "sdremote.bluetooth", "no valid reply / timeout" );
171 dbus_pending_call_unref( pPending
);
176 isBluez5Available(DBusConnection
*pConnection
)
180 // Simplest wasy to check whether we have Bluez 5+ is to check
181 // that we can obtain adapters using the new interfaces.
182 // The first two error checks however don't tell us anything as they should
183 // succeed as long as dbus is working correctly.
184 pMsg
= DBusObject( "org.bluez", "/", "org.freedesktop.DBus.ObjectManager" ).getMethodCall( "GetManagedObjects" );
187 SAL_INFO("sdremote.bluetooth", "No GetManagedObjects call created");
191 pMsg
= sendUnrefAndWaitForReply( pConnection
, pMsg
);
194 SAL_INFO("sdremote.bluetooth", "No reply received");
198 // If dbus is working correctly and we aren't on bluez 5 this is where we
199 // should actually get the error.
200 if (dbus_message_get_error_name( pMsg
))
202 SAL_INFO( "sdremote.bluetooth", "GetManagedObjects call failed with \""
203 << dbus_message_get_error_name( pMsg
)
204 << "\" -- we don't seem to have Bluez 5 available");
207 SAL_INFO("sdremote.bluetooth", "GetManagedObjects call seems to have succeeded -- we must be on Bluez 5");
208 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 aAddr
.rc_family
= AF_BLUETOOTH
;
389 // BDADDR_ANY is broken, so use memset to set to 0.
390 memset( &aAddr
.rc_bdaddr
, 0, sizeof( aAddr
.rc_bdaddr
) );
391 aAddr
.rc_channel
= 5;
394 if ( ( a
= bind( nSocket
, (sockaddr
*) &aAddr
, sizeof(aAddr
) ) ) < 0 ) {
395 SAL_WARN( "sdremote.bluetooth", "bind failed with error" << a
);
400 if ( ( a
= listen( nSocket
, 1 ) ) < 0 )
402 SAL_WARN( "sdremote.bluetooth", "listen failed with error" << a
);
407 // set non-blocking behaviour ...
408 if( fcntl( nSocket
, F_SETFL
, O_NONBLOCK
) < 0 )
414 pSocketFD
->fd
= nSocket
;
415 pSocketFD
->events
= G_IO_IN
| G_IO_PRI
;
416 pSocketFD
->revents
= 0;
418 g_main_context_add_poll( pContext
, pSocketFD
, G_PRIORITY_DEFAULT
);
422 bluezDetachCloseSocket( GMainContext
*pContext
, GPollFD
*pSocketFD
)
424 if( pSocketFD
->fd
>= 0 )
426 close( pSocketFD
->fd
);
427 g_main_context_remove_poll( pContext
, pSocketFD
);
432 #endif // LINUX_BLUETOOTH
434 void BluetoothServer::addCommunicator( Communicator
* pCommunicator
)
436 mpCommunicators
->push_back( pCommunicator
);
441 OSXBluetoothWrapper::OSXBluetoothWrapper( IOBluetoothRFCOMMChannel
* channel
) :
448 // silly enough, can't write more than mnMTU bytes at once
449 mnMTU
= [channel getMTU
];
451 SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::OSXBluetoothWrapper(): mnMTU=" << mnMTU
);
454 sal_Int32
OSXBluetoothWrapper::readLine( OString
& aLine
)
456 SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::readLine()" );
461 SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::readLine: entering mutex" );
462 ::osl::MutexGuard
aQueueGuard( mMutex
);
463 SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::readLine: entered mutex" );
466 // We should have in the sal logging some standard way to
467 // output char buffers with non-printables escaped.
468 std::ostringstream s
;
469 if (mBuffer
.size() > 0)
471 for (unsigned char *p
= (unsigned char *) &mBuffer
.front(); p
!= (unsigned char *) &mBuffer
.front() + mBuffer
.size(); p
++)
475 else if (*p
< ' ' || *p
>= 0x7F)
476 s
<< "\\0x" << std::hex
<< std::setw(2) << std::setfill('0') << (int) *p
<< std::setfill(' ') << std::setw(1) << std::dec
;
481 SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::readLine mBuffer: \"" << s
.str() << "\"" );
484 // got enough bytes to return a line?
485 std::vector
<char>::iterator aIt
;
486 if ( (aIt
= find( mBuffer
.begin(), mBuffer
.end(), '\n' ))
489 sal_uInt64 aLocation
= aIt
- mBuffer
.begin();
491 aLine
= OString( &(*mBuffer
.begin()), aLocation
);
493 mBuffer
.erase( mBuffer
.begin(), aIt
+ 1 ); // Also delete the empty line
496 SAL_INFO( "sdremote.bluetooth", " returning, got \"" << OStringToOUString( aLine
, RTL_TEXTENCODING_UTF8
) << "\"" );
497 return aLine
.getLength() + 1;
500 // nope - wait some more (after releasing the mutex)
501 SAL_INFO( "sdremote.bluetooth", " resetting mHaveBytes" );
503 SAL_INFO( "sdremote.bluetooth", " leaving mutex" );
506 SAL_INFO( "sdremote.bluetooth", " waiting for mHaveBytes" );
508 SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::readLine: got mHaveBytes" );
512 sal_Int32
OSXBluetoothWrapper::write( const void* pBuffer
, sal_uInt32 n
)
514 SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::write(" << pBuffer
<< ", " << n
<< ") mpChannel=" << mpChannel
);
516 char* ptr
= (char*)pBuffer
;
517 sal_uInt32 nBytesWritten
= 0;
519 if (mpChannel
== nil
)
522 while( nBytesWritten
< n
)
524 int toWrite
= n
- nBytesWritten
;
525 toWrite
= toWrite
<= mnMTU
? toWrite
: mnMTU
;
526 if ( [mpChannel writeSync
:ptr length
:toWrite
] != kIOReturnSuccess
)
528 SAL_INFO( "sdremote.bluetooth", " [mpChannel writeSync:" << (void *) ptr
<< " length:" << toWrite
<< "] returned error, total written " << nBytesWritten
);
529 return nBytesWritten
;
532 nBytesWritten
+= toWrite
;
534 SAL_INFO( "sdremote.bluetooth", " total written " << nBytesWritten
);
535 return nBytesWritten
;
538 void OSXBluetoothWrapper::appendData(void* pBuffer
, size_t len
)
540 SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::appendData(" << pBuffer
<< ", " << len
<< ")" );
544 SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::appendData: entering mutex" );
545 ::osl::MutexGuard
aQueueGuard( mMutex
);
546 SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::appendData: entered mutex" );
547 mBuffer
.insert(mBuffer
.begin()+mBuffer
.size(),
548 (char*)pBuffer
, (char *)pBuffer
+len
);
549 SAL_INFO( "sdremote.bluetooth", " setting mHaveBytes" );
551 SAL_INFO( "sdremote.bluetooth", " leaving mutex" );
555 void OSXBluetoothWrapper::channelClosed()
557 SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::channelClosed()" );
562 void incomingCallback( void *userRefCon
,
563 IOBluetoothUserNotificationRef inRef
,
564 IOBluetoothObjectRef objectRef
)
568 SAL_INFO( "sdremote.bluetooth", "incomingCallback()" );
570 BluetoothServer
* pServer
= (BluetoothServer
*)userRefCon
;
572 IOBluetoothRFCOMMChannel
* channel
= [IOBluetoothRFCOMMChannel withRFCOMMChannelRef
:(IOBluetoothRFCOMMChannelRef
)objectRef
];
574 OSXBluetoothWrapper
* socket
= new OSXBluetoothWrapper( channel
);
575 Communicator
* pCommunicator
= new Communicator( socket
);
576 pServer
->addCommunicator( pCommunicator
);
578 ChannelDelegate
* delegate
= [[ChannelDelegate alloc
] initWithCommunicatorAndSocket
: pCommunicator socket
: socket
];
579 [channel setDelegate
: delegate
];
582 pCommunicator
->launch();
587 #ifdef LINUX_BLUETOOTH
590 static gboolean
ensureDiscoverable_cb(gpointer
)
592 BluetoothServer::doEnsureDiscoverable();
593 return FALSE
; // remove source
595 static gboolean
restoreDiscoverable_cb(gpointer
)
597 BluetoothServer::doRestoreDiscoverable();
598 return FALSE
; // remove source
603 * Bluez 4 uses custom methods for setting properties, whereas Bluez 5+
604 * implements properties using the generic "org.freedesktop.DBus.Properties"
605 * interface -- hence we have a specific Bluez 4 function to deal with the
606 * old style of reading properties.
609 getBluez4BooleanProperty( DBusConnection
*pConnection
, DBusObject
*pAdapter
,
610 const char *pPropertyName
, bool *pBoolean
)
618 pMsg
= sendUnrefAndWaitForReply( pConnection
,
619 pAdapter
->getMethodCall( "GetProperties" ) );
622 if( !pMsg
|| !dbus_message_iter_init( pMsg
, &it
) )
624 SAL_WARN( "sdremote.bluetooth", "no valid reply / timeout" );
628 if( DBUS_TYPE_ARRAY
!= dbus_message_iter_get_arg_type( &it
) )
630 SAL_WARN( "sdremote.bluetooth", "no valid reply / timeout" );
634 DBusMessageIter arrayIt
;
635 dbus_message_iter_recurse( &it
, &arrayIt
);
637 while( dbus_message_iter_get_arg_type( &arrayIt
) == DBUS_TYPE_DICT_ENTRY
)
639 DBusMessageIter dictIt
;
640 dbus_message_iter_recurse( &arrayIt
, &dictIt
);
642 const char *pName
= NULL
;
643 if( dbus_message_iter_get_arg_type( &dictIt
) == DBUS_TYPE_STRING
)
645 dbus_message_iter_get_basic( &dictIt
, &pName
);
646 if( pName
!= NULL
&& !strcmp( pName
, pPropertyName
) )
648 SAL_INFO( "sdremote.bluetooth", "hit " << pPropertyName
<< " property" );
649 dbus_message_iter_next( &dictIt
);
650 dbus_bool_t bBool
= false;
652 if( dbus_message_iter_get_arg_type( &dictIt
) == DBUS_TYPE_VARIANT
)
654 DBusMessageIter variantIt
;
655 dbus_message_iter_recurse( &dictIt
, &variantIt
);
657 if( dbus_message_iter_get_arg_type( &variantIt
) == DBUS_TYPE_BOOLEAN
)
659 dbus_message_iter_get_basic( &variantIt
, &bBool
);
660 SAL_INFO( "sdremote.bluetooth", "" << pPropertyName
<< " is " << bBool
);
665 SAL_WARN( "sdremote.bluetooth", "" << pPropertyName
<< " type " <<
666 dbus_message_iter_get_arg_type( &variantIt
) );
669 SAL_WARN( "sdremote.bluetooth", "variant type ? " <<
670 dbus_message_iter_get_arg_type( &dictIt
) );
674 const char *pStr
= pName
? pName
: "<null>";
675 SAL_INFO( "sdremote.bluetooth", "property '" << pStr
<< "'" );
679 SAL_WARN( "sdremote.bluetooth", "unexpected property key type "
680 << dbus_message_iter_get_arg_type( &dictIt
) );
681 dbus_message_iter_next( &arrayIt
);
683 dbus_message_unref( pMsg
);
689 * This gets an org.freedesktop.DBus.Properties boolean
690 * (as opposed to the old Bluez 4 custom properties methods as visible above).
693 getDBusBooleanProperty( DBusConnection
*pConnection
, DBusObject
*pAdapter
,
694 const char *pPropertyName
, bool *pBoolean
)
701 ::boost::scoped_ptr
< DBusObject
> pProperties (
702 pAdapter
->cloneForInterface( "org.freedesktop.DBus.Properties" ) );
704 DBusMessage
*pMsg
= pProperties
->getMethodCall( "Get" );
706 DBusMessageIter itIn
;
707 dbus_message_iter_init_append( pMsg
, &itIn
);
708 const char* pInterface
= "org.bluez.Adapter1";
709 dbus_message_iter_append_basic( &itIn
, DBUS_TYPE_STRING
, &pInterface
);
710 dbus_message_iter_append_basic( &itIn
, DBUS_TYPE_STRING
, &pPropertyName
);
711 pMsg
= sendUnrefAndWaitForReply( pConnection
, pMsg
);
714 if( !pMsg
|| !dbus_message_iter_init( pMsg
, &it
) )
716 SAL_WARN( "sdremote.bluetooth", "no valid reply / timeout" );
720 if( DBUS_TYPE_VARIANT
!= dbus_message_iter_get_arg_type( &it
) )
722 SAL_WARN( "sdremote.bluetooth", "invalid return type" );
726 DBusMessageIter variantIt
;
727 dbus_message_iter_recurse( &it
, &variantIt
);
729 if( dbus_message_iter_get_arg_type( &variantIt
) == DBUS_TYPE_BOOLEAN
)
731 dbus_bool_t bBool
= false;
732 dbus_message_iter_get_basic( &variantIt
, &bBool
);
733 SAL_INFO( "sdremote.bluetooth", "" << pPropertyName
<< " is " << bBool
);
739 SAL_WARN( "sdremote.bluetooth", "" << pPropertyName
<< " type " <<
740 dbus_message_iter_get_arg_type( &variantIt
) );
743 const char* pError
= dbus_message_get_error_name( pMsg
);
746 SAL_WARN( "sdremote.bluetooth",
747 "Get failed for " << pPropertyName
<< " on " <<
748 pAdapter
->maPath
<< " with error: " << pError
);
751 dbus_message_unref( pMsg
);
757 setDBusBooleanProperty( DBusConnection
*pConnection
, DBusObject
*pAdapter
,
758 const char *pPropertyName
, bool bBoolean
)
762 ::boost::scoped_ptr
< DBusObject
> pProperties(
763 pAdapter
->cloneForInterface( "org.freedesktop.DBus.Properties" ) );
765 DBusMessage
*pMsg
= pProperties
->getMethodCall( "Set" );
767 DBusMessageIter itIn
;
768 dbus_message_iter_init_append( pMsg
, &itIn
);
769 const char* pInterface
= "org.bluez.Adapter1";
770 dbus_message_iter_append_basic( &itIn
, DBUS_TYPE_STRING
, &pInterface
);
771 dbus_message_iter_append_basic( &itIn
, DBUS_TYPE_STRING
, &pPropertyName
);
774 DBusMessageIter varIt
;
775 dbus_message_iter_open_container( &itIn
, DBUS_TYPE_VARIANT
,
776 DBUS_TYPE_BOOLEAN_AS_STRING
, &varIt
);
777 dbus_bool_t bDBusBoolean
= bBoolean
;
778 dbus_message_iter_append_basic( &varIt
, DBUS_TYPE_BOOLEAN
, &bDBusBoolean
);
779 dbus_message_iter_close_container( &itIn
, &varIt
);
782 pMsg
= sendUnrefAndWaitForReply( pConnection
, pMsg
);
786 SAL_WARN( "sdremote.bluetooth", "no valid reply / timeout" );
790 const char* pError
= dbus_message_get_error_name( pMsg
);
793 SAL_WARN( "sdremote.bluetooth",
794 "Set failed for " << pPropertyName
<< " on " <<
795 pAdapter
->maPath
<< " with error: " << pError
);
797 dbus_message_unref( pMsg
);
802 getDiscoverable( DBusConnection
*pConnection
, DBusObject
*pAdapter
)
804 if (pAdapter
->maInterface
== "org.bluez.Adapter") // Bluez 4
807 if( getBluez4BooleanProperty(pConnection
, pAdapter
, "Discoverable", &bDiscoverable
) )
808 return bDiscoverable
;
810 else if (pAdapter
->maInterface
== "org.bluez.Adapter1") // Bluez 5
813 if ( getDBusBooleanProperty(pConnection
, pAdapter
, "Discoverable", &bDiscoverable
) )
814 return bDiscoverable
;
820 setDiscoverable( DBusConnection
*pConnection
, DBusObject
*pAdapter
, bool bDiscoverable
)
822 SAL_INFO( "sdremote.bluetooth", "setDiscoverable to " << bDiscoverable
);
824 if (pAdapter
->maInterface
== "org.bluez.Adapter") // Bluez 4
826 bool bPowered
= false;
827 if( !getBluez4BooleanProperty( pConnection
, pAdapter
, "Powered", &bPowered
) || !bPowered
)
828 return; // nothing to do
831 DBusMessageIter it
, varIt
;
833 // set timeout to zero
834 pMsg
= pAdapter
->getMethodCall( "SetProperty" );
835 dbus_message_iter_init_append( pMsg
, &it
);
836 const char *pTimeoutStr
= "DiscoverableTimeout";
837 dbus_message_iter_append_basic( &it
, DBUS_TYPE_STRING
, &pTimeoutStr
);
838 dbus_message_iter_open_container( &it
, DBUS_TYPE_VARIANT
,
839 DBUS_TYPE_UINT32_AS_STRING
, &varIt
);
840 dbus_uint32_t nTimeout
= 0;
841 dbus_message_iter_append_basic( &varIt
, DBUS_TYPE_UINT32
, &nTimeout
);
842 dbus_message_iter_close_container( &it
, &varIt
);
843 dbus_connection_send( pConnection
, pMsg
, NULL
); // async send - why not ?
844 dbus_message_unref( pMsg
);
846 // set discoverable value
847 pMsg
= pAdapter
->getMethodCall( "SetProperty" );
848 dbus_message_iter_init_append( pMsg
, &it
);
849 const char *pDiscoverableStr
= "Discoverable";
850 dbus_message_iter_append_basic( &it
, DBUS_TYPE_STRING
, &pDiscoverableStr
);
851 dbus_message_iter_open_container( &it
, DBUS_TYPE_VARIANT
,
852 DBUS_TYPE_BOOLEAN_AS_STRING
, &varIt
);
853 dbus_bool_t bValue
= bDiscoverable
;
854 dbus_message_iter_append_basic( &varIt
, DBUS_TYPE_BOOLEAN
, &bValue
);
855 dbus_message_iter_close_container( &it
, &varIt
); // async send - why not ?
856 dbus_connection_send( pConnection
, pMsg
, NULL
);
857 dbus_message_unref( pMsg
);
859 else if (pAdapter
->maInterface
== "org.bluez.Adapter1") // Bluez 5
861 setDBusBooleanProperty(pConnection
, pAdapter
, "Discoverable", bDiscoverable
);
866 registerWithDefaultAdapter( DBusConnection
*pConnection
)
868 DBusObject
*pService
;
869 pService
= bluez4GetDefaultService( pConnection
);
872 if( !bluez4RegisterServiceRecord( pConnection
, pService
,
873 bluetooth_service_record
) )
883 void ProfileUnregisterFunction
884 (DBusConnection
*connection
, void *user_data
)
886 // We specifically don't need to do anything here.
891 DBusHandlerResult ProfileMessageFunction
892 (DBusConnection
*pConnection
, DBusMessage
*pMessage
, void *user_data
)
894 SAL_INFO("sdremote.bluetooth", "ProfileMessageFunction||" << dbus_message_get_interface(pMessage
) << "||" << dbus_message_get_member(pMessage
));
895 DBusHandlerResult aRet
= DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
897 if (OString(dbus_message_get_interface(pMessage
)).equals("org.bluez.Profile1"))
899 if (OString(dbus_message_get_member(pMessage
)).equals("Release"))
901 return DBUS_HANDLER_RESULT_HANDLED
;
903 else if (OString(dbus_message_get_member(pMessage
)).equals("NewConnection"))
905 if (!dbus_message_has_signature(pMessage
, "oha{sv}"))
907 SAL_WARN("sdremote.bluetooth", "wrong signature for NewConnection");
911 dbus_message_iter_init(pMessage
, &it
);
914 dbus_message_iter_get_basic(&it
, &pPath
);
915 SAL_INFO("sdremote.bluetooth", "Adapter path:" << pPath
);
917 if (!dbus_message_iter_next(&it
))
918 SAL_WARN("sdremote.bluetooth", "not enough parameters passed");
920 // DBUS_TYPE_UNIX_FD == 'h' -- doesn't exist in older versions
921 // of dbus (< 1.3?) hence defined manually for now
922 if ('h' == dbus_message_iter_get_arg_type(&it
))
926 dbus_message_iter_get_basic(&it
, &nDescriptor
);
927 std::vector
<Communicator
*>* pCommunicators
= (std::vector
<Communicator
*>*) user_data
;
929 // Bluez gives us non-blocking sockets, but our code relies
930 // on blocking behaviour.
931 fcntl(nDescriptor
, F_SETFL
, fcntl(nDescriptor
, F_GETFL
) & ~O_NONBLOCK
);
933 SAL_INFO( "sdremote.bluetooth", "connection accepted " << nDescriptor
);
934 Communicator
* pCommunicator
= new Communicator( new BufferedStreamSocket( nDescriptor
) );
935 pCommunicators
->push_back( pCommunicator
);
936 pCommunicator
->launch();
939 // For some reason an (empty?) reply is expected.
940 DBusMessage
* pRet
= dbus_message_new_method_return(pMessage
);
941 dbus_connection_send(pConnection
, pRet
, NULL
);
942 dbus_message_unref(pRet
);
944 // We could read the remote profile version and features here
945 // (i.e. they are provided as part of the DBusMessage),
946 // however for us they are irrelevant (as our protocol handles
947 // equivalent functionality independently of whether we're on
948 // bluetooth or normal network connection).
949 return DBUS_HANDLER_RESULT_HANDLED
;
951 else if (OString(dbus_message_get_member(pMessage
)).equals("RequestDisconnection"))
953 return DBUS_HANDLER_RESULT_HANDLED
;
956 SAL_WARN("sdremote.bluetooth", "Couldn't handle message correctly.");
962 setupBluez5Profile1(DBusConnection
* pConnection
, std::vector
<Communicator
*>* pCommunicators
)
966 SAL_INFO("sdremote.bluetooth", "Attempting to register our org.bluez.Profile1");
967 static DBusObjectPathVTable aVTable
;
968 aVTable
.unregister_function
= ProfileUnregisterFunction
;
969 aVTable
.message_function
= ProfileMessageFunction
;
971 // dbus_connection_try_register_object_path could be used but only exists for
972 // dbus-glib >= 1.2 -- we really shouldn't be trying this twice in any case.
973 // (dbus_connection_try_register_object_path also returns an error with more
974 // information which could be useful for debugging purposes.)
975 bErr
= !dbus_connection_register_object_path(pConnection
, "/org/libreoffice/bluez/profile1", &aVTable
, pCommunicators
);
979 SAL_WARN("sdremote.bluetooth", "Failed to register Bluez 5 Profile1 callback, bluetooth won't work.");
982 dbus_connection_flush( pConnection
);
986 unregisterBluez5Profile(DBusConnection
* pConnection
)
988 DBusMessage
* pMsg
= dbus_message_new_method_call("org.bluez", "/org/bluez",
989 "org.bluez.ProfileManager1", "UnregisterProfile");
991 dbus_message_iter_init_append(pMsg
, &it
);
993 const char *pPath
= "/org/libreoffice/bluez/profile1";
994 dbus_message_iter_append_basic(&it
, DBUS_TYPE_OBJECT_PATH
, &pPath
);
996 pMsg
= sendUnrefAndWaitForReply( pConnection
, pMsg
);
999 dbus_message_unref(pMsg
);
1001 dbus_connection_unregister_object_path( pConnection
, "/org/libreoffice/bluez/profile1");
1003 dbus_connection_flush(pConnection
);
1007 registerBluez5Profile(DBusConnection
* pConnection
, std::vector
<Communicator
*>* pCommunicators
)
1009 setupBluez5Profile1(pConnection
, pCommunicators
);
1014 pMsg
= dbus_message_new_method_call("org.bluez", "/org/bluez",
1015 "org.bluez.ProfileManager1", "RegisterProfile");
1016 dbus_message_iter_init_append(pMsg
, &it
);
1018 const char *pPath
= "/org/libreoffice/bluez/profile1";
1019 dbus_message_iter_append_basic(&it
, DBUS_TYPE_OBJECT_PATH
, &pPath
);
1020 const char *pUUID
= "spp"; // Bluez translates this to 0x1101 for spp
1021 dbus_message_iter_append_basic(&it
, DBUS_TYPE_STRING
, &pUUID
);
1023 DBusMessageIter aOptionsIter
;
1024 dbus_message_iter_open_container(&it
, DBUS_TYPE_ARRAY
, "{sv}", &aOptionsIter
);
1026 DBusMessageIter aEntry
;
1029 dbus_message_iter_open_container(&aOptionsIter
, DBUS_TYPE_DICT_ENTRY
, NULL
, &aEntry
);
1031 const char *pString
= "Name";
1032 dbus_message_iter_append_basic(&aEntry
, DBUS_TYPE_STRING
, &pString
);
1034 const char *pValue
= "LibreOffice Impress Remote";
1035 DBusMessageIter aValue
;
1036 dbus_message_iter_open_container(&aEntry
, DBUS_TYPE_VARIANT
, "s", &aValue
);
1037 dbus_message_iter_append_basic(&aValue
, DBUS_TYPE_STRING
, &pValue
);
1038 dbus_message_iter_close_container(&aEntry
, &aValue
);
1039 dbus_message_iter_close_container(&aOptionsIter
, &aEntry
);
1042 dbus_message_iter_close_container(&it
, &aOptionsIter
);
1044 // Other properties that we could set (but don't, since they appear
1045 // to be useless for us):
1046 // "Service": "0x1101" (not needed, but we used to have it in the manually defined profile).
1047 // "Role": setting this to "server" breaks things, although we think we're a server?
1048 // "Channel": seems to be dealt with automatically (but we used to use 5 in the manual profile).
1050 bool bSuccess
= true;
1052 pMsg
= sendUnrefAndWaitForReply( pConnection
, pMsg
);
1055 dbus_error_init(&aError
);
1056 if (pMsg
&& dbus_set_error_from_message( &aError
, pMsg
))
1059 SAL_WARN("sdremote.bluetooth",
1060 "Failed to register our Profile1 with bluez ProfileManager "
1061 << (const char *)(aError
.message
? aError
.message
: "<null>"));
1064 dbus_error_free(&aError
);
1066 dbus_message_unref(pMsg
);
1068 dbus_connection_flush(pConnection
);
1073 #endif // LINUX_BLUETOOTH
1075 BluetoothServer::BluetoothServer( std::vector
<Communicator
*>* pCommunicators
)
1076 : meWasDiscoverable( UNKNOWN
),
1077 mpCommunicators( pCommunicators
)
1079 #ifdef LINUX_BLUETOOTH
1080 mpImpl
.reset(new BluetoothServer::Impl());
1084 BluetoothServer::~BluetoothServer()
1088 void BluetoothServer::ensureDiscoverable()
1090 #ifdef LINUX_BLUETOOTH
1091 // Push it all across into our mainloop
1094 GSource
*pIdle
= g_idle_source_new();
1095 g_source_set_callback( pIdle
, ensureDiscoverable_cb
, NULL
, NULL
);
1096 g_source_set_priority( pIdle
, G_PRIORITY_DEFAULT
);
1097 g_source_attach( pIdle
, spServer
->mpImpl
->mpContext
);
1098 g_source_unref( pIdle
);
1102 void BluetoothServer::restoreDiscoverable()
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
, restoreDiscoverable_cb
, NULL
, NULL
);
1110 g_source_set_priority( pIdle
, G_PRIORITY_DEFAULT_IDLE
);
1111 g_source_attach( pIdle
, spServer
->mpImpl
->mpContext
);
1112 g_source_unref( pIdle
);
1116 void BluetoothServer::doEnsureDiscoverable()
1118 #ifdef LINUX_BLUETOOTH
1119 if (!spServer
->mpImpl
->mpConnection
||
1120 spServer
->meWasDiscoverable
!= UNKNOWN
)
1123 // Find out if we are discoverable already ...
1124 DBusObject
*pAdapter
= spServer
->mpImpl
->getAdapter();
1128 bool bDiscoverable
= getDiscoverable(spServer
->mpImpl
->mpConnection
, pAdapter
);
1130 spServer
->meWasDiscoverable
= bDiscoverable
? DISCOVERABLE
: NOT_DISCOVERABLE
;
1131 if( !bDiscoverable
)
1132 setDiscoverable( spServer
->mpImpl
->mpConnection
, pAdapter
, true );
1138 void BluetoothServer::doRestoreDiscoverable()
1140 if( spServer
->meWasDiscoverable
== NOT_DISCOVERABLE
)
1142 #ifdef LINUX_BLUETOOTH
1143 DBusObject
*pAdapter
= spServer
->mpImpl
->getAdapter();
1146 setDiscoverable( spServer
->mpImpl
->mpConnection
, pAdapter
, false );
1150 spServer
->meWasDiscoverable
= UNKNOWN
;
1153 // We have to have all our clients shut otherwise we can't
1154 // re-bind to the same port number it appears.
1155 void BluetoothServer::cleanupCommunicators()
1157 for (std::vector
<Communicator
*>::iterator it
= mpCommunicators
->begin();
1158 it
!= mpCommunicators
->end(); ++it
)
1159 (*it
)->forceClose();
1160 // the hope is that all the threads then terminate cleanly and
1161 // clean themselves up.
1164 void SAL_CALL
BluetoothServer::run()
1166 SAL_INFO( "sdremote.bluetooth", "BluetoothServer::run called" );
1168 #ifdef LINUX_BLUETOOTH
1169 DBusConnection
*pConnection
= dbusConnectToNameOnBus();
1174 // For either implementation we need to poll the dbus fd
1177 if( dbus_connection_get_unix_fd( pConnection
, &fd
) && fd
>= 0 )
1180 aDBusFD
.events
= G_IO_IN
| G_IO_PRI
;
1181 g_main_context_add_poll( mpImpl
->mpContext
, &aDBusFD
, G_PRIORITY_DEFAULT
);
1184 SAL_WARN( "sdremote.bluetooth", "failed to poll for incoming dbus signals" );
1186 if (isBluez5Available(pConnection
))
1188 SAL_INFO("sdremote.bluetooth", "Using Bluez 5");
1189 registerBluez5Profile(pConnection
, mpCommunicators
);
1190 mpImpl
->mpConnection
= pConnection
;
1191 mpImpl
->maBluezVersion
= Impl::BLUEZ5
;
1193 // We don't need to listen to adapter changes anymore -- profile
1194 // registration is done globally for the entirety of bluez, so we only
1195 // need adapters when setting discovereability, which can be done
1196 // dyanmically without the need to listen for changes.
1198 // TODO: exit on SD deinit
1199 // Probably best to do that in SdModule::~SdModule?
1200 while (!mpImpl
->mbExitMainloop
)
1202 aDBusFD
.revents
= 0;
1203 g_main_context_iteration( mpImpl
->mpContext
, TRUE
);
1204 if( aDBusFD
.revents
)
1206 dbus_connection_read_write( pConnection
, 0 );
1207 while (DBUS_DISPATCH_DATA_REMAINS
== dbus_connection_get_dispatch_status( pConnection
))
1208 dbus_connection_dispatch( pConnection
);
1211 unregisterBluez5Profile( pConnection
);
1212 g_main_context_unref( mpImpl
->mpContext
);
1213 mpImpl
->mpConnection
= NULL
;
1214 mpImpl
->mpContext
= NULL
;
1218 // Otherwise we could be on Bluez 4 and continue as usual.
1219 mpImpl
->maBluezVersion
= Impl::BLUEZ4
;
1221 // Try to setup the default adapter, otherwise wait for add/remove signal
1222 mpImpl
->mpService
= registerWithDefaultAdapter( pConnection
);
1223 // listen for connection state and power changes - we need to close
1224 // and re-create our socket code on suspend / resume, enable/disable
1226 dbus_error_init( &aError
);
1227 dbus_bus_add_match( pConnection
, "type='signal',interface='org.bluez.Manager'", &aError
);
1228 dbus_connection_flush( pConnection
);
1230 // Try to setup the default adapter, otherwise wait for add/remove signal
1231 mpImpl
->mpService
= registerWithDefaultAdapter( pConnection
);
1233 // poll on our bluetooth socket - if we can.
1235 if( mpImpl
->mpService
)
1236 bluezCreateAttachListeningSocket( mpImpl
->mpContext
, &aSocketFD
);
1238 mpImpl
->mpConnection
= pConnection
;
1240 while( !mpImpl
->mbExitMainloop
)
1242 aDBusFD
.revents
= 0;
1243 aSocketFD
.revents
= 0;
1244 g_main_context_iteration( mpImpl
->mpContext
, TRUE
);
1246 SAL_INFO( "sdremote.bluetooth", "main-loop spin "
1247 << aDBusFD
.revents
<< " " << aSocketFD
.revents
);
1248 if( aDBusFD
.revents
)
1250 dbus_connection_read_write( pConnection
, 0 );
1251 DBusMessage
*pMsg
= dbus_connection_pop_message( pConnection
);
1254 if( dbus_message_is_signal( pMsg
, "org.bluez.Manager", "AdapterRemoved" ) )
1256 SAL_WARN( "sdremote.bluetooth", "lost adapter - cleaning up sockets" );
1257 bluezDetachCloseSocket( mpImpl
->mpContext
, &aSocketFD
);
1258 cleanupCommunicators();
1260 else if( dbus_message_is_signal( pMsg
, "org.bluez.Manager", "AdapterAdded" ) ||
1261 dbus_message_is_signal( pMsg
, "org.bluez.Manager", "DefaultAdapterChanged" ) )
1263 SAL_WARN( "sdremote.bluetooth", "gained adapter - re-generating sockets" );
1264 bluezDetachCloseSocket( mpImpl
->mpContext
, &aSocketFD
);
1265 cleanupCommunicators();
1266 mpImpl
->mpService
= registerWithDefaultAdapter( pConnection
);
1267 if( mpImpl
->mpService
)
1268 bluezCreateAttachListeningSocket( mpImpl
->mpContext
, &aSocketFD
);
1271 SAL_INFO( "sdremote.bluetooth", "unknown incoming dbus message, "
1272 << " type: " << dbus_message_get_type( pMsg
)
1273 << " path: '" << dbus_message_get_path( pMsg
)
1274 << "' interface: '" << dbus_message_get_interface( pMsg
)
1275 << "' member: '" << dbus_message_get_member( pMsg
) );
1277 dbus_message_unref( pMsg
);
1280 if( aSocketFD
.revents
)
1282 sockaddr_rc aRemoteAddr
;
1283 socklen_t aRemoteAddrLen
= sizeof(aRemoteAddr
);
1286 SAL_INFO( "sdremote.bluetooth", "performing accept" );
1287 if ( ( nClient
= accept( aSocketFD
.fd
, (sockaddr
*) &aRemoteAddr
, &aRemoteAddrLen
)) < 0 &&
1290 SAL_WARN( "sdremote.bluetooth", "accept failed with errno " << errno
);
1292 SAL_INFO( "sdremote.bluetooth", "connection accepted " << nClient
);
1293 Communicator
* pCommunicator
= new Communicator( new BufferedStreamSocket( nClient
) );
1294 mpCommunicators
->push_back( pCommunicator
);
1295 pCommunicator
->launch();
1300 unregisterBluez5Profile( pConnection
);
1301 g_main_context_unref( mpImpl
->mpContext
);
1302 mpImpl
->mpConnection
= NULL
;
1303 mpImpl
->mpContext
= NULL
;
1305 #elif defined(WIN32)
1306 WORD wVersionRequested
;
1309 wVersionRequested
= MAKEWORD(2, 2);
1311 if ( WSAStartup(wVersionRequested
, &wsaData
) )
1313 return; // winsock dll couldn't be loaded
1316 int aSocket
= socket( AF_BTH
, SOCK_STREAM
, BTHPROTO_RFCOMM
);
1323 aAddr
.addressFamily
= AF_BTH
;
1325 aAddr
.serviceClassId
= GUID_NULL
;
1326 aAddr
.port
= BT_PORT_ANY
; // Select any free socket.
1327 if ( bind( aSocket
, (SOCKADDR
*) &aAddr
, sizeof(aAddr
) ) == SOCKET_ERROR
)
1329 closesocket( aSocket
);
1335 int aNameSize
= sizeof(aAddr
);
1336 getsockname( aSocket
, &aName
, &aNameSize
); // Retrieve the local address and port
1338 CSADDR_INFO aAddrInfo
;
1339 memset( &aAddrInfo
, 0, sizeof(aAddrInfo
) );
1340 aAddrInfo
.LocalAddr
.lpSockaddr
= &aName
;
1341 aAddrInfo
.LocalAddr
.iSockaddrLength
= sizeof( SOCKADDR_BTH
);
1342 aAddrInfo
.RemoteAddr
.lpSockaddr
= &aName
;
1343 aAddrInfo
.RemoteAddr
.iSockaddrLength
= sizeof( SOCKADDR_BTH
);
1344 aAddrInfo
.iSocketType
= SOCK_STREAM
;
1345 aAddrInfo
.iProtocol
= BTHPROTO_RFCOMM
;
1347 // To be used for setting a custom UUID once available.
1349 // uuid.Data1 = 0x00001101;
1350 // memset( &uuid, 0x1000 + UUID*2^96, sizeof( GUID ) );
1352 // uuid.Data3 = 0x1000;
1353 // ULONGLONG aData4 = 0x800000805F9B34FB;
1354 // memcpy( uuid.Data4, &aData4, sizeof(uuid.Data4) );
1356 WSAQUERYSET aRecord
;
1357 memset( &aRecord
, 0, sizeof(aRecord
));
1358 aRecord
.dwSize
= sizeof(aRecord
);
1359 aRecord
.lpszServiceInstanceName
= "LibreOffice Impress Remote Control";
1360 aRecord
.lpszComment
= "Remote control of presentations over bluetooth.";
1361 aRecord
.lpServiceClassId
= (LPGUID
) &SerialPortServiceClass_UUID
;
1362 aRecord
.dwNameSpace
= NS_BTH
;
1363 aRecord
.dwNumberOfCsAddrs
= 1;
1364 aRecord
.lpcsaBuffer
= &aAddrInfo
;
1366 if ( WSASetService( &aRecord
, RNRSERVICE_REGISTER
, 0 ) == SOCKET_ERROR
)
1368 closesocket( aSocket
);
1373 if ( listen( aSocket
, 1 ) == SOCKET_ERROR
)
1375 closesocket( aSocket
);
1380 SOCKADDR_BTH aRemoteAddr
;
1381 int aRemoteAddrLen
= sizeof(aRemoteAddr
);
1385 if ( (socket
= accept(aSocket
, (sockaddr
*) &aRemoteAddr
, &aRemoteAddrLen
)) == INVALID_SOCKET
)
1387 closesocket( aSocket
);
1391 Communicator
* pCommunicator
= new Communicator( new BufferedStreamSocket( socket
) );
1392 mpCommunicators
->push_back( pCommunicator
);
1393 pCommunicator
->launch();
1397 #elif defined(MACOSX)
1398 // Build up dictionary at run-time instead of bothering with a
1399 // .plist file, using the Objective-C API
1401 // Compare to BluetoothServiceRecord.hxx
1403 NSAutoreleasePool
* pool
= [[NSAutoreleasePool alloc
] init
];
1405 NSDictionary
*dict
=
1406 [NSDictionary dictionaryWithObjectsAndKeys
:
1408 // Service class ID list
1409 [NSArray arrayWithObject
:
1410 [IOBluetoothSDPUUID uuid16
: kBluetoothSDPUUID16ServiceClassSerialPort
]],
1411 @
"0001 - ServiceClassIDList",
1413 // Protocol descriptor list
1414 [NSArray arrayWithObjects
:
1415 [NSArray arrayWithObject
: [IOBluetoothSDPUUID uuid16
: kBluetoothSDPUUID16L2CAP
]],
1416 [NSArray arrayWithObjects
:
1417 [IOBluetoothSDPUUID uuid16
: kBluetoothL2CAPPSMRFCOMM
],
1418 [NSDictionary dictionaryWithObjectsAndKeys
:
1419 [NSNumber numberWithInt
: 1],
1421 [NSNumber numberWithInt
: 1],
1423 [NSNumber numberWithInt
: 5], // RFCOMM port number, will be replaced if necessary automatically
1424 @
"DataElementValue",
1428 @
"0004 - Protocol descriptor list",
1430 // Browse group list
1431 [NSArray arrayWithObject
:
1432 [IOBluetoothSDPUUID uuid16
: kBluetoothSDPUUID16ServiceClassPublicBrowseGroup
]],
1433 @
"0005 - BrowseGroupList",
1435 // Language base attribute ID list
1436 [NSArray arrayWithObjects
:
1437 [NSData dataWithBytes
: "en" length
: 2],
1438 [NSDictionary dictionaryWithObjectsAndKeys
:
1439 [NSNumber numberWithInt
: 2],
1441 [NSNumber numberWithInt
: 1],
1443 [NSNumber numberWithInt
: 0x006a], // encoding
1444 @
"DataElementValue",
1446 [NSDictionary dictionaryWithObjectsAndKeys
:
1447 [NSNumber numberWithInt
: 2],
1449 [NSNumber numberWithInt
: 1],
1451 [NSNumber numberWithInt
: 0x0100], // offset
1452 @
"DataElementValue",
1455 @
"0006 - LanguageBaseAttributeIDList",
1457 // Bluetooth profile descriptor list
1458 [NSArray arrayWithObject
:
1459 [NSArray arrayWithObjects
:
1460 [IOBluetoothSDPUUID uuid16
: kBluetoothSDPUUID16ServiceClassSerialPort
],
1461 [NSDictionary dictionaryWithObjectsAndKeys
:
1462 [NSNumber numberWithInt
: 2],
1464 [NSNumber numberWithInt
: 1],
1466 [NSNumber numberWithInt
: 0x0100], // version number ?
1467 @
"DataElementValue",
1470 @
"0009 - BluetoothProfileDescriptorList",
1472 // Attributes pointed to by the LanguageBaseAttributeIDList
1473 @
"LibreOffice Impress Remote Control",
1474 @
"0100 - ServiceName",
1475 @
"The Document Foundation",
1476 @
"0102 - ProviderName",
1480 IOBluetoothSDPServiceRecordRef serviceRecordRef
;
1481 IOReturn rc
= IOBluetoothAddServiceDict((CFDictionaryRef
) dict
, &serviceRecordRef
);
1483 SAL_INFO("sdremote.bluetooth", "IOBluetoothAddServiceDict returned " << rc
);
1485 if (rc
== kIOReturnSuccess
)
1487 IOBluetoothSDPServiceRecord
*serviceRecord
=
1488 [IOBluetoothSDPServiceRecord withSDPServiceRecordRef
: serviceRecordRef
];
1490 BluetoothRFCOMMChannelID channelID
;
1491 [serviceRecord getRFCOMMChannelID
: &channelID
];
1493 BluetoothSDPServiceRecordHandle serviceRecordHandle
;
1494 [serviceRecord getServiceRecordHandle
: &serviceRecordHandle
];
1496 // Register callback for incoming connections
1497 IOBluetoothUserNotificationRef callbackRef
=
1498 IOBluetoothRegisterForFilteredRFCOMMChannelOpenNotifications(
1502 kIOBluetoothUserNotificationChannelDirectionIncoming
);
1506 [serviceRecord release
];
1511 (void) mpCommunicators
;
1513 (void) mpCommunicators
; // avoid warnings about unused member
1517 BluetoothServer
*sd::BluetoothServer::spServer
= NULL
;
1519 void BluetoothServer::setup( std::vector
<Communicator
*>* pCommunicators
)
1524 spServer
= new BluetoothServer( pCommunicators
);
1528 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */