Update ooo320-m1
[ooovba.git] / sal / osl / w32 / pipe.c
blobfbc4e19236190399c3a2af0d329b081e0ba8cb23
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: pipe.c,v $
10 * $Revision: 1.20 $
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 ************************************************************************/
31 #include "system.h"
33 #include "pipeimpl.h"
35 #include <osl/pipe.h>
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_"
50 typedef struct
52 sal_uInt32 m_Size;
53 sal_uInt32 m_ReadPos;
54 sal_uInt32 m_WritePos;
55 BYTE m_Data[1];
57 } oslPipeBuffer;
59 /*****************************************************************************/
60 /* oslPipeImpl */
61 /*****************************************************************************/
63 struct oslPipeImpl {
64 oslInterlockedCount m_Reference;
65 HANDLE m_File;
66 HANDLE m_NamedObject;
67 PSECURITY_ATTRIBUTES m_Security;
68 HANDLE m_ReadEvent;
69 HANDLE m_WriteEvent;
70 HANDLE m_AcceptEvent;
71 rtl_uString* m_Name;
72 oslPipeError m_Error;
73 sal_Bool m_bClosed;
77 /*****************************************************************************/
78 /* osl_create/destroy-PipeImpl */
79 /*****************************************************************************/
81 static oslInterlockedCount nPipes = 0;
83 oslPipe __osl_createPipeImpl(void)
85 oslPipe pPipe;
87 pPipe = (oslPipe) rtl_allocateZeroMemory(sizeof(struct oslPipeImpl));
89 pPipe->m_bClosed = sal_False;
90 pPipe->m_Reference = 0;
91 pPipe->m_Name = NULL;
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);
99 return pPipe;
102 void __osl_destroyPipeImpl(oslPipe pPipe)
104 if (pPipe != NULL)
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);
119 if (pPipe->m_Name)
120 rtl_uString_release(pPipe->m_Name);
122 rtl_freeMemory(pPipe);
128 /*****************************************************************************/
129 /* osl_createPipe */
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;
137 oslPipe pPipe;
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);
158 else
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);
180 /* alloc memory */
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);
188 temp = NULL;
190 if (Options & osl_Pipe_CREATE)
192 SetLastError( ERROR_SUCCESS );
194 if ( IS_NT )
195 pPipe->m_NamedObject = CreateMutexW( NULL, FALSE, name->buffer );
196 else
198 LPSTR pszTempBuffer = NULL;
199 int nCharsNeeded;
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);
216 if (IS_NT)
218 /* try to open system pipe */
219 pPipe->m_File = CreateNamedPipeW(
220 path->buffer,
221 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
222 PIPE_WAIT | PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE,
223 PIPE_UNLIMITED_INSTANCES,
224 4096, 4096,
225 NMPWAIT_WAIT_FOREVER,
226 pPipe->m_Security);
228 if (pPipe->m_File != INVALID_HANDLE_VALUE)
230 rtl_uString_release( name );
231 rtl_uString_release( path );
233 return pPipe;
236 else /* Win 9x */
238 LPSTR pszTempBuffer = NULL;
239 int nCharsNeeded;
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 );
253 return pPipe;
257 else
259 CloseHandle( pPipe->m_NamedObject );
260 pPipe->m_NamedObject = INVALID_HANDLE_VALUE;
264 else
266 if (IS_NT)
268 BOOL fPipeAvailable;
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(
279 path->buffer,
280 GENERIC_READ|GENERIC_WRITE,
281 FILE_SHARE_READ | FILE_SHARE_WRITE,
282 NULL,
283 OPEN_EXISTING,
284 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
285 NULL);
287 if ( pPipe->m_File != INVALID_HANDLE_VALUE )
289 // We got it !
290 rtl_uString_release( name );
291 rtl_uString_release( path );
293 return (pPipe);
295 else
297 // Pipe instance maybe catched by another client -> try again
300 } while ( fPipeAvailable );
302 else /* Win 9x */
304 LPSTR pszTempBuffer = NULL;
305 int nCharsNeeded;
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) )
316 // We got it !
317 rtl_uString_release( name );
318 rtl_uString_release( path );
320 return (pPipe);
325 /* if we reach here something went wrong */
326 __osl_destroyPipeImpl(pPipe);
328 return NULL;
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 );
340 if( 0 == pPipe )
341 return;
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;
357 if (IS_NT)
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);
367 else
369 CloseSimplePipe( pPipe->m_File );
375 /*****************************************************************************/
376 /* osl_acceptPipe */
377 /*****************************************************************************/
378 oslPipe SAL_CALL osl_acceptPipe(oslPipe pPipe)
380 oslPipe pAcceptedPipe = NULL;
382 HANDLE Event;
383 OVERLAPPED os;
385 OSL_ASSERT(pPipe);
387 if (IS_NT)
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.
408 break;
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
416 // took place.
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 !!!
423 default:
424 // Something went wrong
425 return 0;
428 break;
429 default: // All other error say that somethings going wrong.
430 return 0;
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
447 pPipe->m_File =
448 CreateNamedPipeW(path->buffer,
449 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
450 PIPE_WAIT | PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE,
451 PIPE_UNLIMITED_INSTANCES,
452 4096, 4096,
453 NMPWAIT_WAIT_FOREVER,
454 pAcceptedPipe->m_Security);
455 rtl_uString_release( path );
457 else /* Win9x */
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,
476 void* pBuffer,
477 sal_Int32 BytesToRead)
479 DWORD nBytes;
481 OSL_ASSERT(pPipe);
483 /* if we have a system pipe use it */
484 if ( IS_NT /*pPipe->m_File != INVALID_HANDLE_VALUE*/)
486 OVERLAPPED os;
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;
500 else
502 if (lastError == ERROR_PIPE_NOT_CONNECTED)
503 nBytes = 0;
504 else
505 nBytes = (DWORD) -1;
507 pPipe->m_Error = osl_Pipe_E_ConnectionAbort;
511 else
513 BOOL fSuccess = ReadSimplePipe( pPipe->m_File, pBuffer, BytesToRead, &nBytes, TRUE );
515 if ( !fSuccess )
517 nBytes = 0;
518 pPipe->m_Error = osl_Pipe_E_ConnectionAbort;
523 return (nBytes);
526 /*****************************************************************************/
527 /* osl_sendPipe */
528 /*****************************************************************************/
529 sal_Int32 SAL_CALL osl_sendPipe(oslPipe pPipe,
530 const void* pBuffer,
531 sal_Int32 BytesToSend)
533 DWORD nBytes;
534 OSL_ASSERT(pPipe);
536 if (IS_NT/*pPipe->m_File != INVALID_HANDLE_VALUE*/)
538 OVERLAPPED os;
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)
548 nBytes = 0;
549 else
550 nBytes = (DWORD) -1;
552 pPipe->m_Error = osl_Pipe_E_ConnectionAbort;
555 else
557 BOOL fSuccess = WriteSimplePipe( pPipe->m_File, pBuffer, BytesToSend, &nBytes, TRUE );
559 if ( !fSuccess )
561 nBytes = 0;
562 pPipe->m_Error = osl_Pipe_E_ConnectionAbort;
566 return (nBytes);
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;
575 OSL_ASSERT(pPipe);
576 while (BytesToSend > 0)
578 sal_Int32 RetVal;
580 RetVal= osl_sendPipe(pPipe, pBuffer, BytesToSend);
582 /* error occured? */
583 if(RetVal <= 0)
585 break;
588 BytesToSend -= RetVal;
589 BytesSend += RetVal;
590 pBuffer= (sal_Char*)pBuffer + RetVal;
593 return BytesSend;
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;
602 OSL_ASSERT( pPipe );
603 while (BytesToRead > 0)
605 sal_Int32 RetVal;
606 RetVal= osl_receivePipe(pPipe, pBuffer, BytesToRead);
608 /* error occured? */
609 if(RetVal <= 0)
611 break;
614 BytesToRead -= RetVal;
615 BytesRead += RetVal;
616 pBuffer= (sal_Char*)pBuffer + RetVal;
618 return BytesRead;
622 /*****************************************************************************/
623 /* osl_getLastPipeError */
624 /*****************************************************************************/
625 oslPipeError SAL_CALL osl_getLastPipeError(oslPipe pPipe)
627 oslPipeError Error;
629 if (pPipe != NULL)
631 Error = pPipe->m_Error;
632 pPipe->m_Error = osl_Pipe_E_None;
634 else
635 Error = osl_Pipe_E_None;
637 return (Error);