LCOV - code coverage report
Current view: top level - usr/local/src/libreoffice/sd/source/ui/remotecontrol - BluetoothServer.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 67 254 26.4 %
Date: 2013-07-09 Functions: 13 30 43.3 %
Legend: Lines: hit not hit

          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: */

Generated by: LCOV version 1.10