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/.
14 #include <officecfg/Office/Impress.hxx>
15 #include <officecfg/Office/Security.hxx>
17 #include <com/sun/star/container/XNameAccess.hpp>
18 #include <com/sun/star/container/XNameContainer.hpp>
19 #include <com/sun/star/uno/Sequence.hxx>
20 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
22 #include <comphelper/processfactory.hxx>
23 #include <comphelper/configuration.hxx>
24 #include <comphelper/sequence.hxx>
25 #include <sal/log.hxx>
26 #include <vcl/svapp.hxx>
27 #include <osl/socket.hxx>
31 #include "DiscoveryService.hxx"
32 #include "Listener.hxx"
33 #include <RemoteServer.hxx>
34 #include "BluetoothServer.hxx"
35 #include "Communicator.hxx"
36 #include "BufferedStreamSocket.hxx"
39 using namespace ::com::sun::star
;
40 using namespace ::com::sun::star::uno
;
41 using namespace ::com::sun::star::container
;
42 using namespace ::com::sun::star::lang
;
43 using namespace ::osl
;
44 using namespace ::comphelper
;
48 * Used to keep track of clients that have attempted to connect, but haven't
51 struct ClientInfoInternal
:
54 BufferedStreamSocket
*mpStreamSocket
;
57 ClientInfoInternal( const OUString
& rName
,
58 BufferedStreamSocket
*pSocket
,
60 ClientInfo( rName
, false ),
61 mpStreamSocket( pSocket
),
62 mPin(std::move( aPin
)) {}
66 IPRemoteServer::IPRemoteServer()
67 : Thread("IPRemoteServerThread")
69 SAL_INFO("sdremote", "Instantiated IPRemoteServer");
72 IPRemoteServer::~IPRemoteServer()
76 void IPRemoteServer::execute()
78 SAL_INFO("sdremote", "IPRemoteServer::execute called");
79 osl::SocketAddr
aAddr( u
"0.0.0.0"_ustr
, PORT
);
80 if ( !mSocket
.bind( aAddr
) )
82 SAL_WARN( "sdremote", "bind failed" << mSocket
.getErrorAsString() );
87 if ( !mSocket
.listen(3) )
89 SAL_WARN( "sdremote", "listen failed" << mSocket
.getErrorAsString() );
96 SAL_INFO( "sdremote", "waiting on accept" );
97 if ( mSocket
.acceptConnection( aSocket
) == osl_Socket_Error
)
99 SAL_WARN( "sdremote", "accept failed" << mSocket
.getErrorAsString() );
100 break; // Closed, or other issue.
102 BufferedStreamSocket
*pSocket
= new BufferedStreamSocket( aSocket
);
103 handleAcceptedConnection( pSocket
);
105 SAL_INFO("sdremote", "shutting down IPRemoteServer");
106 spServer
= nullptr; // Object is destroyed when Thread::execute() ends.
109 void IPRemoteServer::handleAcceptedConnection( BufferedStreamSocket
*pSocket
)
112 if ( ! ( pSocket
->readLine( aLine
)
113 && aLine
== "LO_SERVER_CLIENT_PAIR"
114 && pSocket
->readLine( aLine
) ) )
116 SAL_INFO( "sdremote", "client failed to send LO_SERVER_CLIENT_PAIR, ignoring" );
121 OString
aName( aLine
);
123 if ( ! pSocket
->readLine( aLine
) )
128 OString
aPin( aLine
);
130 SocketAddr aClientAddr
;
131 pSocket
->getPeerAddr( aClientAddr
);
135 // Read off any additional non-empty lines
136 // We know that we at least have the empty termination line to read.
137 if ( ! pSocket
->readLine( aLine
) ) {
142 while ( aLine
.getLength() > 0 );
144 MutexGuard
aGuard(RemoteServer::sDataMutex
);
145 std::shared_ptr
< ClientInfoInternal
> pClient
=
146 std::make_shared
<ClientInfoInternal
>(
147 OStringToOUString( aName
, RTL_TEXTENCODING_UTF8
),
148 pSocket
, OStringToOUString( aPin
, RTL_TEXTENCODING_UTF8
) );
149 mAvailableClients
.push_back( pClient
);
151 // Check if we already have this server.
152 Reference
< XNameAccess
> const xConfig
= officecfg::Office::Impress::Misc::AuthorisedRemotes::get();
153 const Sequence
< OUString
> aNames
= xConfig
->getElementNames();
154 for ( const auto& rName
: aNames
)
156 if ( rName
== pClient
->mName
)
158 Reference
<XNameAccess
> xSetItem( xConfig
->getByName(rName
), UNO_QUERY
);
159 Any
axPin(xSetItem
->getByName(u
"PIN"_ustr
));
163 if ( sPin
== pClient
->mPin
) {
164 SAL_INFO( "sdremote", "client found on validated list -- connecting" );
165 connectClient( pClient
, sPin
);
171 // 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 IPRemoteServer
*sd::IPRemoteServer::spServer
= nullptr;
178 ::osl::Mutex
sd::RemoteServer::sDataMutex
;
179 ::std::vector
<Communicator
*> sd::RemoteServer::sCommunicators
;
181 void IPRemoteServer::setup()
186 spServer
= new IPRemoteServer();
190 void RemoteServer::presentationStarted( const css::uno::Reference
<
191 css::presentation::XSlideShowController
> &rController
)
193 // note this can be invoked even when there is no IPRemoteServer instance
194 // but there are communicators belonging to a BluetoothServer
195 MutexGuard
aGuard( sDataMutex
);
196 for ( const auto& rpCommunicator
: sCommunicators
)
198 rpCommunicator
->presentationStarted( rController
);
201 void RemoteServer::presentationStopped()
203 MutexGuard
aGuard( sDataMutex
);
204 for ( const auto& rpCommunicator
: sCommunicators
)
206 rpCommunicator
->disposeListener();
210 void RemoteServer::removeCommunicator( Communicator
const * mCommunicator
)
212 MutexGuard
aGuard( sDataMutex
);
213 auto aIt
= std::find(sCommunicators
.begin(), sCommunicators
.end(), mCommunicator
);
214 if (aIt
!= sCommunicators
.end())
215 sCommunicators
.erase( aIt
);
218 std::vector
<std::shared_ptr
<ClientInfo
>> IPRemoteServer::getClients()
220 SAL_INFO( "sdremote", "IPRemoteServer::getClients() called" );
221 std::vector
< std::shared_ptr
< ClientInfo
> > aClients
;
224 MutexGuard
aGuard(RemoteServer::sDataMutex
);
225 aClients
.assign( spServer
->mAvailableClients
.begin(),
226 spServer
->mAvailableClients
.end() );
230 SAL_INFO( "sdremote", "No remote server instance => no remote clients" );
232 // We also need to provide authorised clients (no matter whether or not
233 // they are actually available), so that they can be de-authorised if
234 // necessary. We specifically want these to be at the end of the list
235 // since the user is more likely to be trying to connect a new remote
236 // than removing an existing remote.
237 // We can also be sure that pre-authorised clients will not be on the
238 // available clients list, as they get automatically connected if seen.
239 // TODO: we should probably add some sort of extra labelling to mark
240 // authorised AND connected client.
241 Reference
< XNameAccess
> const xConfig
= officecfg::Office::Impress::Misc::AuthorisedRemotes::get();
242 const Sequence
< OUString
> aNames
= xConfig
->getElementNames();
243 std::transform(aNames
.begin(), aNames
.end(), std::back_inserter(aClients
),
244 [](const OUString
& rName
) -> std::shared_ptr
<ClientInfo
> {
245 return std::make_shared
<ClientInfo
>(rName
, true); });
250 bool IPRemoteServer::connectClient(const std::shared_ptr
<ClientInfo
>& pClient
, std::u16string_view aPin
)
252 SAL_INFO("sdremote", "IPRemoteServer::connectClient called");
256 ClientInfoInternal
* apClient
= dynamic_cast< ClientInfoInternal
* >( pClient
.get() );
258 // could happen if we try to "connect" an already authorised client
263 if ( apClient
->mPin
== aPin
)
265 // Save in settings first
266 std::shared_ptr
< ConfigurationChanges
> aChanges
= ConfigurationChanges::create();
267 Reference
< XNameContainer
> const xConfig
= officecfg::Office::Impress::Misc::AuthorisedRemotes::get( aChanges
);
269 Reference
<XSingleServiceFactory
> xChildFactory (
271 Reference
<XNameReplace
> xChild( xChildFactory
->createInstance(), UNO_QUERY
);
275 // Check whether the client is already saved
276 Sequence
< OUString
> aNames
= xConfig
->getElementNames();
277 if (comphelper::findValue(aNames
, apClient
->mName
) != -1)
278 xConfig
->replaceByName( apClient
->mName
, Any( xChild
) );
280 xConfig
->insertByName( apClient
->mName
, Any( xChild
) );
281 aValue
<<= apClient
->mPin
;
282 xChild
->replaceByName(u
"PIN"_ustr
, aValue
);
286 Communicator
* pCommunicator
= new Communicator( std::unique_ptr
<IBluetoothSocket
>(apClient
->mpStreamSocket
) );
287 MutexGuard
aGuard(RemoteServer::sDataMutex
);
289 RemoteServer::sCommunicators
.push_back( pCommunicator
);
291 auto aIt
= std::find(spServer
->mAvailableClients
.begin(), spServer
->mAvailableClients
.end(), pClient
);
292 if (aIt
!= spServer
->mAvailableClients
.end())
293 spServer
->mAvailableClients
.erase( aIt
);
294 pCommunicator
->launch();
303 void IPRemoteServer::deauthoriseClient(const std::shared_ptr
<ClientInfo
>& pClient
)
305 // TODO: we probably want to forcefully disconnect at this point too?
306 // But possibly via a separate function to allow just disconnecting from
309 SAL_INFO("sdremote", "IPRemoteServer::deauthoriseClient called");
311 if ( !pClient
->mbIsAlreadyAuthorised
)
312 // We can't remove unauthorised clients from the authorised list...
317 std::shared_ptr
< ConfigurationChanges
> aChanges
= ConfigurationChanges::create();
318 Reference
< XNameContainer
> const xConfig
=
319 officecfg::Office::Impress::Misc::AuthorisedRemotes::get( aChanges
);
321 xConfig
->removeByName( pClient
->mName
);
325 void SdDLL::RegisterRemotes()
327 SAL_INFO( "sdremote", "SdDLL::RegisterRemotes called" );
329 // The remote server is likely of no use in headless mode. And as only
330 // one instance of the server can actually own the appropriate ports its
331 // probably best to not even try to do so from our headless instance
332 // (i.e. as to avoid blocking expected usage).
333 // It could perhaps be argued that we would still need the remote
334 // server for tiled rendering of presentations, but even then this
335 // implementation would not be of much use, i.e. would be controlling
336 // the purely imaginary headless presentation -- instead we'd need
337 // to have some sort of mechanism of plugging in our tiled rendering
338 // client to be controlled by the remote server, or provide an
339 // alternative implementation.
340 if ( Application::IsHeadlessModeEnabled() )
343 if ( !officecfg::Office::Impress::Misc::Start::EnableSdremote::get() )
346 #ifdef ENABLE_SDREMOTE_BLUETOOTH
347 sd::BluetoothServer::setup( &RemoteServer::sCommunicators
);
350 if (!officecfg::Office::Security::Net::AllowInsecureImpressRemoteWiFi::get())
352 SAL_WARN("desktop", "Impress remote WiFi is disabled by configuration");
356 // this is the IP/WiFi server
357 sd::IPRemoteServer::setup();
358 // assumption is that BluetoothServer doesn't need DiscoveryService
359 sd::DiscoveryService::setup();
362 void RemoteServer::ensureDiscoverable()
364 // FIXME: we could also enable listening on our WiFi
365 // socket here to significantly reduce the attack surface.
366 #ifdef ENABLE_SDREMOTE_BLUETOOTH
367 BluetoothServer::ensureDiscoverable();
371 void RemoteServer::restoreDiscoverable()
373 #ifdef ENABLE_SDREMOTE_BLUETOOTH
374 BluetoothServer::restoreDiscoverable();
377 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */