1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
36 #include <osl/diagnose.h>
37 #include <osl/thread.h>
38 #include <osl/mutex.h>
39 #include <osl/semaphor.h>
40 #include <osl/conditn.h>
41 #include <osl/interlck.h>
42 #include <osl/process.h>
44 #include <rtl/alloc.h>
45 #include <rtl/memory.h>
47 #define PIPESYSTEM "\\\\.\\pipe\\"
48 #define PIPEPREFIX "OSL_PIPE_"
54 sal_uInt32 m_WritePos
;
59 /*****************************************************************************/
61 /*****************************************************************************/
64 oslInterlockedCount m_Reference
;
67 PSECURITY_ATTRIBUTES m_Security
;
77 /*****************************************************************************/
78 /* osl_create/destroy-PipeImpl */
79 /*****************************************************************************/
81 static oslInterlockedCount nPipes
= 0;
83 oslPipe
__osl_createPipeImpl(void)
87 pPipe
= (oslPipe
) rtl_allocateZeroMemory(sizeof(struct oslPipeImpl
));
89 pPipe
->m_bClosed
= sal_False
;
90 pPipe
->m_Reference
= 0;
92 pPipe
->m_File
= INVALID_HANDLE_VALUE
;
93 pPipe
->m_NamedObject
= INVALID_HANDLE_VALUE
;
95 pPipe
->m_ReadEvent
= CreateEvent(NULL
, TRUE
, FALSE
, NULL
);
96 pPipe
->m_WriteEvent
= CreateEvent(NULL
, TRUE
, FALSE
, NULL
);
97 pPipe
->m_AcceptEvent
= CreateEvent(NULL
, TRUE
, FALSE
, NULL
);
102 void __osl_destroyPipeImpl(oslPipe pPipe
)
106 if ( pPipe
->m_NamedObject
!= INVALID_HANDLE_VALUE
&& pPipe
->m_NamedObject
!= NULL
)
107 CloseHandle( pPipe
->m_NamedObject
);
109 if (pPipe
->m_Security
!= NULL
)
111 rtl_freeMemory(pPipe
->m_Security
->lpSecurityDescriptor
);
112 rtl_freeMemory(pPipe
->m_Security
);
115 CloseHandle(pPipe
->m_ReadEvent
);
116 CloseHandle(pPipe
->m_WriteEvent
);
117 CloseHandle(pPipe
->m_AcceptEvent
);
120 rtl_uString_release(pPipe
->m_Name
);
122 rtl_freeMemory(pPipe
);
128 /*****************************************************************************/
130 /*****************************************************************************/
131 oslPipe SAL_CALL
osl_createPipe(rtl_uString
*strPipeName
, oslPipeOptions Options
,
132 oslSecurity Security
)
134 rtl_uString
* name
= NULL
;
135 rtl_uString
* path
= NULL
;
136 rtl_uString
* temp
= NULL
;
139 PSECURITY_ATTRIBUTES pSecAttr
= NULL
;
141 rtl_uString_newFromAscii(&path
, PIPESYSTEM
);
142 rtl_uString_newFromAscii(&name
, PIPEPREFIX
);
144 if ( /*IS_NT &&*/ Security
)
146 rtl_uString
*Ident
= NULL
;
147 rtl_uString
*Delim
= NULL
;
149 OSL_VERIFY(osl_getUserIdent(Security
, &Ident
));
150 rtl_uString_newFromAscii(&Delim
, "_");
152 rtl_uString_newConcat(&temp
, name
, Ident
);
153 rtl_uString_newConcat(&name
, temp
, Delim
);
155 rtl_uString_release(Ident
);
156 rtl_uString_release(Delim
);
160 if (Options
& osl_Pipe_CREATE
)
162 PSECURITY_DESCRIPTOR pSecDesc
;
164 pSecDesc
= (PSECURITY_DESCRIPTOR
) rtl_allocateMemory(SECURITY_DESCRIPTOR_MIN_LENGTH
);
166 /* add a NULL disc. ACL to the security descriptor */
167 OSL_VERIFY(InitializeSecurityDescriptor(pSecDesc
, SECURITY_DESCRIPTOR_REVISION
));
168 OSL_VERIFY(SetSecurityDescriptorDacl(pSecDesc
, TRUE
, (PACL
) NULL
, FALSE
));
170 pSecAttr
= rtl_allocateMemory(sizeof(SECURITY_ATTRIBUTES
));
171 pSecAttr
->nLength
= sizeof(SECURITY_ATTRIBUTES
);
172 pSecAttr
->lpSecurityDescriptor
= pSecDesc
;
173 pSecAttr
->bInheritHandle
= TRUE
;
177 rtl_uString_assign(&temp
, name
);
178 rtl_uString_newConcat(&name
, temp
, strPipeName
);
181 pPipe
= __osl_createPipeImpl();
182 osl_incrementInterlockedCount(&(pPipe
->m_Reference
));
184 /* build system pipe name */
185 rtl_uString_assign(&temp
, path
);
186 rtl_uString_newConcat(&path
, temp
, name
);
187 rtl_uString_release(temp
);
190 if (Options
& osl_Pipe_CREATE
)
192 SetLastError( ERROR_SUCCESS
);
195 pPipe
->m_NamedObject
= CreateMutexW( NULL
, FALSE
, name
->buffer
);
198 LPSTR pszTempBuffer
= NULL
;
201 nCharsNeeded
= WideCharToMultiByte( CP_ACP
, 0, name
->buffer
, name
->length
, NULL
, 0, NULL
, NULL
);
202 pszTempBuffer
= alloca( nCharsNeeded
* sizeof(CHAR
) );
203 nCharsNeeded
= WideCharToMultiByte( CP_ACP
, 0, name
->buffer
, name
->length
, pszTempBuffer
, nCharsNeeded
, NULL
, NULL
);
204 pszTempBuffer
[nCharsNeeded
-1] = 0;
206 pPipe
->m_NamedObject
= CreateMutexA( NULL
, FALSE
, pszTempBuffer
);
209 if ( pPipe
->m_NamedObject
!= INVALID_HANDLE_VALUE
&& pPipe
->m_NamedObject
!= NULL
)
211 if ( GetLastError() != ERROR_ALREADY_EXISTS
)
213 pPipe
->m_Security
= pSecAttr
;
214 rtl_uString_assign(&pPipe
->m_Name
, name
);
218 /* try to open system pipe */
219 pPipe
->m_File
= CreateNamedPipeW(
221 PIPE_ACCESS_DUPLEX
| FILE_FLAG_OVERLAPPED
,
222 PIPE_WAIT
| PIPE_TYPE_MESSAGE
| PIPE_READMODE_MESSAGE
,
223 PIPE_UNLIMITED_INSTANCES
,
225 NMPWAIT_WAIT_FOREVER
,
228 if (pPipe
->m_File
!= INVALID_HANDLE_VALUE
)
230 rtl_uString_release( name
);
231 rtl_uString_release( path
);
238 LPSTR pszTempBuffer
= NULL
;
241 nCharsNeeded
= WideCharToMultiByte( CP_ACP
, 0, path
->buffer
, path
->length
, NULL
, 0, NULL
, NULL
);
242 pszTempBuffer
= alloca( nCharsNeeded
* sizeof(CHAR
) );
243 nCharsNeeded
= WideCharToMultiByte( CP_ACP
, 0, path
->buffer
, path
->length
, pszTempBuffer
, nCharsNeeded
, NULL
, NULL
);
244 pszTempBuffer
[nCharsNeeded
-1] = 0;
246 pPipe
->m_File
= CreateSimplePipe( pszTempBuffer
);
248 if ( IsValidHandle(pPipe
->m_File
) )
250 rtl_uString_release( name
);
251 rtl_uString_release( path
);
259 CloseHandle( pPipe
->m_NamedObject
);
260 pPipe
->m_NamedObject
= INVALID_HANDLE_VALUE
;
272 /* free instance should be available first */
273 fPipeAvailable
= WaitNamedPipeW(path
->buffer
, NMPWAIT_WAIT_FOREVER
);
275 /* first try to open system pipe */
276 if ( fPipeAvailable
)
278 pPipe
->m_File
= CreateFileW(
280 GENERIC_READ
|GENERIC_WRITE
,
281 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
284 FILE_ATTRIBUTE_NORMAL
| FILE_FLAG_OVERLAPPED
,
287 if ( pPipe
->m_File
!= INVALID_HANDLE_VALUE
)
290 rtl_uString_release( name
);
291 rtl_uString_release( path
);
297 // Pipe instance maybe catched by another client -> try again
300 } while ( fPipeAvailable
);
304 LPSTR pszTempBuffer
= NULL
;
307 nCharsNeeded
= WideCharToMultiByte( CP_ACP
, 0, path
->buffer
, path
->length
, NULL
, 0, NULL
, NULL
);
308 pszTempBuffer
= alloca( nCharsNeeded
* sizeof(CHAR
) );
309 nCharsNeeded
= WideCharToMultiByte( CP_ACP
, 0, path
->buffer
, path
->length
, pszTempBuffer
, nCharsNeeded
, NULL
, NULL
);
310 pszTempBuffer
[nCharsNeeded
-1] = 0;
312 pPipe
->m_File
= OpenSimplePipe( pszTempBuffer
);
314 if ( IsValidHandle(pPipe
->m_File
) )
317 rtl_uString_release( name
);
318 rtl_uString_release( path
);
325 /* if we reach here something went wrong */
326 __osl_destroyPipeImpl(pPipe
);
331 void SAL_CALL
osl_acquirePipe( oslPipe pPipe
)
333 osl_incrementInterlockedCount( &(pPipe
->m_Reference
) );
336 void SAL_CALL
osl_releasePipe( oslPipe pPipe
)
338 // OSL_ASSERT( pPipe );
343 if( 0 == osl_decrementInterlockedCount( &(pPipe
->m_Reference
) ) )
345 if( ! pPipe
->m_bClosed
)
346 osl_closePipe( pPipe
);
348 __osl_destroyPipeImpl( pPipe
);
352 void SAL_CALL
osl_closePipe( oslPipe pPipe
)
354 if( pPipe
&& ! pPipe
->m_bClosed
)
356 pPipe
->m_bClosed
= sal_True
;
359 /* if we have a system pipe close it */
360 if (pPipe
->m_File
!= INVALID_HANDLE_VALUE
)
362 /* FlushFileBuffers(pPipe->m_File); */
363 DisconnectNamedPipe(pPipe
->m_File
);
364 CloseHandle(pPipe
->m_File
);
369 CloseSimplePipe( pPipe
->m_File
);
375 /*****************************************************************************/
377 /*****************************************************************************/
378 oslPipe SAL_CALL
osl_acceptPipe(oslPipe pPipe
)
380 oslPipe pAcceptedPipe
= NULL
;
389 DWORD nBytesTransfered
;
390 rtl_uString
* path
= NULL
;
391 rtl_uString
* temp
= NULL
;
393 OSL_ASSERT (pPipe
->m_File
!= INVALID_HANDLE_VALUE
);
395 Event
= pPipe
->m_AcceptEvent
;
396 rtl_zeroMemory(&os
, sizeof(OVERLAPPED
));
397 os
.hEvent
= pPipe
->m_AcceptEvent
;
398 ResetEvent(pPipe
->m_AcceptEvent
);
400 if ( !ConnectNamedPipe(pPipe
->m_File
, &os
))
402 switch ( GetLastError() )
404 case ERROR_PIPE_CONNECTED
: // Client already connected to pipe
405 case ERROR_NO_DATA
: // Client was connected but has already closed pipe end
406 // should only appear in nonblocking mode but in fact does
407 // in blocking asynchronous mode.
409 case ERROR_PIPE_LISTENING
: // Only for nonblocking mode but see ERROR_NO_DATA
410 case ERROR_IO_PENDING
: // This is normal if not client is connected yet
411 case ERROR_MORE_DATA
: // Should not happen
412 // blocking call to accept
413 if( !GetOverlappedResult( pPipe
->m_File
, &os
, &nBytesTransfered
, TRUE
) )
415 // Possible error could be that between ConnectNamedPipe and GetOverlappedResult a connect
418 switch ( GetLastError() )
420 case ERROR_PIPE_CONNECTED
: // Pipe was already connected
421 case ERROR_NO_DATA
: // Pipe was connected but client has already closed -> ver fast client ;-)
422 break; // Everything's fine !!!
424 // Something went wrong
429 default: // All other error say that somethings going wrong.
435 pAcceptedPipe
= __osl_createPipeImpl();
436 OSL_ASSERT(pAcceptedPipe
);
438 osl_incrementInterlockedCount(&(pAcceptedPipe
->m_Reference
));
439 rtl_uString_assign(&pAcceptedPipe
->m_Name
, pPipe
->m_Name
);
440 pAcceptedPipe
->m_File
= pPipe
->m_File
;
442 rtl_uString_newFromAscii(&temp
, PIPESYSTEM
);
443 rtl_uString_newConcat(&path
, temp
, pPipe
->m_Name
);
444 rtl_uString_release(temp
);
446 // prepare for next accept
448 CreateNamedPipeW(path
->buffer
,
449 PIPE_ACCESS_DUPLEX
| FILE_FLAG_OVERLAPPED
,
450 PIPE_WAIT
| PIPE_TYPE_MESSAGE
| PIPE_READMODE_MESSAGE
,
451 PIPE_UNLIMITED_INSTANCES
,
453 NMPWAIT_WAIT_FOREVER
,
454 pAcceptedPipe
->m_Security
);
455 rtl_uString_release( path
);
459 pAcceptedPipe
= __osl_createPipeImpl();
460 OSL_ASSERT(pAcceptedPipe
);
462 osl_incrementInterlockedCount(&(pAcceptedPipe
->m_Reference
));
463 rtl_uString_assign(&pAcceptedPipe
->m_Name
, pPipe
->m_Name
);
464 pAcceptedPipe
->m_File
= pPipe
->m_File
;
466 pAcceptedPipe
->m_File
= AcceptSimplePipeConnection( pPipe
->m_File
);
469 return pAcceptedPipe
;
472 /*****************************************************************************/
473 /* osl_receivePipe */
474 /*****************************************************************************/
475 sal_Int32 SAL_CALL
osl_receivePipe(oslPipe pPipe
,
477 sal_Int32 BytesToRead
)
483 /* if we have a system pipe use it */
484 if ( IS_NT
/*pPipe->m_File != INVALID_HANDLE_VALUE*/)
487 rtl_zeroMemory(&os
,sizeof(OVERLAPPED
));
488 os
.hEvent
= pPipe
->m_ReadEvent
;
490 ResetEvent(pPipe
->m_ReadEvent
);
492 if (! ReadFile(pPipe
->m_File
, pBuffer
, BytesToRead
, &nBytes
, &os
) &&
493 ((GetLastError() != ERROR_IO_PENDING
) ||
494 ! GetOverlappedResult(pPipe
->m_File
, &os
, &nBytes
, TRUE
)))
496 DWORD lastError
= GetLastError();
498 if (lastError
== ERROR_MORE_DATA
)
499 nBytes
= BytesToRead
;
502 if (lastError
== ERROR_PIPE_NOT_CONNECTED
)
507 pPipe
->m_Error
= osl_Pipe_E_ConnectionAbort
;
513 BOOL fSuccess
= ReadSimplePipe( pPipe
->m_File
, pBuffer
, BytesToRead
, &nBytes
, TRUE
);
518 pPipe
->m_Error
= osl_Pipe_E_ConnectionAbort
;
526 /*****************************************************************************/
528 /*****************************************************************************/
529 sal_Int32 SAL_CALL
osl_sendPipe(oslPipe pPipe
,
531 sal_Int32 BytesToSend
)
536 if (IS_NT
/*pPipe->m_File != INVALID_HANDLE_VALUE*/)
539 rtl_zeroMemory(&os
, sizeof(OVERLAPPED
));
540 os
.hEvent
= pPipe
->m_WriteEvent
;
541 ResetEvent(pPipe
->m_WriteEvent
);
543 if (! WriteFile(pPipe
->m_File
, pBuffer
, BytesToSend
, &nBytes
, &os
) &&
544 ((GetLastError() != ERROR_IO_PENDING
) ||
545 ! GetOverlappedResult(pPipe
->m_File
, &os
, &nBytes
, TRUE
)))
547 if (GetLastError() == ERROR_PIPE_NOT_CONNECTED
)
552 pPipe
->m_Error
= osl_Pipe_E_ConnectionAbort
;
557 BOOL fSuccess
= WriteSimplePipe( pPipe
->m_File
, pBuffer
, BytesToSend
, &nBytes
, TRUE
);
562 pPipe
->m_Error
= osl_Pipe_E_ConnectionAbort
;
569 sal_Int32 SAL_CALL
osl_writePipe( oslPipe pPipe
, const void *pBuffer
, sal_Int32 n
)
571 /* loop until all desired bytes were send or an error occured */
572 sal_Int32 BytesSend
= 0;
573 sal_Int32 BytesToSend
= n
;
576 while (BytesToSend
> 0)
580 RetVal
= osl_sendPipe(pPipe
, pBuffer
, BytesToSend
);
588 BytesToSend
-= RetVal
;
590 pBuffer
= (sal_Char
*)pBuffer
+ RetVal
;
596 sal_Int32 SAL_CALL
osl_readPipe( oslPipe pPipe
, void *pBuffer
, sal_Int32 n
)
598 /* loop until all desired bytes were read or an error occured */
599 sal_Int32 BytesRead
= 0;
600 sal_Int32 BytesToRead
= n
;
603 while (BytesToRead
> 0)
606 RetVal
= osl_receivePipe(pPipe
, pBuffer
, BytesToRead
);
614 BytesToRead
-= RetVal
;
616 pBuffer
= (sal_Char
*)pBuffer
+ RetVal
;
622 /*****************************************************************************/
623 /* osl_getLastPipeError */
624 /*****************************************************************************/
625 oslPipeError SAL_CALL
osl_getLastPipeError(oslPipe pPipe
)
631 Error
= pPipe
->m_Error
;
632 pPipe
->m_Error
= osl_Pipe_E_None
;
635 Error
= osl_Pipe_E_None
;