xref: /AOO41X/main/sal/osl/w32/pipe.c (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
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