From 267c6f2ac71f92999e969232431ba04678e7437e Mon Sep 17 00:00:00 2001
From: Daniel Baumann <daniel.baumann@progress-linux.org>
Date: Mon, 15 Apr 2024 07:54:39 +0200
Subject: Adding upstream version 4:24.2.0.

Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
---
 io/source/acceptor/acc_pipe.cxx   | 191 +++++++++++++++++++++
 io/source/acceptor/acc_socket.cxx | 350 ++++++++++++++++++++++++++++++++++++++
 io/source/acceptor/acceptor.cxx   | 253 +++++++++++++++++++++++++++
 io/source/acceptor/acceptor.hxx   |  76 +++++++++
 4 files changed, 870 insertions(+)
 create mode 100644 io/source/acceptor/acc_pipe.cxx
 create mode 100644 io/source/acceptor/acc_socket.cxx
 create mode 100644 io/source/acceptor/acceptor.cxx
 create mode 100644 io/source/acceptor/acceptor.hxx

(limited to 'io/source/acceptor')

diff --git a/io/source/acceptor/acc_pipe.cxx b/io/source/acceptor/acc_pipe.cxx
new file mode 100644
index 0000000000..c3af874498
--- /dev/null
+++ b/io/source/acceptor/acc_pipe.cxx
@@ -0,0 +1,191 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <osl/security.hxx>
+#include "acceptor.hxx"
+#include <com/sun/star/connection/XConnection.hpp>
+#include <com/sun/star/connection/ConnectionSetupException.hpp>
+#include <com/sun/star/io/IOException.hpp>
+
+#include <osl/diagnose.h>
+#include <cppuhelper/implbase.hxx>
+#include <rtl/ref.hxx>
+#include <utility>
+
+using namespace ::osl;
+using namespace ::cppu;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::connection;
+using namespace ::com::sun::star::io;
+
+
+namespace io_acceptor
+{
+    namespace {
+
+    class PipeConnection :
+        public WeakImplHelper< XConnection >
+    {
+    public:
+        explicit PipeConnection( OUString sConnectionDescription);
+
+        virtual sal_Int32 SAL_CALL read( Sequence< sal_Int8 >& aReadBytes, sal_Int32 nBytesToRead ) override;
+        virtual void SAL_CALL write( const Sequence< sal_Int8 >& aData ) override;
+        virtual void SAL_CALL flush(  ) override;
+        virtual void SAL_CALL close(  ) override;
+        virtual OUString SAL_CALL getDescription(  ) override;
+    public:
+        ::osl::StreamPipe m_pipe;
+        oslInterlockedCount m_nStatus;
+        OUString m_sDescription;
+    };
+
+    }
+
+    PipeConnection::PipeConnection( OUString sConnectionDescription) :
+        m_nStatus( 0 ),
+        m_sDescription(std::move( sConnectionDescription ))
+    {
+        // make it unique
+        m_sDescription += ",uniqueValue=";
+        m_sDescription += OUString::number(
+            sal::static_int_cast<sal_Int64 >(
+                reinterpret_cast< sal_IntPtr >(&m_pipe)) );
+    }
+
+    sal_Int32 PipeConnection::read( Sequence < sal_Int8 > & aReadBytes , sal_Int32 nBytesToRead )
+    {
+        if( m_nStatus )
+        {
+            throw IOException("pipe already closed");
+        }
+        if( aReadBytes.getLength() < nBytesToRead )
+        {
+            aReadBytes.realloc( nBytesToRead );
+        }
+        sal_Int32 n = m_pipe.read( aReadBytes.getArray(), nBytesToRead );
+        OSL_ASSERT( n >= 0 && n <= aReadBytes.getLength() );
+        if( n < aReadBytes.getLength() )
+        {
+            aReadBytes.realloc( n );
+        }
+        return n;
+
+    }
+
+    void PipeConnection::write( const Sequence < sal_Int8 > &seq )
+    {
+        if( m_nStatus )
+        {
+            throw IOException("pipe already closed");
+        }
+        if( m_pipe.write( seq.getConstArray() , seq.getLength() ) != seq.getLength() )
+        {
+            throw IOException("short write");
+        }
+    }
+
+    void PipeConnection::flush( )
+    {
+    }
+
+    void PipeConnection::close()
+    {
+        if(  1 == osl_atomic_increment( (&m_nStatus) ) )
+        {
+            m_pipe.close();
+        }
+    }
+
+    OUString PipeConnection::getDescription()
+    {
+        return m_sDescription;
+    }
+
+    /***************
+     * PipeAcceptor
+     **************/
+    PipeAcceptor::PipeAcceptor( OUString sPipeName , OUString sConnectionDescription) :
+        m_sPipeName(std::move( sPipeName )),
+        m_sConnectionDescription(std::move( sConnectionDescription )),
+        m_bClosed( false )
+    {
+    }
+
+
+    void PipeAcceptor::init()
+    {
+        m_pipe = Pipe( m_sPipeName.pData , osl_Pipe_CREATE , osl::Security() );
+        if( ! m_pipe.is() )
+        {
+            OUString error = "io.acceptor: Couldn't setup pipe " + m_sPipeName;
+            throw ConnectionSetupException( error );
+        }
+    }
+
+    Reference< XConnection > PipeAcceptor::accept( )
+    {
+        Pipe pipe;
+        {
+            std::unique_lock guard( m_mutex );
+            pipe = m_pipe;
+        }
+        if( ! pipe.is() )
+        {
+            OUString error = "io.acceptor: pipe already closed" + m_sPipeName;
+            throw ConnectionSetupException( error );
+        }
+        rtl::Reference<PipeConnection> pConn(new PipeConnection( m_sConnectionDescription ));
+
+        oslPipeError status = pipe.accept( pConn->m_pipe );
+
+        if( m_bClosed )
+        {
+            // stopAccepting was called !
+            return Reference < XConnection >();
+        }
+        else if( osl_Pipe_E_None == status )
+        {
+            return pConn;
+        }
+        else
+        {
+            OUString error = "io.acceptor: Couldn't setup pipe " + m_sPipeName;
+            throw ConnectionSetupException( error );
+        }
+    }
+
+    void PipeAcceptor::stopAccepting()
+    {
+        m_bClosed = true;
+        Pipe pipe;
+        {
+            std::unique_lock guard( m_mutex );
+            pipe = m_pipe;
+            m_pipe.clear();
+        }
+        if( pipe.is() )
+        {
+            pipe.close();
+        }
+    }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/io/source/acceptor/acc_socket.cxx b/io/source/acceptor/acc_socket.cxx
new file mode 100644
index 0000000000..c211acdc3a
--- /dev/null
+++ b/io/source/acceptor/acc_socket.cxx
@@ -0,0 +1,350 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "acceptor.hxx"
+
+#include <unordered_set>
+
+#include <mutex>
+#include <rtl/ref.hxx>
+#include <com/sun/star/connection/XConnection.hpp>
+#include <com/sun/star/connection/XConnectionBroadcaster.hpp>
+#include <com/sun/star/connection/ConnectionSetupException.hpp>
+#include <com/sun/star/io/IOException.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <utility>
+
+using namespace ::osl;
+using namespace ::cppu;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::connection;
+
+
+namespace io_acceptor {
+
+    typedef std::unordered_set< css::uno::Reference< css::io::XStreamListener> >
+            XStreamListener_hash_set;
+
+    namespace {
+
+    class SocketConnection : public ::cppu::WeakImplHelper<
+        css::connection::XConnection,
+        css::connection::XConnectionBroadcaster>
+
+    {
+    public:
+        explicit SocketConnection( OUString sConnectionDescription );
+
+        virtual sal_Int32 SAL_CALL read( css::uno::Sequence< sal_Int8 >& aReadBytes,
+                                         sal_Int32 nBytesToRead ) override;
+        virtual void SAL_CALL write( const css::uno::Sequence< sal_Int8 >& aData ) override;
+        virtual void SAL_CALL flush(  ) override;
+        virtual void SAL_CALL close(  ) override;
+        virtual OUString SAL_CALL getDescription(  ) override;
+
+        // XConnectionBroadcaster
+        virtual void SAL_CALL addStreamListener(const css::uno::Reference< css::io::XStreamListener>& aListener) override;
+        virtual void SAL_CALL removeStreamListener(const css::uno::Reference< css::io::XStreamListener>& aListener) override;
+
+    public:
+        void completeConnectionString();
+
+        ::osl::StreamSocket m_socket;
+        oslInterlockedCount m_nStatus;
+        OUString m_sDescription;
+
+        std::mutex _mutex;
+        bool     _started;
+        bool     _closed;
+        bool     _error;
+        XStreamListener_hash_set _listeners;
+    };
+
+    }
+
+    template<class T>
+    static void notifyListeners(SocketConnection * pCon, bool * notified, T t)
+    {
+        XStreamListener_hash_set listeners;
+
+        {
+            std::unique_lock guard(pCon->_mutex);
+            if(!*notified)
+            {
+                *notified = true;
+                listeners = pCon->_listeners;
+            }
+        }
+
+        for(auto& listener : listeners)
+            t(listener);
+    }
+
+    static void callStarted(const Reference<XStreamListener>& xStreamListener)
+    {
+        xStreamListener->started();
+    }
+
+    namespace {
+
+    struct callError {
+        const Any & any;
+
+        explicit callError(const Any & any);
+
+        void operator () (const Reference<XStreamListener>& xStreamListener);
+    };
+
+    }
+
+    callError::callError(const Any & aAny)
+        : any(aAny)
+    {
+    }
+
+    void callError::operator () (const Reference<XStreamListener>& xStreamListener)
+    {
+        xStreamListener->error(any);
+    }
+
+    static void callClosed(const Reference<XStreamListener>& xStreamListener)
+    {
+        xStreamListener->closed();
+    }
+
+
+    SocketConnection::SocketConnection( OUString sConnectionDescription) :
+        m_nStatus( 0 ),
+        m_sDescription(std::move( sConnectionDescription )),
+        _started(false),
+        _closed(false),
+        _error(false)
+    {
+        // make it unique
+        m_sDescription += ",uniqueValue=" ;
+        m_sDescription += OUString::number(
+            sal::static_int_cast< sal_Int64 >(
+                reinterpret_cast< sal_IntPtr >(&m_socket)) );
+    }
+
+    void SocketConnection::completeConnectionString()
+    {
+        m_sDescription +=
+            ",peerPort=" + OUString::number(m_socket.getPeerPort()) +
+            ",peerHost=" + m_socket.getPeerHost( ) +
+            ",localPort=" + OUString::number( m_socket.getLocalPort() ) +
+            ",localHost=" + m_socket.getLocalHost();
+    }
+
+    sal_Int32 SocketConnection::read( Sequence < sal_Int8 > & aReadBytes , sal_Int32 nBytesToRead )
+    {
+        if( ! m_nStatus )
+        {
+            notifyListeners(this, &_started, callStarted);
+
+            if( aReadBytes.getLength() != nBytesToRead )
+            {
+                aReadBytes.realloc( nBytesToRead );
+            }
+
+            sal_Int32 i = m_socket.read(
+                aReadBytes.getArray(), aReadBytes.getLength());
+
+            if(i != nBytesToRead)
+            {
+                OUString message = "acc_socket.cxx:SocketConnection::read: error - " +
+                    m_socket.getErrorAsString();
+
+                IOException ioException(message, static_cast<XConnection *>(this));
+
+                Any any;
+                any <<= ioException;
+
+                notifyListeners(this, &_error, callError(any));
+
+                throw ioException;
+            }
+
+            return i;
+        }
+        else
+        {
+            IOException ioException("acc_socket.cxx:SocketConnection::read: error - connection already closed", static_cast<XConnection *>(this));
+
+            Any any;
+            any <<= ioException;
+
+            notifyListeners(this, &_error, callError(any));
+
+            throw ioException;
+        }
+    }
+
+    void SocketConnection::write( const Sequence < sal_Int8 > &seq )
+    {
+        if( ! m_nStatus )
+        {
+            if( m_socket.write( seq.getConstArray() , seq.getLength() ) != seq.getLength() )
+            {
+                OUString message = "acc_socket.cxx:SocketConnection::write: error - " +
+                    m_socket.getErrorAsString();
+
+                IOException ioException(message, static_cast<XConnection *>(this));
+
+                Any any;
+                any <<= ioException;
+
+                notifyListeners(this, &_error, callError(any));
+
+                throw ioException;
+            }
+        }
+        else
+        {
+            IOException ioException("acc_socket.cxx:SocketConnection::write: error - connection already closed", static_cast<XConnection *>(this));
+
+            Any any;
+            any <<= ioException;
+
+            notifyListeners(this, &_error, callError(any));
+
+            throw ioException;
+        }
+    }
+
+    void SocketConnection::flush( )
+    {
+
+    }
+
+    void SocketConnection::close()
+    {
+        // ensure close is called only once
+        if(  1 == osl_atomic_increment( (&m_nStatus) ) )
+        {
+            m_socket.shutdown();
+            notifyListeners(this, &_closed, callClosed);
+        }
+    }
+
+    OUString SocketConnection::getDescription()
+    {
+        return m_sDescription;
+    }
+
+
+    // XConnectionBroadcaster
+    void SAL_CALL SocketConnection::addStreamListener(const Reference<XStreamListener> & aListener)
+    {
+        std::unique_lock guard(_mutex);
+
+        _listeners.insert(aListener);
+    }
+
+    void SAL_CALL SocketConnection::removeStreamListener(const Reference<XStreamListener> & aListener)
+    {
+        std::unique_lock guard(_mutex);
+
+        _listeners.erase(aListener);
+    }
+
+    SocketAcceptor::SocketAcceptor( OUString sSocketName,
+                                    sal_uInt16 nPort,
+                                    bool bTcpNoDelay,
+                                    OUString sConnectionDescription) :
+        m_sSocketName(std::move( sSocketName )),
+        m_sConnectionDescription(std::move( sConnectionDescription )),
+        m_nPort( nPort ),
+        m_bTcpNoDelay( bTcpNoDelay ),
+        m_bClosed( false )
+    {
+    }
+
+
+    void SocketAcceptor::init()
+    {
+        if( ! m_addr.setPort( m_nPort ) )
+        {
+            throw ConnectionSetupException(
+                "acc_socket.cxx:SocketAcceptor::init - error - invalid tcp/ip port " +
+                OUString::number( m_nPort ));
+        }
+        if( ! m_addr.setHostname( m_sSocketName.pData ) )
+        {
+            throw ConnectionSetupException(
+                "acc_socket.cxx:SocketAcceptor::init - error - invalid host " + m_sSocketName );
+        }
+        m_socket.setOption( osl_Socket_OptionReuseAddr, 1);
+
+        if(! m_socket.bind(m_addr) )
+        {
+            throw ConnectionSetupException(
+                "acc_socket.cxx:SocketAcceptor::init - error - couldn't bind on " +
+                m_sSocketName + ":" + OUString::number(m_nPort));
+        }
+
+        if(! m_socket.listen() )
+        {
+            throw ConnectionSetupException(
+                "acc_socket.cxx:SocketAcceptor::init - error - can't listen on " +
+                m_sSocketName  + ":" + OUString::number(m_nPort) );
+        }
+    }
+
+    Reference< XConnection > SocketAcceptor::accept( )
+    {
+        rtl::Reference<SocketConnection> pConn(new SocketConnection( m_sConnectionDescription ));
+
+        if( m_socket.acceptConnection( pConn->m_socket )!= osl_Socket_Ok )
+        {
+            // stopAccepting was called
+            return Reference < XConnection > ();
+        }
+        if( m_bClosed )
+        {
+            return Reference < XConnection > ();
+        }
+
+        pConn->completeConnectionString();
+        ::osl::SocketAddr remoteAddr;
+        pConn->m_socket.getPeerAddr(remoteAddr);
+        OUString remoteHostname = remoteAddr.getHostname();
+        // we enable tcpNoDelay for loopback connections because
+        // it can make a significant speed difference on linux boxes.
+        if( m_bTcpNoDelay || remoteHostname == "localhost" ||
+            remoteHostname.startsWith("127.0.0.") )
+        {
+            sal_Int32 nTcpNoDelay = sal_Int32(true);
+            pConn->m_socket.setOption( osl_Socket_OptionTcpNoDelay , &nTcpNoDelay,
+                                       sizeof( nTcpNoDelay ) , osl_Socket_LevelTcp );
+        }
+
+        return pConn;
+    }
+
+    void SocketAcceptor::stopAccepting()
+    {
+        m_bClosed = true;
+        m_socket.close();
+    }
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/io/source/acceptor/acceptor.cxx b/io/source/acceptor/acceptor.cxx
new file mode 100644
index 0000000000..af0883be97
--- /dev/null
+++ b/io/source/acceptor/acceptor.cxx
@@ -0,0 +1,253 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/unourl.hxx>
+#include <rtl/malformeduriexception.hxx>
+
+#include <com/sun/star/connection/AlreadyAcceptingException.hpp>
+#include <com/sun/star/connection/ConnectionSetupException.hpp>
+#include <com/sun/star/connection/XAcceptor.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+#include "acceptor.hxx"
+#include <memory>
+#include <mutex>
+#include <string_view>
+
+using namespace ::osl;
+using namespace ::cppu;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::connection;
+
+namespace {
+
+    class OAcceptor : public WeakImplHelper< XAcceptor, XServiceInfo >
+    {
+    public:
+        explicit OAcceptor(const Reference< XComponentContext > & xCtx);
+        virtual ~OAcceptor() override;
+    public:
+        // Methods
+        virtual Reference< XConnection > SAL_CALL accept( const OUString& sConnectionDescription ) override;
+        virtual void SAL_CALL stopAccepting(  ) override;
+
+    public: // XServiceInfo
+                virtual OUString              SAL_CALL getImplementationName() override;
+                virtual Sequence< OUString >  SAL_CALL getSupportedServiceNames() override;
+                virtual sal_Bool              SAL_CALL supportsService(const OUString& ServiceName) override;
+
+    private:
+        std::unique_ptr<io_acceptor::PipeAcceptor> m_pPipe;
+        std::unique_ptr<io_acceptor::SocketAcceptor> m_pSocket;
+        std::mutex m_mutex;
+        OUString m_sLastDescription;
+        bool m_bInAccept;
+
+        Reference< XMultiComponentFactory > _xSMgr;
+        Reference< XComponentContext > _xCtx;
+        Reference<XAcceptor>         _xAcceptor;
+    };
+
+}
+
+OAcceptor::OAcceptor( const Reference< XComponentContext > & xCtx )
+    : m_bInAccept( false )
+    , _xSMgr( xCtx->getServiceManager() )
+    , _xCtx( xCtx )
+{}
+
+OAcceptor::~OAcceptor()
+{
+    m_pPipe.reset();
+}
+
+namespace {
+struct BeingInAccept
+{
+    /// @throws AlreadyAcceptingException
+    BeingInAccept( bool *pFlag,std::u16string_view sConnectionDescription  )
+        : m_pFlag( pFlag )
+        {
+              if( *m_pFlag )
+                  throw AlreadyAcceptingException( OUString::Concat("AlreadyAcceptingException :") + sConnectionDescription );
+              *m_pFlag = true;
+        }
+    ~BeingInAccept()
+        {
+            *m_pFlag = false;
+        }
+    bool *m_pFlag;
+};
+}
+
+Reference< XConnection > OAcceptor::accept( const OUString &sConnectionDescription )
+{
+    // if there is a thread already accepting in this object, throw an exception.
+    struct BeingInAccept guard( &m_bInAccept, sConnectionDescription );
+
+    Reference< XConnection > r;
+    if( !m_sLastDescription.isEmpty() &&
+        m_sLastDescription != sConnectionDescription )
+    {
+        // instantiate another acceptor for different ports
+        throw ConnectionSetupException( "acceptor::accept called multiple times with different connection strings\n" );
+    }
+
+    if( m_sLastDescription.isEmpty() )
+    {
+        // setup the acceptor
+        try
+        {
+            cppu::UnoUrlDescriptor aDesc(sConnectionDescription);
+            if ( aDesc.getName() == "pipe" )
+            {
+                OUString aName(
+                    aDesc.getParameter(
+                        "name"));
+
+                m_pPipe.reset(new io_acceptor::PipeAcceptor(aName, sConnectionDescription));
+
+                try
+                {
+                    m_pPipe->init();
+                }
+                catch( ... )
+                {
+                    {
+                        std::unique_lock g( m_mutex );
+                        m_pPipe.reset();
+                    }
+                    throw;
+                }
+            }
+            else if ( aDesc.getName() == "socket" )
+            {
+                OUString aHost;
+                if (aDesc.hasParameter(
+                        "host"))
+                    aHost = aDesc.getParameter(
+                        "host");
+                else
+                    aHost = "localhost";
+                sal_uInt16 nPort = static_cast< sal_uInt16 >(
+                    aDesc.getParameter(
+                        "port").
+                    toInt32());
+                bool bTcpNoDelay
+                    = aDesc.getParameter(
+                        "tcpnodelay").toInt32() != 0;
+
+                m_pSocket.reset(new io_acceptor::SocketAcceptor(
+                    aHost, nPort, bTcpNoDelay, sConnectionDescription));
+
+                try
+                {
+                    m_pSocket->init();
+                }
+                catch( ... )
+                {
+                    {
+                        std::unique_lock g( m_mutex );
+                        m_pSocket.reset();
+                    }
+                    throw;
+                }
+            }
+            else
+            {
+                OUString delegatee = "com.sun.star.connection.Acceptor." + aDesc.getName();
+                _xAcceptor.set(_xSMgr->createInstanceWithContext(delegatee, _xCtx), UNO_QUERY);
+
+                if(!_xAcceptor.is())
+                    throw ConnectionSetupException("Acceptor: unknown delegatee " + delegatee);
+            }
+        }
+        catch (const rtl::MalformedUriException & rEx)
+        {
+            throw IllegalArgumentException(
+                rEx.getMessage(),
+                Reference< XInterface > (),
+                0 );
+        }
+        m_sLastDescription = sConnectionDescription;
+    }
+
+    if( m_pPipe )
+    {
+        r = m_pPipe->accept();
+    }
+    else if( m_pSocket )
+    {
+        r = m_pSocket->accept();
+    }
+    else
+    {
+        r = _xAcceptor->accept(sConnectionDescription);
+    }
+
+    return r;
+}
+
+void SAL_CALL OAcceptor::stopAccepting(  )
+{
+    std::unique_lock guard( m_mutex );
+
+    if( m_pPipe )
+    {
+        m_pPipe->stopAccepting();
+    }
+    else if ( m_pSocket )
+    {
+        m_pSocket->stopAccepting();
+    }
+    else if( _xAcceptor.is() )
+    {
+        _xAcceptor->stopAccepting();
+    }
+
+}
+
+OUString OAcceptor::getImplementationName()
+{
+    return "com.sun.star.comp.io.Acceptor";
+}
+
+sal_Bool OAcceptor::supportsService(const OUString& ServiceName)
+{
+    return cppu::supportsService(this, ServiceName);
+}
+
+Sequence< OUString > OAcceptor::getSupportedServiceNames()
+{
+    return { "com.sun.star.connection.Acceptor" };
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+io_OAcceptor_get_implementation(
+    css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
+{
+    return cppu::acquire(new OAcceptor(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/io/source/acceptor/acceptor.hxx b/io/source/acceptor/acceptor.hxx
new file mode 100644
index 0000000000..221ad16d2b
--- /dev/null
+++ b/io/source/acceptor/acceptor.hxx
@@ -0,0 +1,76 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <osl/pipe.hxx>
+#include <osl/socket.hxx>
+#include <mutex>
+
+#include <com/sun/star/uno/Reference.hxx>
+
+namespace com::sun::star::connection { class XConnection; }
+
+namespace io_acceptor {
+
+    class PipeAcceptor
+    {
+    public:
+        PipeAcceptor( OUString sPipeName, OUString sConnectionDescription );
+
+        void init();
+        css::uno::Reference < css::connection::XConnection >  accept(  );
+
+        void stopAccepting();
+
+    private:
+        std::mutex m_mutex;
+        ::osl::Pipe m_pipe;
+        OUString m_sPipeName;
+        OUString m_sConnectionDescription;
+        bool m_bClosed;
+    };
+
+    class SocketAcceptor
+    {
+    public:
+        SocketAcceptor( OUString sSocketName ,
+                        sal_uInt16 nPort,
+                        bool bTcpNoDelay,
+                        OUString sConnectionDescription );
+
+        void init();
+        css::uno::Reference < css::connection::XConnection > accept();
+
+        void stopAccepting();
+
+    private:
+        ::osl::SocketAddr m_addr;
+        ::osl::AcceptorSocket m_socket;
+        OUString m_sSocketName;
+        OUString m_sConnectionDescription;
+        sal_uInt16 m_nPort;
+        bool m_bTcpNoDelay;
+        bool m_bClosed;
+    };
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
-- 
cgit v1.2.3