xref: /trunk/main/sal/osl/w32/pipe.c (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 #include "system.h"
29 
30 #include "pipeimpl.h"
31 
32 #include <osl/pipe.h>
33 #include <osl/diagnose.h>
34 #include <osl/thread.h>
35 #include <osl/mutex.h>
36 #include <osl/semaphor.h>
37 #include <osl/conditn.h>
38 #include <osl/interlck.h>
39 #include <osl/process.h>
40 
41 #include <rtl/alloc.h>
42 #include <rtl/memory.h>
43 
44 #define PIPESYSTEM      "\\\\.\\pipe\\"
45 #define PIPEPREFIX    "OSL_PIPE_"
46 
47 typedef struct
48 {
49     sal_uInt32 m_Size;
50     sal_uInt32 m_ReadPos;
51     sal_uInt32 m_WritePos;
52     BYTE   m_Data[1];
53 
54 } oslPipeBuffer;
55 
56 /*****************************************************************************/
57 /* oslPipeImpl */
58 /*****************************************************************************/
59 
60 struct oslPipeImpl {
61     oslInterlockedCount  m_Reference;
62     HANDLE               m_File;
63     HANDLE               m_NamedObject;
64     PSECURITY_ATTRIBUTES m_Security;
65     HANDLE               m_ReadEvent;
66     HANDLE               m_WriteEvent;
67     HANDLE               m_AcceptEvent;
68     rtl_uString*         m_Name;
69     oslPipeError         m_Error;
70     sal_Bool             m_bClosed;
71 };
72 
73 
74 /*****************************************************************************/
75 /* osl_create/destroy-PipeImpl */
76 /*****************************************************************************/
77 
78 static oslInterlockedCount nPipes = 0;
79 
80 oslPipe __osl_createPipeImpl(void)
81 {
82     oslPipe pPipe;
83 
84     pPipe = (oslPipe) rtl_allocateZeroMemory(sizeof(struct oslPipeImpl));
85 
86     pPipe->m_bClosed = sal_False;
87     pPipe->m_Reference = 0;
88     pPipe->m_Name = NULL;
89     pPipe->m_File = INVALID_HANDLE_VALUE;
90     pPipe->m_NamedObject = INVALID_HANDLE_VALUE;
91 
92     pPipe->m_ReadEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
93     pPipe->m_WriteEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
94     pPipe->m_AcceptEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
95 
96     return pPipe;
97 }
98 
99 void __osl_destroyPipeImpl(oslPipe pPipe)
100 {
101     if (pPipe != NULL)
102     {
103         if ( pPipe->m_NamedObject != INVALID_HANDLE_VALUE && pPipe->m_NamedObject != NULL )
104             CloseHandle( pPipe->m_NamedObject );
105 
106         if (pPipe->m_Security != NULL)
107         {
108             rtl_freeMemory(pPipe->m_Security->lpSecurityDescriptor);
109             rtl_freeMemory(pPipe->m_Security);
110         }
111 
112         CloseHandle(pPipe->m_ReadEvent);
113         CloseHandle(pPipe->m_WriteEvent);
114         CloseHandle(pPipe->m_AcceptEvent);
115 
116         if (pPipe->m_Name)
117             rtl_uString_release(pPipe->m_Name);
118 
119         rtl_freeMemory(pPipe);
120     }
121 }
122 
123 
124 
125 /*****************************************************************************/
126 /* osl_createPipe  */
127 /*****************************************************************************/
128 oslPipe SAL_CALL osl_createPipe(rtl_uString *strPipeName, oslPipeOptions Options,
129                        oslSecurity Security)
130 {
131     rtl_uString* name = NULL;
132     rtl_uString* path = NULL;
133     rtl_uString* temp = NULL;
134     oslPipe pPipe;
135 
136     PSECURITY_ATTRIBUTES  pSecAttr = NULL;
137 
138     rtl_uString_newFromAscii(&path, PIPESYSTEM);
139     rtl_uString_newFromAscii(&name, PIPEPREFIX);
140 
141     if ( /*IS_NT &&*/ Security)
142     {
143         rtl_uString *Ident = NULL;
144         rtl_uString *Delim = NULL;
145 
146         OSL_VERIFY(osl_getUserIdent(Security, &Ident));
147         rtl_uString_newFromAscii(&Delim, "_");
148 
149         rtl_uString_newConcat(&temp, name, Ident);
150         rtl_uString_newConcat(&name, temp, Delim);
151 
152         rtl_uString_release(Ident);
153         rtl_uString_release(Delim);
154     }
155     else
156     {
157         if (Options & osl_Pipe_CREATE)
158         {
159             PSECURITY_DESCRIPTOR pSecDesc;
160 
161             pSecDesc = (PSECURITY_DESCRIPTOR) rtl_allocateMemory(SECURITY_DESCRIPTOR_MIN_LENGTH);
162 
163             /* add a NULL disc. ACL to the security descriptor */
164             OSL_VERIFY(InitializeSecurityDescriptor(pSecDesc, SECURITY_DESCRIPTOR_REVISION));
165             OSL_VERIFY(SetSecurityDescriptorDacl(pSecDesc, TRUE, (PACL) NULL, FALSE));
166 
167             pSecAttr = rtl_allocateMemory(sizeof(SECURITY_ATTRIBUTES));
168             pSecAttr->nLength = sizeof(SECURITY_ATTRIBUTES);
169             pSecAttr->lpSecurityDescriptor = pSecDesc;
170             pSecAttr->bInheritHandle = TRUE;
171         }
172     }
173 
174     rtl_uString_assign(&temp, name);
175     rtl_uString_newConcat(&name, temp, strPipeName);
176 
177     /* alloc memory */
178     pPipe= __osl_createPipeImpl();
179     osl_incrementInterlockedCount(&(pPipe->m_Reference));
180 
181     /* build system pipe name */
182     rtl_uString_assign(&temp, path);
183     rtl_uString_newConcat(&path, temp, name);
184     rtl_uString_release(temp);
185     temp = NULL;
186 
187     if (Options & osl_Pipe_CREATE)
188     {
189         SetLastError( ERROR_SUCCESS );
190 
191         if ( IS_NT )
192             pPipe->m_NamedObject = CreateMutexW( NULL, FALSE, name->buffer );
193         else
194         {
195             LPSTR   pszTempBuffer = NULL;
196             int     nCharsNeeded;
197 
198             nCharsNeeded = WideCharToMultiByte( CP_ACP, 0, name->buffer, name->length, NULL, 0, NULL, NULL );
199             pszTempBuffer = alloca( nCharsNeeded * sizeof(CHAR) );
200             nCharsNeeded = WideCharToMultiByte( CP_ACP, 0, name->buffer, name->length, pszTempBuffer, nCharsNeeded, NULL, NULL );
201             pszTempBuffer[nCharsNeeded-1] = 0;
202 
203             pPipe->m_NamedObject = CreateMutexA( NULL, FALSE, pszTempBuffer );
204         }
205 
206         if ( pPipe->m_NamedObject != INVALID_HANDLE_VALUE && pPipe->m_NamedObject != NULL )
207         {
208             if ( GetLastError() != ERROR_ALREADY_EXISTS )
209             {
210                 pPipe->m_Security = pSecAttr;
211                 rtl_uString_assign(&pPipe->m_Name, name);
212 
213                 if (IS_NT)
214                 {
215                     /* try to open system pipe */
216                     pPipe->m_File = CreateNamedPipeW(
217                         path->buffer,
218                         PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
219                         PIPE_WAIT | PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE,
220                         PIPE_UNLIMITED_INSTANCES,
221                         4096, 4096,
222                         NMPWAIT_WAIT_FOREVER,
223                         pPipe->m_Security);
224 
225                     if (pPipe->m_File != INVALID_HANDLE_VALUE)
226                     {
227                         rtl_uString_release( name );
228                         rtl_uString_release( path );
229 
230                         return pPipe;
231                     }
232                 }
233                 else /* Win 9x */
234                 {
235                     LPSTR   pszTempBuffer = NULL;
236                     int     nCharsNeeded;
237 
238                     nCharsNeeded = WideCharToMultiByte( CP_ACP, 0, path->buffer, path->length, NULL, 0, NULL, NULL );
239                     pszTempBuffer = alloca( nCharsNeeded * sizeof(CHAR) );
240                     nCharsNeeded = WideCharToMultiByte( CP_ACP, 0, path->buffer, path->length, pszTempBuffer, nCharsNeeded, NULL, NULL );
241                     pszTempBuffer[nCharsNeeded-1] = 0;
242 
243                     pPipe->m_File = CreateSimplePipe( pszTempBuffer );
244 
245                     if ( IsValidHandle(pPipe->m_File) )
246                     {
247                         rtl_uString_release( name );
248                         rtl_uString_release( path );
249 
250                         return pPipe;
251                     }
252                 }
253             }
254             else
255             {
256                 CloseHandle( pPipe->m_NamedObject );
257                 pPipe->m_NamedObject = INVALID_HANDLE_VALUE;
258             }
259         }
260     }
261     else
262     {
263         if (IS_NT)
264         {
265             BOOL    fPipeAvailable;
266 
267             do
268             {
269                 /* free instance should be available first */
270                 fPipeAvailable = WaitNamedPipeW(path->buffer, NMPWAIT_WAIT_FOREVER);
271 
272                 /* first try to open system pipe */
273                 if ( fPipeAvailable )
274                 {
275                     pPipe->m_File = CreateFileW(
276                             path->buffer,
277                             GENERIC_READ|GENERIC_WRITE,
278                             FILE_SHARE_READ | FILE_SHARE_WRITE,
279                             NULL,
280                             OPEN_EXISTING,
281                             FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
282                             NULL);
283 
284                     if ( pPipe->m_File != INVALID_HANDLE_VALUE )
285                     {
286                         // We got it !
287                         rtl_uString_release( name );
288                         rtl_uString_release( path );
289 
290                         return (pPipe);
291                     }
292                     else
293                     {
294                         // Pipe instance maybe catched by another client -> try again
295                     }
296                 }
297             } while ( fPipeAvailable );
298         }
299         else /* Win 9x */
300         {
301             LPSTR   pszTempBuffer = NULL;
302             int     nCharsNeeded;
303 
304             nCharsNeeded = WideCharToMultiByte( CP_ACP, 0, path->buffer, path->length, NULL, 0, NULL, NULL );
305             pszTempBuffer = alloca( nCharsNeeded * sizeof(CHAR) );
306             nCharsNeeded = WideCharToMultiByte( CP_ACP, 0, path->buffer, path->length, pszTempBuffer, nCharsNeeded, NULL, NULL );
307             pszTempBuffer[nCharsNeeded-1] = 0;
308 
309             pPipe->m_File = OpenSimplePipe( pszTempBuffer );
310 
311             if ( IsValidHandle(pPipe->m_File) )
312             {
313                 // We got it !
314                 rtl_uString_release( name );
315                 rtl_uString_release( path );
316 
317                 return (pPipe);
318             }
319         }
320     }
321 
322     /* if we reach here something went wrong */
323     __osl_destroyPipeImpl(pPipe);
324 
325     return NULL;
326 }
327 
328 void SAL_CALL osl_acquirePipe( oslPipe pPipe )
329 {
330     osl_incrementInterlockedCount( &(pPipe->m_Reference) );
331 }
332 
333 void SAL_CALL osl_releasePipe( oslPipe pPipe )
334 {
335 //      OSL_ASSERT( pPipe );
336 
337     if( 0 == pPipe )
338         return;
339 
340     if( 0 == osl_decrementInterlockedCount( &(pPipe->m_Reference) ) )
341     {
342         if( ! pPipe->m_bClosed )
343             osl_closePipe( pPipe );
344 
345         __osl_destroyPipeImpl( pPipe );
346     }
347 }
348 
349 void SAL_CALL osl_closePipe( oslPipe pPipe )
350 {
351     if( pPipe && ! pPipe->m_bClosed )
352     {
353         pPipe->m_bClosed = sal_True;
354         if (IS_NT)
355         {
356             /* if we have a system pipe close it */
357             if (pPipe->m_File != INVALID_HANDLE_VALUE)
358             {
359                 /*          FlushFileBuffers(pPipe->m_File); */
360                 DisconnectNamedPipe(pPipe->m_File);
361                 CloseHandle(pPipe->m_File);
362             }
363         }
364         else
365         {
366             CloseSimplePipe( pPipe->m_File );
367         }
368 
369     }
370 }
371 
372 /*****************************************************************************/
373 /* osl_acceptPipe  */
374 /*****************************************************************************/
375 oslPipe SAL_CALL osl_acceptPipe(oslPipe pPipe)
376 {
377     oslPipe  pAcceptedPipe = NULL;
378 
379     HANDLE       Event;
380     OVERLAPPED   os;
381 
382     OSL_ASSERT(pPipe);
383 
384     if (IS_NT)
385     {
386         DWORD nBytesTransfered;
387         rtl_uString* path = NULL;
388         rtl_uString* temp = NULL;
389 
390         OSL_ASSERT (pPipe->m_File != INVALID_HANDLE_VALUE);
391 
392         Event = pPipe->m_AcceptEvent;
393         rtl_zeroMemory(&os, sizeof(OVERLAPPED));
394         os.hEvent = pPipe->m_AcceptEvent;
395         ResetEvent(pPipe->m_AcceptEvent);
396 
397         if ( !ConnectNamedPipe(pPipe->m_File, &os))
398         {
399             switch ( GetLastError() )
400             {
401             case ERROR_PIPE_CONNECTED:  // Client already connected to pipe
402             case ERROR_NO_DATA:         // Client was connected but has already closed pipe end
403                                         // should only appear in nonblocking mode but in fact does
404                                         // in blocking asynchronous mode.
405                 break;
406             case ERROR_PIPE_LISTENING:  // Only for nonblocking mode but see ERROR_NO_DATA
407             case ERROR_IO_PENDING:      // This is normal if not client is connected yet
408             case ERROR_MORE_DATA:       // Should not happen
409                 // blocking call to accept
410                 if( !GetOverlappedResult( pPipe->m_File, &os, &nBytesTransfered, TRUE ) )
411                 {
412                     // Possible error could be that between ConnectNamedPipe and GetOverlappedResult a connect
413                     // took place.
414 
415                     switch ( GetLastError() )
416                     {
417                     case ERROR_PIPE_CONNECTED:  // Pipe was already connected
418                     case ERROR_NO_DATA:         // Pipe was connected but client has already closed -> ver fast client ;-)
419                         break;                  // Everything's fine !!!
420                     default:
421                         // Something went wrong
422                         return 0;
423                     }
424                 }
425                 break;
426             default:                    // All other error say that somethings going wrong.
427                 return 0;
428             }
429         }
430 
431 
432         pAcceptedPipe = __osl_createPipeImpl();
433         OSL_ASSERT(pAcceptedPipe);
434 
435         osl_incrementInterlockedCount(&(pAcceptedPipe->m_Reference));
436         rtl_uString_assign(&pAcceptedPipe->m_Name, pPipe->m_Name);
437         pAcceptedPipe->m_File = pPipe->m_File;
438 
439         rtl_uString_newFromAscii(&temp, PIPESYSTEM);
440         rtl_uString_newConcat(&path, temp, pPipe->m_Name);
441         rtl_uString_release(temp);
442 
443         // prepare for next accept
444         pPipe->m_File =
445             CreateNamedPipeW(path->buffer,
446                 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
447                 PIPE_WAIT | PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE,
448                 PIPE_UNLIMITED_INSTANCES,
449                 4096, 4096,
450                 NMPWAIT_WAIT_FOREVER,
451                 pAcceptedPipe->m_Security);
452         rtl_uString_release( path );
453     }
454     else /* Win9x */
455     {
456         pAcceptedPipe = __osl_createPipeImpl();
457         OSL_ASSERT(pAcceptedPipe);
458 
459         osl_incrementInterlockedCount(&(pAcceptedPipe->m_Reference));
460         rtl_uString_assign(&pAcceptedPipe->m_Name, pPipe->m_Name);
461         pAcceptedPipe->m_File = pPipe->m_File;
462 
463         pAcceptedPipe->m_File = AcceptSimplePipeConnection( pPipe->m_File );
464     }
465 
466     return pAcceptedPipe;
467 }
468 
469 /*****************************************************************************/
470 /* osl_receivePipe  */
471 /*****************************************************************************/
472 sal_Int32 SAL_CALL osl_receivePipe(oslPipe pPipe,
473                         void* pBuffer,
474                         sal_Int32 BytesToRead)
475 {
476     DWORD nBytes;
477 
478     OSL_ASSERT(pPipe);
479 
480     /* if we have a system pipe use it */
481     if ( IS_NT /*pPipe->m_File != INVALID_HANDLE_VALUE*/)
482     {
483         OVERLAPPED   os;
484         rtl_zeroMemory(&os,sizeof(OVERLAPPED));
485         os.hEvent = pPipe->m_ReadEvent;
486 
487         ResetEvent(pPipe->m_ReadEvent);
488 
489         if (! ReadFile(pPipe->m_File, pBuffer, BytesToRead, &nBytes, &os) &&
490             ((GetLastError() != ERROR_IO_PENDING) ||
491              ! GetOverlappedResult(pPipe->m_File, &os, &nBytes, TRUE)))
492         {
493             DWORD lastError = GetLastError();
494 
495             if (lastError == ERROR_MORE_DATA)
496                 nBytes = BytesToRead;
497             else
498             {
499                 if (lastError == ERROR_PIPE_NOT_CONNECTED)
500                     nBytes = 0;
501                 else
502                     nBytes = (DWORD) -1;
503 
504                 pPipe->m_Error = osl_Pipe_E_ConnectionAbort;
505             }
506         }
507     }
508     else
509     {
510         BOOL fSuccess = ReadSimplePipe( pPipe->m_File, pBuffer, BytesToRead, &nBytes, TRUE );
511 
512         if ( !fSuccess )
513         {
514             nBytes = 0;
515             pPipe->m_Error = osl_Pipe_E_ConnectionAbort;
516         }
517 
518     }
519 
520     return (nBytes);
521 }
522 
523 /*****************************************************************************/
524 /* osl_sendPipe  */
525 /*****************************************************************************/
526 sal_Int32 SAL_CALL osl_sendPipe(oslPipe pPipe,
527                        const void* pBuffer,
528                        sal_Int32 BytesToSend)
529 {
530     DWORD nBytes;
531     OSL_ASSERT(pPipe);
532 
533     if (IS_NT/*pPipe->m_File != INVALID_HANDLE_VALUE*/)
534     {
535         OVERLAPPED   os;
536         rtl_zeroMemory(&os, sizeof(OVERLAPPED));
537         os.hEvent = pPipe->m_WriteEvent;
538         ResetEvent(pPipe->m_WriteEvent);
539 
540         if (! WriteFile(pPipe->m_File, pBuffer, BytesToSend, &nBytes, &os) &&
541             ((GetLastError() != ERROR_IO_PENDING) ||
542               ! GetOverlappedResult(pPipe->m_File, &os, &nBytes, TRUE)))
543         {
544             if (GetLastError() == ERROR_PIPE_NOT_CONNECTED)
545                 nBytes = 0;
546             else
547                 nBytes = (DWORD) -1;
548 
549             pPipe->m_Error = osl_Pipe_E_ConnectionAbort;
550         }
551     }
552     else
553     {
554         BOOL fSuccess = WriteSimplePipe( pPipe->m_File, pBuffer, BytesToSend, &nBytes, TRUE );
555 
556         if ( !fSuccess )
557         {
558             nBytes = 0;
559             pPipe->m_Error = osl_Pipe_E_ConnectionAbort;
560         }
561     }
562 
563     return (nBytes);
564 }
565 
566 sal_Int32 SAL_CALL osl_writePipe( oslPipe pPipe, const void *pBuffer , sal_Int32 n )
567 {
568     /* loop until all desired bytes were send or an error occured */
569     sal_Int32 BytesSend= 0;
570     sal_Int32 BytesToSend= n;
571 
572     OSL_ASSERT(pPipe);
573     while (BytesToSend > 0)
574     {
575         sal_Int32 RetVal;
576 
577         RetVal= osl_sendPipe(pPipe, pBuffer, BytesToSend);
578 
579         /* error occured? */
580         if(RetVal <= 0)
581         {
582             break;
583         }
584 
585         BytesToSend -= RetVal;
586         BytesSend += RetVal;
587         pBuffer= (sal_Char*)pBuffer + RetVal;
588     }
589 
590     return BytesSend;
591 }
592 
593 sal_Int32 SAL_CALL osl_readPipe( oslPipe pPipe, void *pBuffer , sal_Int32 n )
594 {
595     /* loop until all desired bytes were read or an error occured */
596     sal_Int32 BytesRead= 0;
597     sal_Int32 BytesToRead= n;
598 
599     OSL_ASSERT( pPipe );
600     while (BytesToRead > 0)
601     {
602         sal_Int32 RetVal;
603         RetVal= osl_receivePipe(pPipe, pBuffer, BytesToRead);
604 
605         /* error occured? */
606         if(RetVal <= 0)
607         {
608             break;
609         }
610 
611         BytesToRead -= RetVal;
612         BytesRead += RetVal;
613         pBuffer= (sal_Char*)pBuffer + RetVal;
614     }
615     return BytesRead;
616 }
617 
618 
619 /*****************************************************************************/
620 /* osl_getLastPipeError  */
621 /*****************************************************************************/
622 oslPipeError SAL_CALL osl_getLastPipeError(oslPipe pPipe)
623 {
624     oslPipeError Error;
625 
626     if (pPipe != NULL)
627     {
628         Error = pPipe->m_Error;
629         pPipe->m_Error = osl_Pipe_E_None;
630     }
631     else
632         Error = osl_Pipe_E_NotFound;
633 
634     return (Error);
635 }
636 
637