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>
19 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
21 #include <comphelper/processfactory.hxx>
22 #include <comphelper/configuration.hxx>
23 #include <sal/log.hxx>
24 #include <vcl/svapp.hxx>
25 #include <osl/socket.hxx>
29 #include "DiscoveryService.hxx"
30 #include "Listener.hxx"
31 #include "Receiver.hxx"
32 #include <RemoteServer.hxx>
33 #include "BluetoothServer.hxx"
34 #include "Communicator.hxx"
35 #include "BufferedStreamSocket.hxx"
39 using namespace ::com::sun::star
;
40 using namespace ::com::sun::star::uno
;
41 using namespace ::com::sun::star::beans
;
42 using namespace ::com::sun::star::container
;
43 using namespace ::com::sun::star::lang
;
44 using namespace ::osl
;
45 using namespace ::comphelper
;
49 * Used to keep track of clients that have attempted to connect, but haven't
52 struct ClientInfoInternal
:
55 BufferedStreamSocket
* const mpStreamSocket
;
58 ClientInfoInternal( const OUString
& rName
,
59 BufferedStreamSocket
*pSocket
,
60 const OUString
& rPin
):
61 ClientInfo( rName
, false ),
62 mpStreamSocket( pSocket
),
67 RemoteServer::RemoteServer() :
68 Thread( "RemoteServerThread" ),
72 SAL_INFO( "sdremote", "Instantiated RemoteServer" );
75 RemoteServer::~RemoteServer()
79 void RemoteServer::execute()
81 SAL_INFO( "sdremote", "RemoteServer::execute called" );
82 uno::Reference
< uno::XComponentContext
> xContext
= comphelper::getProcessComponentContext();
83 if (!xContext
.is()/* || !officecfg::Office::Common::Misc::ExperimentalMode::get(xContext)*/)
85 // SAL_INFO("sdremote", "not in experimental mode, disabling TCP server");
89 osl::SocketAddr
aAddr( "0.0.0.0", PORT
);
90 if ( !mSocket
.bind( aAddr
) )
92 SAL_WARN( "sdremote", "bind failed" << mSocket
.getErrorAsString() );
97 if ( !mSocket
.listen(3) )
99 SAL_WARN( "sdremote", "listen failed" << mSocket
.getErrorAsString() );
105 StreamSocket aSocket
;
106 SAL_INFO( "sdremote", "waiting on accept" );
107 if ( mSocket
.acceptConnection( aSocket
) == osl_Socket_Error
)
109 SAL_WARN( "sdremote", "accept failed" << mSocket
.getErrorAsString() );
111 return; // Closed, or other issue.
113 BufferedStreamSocket
*pSocket
= new BufferedStreamSocket( aSocket
);
115 if ( pSocket
->readLine( aLine
)
116 && aLine
== "LO_SERVER_CLIENT_PAIR"
117 && pSocket
->readLine( aLine
) )
119 OString
aName( aLine
);
121 if ( ! pSocket
->readLine( aLine
) )
126 OString
aPin( aLine
);
128 SocketAddr aClientAddr
;
129 pSocket
->getPeerAddr( aClientAddr
);
131 MutexGuard
aGuard( sDataMutex
);
132 std::shared_ptr
< ClientInfoInternal
> pClient(
133 new ClientInfoInternal(
134 OStringToOUString( aName
, RTL_TEXTENCODING_UTF8
),
135 pSocket
, OStringToOUString( aPin
, RTL_TEXTENCODING_UTF8
) ) );
136 mAvailableClients
.push_back( pClient
);
138 // Read off any additional non-empty lines
139 // We know that we at least have the empty termination line to read.
142 pSocket
->readLine( aLine
);
144 while ( aLine
.getLength() > 0 );
146 // Check if we already have this server.
147 Reference
< XNameAccess
> const xConfig
= officecfg::Office::Impress::Misc::AuthorisedRemotes::get();
148 Sequence
< OUString
> aNames
= xConfig
->getElementNames();
150 for ( int i
= 0; i
< aNames
.getLength(); i
++ )
152 if ( aNames
[i
] == pClient
->mName
)
154 Reference
<XNameAccess
> xSetItem( xConfig
->getByName(aNames
[i
]), UNO_QUERY
);
155 Any
axPin(xSetItem
->getByName("PIN"));
159 if ( sPin
== pClient
->mPin
) {
160 SAL_INFO( "sdremote", "client found on validated list -- connecting" );
161 connectClient( pClient
, sPin
);
168 // Pin not found so inform the client.
171 SAL_INFO( "sdremote", "client not found on validated list" );
172 pSocket
->write( "LO_SERVER_VALIDATING_PIN\n\n",
173 strlen( "LO_SERVER_VALIDATING_PIN\n\n" ) );
176 SAL_INFO( "sdremote", "client failed to send LO_SERVER_CLIENT_PAIR, ignoring" );
180 SAL_INFO( "sdremote", "shutting down RemoteServer" );
181 spServer
= nullptr; // Object is destroyed when Thread::execute() ends.
184 RemoteServer
*sd::RemoteServer::spServer
= nullptr;
185 ::osl::Mutex
sd::RemoteServer::sDataMutex
;
186 ::std::vector
<Communicator
*> sd::RemoteServer::sCommunicators
;
188 void RemoteServer::setup()
193 spServer
= new RemoteServer();
196 #ifdef ENABLE_SDREMOTE_BLUETOOTH
197 sd::BluetoothServer::setup( &sCommunicators
);
201 void RemoteServer::presentationStarted( const css::uno::Reference
<
202 css::presentation::XSlideShowController
> &rController
)
206 MutexGuard
aGuard( sDataMutex
);
207 for ( const auto& rpCommunicator
: sCommunicators
)
209 rpCommunicator
->presentationStarted( rController
);
212 void RemoteServer::presentationStopped()
216 MutexGuard
aGuard( sDataMutex
);
217 for ( const auto& rpCommunicator
: sCommunicators
)
219 rpCommunicator
->disposeListener();
223 void RemoteServer::removeCommunicator( Communicator
const * mCommunicator
)
227 MutexGuard
aGuard( sDataMutex
);
228 auto aIt
= std::find(sCommunicators
.begin(), sCommunicators
.end(), mCommunicator
);
229 if (aIt
!= sCommunicators
.end())
230 sCommunicators
.erase( aIt
);
233 std::vector
< std::shared_ptr
< ClientInfo
> > RemoteServer::getClients()
235 SAL_INFO( "sdremote", "RemoteServer::getClients() called" );
236 std::vector
< std::shared_ptr
< ClientInfo
> > aClients
;
239 MutexGuard
aGuard( sDataMutex
);
240 aClients
.assign( spServer
->mAvailableClients
.begin(),
241 spServer
->mAvailableClients
.end() );
245 SAL_INFO( "sdremote", "No remote server instance => no remote clients" );
247 // We also need to provide authorised clients (no matter whether or not
248 // they are actually available), so that they can be de-authorised if
249 // necessary. We specifically want these to be at the end of the list
250 // since the user is more likely to be trying to connect a new remote
251 // than removing an existing remote.
252 // We can also be sure that pre-authorised clients will not be on the
253 // available clients list, as they get automatically connected if seen.
254 // TODO: we should probably add some sort of extra labelling to mark
255 // authorised AND connected client.
256 Reference
< XNameAccess
> const xConfig
= officecfg::Office::Impress::Misc::AuthorisedRemotes::get();
257 Sequence
< OUString
> aNames
= xConfig
->getElementNames();
258 for ( int i
= 0; i
< aNames
.getLength(); i
++ )
260 aClients
.push_back( std::make_shared
< ClientInfo
> ( aNames
[i
], true ) );
266 bool RemoteServer::connectClient( const std::shared_ptr
< ClientInfo
>& pClient
, const OUString
& aPin
)
268 SAL_INFO( "sdremote", "RemoteServer::connectClient called" );
272 ClientInfoInternal
* apClient
= dynamic_cast< ClientInfoInternal
* >( pClient
.get() );
274 // could happen if we try to "connect" an already authorised client
279 if ( apClient
->mPin
== aPin
)
281 // Save in settings first
282 std::shared_ptr
< ConfigurationChanges
> aChanges
= ConfigurationChanges::create();
283 Reference
< XNameContainer
> const xConfig
= officecfg::Office::Impress::Misc::AuthorisedRemotes::get( aChanges
);
285 Reference
<XSingleServiceFactory
> xChildFactory (
287 Reference
<XNameReplace
> xChild( xChildFactory
->createInstance(), UNO_QUERY
);
291 // Check whether the client is already saved
293 Sequence
< OUString
> aNames
= xConfig
->getElementNames();
294 for ( int i
= 0; i
< aNames
.getLength(); i
++ )
296 if ( aNames
[i
] == apClient
->mName
)
298 xConfig
->replaceByName( apClient
->mName
, makeAny( xChild
) );
304 xConfig
->insertByName( apClient
->mName
, makeAny( xChild
) );
305 aValue
<<= apClient
->mPin
;
306 xChild
->replaceByName("PIN", aValue
);
310 Communicator
* pCommunicator
= new Communicator( std::unique_ptr
<IBluetoothSocket
>(apClient
->mpStreamSocket
) );
311 MutexGuard
aGuard( sDataMutex
);
313 sCommunicators
.push_back( pCommunicator
);
315 auto aIt
= std::find(spServer
->mAvailableClients
.begin(), spServer
->mAvailableClients
.end(), pClient
);
316 if (aIt
!= spServer
->mAvailableClients
.end())
317 spServer
->mAvailableClients
.erase( aIt
);
318 pCommunicator
->launch();
327 void RemoteServer::deauthoriseClient( const std::shared_ptr
< ClientInfo
>& pClient
)
329 // TODO: we probably want to forcefully disconnect at this point too?
330 // But possibly via a separate function to allow just disconnecting from
333 SAL_INFO( "sdremote", "RemoteServer::deauthoriseClient called" );
335 if ( !pClient
->mbIsAlreadyAuthorised
)
336 // We can't remove unauthorised clients from the authorised list...
341 std::shared_ptr
< ConfigurationChanges
> aChanges
= ConfigurationChanges::create();
342 Reference
< XNameContainer
> const xConfig
=
343 officecfg::Office::Impress::Misc::AuthorisedRemotes::get( aChanges
);
345 xConfig
->removeByName( pClient
->mName
);
349 void SdDLL::RegisterRemotes()
351 SAL_INFO( "sdremote", "SdDLL::RegisterRemotes called" );
353 // The remote server is likely of no use in headless mode. And as only
354 // one instance of the server can actually own the appropriate ports its
355 // probably best to not even try to do so from our headless instance
356 // (i.e. as to avoid blocking expected usage).
357 // It could perhaps be argued that we would still need the remote
358 // server for tiled rendering of presentations, but even then this
359 // implementation would not be of much use, i.e. would be controlling
360 // the purely imaginary headless presentation -- instead we'd need
361 // to have some sort of mechanism of plugging in our tiled rendering
362 // client to be controlled by the remote server, or provide an
363 // alternative implementation.
364 if ( Application::IsHeadlessModeEnabled() )
367 uno::Reference
< uno::XComponentContext
> xContext
= comphelper::getProcessComponentContext();
368 if ( xContext
.is() && !officecfg::Office::Impress::Misc::Start::EnableSdremote::get( xContext
) )
371 sd::RemoteServer::setup();
372 sd::DiscoveryService::setup();
375 void RemoteServer::ensureDiscoverable()
377 // FIXME: we could also enable listening on our WiFi
378 // socket here to significantly reduce the attack surface.
379 #ifdef ENABLE_SDREMOTE_BLUETOOTH
380 BluetoothServer::ensureDiscoverable();
384 void RemoteServer::restoreDiscoverable()
386 #ifdef ENABLE_SDREMOTE_BLUETOOTH
387 BluetoothServer::restoreDiscoverable();
390 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */