bump product version to 5.0.4.1
[LibreOffice.git] / sd / source / ui / remotecontrol / Server.cxx
blob06093bb38104b6e6704ce46ca818bc2878578312
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>
20 #include <comphelper/processfactory.hxx>
21 #include <comphelper/configuration.hxx>
22 #include <sal/log.hxx>
24 #include "sddll.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"
34 using namespace std;
35 using namespace sd;
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;
44 namespace sd {
45 /**
46 * Used to keep track of clients that have attempted to connect, but haven't
47 * yet been approved.
49 struct ClientInfoInternal:
50 ClientInfo
52 BufferedStreamSocket *mpStreamSocket;
53 OUString mPin;
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 ),
62 mPin( rPin ) {}
66 RemoteServer::RemoteServer() :
67 Thread( "RemoteServerThread" ),
68 mSocket(),
69 mAvailableClients()
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");
85 spServer = NULL;
86 return;
88 osl::SocketAddr aAddr( "0", PORT );
89 if ( !mSocket.bind( aAddr ) )
91 SAL_WARN( "sdremote", "bind failed" << mSocket.getErrorAsString() );
92 spServer = NULL;
93 return;
96 if ( !mSocket.listen(3) )
98 SAL_WARN( "sdremote", "listen failed" << mSocket.getErrorAsString() );
99 spServer = NULL;
100 return;
102 while ( true )
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() );
109 spServer = NULL;
110 return; // Closed, or other issue.
112 BufferedStreamSocket *pSocket = new BufferedStreamSocket( aSocket);
113 OString aLine;
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 ) )
122 delete pSocket;
123 continue;
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();
150 bool aFound = false;
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"));
157 OUString sPin;
158 axPin >>= sPin;
160 if ( sPin.equals( pClient->mPin ) ) {
161 SAL_INFO( "sdremote", "client found on validated list -- connecting" );
162 connectClient( pClient, sPin );
163 aFound = true;
164 break;
169 // Pin not found so inform the client.
170 if ( !aFound )
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" ) );
176 } else {
177 SAL_INFO( "sdremote", "client failed to send LO_SERVER_CLIENT_PAIR, ignoring" );
178 delete pSocket;
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()
191 if (spServer)
192 return;
194 spServer = new RemoteServer();
195 spServer->launch();
197 #ifdef ENABLE_SDREMOTE_BLUETOOTH
198 sd::BluetoothServer::setup( &sCommunicators );
199 #endif
202 void RemoteServer::presentationStarted( const css::uno::Reference<
203 css::presentation::XSlideShowController > &rController )
205 if ( !spServer )
206 return;
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()
216 if ( !spServer )
217 return;
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 )
228 if ( !spServer )
229 return;
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 );
237 break;
242 std::vector< ::boost::shared_ptr< ClientInfo > > RemoteServer::getClients()
244 SAL_INFO( "sdremote", "RemoteServer::getClients() called" );
245 std::vector< ::boost::shared_ptr< ClientInfo > > aClients;
246 if ( spServer )
248 MutexGuard aGuard( sDataMutex );
249 aClients.assign( spServer->mAvailableClients.begin(),
250 spServer->mAvailableClients.end() );
252 else
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 ) ) );
272 return aClients;
275 bool RemoteServer::connectClient( ::boost::shared_ptr< ClientInfo > pClient, const OUString& aPin )
277 SAL_INFO( "sdremote", "RemoteServer::connectClient called" );
278 if ( !spServer )
279 return false;
281 ClientInfoInternal* apClient = dynamic_cast< ClientInfoInternal* >( pClient.get() );
282 if ( !apClient )
283 // could happen if we try to "connect" an already authorised client
285 return false;
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 (
295 xConfig, UNO_QUERY);
296 Reference<XNameReplace> xChild( xChildFactory->createInstance(), UNO_QUERY);
297 Any aValue;
298 if (xChild.is())
300 // Check whether the client is already saved
301 bool aSaved = false;
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 ) );
308 aSaved = true;
309 break;
312 if ( !aSaved )
313 xConfig->insertByName( apClient->mName, makeAny( xChild ) );
314 aValue <<= OUString( apClient->mPin );
315 xChild->replaceByName("PIN", aValue);
316 aChanges->commit();
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 );
330 break;
333 pCommunicator->launch();
334 return true;
336 else
338 return false;
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
346 // the UI.
348 SAL_INFO( "sdremote", "RemoteServer::deauthoriseClient called" );
350 if ( !pClient->mbIsAlreadyAuthorised )
351 // We can't remove unauthorised clients from the authorised list...
353 return;
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 );
361 aChanges->commit();
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() )
380 return;
382 uno::Reference< uno::XComponentContext > xContext = comphelper::getProcessComponentContext();
383 if ( xContext.is() && !officecfg::Office::Impress::Misc::Start::EnableSdremote::get( xContext ) )
384 return;
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();
396 #endif
399 void RemoteServer::restoreDiscoverable()
401 #ifdef ENABLE_SDREMOTE_BLUETOOTH
402 BluetoothServer::restoreDiscoverable();
403 #endif
405 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */