1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/.
9 * This file incorporates work covered by the following license notice:
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 .
25 #include <osl/diagnose.h>
26 #include <osl/thread.h>
27 #include <osl/mutex.h>
28 #include <osl/conditn.h>
29 #include <osl/interlck.h>
30 #include <osl/process.h>
32 #include <rtl/alloc.h>
34 #define PIPESYSTEM "\\\\.\\pipe\\"
35 #define PIPEPREFIX "OSL_PIPE_"
41 sal_uInt32 m_WritePos
;
46 /*****************************************************************************/
48 /*****************************************************************************/
51 oslInterlockedCount m_Reference
;
54 PSECURITY_ATTRIBUTES m_Security
;
64 /*****************************************************************************/
65 /* osl_create/destroy-PipeImpl */
66 /*****************************************************************************/
68 oslPipe
__osl_createPipeImpl(void)
72 pPipe
= (oslPipe
) rtl_allocateZeroMemory(sizeof(struct oslPipeImpl
));
74 pPipe
->m_bClosed
= sal_False
;
75 pPipe
->m_Reference
= 0;
77 pPipe
->m_File
= INVALID_HANDLE_VALUE
;
78 pPipe
->m_NamedObject
= INVALID_HANDLE_VALUE
;
80 pPipe
->m_ReadEvent
= CreateEvent(NULL
, TRUE
, FALSE
, NULL
);
81 pPipe
->m_WriteEvent
= CreateEvent(NULL
, TRUE
, FALSE
, NULL
);
82 pPipe
->m_AcceptEvent
= CreateEvent(NULL
, TRUE
, FALSE
, NULL
);
87 void __osl_destroyPipeImpl(oslPipe pPipe
)
91 if ( pPipe
->m_NamedObject
!= INVALID_HANDLE_VALUE
&& pPipe
->m_NamedObject
!= NULL
)
92 CloseHandle( pPipe
->m_NamedObject
);
94 if (pPipe
->m_Security
!= NULL
)
96 rtl_freeMemory(pPipe
->m_Security
->lpSecurityDescriptor
);
97 rtl_freeMemory(pPipe
->m_Security
);
100 CloseHandle(pPipe
->m_ReadEvent
);
101 CloseHandle(pPipe
->m_WriteEvent
);
102 CloseHandle(pPipe
->m_AcceptEvent
);
105 rtl_uString_release(pPipe
->m_Name
);
107 rtl_freeMemory(pPipe
);
113 /*****************************************************************************/
115 /*****************************************************************************/
116 oslPipe SAL_CALL
osl_createPipe(rtl_uString
*strPipeName
, oslPipeOptions Options
,
117 oslSecurity Security
)
119 rtl_uString
* name
= NULL
;
120 rtl_uString
* path
= NULL
;
121 rtl_uString
* temp
= NULL
;
124 PSECURITY_ATTRIBUTES pSecAttr
= NULL
;
126 rtl_uString_newFromAscii(&path
, PIPESYSTEM
);
127 rtl_uString_newFromAscii(&name
, PIPEPREFIX
);
131 rtl_uString
*Ident
= NULL
;
132 rtl_uString
*Delim
= NULL
;
134 OSL_VERIFY(osl_getUserIdent(Security
, &Ident
));
135 rtl_uString_newFromAscii(&Delim
, "_");
137 rtl_uString_newConcat(&temp
, name
, Ident
);
138 rtl_uString_newConcat(&name
, temp
, Delim
);
140 rtl_uString_release(Ident
);
141 rtl_uString_release(Delim
);
145 if (Options
& osl_Pipe_CREATE
)
147 PSECURITY_DESCRIPTOR pSecDesc
;
149 pSecDesc
= (PSECURITY_DESCRIPTOR
) rtl_allocateMemory(SECURITY_DESCRIPTOR_MIN_LENGTH
);
151 /* add a NULL disc. ACL to the security descriptor */
152 OSL_VERIFY(InitializeSecurityDescriptor(pSecDesc
, SECURITY_DESCRIPTOR_REVISION
));
153 OSL_VERIFY(SetSecurityDescriptorDacl(pSecDesc
, TRUE
, (PACL
) NULL
, FALSE
));
155 pSecAttr
= rtl_allocateMemory(sizeof(SECURITY_ATTRIBUTES
));
156 pSecAttr
->nLength
= sizeof(SECURITY_ATTRIBUTES
);
157 pSecAttr
->lpSecurityDescriptor
= pSecDesc
;
158 pSecAttr
->bInheritHandle
= TRUE
;
162 rtl_uString_assign(&temp
, name
);
163 rtl_uString_newConcat(&name
, temp
, strPipeName
);
166 pPipe
= __osl_createPipeImpl();
167 osl_atomic_increment(&(pPipe
->m_Reference
));
169 /* build system pipe name */
170 rtl_uString_assign(&temp
, path
);
171 rtl_uString_newConcat(&path
, temp
, name
);
172 rtl_uString_release(temp
);
175 if (Options
& osl_Pipe_CREATE
)
177 SetLastError( ERROR_SUCCESS
);
179 pPipe
->m_NamedObject
= CreateMutexW( NULL
, FALSE
, name
->buffer
);
181 if ( pPipe
->m_NamedObject
!= INVALID_HANDLE_VALUE
&& pPipe
->m_NamedObject
!= NULL
)
183 if ( GetLastError() != ERROR_ALREADY_EXISTS
)
185 pPipe
->m_Security
= pSecAttr
;
186 rtl_uString_assign(&pPipe
->m_Name
, name
);
188 /* try to open system pipe */
189 pPipe
->m_File
= CreateNamedPipeW(
191 PIPE_ACCESS_DUPLEX
| FILE_FLAG_OVERLAPPED
,
192 PIPE_WAIT
| PIPE_TYPE_MESSAGE
| PIPE_READMODE_MESSAGE
,
193 PIPE_UNLIMITED_INSTANCES
,
195 NMPWAIT_WAIT_FOREVER
,
198 if (pPipe
->m_File
!= INVALID_HANDLE_VALUE
)
200 rtl_uString_release( name
);
201 rtl_uString_release( path
);
208 CloseHandle( pPipe
->m_NamedObject
);
209 pPipe
->m_NamedObject
= INVALID_HANDLE_VALUE
;
219 /* free instance should be available first */
220 fPipeAvailable
= WaitNamedPipeW(path
->buffer
, NMPWAIT_WAIT_FOREVER
);
222 /* first try to open system pipe */
223 if ( fPipeAvailable
)
225 pPipe
->m_File
= CreateFileW(
227 GENERIC_READ
|GENERIC_WRITE
,
228 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
231 FILE_ATTRIBUTE_NORMAL
| FILE_FLAG_OVERLAPPED
,
234 if ( pPipe
->m_File
!= INVALID_HANDLE_VALUE
)
237 rtl_uString_release( name
);
238 rtl_uString_release( path
);
244 // Pipe instance maybe catched by another client -> try again
247 } while ( fPipeAvailable
);
250 /* if we reach here something went wrong */
251 __osl_destroyPipeImpl(pPipe
);
256 void SAL_CALL
osl_acquirePipe( oslPipe pPipe
)
258 osl_atomic_increment( &(pPipe
->m_Reference
) );
261 void SAL_CALL
osl_releasePipe( oslPipe pPipe
)
263 // OSL_ASSERT( pPipe );
268 if( 0 == osl_atomic_decrement( &(pPipe
->m_Reference
) ) )
270 if( ! pPipe
->m_bClosed
)
271 osl_closePipe( pPipe
);
273 __osl_destroyPipeImpl( pPipe
);
277 void SAL_CALL
osl_closePipe( oslPipe pPipe
)
279 if( pPipe
&& ! pPipe
->m_bClosed
)
281 pPipe
->m_bClosed
= sal_True
;
282 /* if we have a system pipe close it */
283 if (pPipe
->m_File
!= INVALID_HANDLE_VALUE
)
285 /* FlushFileBuffers(pPipe->m_File); */
286 DisconnectNamedPipe(pPipe
->m_File
);
287 CloseHandle(pPipe
->m_File
);
292 /*****************************************************************************/
294 /*****************************************************************************/
295 oslPipe SAL_CALL
osl_acceptPipe(oslPipe pPipe
)
297 oslPipe pAcceptedPipe
= NULL
;
301 DWORD nBytesTransfered
;
302 rtl_uString
* path
= NULL
;
303 rtl_uString
* temp
= NULL
;
306 OSL_ASSERT(pPipe
->m_File
!= INVALID_HANDLE_VALUE
);
308 memset(&os
, 0, sizeof(OVERLAPPED
));
309 os
.hEvent
= pPipe
->m_AcceptEvent
;
310 ResetEvent(pPipe
->m_AcceptEvent
);
312 if ( !ConnectNamedPipe(pPipe
->m_File
, &os
))
314 switch ( GetLastError() )
316 case ERROR_PIPE_CONNECTED
: // Client already connected to pipe
317 case ERROR_NO_DATA
: // Client was connected but has already closed pipe end
318 // should only appear in nonblocking mode but in fact does
319 // in blocking asynchronous mode.
321 case ERROR_PIPE_LISTENING
: // Only for nonblocking mode but see ERROR_NO_DATA
322 case ERROR_IO_PENDING
: // This is normal if not client is connected yet
323 case ERROR_MORE_DATA
: // Should not happen
324 // blocking call to accept
325 if( !GetOverlappedResult( pPipe
->m_File
, &os
, &nBytesTransfered
, TRUE
) )
327 // Possible error could be that between ConnectNamedPipe and GetOverlappedResult a connect
330 switch ( GetLastError() )
332 case ERROR_PIPE_CONNECTED
: // Pipe was already connected
333 case ERROR_NO_DATA
: // Pipe was connected but client has already closed -> ver fast client ;-)
334 break; // Everything's fine !!!
336 // Something went wrong
341 default: // All other error say that somethings going wrong.
346 pAcceptedPipe
= __osl_createPipeImpl();
347 OSL_ASSERT(pAcceptedPipe
);
349 osl_atomic_increment(&(pAcceptedPipe
->m_Reference
));
350 rtl_uString_assign(&pAcceptedPipe
->m_Name
, pPipe
->m_Name
);
351 pAcceptedPipe
->m_File
= pPipe
->m_File
;
353 rtl_uString_newFromAscii(&temp
, PIPESYSTEM
);
354 rtl_uString_newConcat(&path
, temp
, pPipe
->m_Name
);
355 rtl_uString_release(temp
);
357 // prepare for next accept
359 CreateNamedPipeW(path
->buffer
,
360 PIPE_ACCESS_DUPLEX
| FILE_FLAG_OVERLAPPED
,
361 PIPE_WAIT
| PIPE_TYPE_MESSAGE
| PIPE_READMODE_MESSAGE
,
362 PIPE_UNLIMITED_INSTANCES
,
364 NMPWAIT_WAIT_FOREVER
,
365 pAcceptedPipe
->m_Security
);
366 rtl_uString_release( path
);
368 return pAcceptedPipe
;
371 /*****************************************************************************/
372 /* osl_receivePipe */
373 /*****************************************************************************/
374 sal_Int32 SAL_CALL
osl_receivePipe(oslPipe pPipe
,
376 sal_Int32 BytesToRead
)
383 memset(&os
, 0, sizeof(OVERLAPPED
));
384 os
.hEvent
= pPipe
->m_ReadEvent
;
386 ResetEvent(pPipe
->m_ReadEvent
);
388 if (! ReadFile(pPipe
->m_File
, pBuffer
, BytesToRead
, &nBytes
, &os
) &&
389 ((GetLastError() != ERROR_IO_PENDING
) ||
390 ! GetOverlappedResult(pPipe
->m_File
, &os
, &nBytes
, TRUE
)))
392 DWORD lastError
= GetLastError();
394 if (lastError
== ERROR_MORE_DATA
)
395 nBytes
= BytesToRead
;
398 if (lastError
== ERROR_PIPE_NOT_CONNECTED
)
403 pPipe
->m_Error
= osl_Pipe_E_ConnectionAbort
;
410 /*****************************************************************************/
412 /*****************************************************************************/
413 sal_Int32 SAL_CALL
osl_sendPipe(oslPipe pPipe
,
415 sal_Int32 BytesToSend
)
422 memset(&os
, 0, sizeof(OVERLAPPED
));
423 os
.hEvent
= pPipe
->m_WriteEvent
;
424 ResetEvent(pPipe
->m_WriteEvent
);
426 if (! WriteFile(pPipe
->m_File
, pBuffer
, BytesToSend
, &nBytes
, &os
) &&
427 ((GetLastError() != ERROR_IO_PENDING
) ||
428 ! GetOverlappedResult(pPipe
->m_File
, &os
, &nBytes
, TRUE
)))
430 if (GetLastError() == ERROR_PIPE_NOT_CONNECTED
)
435 pPipe
->m_Error
= osl_Pipe_E_ConnectionAbort
;
441 sal_Int32 SAL_CALL
osl_writePipe( oslPipe pPipe
, const void *pBuffer
, sal_Int32 n
)
443 /* loop until all desired bytes were send or an error occurred */
444 sal_Int32 BytesSend
= 0;
445 sal_Int32 BytesToSend
= n
;
448 while (BytesToSend
> 0)
452 RetVal
= osl_sendPipe(pPipe
, pBuffer
, BytesToSend
);
454 /* error occurred? */
460 BytesToSend
-= RetVal
;
462 pBuffer
= (sal_Char
*)pBuffer
+ RetVal
;
468 sal_Int32 SAL_CALL
osl_readPipe( oslPipe pPipe
, void *pBuffer
, sal_Int32 n
)
470 /* loop until all desired bytes were read or an error occurred */
471 sal_Int32 BytesRead
= 0;
472 sal_Int32 BytesToRead
= n
;
475 while (BytesToRead
> 0)
478 RetVal
= osl_receivePipe(pPipe
, pBuffer
, BytesToRead
);
480 /* error occurred? */
486 BytesToRead
-= RetVal
;
488 pBuffer
= (sal_Char
*)pBuffer
+ RetVal
;
494 /*****************************************************************************/
495 /* osl_getLastPipeError */
496 /*****************************************************************************/
497 oslPipeError SAL_CALL
osl_getLastPipeError(oslPipe pPipe
)
503 Error
= pPipe
->m_Error
;
504 pPipe
->m_Error
= osl_Pipe_E_None
;
507 Error
= osl_Pipe_E_NotFound
;
512 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */