Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/sd/source/ui/remotecontrol/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 12 kB image not shown  

Quelle  Server.cxx   Sprache: C

 
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */


#include <algorithm>
#include <utility>
#include <vector>

#include <officecfg/Office/Impress.hxx>
#include <officecfg/Office/Security.hxx>

#include <com/sun/star/container/XNameAccess.hpp>
#include <com/sun/star/container/XNameContainer.hpp>
#include <com/sun/star/uno/Sequence.hxx>
#include <com/sun/star/lang/XSingleServiceFactory.hpp>

#include <comphelper/processfactory.hxx>
#include <comphelper/configuration.hxx>
#include <comphelper/sequence.hxx>
#include <sal/log.hxx>
#include <vcl/svapp.hxx>
#include <osl/socket.hxx>

#include <sddll.hxx>

#include "DiscoveryService.hxx"
#include "Listener.hxx"
#include <RemoteServer.hxx>
#include "BluetoothServer.hxx"
#include "Communicator.hxx"
#include "BufferedStreamSocket.hxx"

using namespace sd;
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::container;
using namespace ::com::sun::star::lang;
using namespace ::osl;
using namespace ::comphelper;

namespace sd {
    /**
     * Used to keep track of clients that have attempted to connect, but haven't
     * yet been approved.
     */

    struct ClientInfoInternal:
        ClientInfo
    {
        BufferedStreamSocket *mpStreamSocket;
        OUString mPin;

        ClientInfoInternal( const OUString& rName,
                            BufferedStreamSocket *pSocket,
                            OUString aPin ):
                ClientInfo( rName, false ),
                mpStreamSocket( pSocket ),
                mPin(std::move( aPin )) {}
    };
}

IPRemoteServer::IPRemoteServer()
    : Thread("IPRemoteServerThread")
{
    SAL_INFO("sdremote""Instantiated IPRemoteServer");
}

IPRemoteServer::~IPRemoteServer()
{
}

void IPRemoteServer::execute()
{
    SAL_INFO("sdremote""IPRemoteServer::execute called");
    osl::SocketAddr aAddr( u"0.0.0.0"_ustr, PORT );
    if ( !mSocket.bind( aAddr ) )
    {
        SAL_WARN( "sdremote""bind failed" << mSocket.getErrorAsString() );
        spServer = nullptr;
        return;
    }

    if ( !mSocket.listen(3) )
    {
        SAL_WARN( "sdremote""listen failed" << mSocket.getErrorAsString() );
        spServer = nullptr;
        return;
    }
    while ( true )
    {
        StreamSocket aSocket;
        SAL_INFO( "sdremote""waiting on accept" );
        if ( mSocket.acceptConnection( aSocket ) == osl_Socket_Error )
        {
            SAL_WARN( "sdremote""accept failed" << mSocket.getErrorAsString() );
            break// Closed, or other issue.
        }
        BufferedStreamSocket *pSocket = new BufferedStreamSocket( aSocket);
        handleAcceptedConnection( pSocket );
    }
    SAL_INFO("sdremote""shutting down IPRemoteServer");
    spServer = nullptr; // Object is destroyed when Thread::execute() ends.
}

void IPRemoteServer::handleAcceptedConnection( BufferedStreamSocket *pSocket )
{
    OString aLine;
    if ( ! ( pSocket->readLine( aLine)
             && aLine == "LO_SERVER_CLIENT_PAIR"
             && pSocket->readLine( aLine ) ) )
    {
        SAL_INFO( "sdremote""client failed to send LO_SERVER_CLIENT_PAIR, ignoring" );
        delete pSocket;
        return;
    }

    OString aName( aLine );

    if ( ! pSocket->readLine( aLine ) )
    {
        delete pSocket;
        return;
    }
    OString aPin( aLine );

    SocketAddr aClientAddr;
    pSocket->getPeerAddr( aClientAddr );

    do
    {
        // Read off any additional non-empty lines
        // We know that we at least have the empty termination line to read.
        if ( ! pSocket->readLine( aLine ) ) {
            delete pSocket;
            return;
        }
    }
    while ( aLine.getLength() > 0 );

    MutexGuard aGuard(RemoteServer::sDataMutex);
    std::shared_ptr< ClientInfoInternal > pClient =
        std::make_shared<ClientInfoInternal>(
            OStringToOUString( aName, RTL_TEXTENCODING_UTF8 ),
            pSocket, OStringToOUString( aPin, RTL_TEXTENCODING_UTF8 ) );
    mAvailableClients.push_back( pClient );

    // Check if we already have this server.
    Reference< XNameAccess > const xConfig = officecfg::Office::Impress::Misc::AuthorisedRemotes::get();
    const Sequence< OUString > aNames = xConfig->getElementNames();
    for ( const auto& rName : aNames )
    {
        if ( rName == pClient->mName )
        {
            Reference<XNameAccess> xSetItem( xConfig->getByName(rName), UNO_QUERY );
            Any axPin(xSetItem->getByName(u"PIN"_ustr));
            OUString sPin;
            axPin >>= sPin;

            if ( sPin == pClient->mPin ) {
                SAL_INFO( "sdremote""client found on validated list -- connecting" );
                connectClient( pClient, sPin );
                return;
            }
        }
    }

    // Pin not found so inform the client.
    SAL_INFO( "sdremote""client not found on validated list" );
    pSocket->write( "LO_SERVER_VALIDATING_PIN\n\n",
                    strlen( "LO_SERVER_VALIDATING_PIN\n\n" ) );
}

IPRemoteServer *sd::IPRemoteServer::spServer = nullptr;
::osl::Mutex sd::RemoteServer::sDataMutex;
::std::vector<Communicator*> sd::RemoteServer::sCommunicators;

void IPRemoteServer::setup()
{
    if (spServer)
        return;

    spServer = new IPRemoteServer();
    spServer->launch();
}

void RemoteServer::presentationStarted( const css::uno::Reference<
                css::presentation::XSlideShowController > &rController )
{
    // note this can be invoked even when there is no IPRemoteServer instance
    // but there are communicators belonging to a BluetoothServer
    MutexGuard aGuard( sDataMutex );
    for ( const auto& rpCommunicator : sCommunicators )
    {
        rpCommunicator->presentationStarted( rController );
    }
}
void RemoteServer::presentationStopped()
{
    MutexGuard aGuard( sDataMutex );
    for ( const auto& rpCommunicator : sCommunicators )
    {
        rpCommunicator->disposeListener();
    }
}

void RemoteServer::removeCommunicator( Communicator const * mCommunicator )
{
    MutexGuard aGuard( sDataMutex );
    auto aIt = std::find(sCommunicators.begin(), sCommunicators.end(), mCommunicator);
    if (aIt != sCommunicators.end())
        sCommunicators.erase( aIt );
}

std::vector<std::shared_ptr<ClientInfo>> IPRemoteServer::getClients()
{
    SAL_INFO( "sdremote""IPRemoteServer::getClients() called" );
    std::vector< std::shared_ptr< ClientInfo > > aClients;
    if ( spServer )
    {
        MutexGuard aGuard(RemoteServer::sDataMutex);
        aClients.assign( spServer->mAvailableClients.begin(),
                         spServer->mAvailableClients.end() );
    }
    else
    {
        SAL_INFO( "sdremote""No remote server instance => no remote clients" );
    }
    // We also need to provide authorised clients (no matter whether or not
    // they are actually available), so that they can be de-authorised if
    // necessary. We specifically want these to be at the end of the list
    // since the user is more likely to be trying to connect a new remote
    // than removing an existing remote.
    // We can also be sure that pre-authorised clients will not be on the
    // available clients list, as they get automatically connected if seen.
    // TODO: we should probably add some sort of extra labelling to mark
    // authorised AND connected client.
    Reference< XNameAccess > const xConfig = officecfg::Office::Impress::Misc::AuthorisedRemotes::get();
    const Sequence< OUString > aNames = xConfig->getElementNames();
    std::transform(aNames.begin(), aNames.end(), std::back_inserter(aClients),
        [](const OUString& rName) -> std::shared_ptr<ClientInfo> {
            return std::make_shared<ClientInfo>(rName, true); });

    return aClients;
}

bool IPRemoteServer::connectClient(const std::shared_ptr<ClientInfo>& pClient, std::u16string_view aPin)
{
    SAL_INFO("sdremote""IPRemoteServer::connectClient called");
    if ( !spServer )
        return false;

    ClientInfoInternal* apClient = dynamic_cast< ClientInfoInternal* >( pClient.get() );
    if ( !apClient )
    // could happen if we try to "connect" an already authorised client
    {
        return false;
    }

    if ( apClient->mPin == aPin )
    {
        // Save in settings first
        std::shared_ptr< ConfigurationChanges > aChanges = ConfigurationChanges::create();
        Reference< XNameContainer > const xConfig = officecfg::Office::Impress::Misc::AuthorisedRemotes::get( aChanges );

        Reference<XSingleServiceFactory> xChildFactory (
            xConfig, UNO_QUERY);
        Reference<XNameReplace> xChild( xChildFactory->createInstance(), UNO_QUERY);
        Any aValue;
        if (xChild.is())
        {
            // Check whether the client is already saved
            Sequence< OUString > aNames = xConfig->getElementNames();
            if (comphelper::findValue(aNames, apClient->mName) != -1)
                xConfig->replaceByName( apClient->mName, Any( xChild ) );
            else
                xConfig->insertByName( apClient->mName, Any( xChild ) );
            aValue <<= apClient->mPin;
            xChild->replaceByName(u"PIN"_ustr, aValue);
            aChanges->commit();
        }

        Communicator* pCommunicator = new Communicator( std::unique_ptr<IBluetoothSocket>(apClient->mpStreamSocket) );
        MutexGuard aGuard(RemoteServer::sDataMutex);

        RemoteServer::sCommunicators.push_back( pCommunicator );

        auto aIt = std::find(spServer->mAvailableClients.begin(), spServer->mAvailableClients.end(), pClient);
        if (aIt != spServer->mAvailableClients.end())
            spServer->mAvailableClients.erase( aIt );
        pCommunicator->launch();
        return true;
    }
    else
    {
        return false;
    }
}

void IPRemoteServer::deauthoriseClient(const std::shared_ptr<ClientInfo>& pClient)
{
    // TODO: we probably want to forcefully disconnect at this point too?
    // But possibly via a separate function to allow just disconnecting from
    // the UI.

    SAL_INFO("sdremote""IPRemoteServer::deauthoriseClient called");

    if ( !pClient->mbIsAlreadyAuthorised )
    // We can't remove unauthorised clients from the authorised list...
    {
        return;
    }

    std::shared_ptr< ConfigurationChanges > aChanges = ConfigurationChanges::create();
    Reference< XNameContainer > const xConfig =
        officecfg::Office::Impress::Misc::AuthorisedRemotes::get( aChanges );

    xConfig->removeByName( pClient->mName );
    aChanges->commit();
}

void SdDLL::RegisterRemotes()
{
    SAL_INFO( "sdremote""SdDLL::RegisterRemotes called" );

    // The remote server is likely of no use in headless mode. And as only
    // one instance of the server can actually own the appropriate ports its
    // probably best to not even try to do so from our headless instance
    // (i.e. as to avoid blocking expected usage).
    // It could perhaps be argued that we would still need the remote
    // server for tiled rendering of presentations, but even then this
    // implementation would not be of much use, i.e. would be controlling
    // the purely imaginary headless presentation -- instead we'd need
    // to have some sort of mechanism of plugging in our tiled rendering
    // client to be controlled by the remote server, or provide an
    // alternative implementation.
    if ( Application::IsHeadlessModeEnabled() )
        return;

    if ( !officecfg::Office::Impress::Misc::Start::EnableSdremote::get() )
        return;

#ifdef ENABLE_SDREMOTE_BLUETOOTH
    sd::BluetoothServer::setup( &RemoteServer::sCommunicators );
#endif

    if (!officecfg::Office::Security::Net::AllowInsecureImpressRemoteWiFi::get())
    {
        SAL_WARN("desktop""Impress remote WiFi is disabled by configuration");
        return;
    }

    // this is the IP/WiFi server
    sd::IPRemoteServer::setup();
    // assumption is that BluetoothServer doesn't need DiscoveryService
    sd::DiscoveryService::setup();
}

void RemoteServer::ensureDiscoverable()
{
    // FIXME: we could also enable listening on our WiFi
    // socket here to significantly reduce the attack surface.
#ifdef ENABLE_SDREMOTE_BLUETOOTH
    BluetoothServer::ensureDiscoverable();
#endif
}

void RemoteServer::restoreDiscoverable()
{
#ifdef ENABLE_SDREMOTE_BLUETOOTH
    BluetoothServer::restoreDiscoverable();
#endif
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Messung V0.5
C=93 H=94 G=93

¤ Dauer der Verarbeitung: 0.1 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.