Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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>
12 :
13 : #include <officecfg/Office/Common.hxx>
14 : #include <officecfg/Office/Impress.hxx>
15 :
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 :
20 : #include <comphelper/processfactory.hxx>
21 : #include <comphelper/configuration.hxx>
22 : #include <sal/log.hxx>
23 :
24 : #include "sddll.hxx"
25 :
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"
33 :
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;
43 :
44 : namespace sd {
45 : /**
46 : * Used to keep track of clients that have attempted to connect, but haven't
47 : * yet been approved.
48 : */
49 0 : struct ClientInfoInternal:
50 : ClientInfo
51 : {
52 : BufferedStreamSocket *mpStreamSocket;
53 : OUString mPin;
54 :
55 0 : 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 0 : mPin( rPin ) {}
63 : };
64 : }
65 :
66 0 : RemoteServer::RemoteServer() :
67 : Thread( "RemoteServerThread" ),
68 : mSocket(),
69 0 : mAvailableClients()
70 : {
71 : SAL_INFO( "sdremote", "Instantiated RemoteServer" );
72 0 : }
73 :
74 0 : RemoteServer::~RemoteServer()
75 : {
76 0 : }
77 :
78 0 : void RemoteServer::execute()
79 : {
80 : SAL_INFO( "sdremote", "RemoteServer::execute called" );
81 0 : uno::Reference< uno::XComponentContext > xContext = comphelper::getProcessComponentContext();
82 0 : if (!xContext.is()/* || !officecfg::Office::Common::Misc::ExperimentalMode::get(xContext)*/)
83 : {
84 : // SAL_INFO("sdremote", "not in experimental mode, disabling TCP server");
85 0 : spServer = NULL;
86 0 : return;
87 : }
88 0 : osl::SocketAddr aAddr( "0", PORT );
89 0 : if ( !mSocket.bind( aAddr ) )
90 : {
91 : SAL_WARN( "sdremote", "bind failed" << mSocket.getErrorAsString() );
92 0 : spServer = NULL;
93 0 : return;
94 : }
95 :
96 0 : if ( !mSocket.listen(3) )
97 : {
98 : SAL_WARN( "sdremote", "listen failed" << mSocket.getErrorAsString() );
99 0 : spServer = NULL;
100 0 : return;
101 : }
102 : while ( true )
103 : {
104 0 : StreamSocket aSocket;
105 : SAL_INFO( "sdremote", "waiting on accept" );
106 0 : if ( mSocket.acceptConnection( aSocket ) == osl_Socket_Error )
107 : {
108 : SAL_WARN( "sdremote", "accept failed" << mSocket.getErrorAsString() );
109 0 : spServer = NULL;
110 0 : return; // Closed, or other issue.
111 : }
112 0 : BufferedStreamSocket *pSocket = new BufferedStreamSocket( aSocket);
113 0 : OString aLine;
114 0 : if ( pSocket->readLine( aLine)
115 0 : && aLine.equals( "LO_SERVER_CLIENT_PAIR" ) &&
116 0 : pSocket->readLine( aLine ) )
117 : {
118 0 : OString aName( aLine );
119 :
120 0 : if ( ! pSocket->readLine( aLine ) )
121 : {
122 0 : delete pSocket;
123 0 : continue;
124 : }
125 0 : OString aPin( aLine );
126 :
127 0 : SocketAddr aClientAddr;
128 0 : pSocket->getPeerAddr( aClientAddr );
129 0 : OUString aAddress = aClientAddr.getHostname();
130 :
131 0 : 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 0 : RTL_TEXTENCODING_UTF8 ) ) );
137 0 : mAvailableClients.push_back( pClient );
138 :
139 : // Read off any additional non-empty lines
140 : // We know that we at least have the empty termination line to read.
141 0 : do
142 : {
143 0 : pSocket->readLine( aLine );
144 : }
145 0 : while ( aLine.getLength() > 0 );
146 :
147 : // Check if we already have this server.
148 0 : Reference< XNameAccess > const xConfig = officecfg::Office::Impress::Misc::AuthorisedRemotes::get();
149 0 : Sequence< OUString > aNames = xConfig->getElementNames();
150 0 : bool aFound = false;
151 0 : for ( int i = 0; i < aNames.getLength(); i++ )
152 : {
153 0 : if ( aNames[i].equals( pClient->mName ) )
154 : {
155 0 : Reference<XNameAccess> xSetItem( xConfig->getByName(aNames[i]), UNO_QUERY );
156 0 : Any axPin(xSetItem->getByName("PIN"));
157 0 : OUString sPin;
158 0 : axPin >>= sPin;
159 :
160 0 : if ( sPin.equals( pClient->mPin ) ) {
161 : SAL_INFO( "sdremote", "client found on validated list -- connecting" );
162 0 : connectClient( pClient, sPin );
163 0 : aFound = true;
164 0 : break;
165 0 : }
166 : }
167 :
168 : }
169 : // Pin not found so inform the client.
170 0 : if ( !aFound )
171 : {
172 : SAL_INFO( "sdremote", "client not found on validated list" );
173 : pSocket->write( "LO_SERVER_VALIDATING_PIN\n\n",
174 0 : strlen( "LO_SERVER_VALIDATING_PIN\n\n" ) );
175 0 : }
176 : } else {
177 : SAL_INFO( "sdremote", "client failed to send LO_SERVER_CLIENT_PAIR, ignoring" );
178 0 : delete pSocket;
179 : }
180 0 : }
181 : SAL_INFO( "sdremote", "shutting down RemoteServer" );
182 0 : spServer = NULL; // Object is destroyed when Thread::execute() ends.
183 : }
184 :
185 : RemoteServer *sd::RemoteServer::spServer = NULL;
186 22 : ::osl::Mutex sd::RemoteServer::sDataMutex;
187 22 : ::std::vector<Communicator*> sd::RemoteServer::sCommunicators;
188 :
189 0 : void RemoteServer::setup()
190 : {
191 0 : if (spServer)
192 0 : return;
193 :
194 0 : spServer = new RemoteServer();
195 0 : spServer->launch();
196 :
197 : #ifdef ENABLE_SDREMOTE_BLUETOOTH
198 0 : sd::BluetoothServer::setup( &sCommunicators );
199 : #endif
200 : }
201 :
202 0 : void RemoteServer::presentationStarted( const css::uno::Reference<
203 : css::presentation::XSlideShowController > &rController )
204 : {
205 0 : if ( !spServer )
206 0 : return;
207 0 : MutexGuard aGuard( sDataMutex );
208 0 : for ( vector<Communicator*>::const_iterator aIt = sCommunicators.begin();
209 0 : aIt != sCommunicators.end(); ++aIt )
210 : {
211 0 : (*aIt)->presentationStarted( rController );
212 0 : }
213 : }
214 0 : void RemoteServer::presentationStopped()
215 : {
216 0 : if ( !spServer )
217 0 : return;
218 0 : MutexGuard aGuard( sDataMutex );
219 0 : for ( vector<Communicator*>::const_iterator aIt = sCommunicators.begin();
220 0 : aIt != sCommunicators.end(); ++aIt )
221 : {
222 0 : (*aIt)->disposeListener();
223 0 : }
224 : }
225 :
226 0 : void RemoteServer::removeCommunicator( Communicator* mCommunicator )
227 : {
228 0 : if ( !spServer )
229 0 : return;
230 0 : MutexGuard aGuard( sDataMutex );
231 0 : for ( vector<Communicator*>::iterator aIt = sCommunicators.begin();
232 0 : aIt != sCommunicators.end(); ++aIt )
233 : {
234 0 : if ( mCommunicator == *aIt )
235 : {
236 0 : sCommunicators.erase( aIt );
237 0 : break;
238 : }
239 0 : }
240 : }
241 :
242 0 : std::vector< ::boost::shared_ptr< ClientInfo > > RemoteServer::getClients()
243 : {
244 : SAL_INFO( "sdremote", "RemoteServer::getClients() called" );
245 0 : std::vector< ::boost::shared_ptr< ClientInfo > > aClients;
246 0 : if ( spServer )
247 : {
248 0 : MutexGuard aGuard( sDataMutex );
249 : aClients.assign( spServer->mAvailableClients.begin(),
250 0 : spServer->mAvailableClients.end() );
251 : }
252 : else
253 : {
254 : SAL_INFO( "sdremote", "No remote server instance => no remote clients" );
255 : }
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 0 : Reference< XNameAccess > const xConfig = officecfg::Office::Impress::Misc::AuthorisedRemotes::get();
266 0 : Sequence< OUString > aNames = xConfig->getElementNames();
267 0 : for ( int i = 0; i < aNames.getLength(); i++ )
268 : {
269 0 : aClients.push_back( ::boost::shared_ptr< ClientInfo > ( new ClientInfo( aNames[i], "", true ) ) );
270 : }
271 :
272 0 : return aClients;
273 : }
274 :
275 0 : bool RemoteServer::connectClient( ::boost::shared_ptr< ClientInfo > pClient, const OUString& aPin )
276 : {
277 : SAL_INFO( "sdremote", "RemoteServer::connectClient called" );
278 0 : if ( !spServer )
279 0 : return false;
280 :
281 0 : ClientInfoInternal* apClient = dynamic_cast< ClientInfoInternal* >( pClient.get() );
282 0 : if ( !apClient )
283 : // could happen if we try to "connect" an already authorised client
284 : {
285 0 : return false;
286 : }
287 :
288 0 : if ( apClient->mPin.equals( aPin ) )
289 : {
290 : // Save in settings first
291 0 : std::shared_ptr< ConfigurationChanges > aChanges = ConfigurationChanges::create();
292 0 : Reference< XNameContainer > const xConfig = officecfg::Office::Impress::Misc::AuthorisedRemotes::get( aChanges );
293 :
294 : Reference<XSingleServiceFactory> xChildFactory (
295 0 : xConfig, UNO_QUERY);
296 0 : Reference<XNameReplace> xChild( xChildFactory->createInstance(), UNO_QUERY);
297 0 : Any aValue;
298 0 : if (xChild.is())
299 : {
300 : // Check whether the client is already saved
301 0 : bool aSaved = false;
302 0 : Sequence< OUString > aNames = xConfig->getElementNames();
303 0 : for ( int i = 0; i < aNames.getLength(); i++ )
304 : {
305 0 : if ( aNames[i].equals( apClient->mName ) )
306 : {
307 0 : xConfig->replaceByName( apClient->mName, makeAny( xChild ) );
308 0 : aSaved = true;
309 0 : break;
310 : }
311 : }
312 0 : if ( !aSaved )
313 0 : xConfig->insertByName( apClient->mName, makeAny( xChild ) );
314 0 : aValue <<= OUString( apClient->mPin );
315 0 : xChild->replaceByName("PIN", aValue);
316 0 : aChanges->commit();
317 : }
318 :
319 0 : Communicator* pCommunicator = new Communicator( apClient->mpStreamSocket );
320 0 : MutexGuard aGuard( sDataMutex );
321 :
322 0 : sCommunicators.push_back( pCommunicator );
323 :
324 0 : for ( vector< ::boost::shared_ptr< ClientInfoInternal > >::iterator aIt = spServer->mAvailableClients.begin();
325 0 : aIt != spServer->mAvailableClients.end(); ++aIt )
326 : {
327 0 : if ( pClient == *aIt )
328 : {
329 0 : spServer->mAvailableClients.erase( aIt );
330 0 : break;
331 : }
332 : }
333 0 : pCommunicator->launch();
334 0 : return true;
335 : }
336 : else
337 : {
338 0 : return false;
339 : }
340 : }
341 :
342 0 : void RemoteServer::deauthoriseClient( ::boost::shared_ptr< ClientInfo > pClient )
343 : {
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.
347 :
348 : SAL_INFO( "sdremote", "RemoteServer::deauthoriseClient called" );
349 :
350 0 : if ( !pClient->mbIsAlreadyAuthorised )
351 : // We can't remove unauthorised clients from the authorised list...
352 : {
353 0 : return;
354 : }
355 :
356 0 : std::shared_ptr< ConfigurationChanges > aChanges = ConfigurationChanges::create();
357 : Reference< XNameContainer > const xConfig =
358 0 : officecfg::Office::Impress::Misc::AuthorisedRemotes::get( aChanges );
359 :
360 0 : xConfig->removeByName( pClient->mName );
361 0 : aChanges->commit();
362 : }
363 :
364 2 : void SdDLL::RegisterRemotes()
365 : {
366 : SAL_INFO( "sdremote", "SdDLL::RegisterRemotes called" );
367 :
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 2 : if ( Application::IsHeadlessModeEnabled() )
380 2 : return;
381 :
382 2 : uno::Reference< uno::XComponentContext > xContext = comphelper::getProcessComponentContext();
383 2 : if ( xContext.is() && !officecfg::Office::Impress::Misc::Start::EnableSdremote::get( xContext ) )
384 2 : return;
385 :
386 0 : sd::RemoteServer::setup();
387 0 : sd::DiscoveryService::setup();
388 : }
389 :
390 0 : void RemoteServer::ensureDiscoverable()
391 : {
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 0 : BluetoothServer::ensureDiscoverable();
396 : #endif
397 0 : }
398 :
399 0 : void RemoteServer::restoreDiscoverable()
400 : {
401 : #ifdef ENABLE_SDREMOTE_BLUETOOTH
402 0 : BluetoothServer::restoreDiscoverable();
403 : #endif
404 66 : }
405 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|