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