xref: /trunk/main/sal/osl/w32/pipe.c (revision 86e1cf34)
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 occurred */
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 occurred? */
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 occurred */
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 occurred? */
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