bump product version to 6.3.0.0.beta1
[LibreOffice.git] / sd / source / ui / remotecontrol / Server.cxx
bloba4cc985595fffc61f457866e6f785882f6cf9295
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/.
8 */
9 #include <stdlib.h>
10 #include <algorithm>
11 #include <vector>
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>
27 #include <sddll.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"
37 using namespace std;
38 using namespace sd;
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;
47 namespace sd {
48 /**
49 * Used to keep track of clients that have attempted to connect, but haven't
50 * yet been approved.
52 struct ClientInfoInternal:
53 ClientInfo
55 BufferedStreamSocket * const mpStreamSocket;
56 OUString const mPin;
58 ClientInfoInternal( const OUString& rName,
59 BufferedStreamSocket *pSocket,
60 const OUString& rPin ):
61 ClientInfo( rName, false ),
62 mpStreamSocket( pSocket ),
63 mPin( rPin ) {}
67 RemoteServer::RemoteServer() :
68 Thread( "RemoteServerThread" ),
69 mSocket(),
70 mAvailableClients()
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");
86 spServer = nullptr;
87 return;
89 osl::SocketAddr aAddr( "0.0.0.0", PORT );
90 if ( !mSocket.bind( aAddr ) )
92 SAL_WARN( "sdremote", "bind failed" << mSocket.getErrorAsString() );
93 spServer = nullptr;
94 return;
97 if ( !mSocket.listen(3) )
99 SAL_WARN( "sdremote", "listen failed" << mSocket.getErrorAsString() );
100 spServer = nullptr;
101 return;
103 while ( true )
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() );
110 spServer = nullptr;
111 return; // Closed, or other issue.
113 BufferedStreamSocket *pSocket = new BufferedStreamSocket( aSocket);
114 OString aLine;
115 if ( pSocket->readLine( aLine)
116 && aLine == "LO_SERVER_CLIENT_PAIR"
117 && pSocket->readLine( aLine ) )
119 OString aName( aLine );
121 if ( ! pSocket->readLine( aLine ) )
123 delete pSocket;
124 continue;
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();
149 bool aFound = false;
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"));
156 OUString sPin;
157 axPin >>= sPin;
159 if ( sPin == pClient->mPin ) {
160 SAL_INFO( "sdremote", "client found on validated list -- connecting" );
161 connectClient( pClient, sPin );
162 aFound = true;
163 break;
168 // Pin not found so inform the client.
169 if ( !aFound )
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" ) );
175 } else {
176 SAL_INFO( "sdremote", "client failed to send LO_SERVER_CLIENT_PAIR, ignoring" );
177 delete pSocket;
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()
190 if (spServer)
191 return;
193 spServer = new RemoteServer();
194 spServer->launch();
196 #ifdef ENABLE_SDREMOTE_BLUETOOTH
197 sd::BluetoothServer::setup( &sCommunicators );
198 #endif
201 void RemoteServer::presentationStarted( const css::uno::Reference<
202 css::presentation::XSlideShowController > &rController )
204 if ( !spServer )
205 return;
206 MutexGuard aGuard( sDataMutex );
207 for ( const auto& rpCommunicator : sCommunicators )
209 rpCommunicator->presentationStarted( rController );
212 void RemoteServer::presentationStopped()
214 if ( !spServer )
215 return;
216 MutexGuard aGuard( sDataMutex );
217 for ( const auto& rpCommunicator : sCommunicators )
219 rpCommunicator->disposeListener();
223 void RemoteServer::removeCommunicator( Communicator const * mCommunicator )
225 if ( !spServer )
226 return;
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;
237 if ( spServer )
239 MutexGuard aGuard( sDataMutex );
240 aClients.assign( spServer->mAvailableClients.begin(),
241 spServer->mAvailableClients.end() );
243 else
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 ) );
263 return aClients;
266 bool RemoteServer::connectClient( const std::shared_ptr< ClientInfo >& pClient, const OUString& aPin )
268 SAL_INFO( "sdremote", "RemoteServer::connectClient called" );
269 if ( !spServer )
270 return false;
272 ClientInfoInternal* apClient = dynamic_cast< ClientInfoInternal* >( pClient.get() );
273 if ( !apClient )
274 // could happen if we try to "connect" an already authorised client
276 return false;
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 (
286 xConfig, UNO_QUERY);
287 Reference<XNameReplace> xChild( xChildFactory->createInstance(), UNO_QUERY);
288 Any aValue;
289 if (xChild.is())
291 // Check whether the client is already saved
292 bool aSaved = false;
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 ) );
299 aSaved = true;
300 break;
303 if ( !aSaved )
304 xConfig->insertByName( apClient->mName, makeAny( xChild ) );
305 aValue <<= apClient->mPin;
306 xChild->replaceByName("PIN", aValue);
307 aChanges->commit();
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();
319 return true;
321 else
323 return false;
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
331 // the UI.
333 SAL_INFO( "sdremote", "RemoteServer::deauthoriseClient called" );
335 if ( !pClient->mbIsAlreadyAuthorised )
336 // We can't remove unauthorised clients from the authorised list...
338 return;
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 );
346 aChanges->commit();
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() )
365 return;
367 uno::Reference< uno::XComponentContext > xContext = comphelper::getProcessComponentContext();
368 if ( xContext.is() && !officecfg::Office::Impress::Misc::Start::EnableSdremote::get( xContext ) )
369 return;
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();
381 #endif
384 void RemoteServer::restoreDiscoverable()
386 #ifdef ENABLE_SDREMOTE_BLUETOOTH
387 BluetoothServer::restoreDiscoverable();
388 #endif
390 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */