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