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  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <osl/security.hxx>
21 #include "acceptor.hxx"
22 #include <com/sun/star/connection/XConnection.hpp>
23 #include <com/sun/star/connection/ConnectionSetupException.hpp>
24 #include <com/sun/star/io/IOException.hpp>
25 
26 #include <osl/diagnose.h>
27 #include <osl/mutex.hxx>
28 #include <cppuhelper/implbase.hxx>
29 #include <rtl/ref.hxx>
30 
31 using namespace ::osl;
32 using namespace ::cppu;
33 using namespace ::com::sun::star::uno;
34 using namespace ::com::sun::star::lang;
35 using namespace ::com::sun::star::connection;
36 using namespace ::com::sun::star::io;
37 
38 
39 namespace io_acceptor
40 {
41     namespace {
42 
43     class PipeConnection :
44         public WeakImplHelper< XConnection >
45     {
46     public:
47         explicit PipeConnection( const OUString &sConnectionDescription);
48 
49         virtual sal_Int32 SAL_CALL read( Sequence< sal_Int8 >& aReadBytes, sal_Int32 nBytesToRead ) override;
50         virtual void SAL_CALL write( const Sequence< sal_Int8 >& aData ) override;
51         virtual void SAL_CALL flush(  ) override;
52         virtual void SAL_CALL close(  ) override;
53         virtual OUString SAL_CALL getDescription(  ) override;
54     public:
55         ::osl::StreamPipe m_pipe;
56         oslInterlockedCount m_nStatus;
57         OUString m_sDescription;
58     };
59 
60     }
61 
PipeConnection(const OUString & sConnectionDescription)62     PipeConnection::PipeConnection( const OUString &sConnectionDescription) :
63         m_nStatus( 0 ),
64         m_sDescription( sConnectionDescription )
65     {
66         // make it unique
67         m_sDescription += ",uniqueValue=";
68         m_sDescription += OUString::number(
69             sal::static_int_cast<sal_Int64 >(
70                 reinterpret_cast< sal_IntPtr >(&m_pipe)) );
71     }
72 
read(Sequence<sal_Int8> & aReadBytes,sal_Int32 nBytesToRead)73     sal_Int32 PipeConnection::read( Sequence < sal_Int8 > & aReadBytes , sal_Int32 nBytesToRead )
74     {
75         if( m_nStatus )
76         {
77             throw IOException("pipe already closed");
78         }
79         if( aReadBytes.getLength() < nBytesToRead )
80         {
81             aReadBytes.realloc( nBytesToRead );
82         }
83         sal_Int32 n = m_pipe.read( aReadBytes.getArray(), nBytesToRead );
84         OSL_ASSERT( n >= 0 && n <= aReadBytes.getLength() );
85         if( n < aReadBytes.getLength() )
86         {
87             aReadBytes.realloc( n );
88         }
89         return n;
90 
91     }
92 
write(const Sequence<sal_Int8> & seq)93     void PipeConnection::write( const Sequence < sal_Int8 > &seq )
94     {
95         if( m_nStatus )
96         {
97             throw IOException("pipe already closed");
98         }
99         if( m_pipe.write( seq.getConstArray() , seq.getLength() ) != seq.getLength() )
100         {
101             throw IOException("short write");
102         }
103     }
104 
flush()105     void PipeConnection::flush( )
106     {
107     }
108 
close()109     void PipeConnection::close()
110     {
111         if(  1 == osl_atomic_increment( (&m_nStatus) ) )
112         {
113             m_pipe.close();
114         }
115     }
116 
getDescription()117     OUString PipeConnection::getDescription()
118     {
119         return m_sDescription;
120     }
121 
122     /***************
123      * PipeAcceptor
124      **************/
PipeAcceptor(const OUString & sPipeName,const OUString & sConnectionDescription)125     PipeAcceptor::PipeAcceptor( const OUString &sPipeName , const OUString & sConnectionDescription) :
126         m_sPipeName( sPipeName ),
127         m_sConnectionDescription( sConnectionDescription ),
128         m_bClosed( false )
129     {
130     }
131 
132 
init()133     void PipeAcceptor::init()
134     {
135         m_pipe = Pipe( m_sPipeName.pData , osl_Pipe_CREATE , osl::Security() );
136         if( ! m_pipe.is() )
137         {
138             OUString error = "io.acceptor: Couldn't setup pipe " + m_sPipeName;
139             throw ConnectionSetupException( error );
140         }
141     }
142 
accept()143     Reference< XConnection > PipeAcceptor::accept( )
144     {
145         Pipe pipe;
146         {
147             MutexGuard guard( m_mutex );
148             pipe = m_pipe;
149         }
150         if( ! pipe.is() )
151         {
152             OUString error = "io.acceptor: pipe already closed" + m_sPipeName;
153             throw ConnectionSetupException( error );
154         }
155         rtl::Reference<PipeConnection> pConn(new PipeConnection( m_sConnectionDescription ));
156 
157         oslPipeError status = pipe.accept( pConn->m_pipe );
158 
159         if( m_bClosed )
160         {
161             // stopAccepting was called !
162             return Reference < XConnection >();
163         }
164         else if( osl_Pipe_E_None == status )
165         {
166             return pConn;
167         }
168         else
169         {
170             OUString error = "io.acceptor: Couldn't setup pipe " + m_sPipeName;
171             throw ConnectionSetupException( error );
172         }
173     }
174 
stopAccepting()175     void PipeAcceptor::stopAccepting()
176     {
177         m_bClosed = true;
178         Pipe pipe;
179         {
180             MutexGuard guard( m_mutex );
181             pipe = m_pipe;
182             m_pipe.clear();
183         }
184         if( pipe.is() )
185         {
186             pipe.close();
187         }
188     }
189 }
190 
191 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
192