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/.
13 #include <officecfg/Office/Common.hxx>
14 #include <officecfg/Office/Impress.hxx>
16 #include <com/sun/star/container/XNameAccess.hpp>
17 #include <com/sun/star/container/XNameContainer.hpp>
18 #include <com/sun/star/uno/Sequence.hxx>
20 #include <comphelper/processfactory.hxx>
21 #include <comphelper/configuration.hxx>
22 #include <sal/log.hxx>
26 #include "DiscoveryService.hxx"
27 #include "Listener.hxx"
28 #include "Receiver.hxx"
29 #include "RemoteServer.hxx"
30 #include "BluetoothServer.hxx"
31 #include "Communicator.hxx"
32 #include "BufferedStreamSocket.hxx"
36 using namespace ::com::sun::star
;
37 using namespace ::com::sun::star::uno
;
38 using namespace ::com::sun::star::beans
;
39 using namespace ::com::sun::star::container
;
40 using namespace ::com::sun::star::lang
;
41 using namespace ::osl
;
42 using namespace ::comphelper
;
46 * Used to keep track of clients that have attempted to connect, but haven't
49 struct ClientInfoInternal
:
52 BufferedStreamSocket
*mpStreamSocket
;
55 ClientInfoInternal( const OUString
& rName
,
56 const OUString
& rAddress
,
57 const bool bIsAlreadyAuthorised
,
58 BufferedStreamSocket
*pSocket
,
59 const OUString
& rPin
):
60 ClientInfo( rName
, rAddress
, bIsAlreadyAuthorised
),
61 mpStreamSocket( pSocket
),
66 RemoteServer::RemoteServer() :
67 Thread( "RemoteServerThread" ),
71 SAL_INFO( "sdremote", "Instantiated RemoteServer" );
74 RemoteServer::~RemoteServer()
78 void RemoteServer::execute()
80 SAL_INFO( "sdremote", "RemoteServer::execute called" );
81 uno::Reference
< uno::XComponentContext
> xContext
= comphelper::getProcessComponentContext();
82 if (!xContext
.is()/* || !officecfg::Office::Common::Misc::ExperimentalMode::get(xContext)*/)
84 // SAL_INFO("sdremote", "not in experimental mode, disabling TCP server");
88 osl::SocketAddr
aAddr( "0", PORT
);
89 if ( !mSocket
.bind( aAddr
) )
91 SAL_WARN( "sdremote", "bind failed" << mSocket
.getErrorAsString() );
96 if ( !mSocket
.listen(3) )
98 SAL_WARN( "sdremote", "listen failed" << mSocket
.getErrorAsString() );
104 StreamSocket aSocket
;
105 SAL_INFO( "sdremote", "waiting on accept" );
106 if ( mSocket
.acceptConnection( aSocket
) == osl_Socket_Error
)
108 SAL_WARN( "sdremote", "accept failed" << mSocket
.getErrorAsString() );
110 return; // Closed, or other issue.
112 BufferedStreamSocket
*pSocket
= new BufferedStreamSocket( aSocket
);
114 if ( pSocket
->readLine( aLine
)
115 && aLine
.equals( "LO_SERVER_CLIENT_PAIR" ) &&
116 pSocket
->readLine( aLine
) )
118 OString
aName( aLine
);
120 if ( ! pSocket
->readLine( aLine
) )
125 OString
aPin( aLine
);
127 SocketAddr aClientAddr
;
128 pSocket
->getPeerAddr( aClientAddr
);
129 OUString aAddress
= aClientAddr
.getHostname();
131 MutexGuard
aGuard( sDataMutex
);
132 ::boost::shared_ptr
< ClientInfoInternal
> pClient(
133 new ClientInfoInternal(
134 OStringToOUString( aName
, RTL_TEXTENCODING_UTF8
),
135 aAddress
, false, pSocket
, OStringToOUString( aPin
,
136 RTL_TEXTENCODING_UTF8
) ) );
137 mAvailableClients
.push_back( pClient
);
139 // Read off any additional non-empty lines
140 // We know that we at least have the empty termination line to read.
143 pSocket
->readLine( aLine
);
145 while ( aLine
.getLength() > 0 );
147 // Check if we already have this server.
148 Reference
< XNameAccess
> const xConfig
= officecfg::Office::Impress::Misc::AuthorisedRemotes::get();
149 Sequence
< OUString
> aNames
= xConfig
->getElementNames();
151 for ( int i
= 0; i
< aNames
.getLength(); i
++ )
153 if ( aNames
[i
].equals( pClient
->mName
) )
155 Reference
<XNameAccess
> xSetItem( xConfig
->getByName(aNames
[i
]), UNO_QUERY
);
156 Any
axPin(xSetItem
->getByName("PIN"));
160 if ( sPin
.equals( pClient
->mPin
) ) {
161 SAL_INFO( "sdremote", "client found on validated list -- connecting" );
162 connectClient( pClient
, sPin
);
169 // Pin not found so inform the client.
172 SAL_INFO( "sdremote", "client not found on validated list" );
173 pSocket
->write( "LO_SERVER_VALIDATING_PIN\n\n",
174 strlen( "LO_SERVER_VALIDATING_PIN\n\n" ) );
177 SAL_INFO( "sdremote", "client failed to send LO_SERVER_CLIENT_PAIR, ignoring" );
181 SAL_INFO( "sdremote", "shutting down RemoteServer" );
182 spServer
= NULL
; // Object is destroyed when Thread::execute() ends.
185 RemoteServer
*sd::RemoteServer::spServer
= NULL
;
186 ::osl::Mutex
sd::RemoteServer::sDataMutex
;
187 ::std::vector
<Communicator
*> sd::RemoteServer::sCommunicators
;
189 void RemoteServer::setup()
194 spServer
= new RemoteServer();
197 #ifdef ENABLE_SDREMOTE_BLUETOOTH
198 sd::BluetoothServer::setup( &sCommunicators
);
202 void RemoteServer::presentationStarted( const css::uno::Reference
<
203 css::presentation::XSlideShowController
> &rController
)
207 MutexGuard
aGuard( sDataMutex
);
208 for ( vector
<Communicator
*>::const_iterator aIt
= sCommunicators
.begin();
209 aIt
!= sCommunicators
.end(); ++aIt
)
211 (*aIt
)->presentationStarted( rController
);
214 void RemoteServer::presentationStopped()
218 MutexGuard
aGuard( sDataMutex
);
219 for ( vector
<Communicator
*>::const_iterator aIt
= sCommunicators
.begin();
220 aIt
!= sCommunicators
.end(); ++aIt
)
222 (*aIt
)->disposeListener();
226 void RemoteServer::removeCommunicator( Communicator
* mCommunicator
)
230 MutexGuard
aGuard( sDataMutex
);
231 for ( vector
<Communicator
*>::iterator aIt
= sCommunicators
.begin();
232 aIt
!= sCommunicators
.end(); ++aIt
)
234 if ( mCommunicator
== *aIt
)
236 sCommunicators
.erase( aIt
);
242 std::vector
< ::boost::shared_ptr
< ClientInfo
> > RemoteServer::getClients()
244 SAL_INFO( "sdremote", "RemoteServer::getClients() called" );
245 std::vector
< ::boost::shared_ptr
< ClientInfo
> > aClients
;
248 MutexGuard
aGuard( sDataMutex
);
249 aClients
.assign( spServer
->mAvailableClients
.begin(),
250 spServer
->mAvailableClients
.end() );
254 SAL_INFO( "sdremote", "No remote server instance => no remote clients" );
256 // We also need to provide authorised clients (no matter whether or not
257 // they are actually available), so that they can be de-authorised if
258 // necessary. We specifically want these to be at the end of the list
259 // since the user is more likely to be trying to connect a new remote
260 // than removing an existing remote.
261 // We can also be sure that pre-authorised clients will not be on the
262 // available clients list, as they get automatially connected if seen.
263 // TODO: we should probably add some sort of extra labelling to mark
264 // authorised AND connected client.
265 Reference
< XNameAccess
> const xConfig
= officecfg::Office::Impress::Misc::AuthorisedRemotes::get();
266 Sequence
< OUString
> aNames
= xConfig
->getElementNames();
267 for ( int i
= 0; i
< aNames
.getLength(); i
++ )
269 aClients
.push_back( ::boost::shared_ptr
< ClientInfo
> ( new ClientInfo( aNames
[i
], "", true ) ) );
275 bool RemoteServer::connectClient( ::boost::shared_ptr
< ClientInfo
> pClient
, const OUString
& aPin
)
277 SAL_INFO( "sdremote", "RemoteServer::connectClient called" );
281 ClientInfoInternal
* apClient
= dynamic_cast< ClientInfoInternal
* >( pClient
.get() );
283 // could happen if we try to "connect" an already authorised client
288 if ( apClient
->mPin
.equals( aPin
) )
290 // Save in settings first
291 std::shared_ptr
< ConfigurationChanges
> aChanges
= ConfigurationChanges::create();
292 Reference
< XNameContainer
> const xConfig
= officecfg::Office::Impress::Misc::AuthorisedRemotes::get( aChanges
);
294 Reference
<XSingleServiceFactory
> xChildFactory (
296 Reference
<XNameReplace
> xChild( xChildFactory
->createInstance(), UNO_QUERY
);
300 // Check whether the client is already saved
302 Sequence
< OUString
> aNames
= xConfig
->getElementNames();
303 for ( int i
= 0; i
< aNames
.getLength(); i
++ )
305 if ( aNames
[i
].equals( apClient
->mName
) )
307 xConfig
->replaceByName( apClient
->mName
, makeAny( xChild
) );
313 xConfig
->insertByName( apClient
->mName
, makeAny( xChild
) );
314 aValue
<<= OUString( apClient
->mPin
);
315 xChild
->replaceByName("PIN", aValue
);
319 Communicator
* pCommunicator
= new Communicator( apClient
->mpStreamSocket
);
320 MutexGuard
aGuard( sDataMutex
);
322 sCommunicators
.push_back( pCommunicator
);
324 for ( vector
< ::boost::shared_ptr
< ClientInfoInternal
> >::iterator aIt
= spServer
->mAvailableClients
.begin();
325 aIt
!= spServer
->mAvailableClients
.end(); ++aIt
)
327 if ( pClient
== *aIt
)
329 spServer
->mAvailableClients
.erase( aIt
);
333 pCommunicator
->launch();
342 void RemoteServer::deauthoriseClient( ::boost::shared_ptr
< ClientInfo
> pClient
)
344 // TODO: we probably want to forcefully disconnect at this point too?
345 // But possibly via a separate function to allow just disconnecting from
348 SAL_INFO( "sdremote", "RemoteServer::deauthoriseClient called" );
350 if ( !pClient
->mbIsAlreadyAuthorised
)
351 // We can't remove unauthorised clients from the authorised list...
356 std::shared_ptr
< ConfigurationChanges
> aChanges
= ConfigurationChanges::create();
357 Reference
< XNameContainer
> const xConfig
=
358 officecfg::Office::Impress::Misc::AuthorisedRemotes::get( aChanges
);
360 xConfig
->removeByName( pClient
->mName
);
364 void SdDLL::RegisterRemotes()
366 SAL_INFO( "sdremote", "SdDLL::RegisterRemotes called" );
368 // The remote server is likely of no use in headless mode. And as only
369 // one instance of the server can actually own the appropriate ports its
370 // probably best to not even try to do so from our headless instance
371 // (i.e. as to avoid blocking expected usage).
372 // It could perhaps be argued that we would still need the remote
373 // server for tiled rendering of presentations, but even then this
374 // implementation would not be of much use, i.e. would be controlling
375 // the purely imaginary headless presentation -- instead we'd need
376 // to have some sort of mechanism of plugging in our tiled rendering
377 // client to be controlled by the remote server, or provide an
378 // alternative implementation.
379 if ( Application::IsHeadlessModeEnabled() )
382 uno::Reference
< uno::XComponentContext
> xContext
= comphelper::getProcessComponentContext();
383 if ( xContext
.is() && !officecfg::Office::Impress::Misc::Start::EnableSdremote::get( xContext
) )
386 sd::RemoteServer::setup();
387 sd::DiscoveryService::setup();
390 void RemoteServer::ensureDiscoverable()
392 // FIXME: we could also enable listening on our WiFi
393 // socket here to significantly reduce the attack surface.
394 #ifdef ENABLE_SDREMOTE_BLUETOOTH
395 BluetoothServer::ensureDiscoverable();
399 void RemoteServer::restoreDiscoverable()
401 #ifdef ENABLE_SDREMOTE_BLUETOOTH
402 BluetoothServer::restoreDiscoverable();
405 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */