Version 4.2.0.1, tag libreoffice-4.2.0.1
[LibreOffice.git] / sal / osl / w32 / pipe.c
blob149de07f73cea456236c1dbfd08446f254a95348
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
20 #include <string.h>
22 #include "system.h"
24 #include <osl/pipe.h>
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_"
37 typedef struct
39 sal_uInt32 m_Size;
40 sal_uInt32 m_ReadPos;
41 sal_uInt32 m_WritePos;
42 BYTE m_Data[1];
44 } oslPipeBuffer;
46 /*****************************************************************************/
47 /* oslPipeImpl */
48 /*****************************************************************************/
50 struct oslPipeImpl {
51 oslInterlockedCount m_Reference;
52 HANDLE m_File;
53 HANDLE m_NamedObject;
54 PSECURITY_ATTRIBUTES m_Security;
55 HANDLE m_ReadEvent;
56 HANDLE m_WriteEvent;
57 HANDLE m_AcceptEvent;
58 rtl_uString* m_Name;
59 oslPipeError m_Error;
60 sal_Bool m_bClosed;
64 /*****************************************************************************/
65 /* osl_create/destroy-PipeImpl */
66 /*****************************************************************************/
68 oslPipe __osl_createPipeImpl(void)
70 oslPipe pPipe;
72 pPipe = (oslPipe) rtl_allocateZeroMemory(sizeof(struct oslPipeImpl));
74 pPipe->m_bClosed = sal_False;
75 pPipe->m_Reference = 0;
76 pPipe->m_Name = NULL;
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);
84 return pPipe;
87 void __osl_destroyPipeImpl(oslPipe pPipe)
89 if (pPipe != NULL)
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);
104 if (pPipe->m_Name)
105 rtl_uString_release(pPipe->m_Name);
107 rtl_freeMemory(pPipe);
113 /*****************************************************************************/
114 /* osl_createPipe */
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;
122 oslPipe pPipe;
124 PSECURITY_ATTRIBUTES pSecAttr = NULL;
126 rtl_uString_newFromAscii(&path, PIPESYSTEM);
127 rtl_uString_newFromAscii(&name, PIPEPREFIX);
129 if ( Security)
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);
143 else
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);
165 /* alloc memory */
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);
173 temp = NULL;
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(
190 path->buffer,
191 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
192 PIPE_WAIT | PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE,
193 PIPE_UNLIMITED_INSTANCES,
194 4096, 4096,
195 NMPWAIT_WAIT_FOREVER,
196 pPipe->m_Security);
198 if (pPipe->m_File != INVALID_HANDLE_VALUE)
200 rtl_uString_release( name );
201 rtl_uString_release( path );
203 return pPipe;
206 else
208 CloseHandle( pPipe->m_NamedObject );
209 pPipe->m_NamedObject = INVALID_HANDLE_VALUE;
213 else
215 BOOL fPipeAvailable;
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(
226 path->buffer,
227 GENERIC_READ|GENERIC_WRITE,
228 FILE_SHARE_READ | FILE_SHARE_WRITE,
229 NULL,
230 OPEN_EXISTING,
231 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
232 NULL);
234 if ( pPipe->m_File != INVALID_HANDLE_VALUE )
236 // We got it !
237 rtl_uString_release( name );
238 rtl_uString_release( path );
240 return (pPipe);
242 else
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);
253 return NULL;
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 );
265 if( 0 == pPipe )
266 return;
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 /*****************************************************************************/
293 /* osl_acceptPipe */
294 /*****************************************************************************/
295 oslPipe SAL_CALL osl_acceptPipe(oslPipe pPipe)
297 oslPipe pAcceptedPipe = NULL;
299 OVERLAPPED os;
301 DWORD nBytesTransfered;
302 rtl_uString* path = NULL;
303 rtl_uString* temp = NULL;
305 OSL_ASSERT(pPipe);
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.
320 break;
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
328 // took place.
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 !!!
335 default:
336 // Something went wrong
337 return 0;
340 break;
341 default: // All other error say that somethings going wrong.
342 return 0;
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
358 pPipe->m_File =
359 CreateNamedPipeW(path->buffer,
360 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
361 PIPE_WAIT | PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE,
362 PIPE_UNLIMITED_INSTANCES,
363 4096, 4096,
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,
375 void* pBuffer,
376 sal_Int32 BytesToRead)
378 DWORD nBytes;
379 OVERLAPPED os;
381 OSL_ASSERT(pPipe);
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;
396 else
398 if (lastError == ERROR_PIPE_NOT_CONNECTED)
399 nBytes = 0;
400 else
401 nBytes = (DWORD) -1;
403 pPipe->m_Error = osl_Pipe_E_ConnectionAbort;
407 return (nBytes);
410 /*****************************************************************************/
411 /* osl_sendPipe */
412 /*****************************************************************************/
413 sal_Int32 SAL_CALL osl_sendPipe(oslPipe pPipe,
414 const void* pBuffer,
415 sal_Int32 BytesToSend)
417 DWORD nBytes;
418 OVERLAPPED os;
420 OSL_ASSERT(pPipe);
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)
431 nBytes = 0;
432 else
433 nBytes = (DWORD) -1;
435 pPipe->m_Error = osl_Pipe_E_ConnectionAbort;
438 return (nBytes);
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;
447 OSL_ASSERT(pPipe);
448 while (BytesToSend > 0)
450 sal_Int32 RetVal;
452 RetVal= osl_sendPipe(pPipe, pBuffer, BytesToSend);
454 /* error occurred? */
455 if(RetVal <= 0)
457 break;
460 BytesToSend -= RetVal;
461 BytesSend += RetVal;
462 pBuffer= (sal_Char*)pBuffer + RetVal;
465 return BytesSend;
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;
474 OSL_ASSERT( pPipe );
475 while (BytesToRead > 0)
477 sal_Int32 RetVal;
478 RetVal= osl_receivePipe(pPipe, pBuffer, BytesToRead);
480 /* error occurred? */
481 if(RetVal <= 0)
483 break;
486 BytesToRead -= RetVal;
487 BytesRead += RetVal;
488 pBuffer= (sal_Char*)pBuffer + RetVal;
490 return BytesRead;
494 /*****************************************************************************/
495 /* osl_getLastPipeError */
496 /*****************************************************************************/
497 oslPipeError SAL_CALL osl_getLastPipeError(oslPipe pPipe)
499 oslPipeError Error;
501 if (pPipe != NULL)
503 Error = pPipe->m_Error;
504 pPipe->m_Error = osl_Pipe_E_None;
506 else
507 Error = osl_Pipe_E_NotFound;
509 return (Error);
512 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */