xref: /trunk/main/sal/osl/unx/pipe.c (revision 22722c36)
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 
25 #include "system.h"
26 
27 #include <osl/pipe.h>
28 #include <osl/diagnose.h>
29 /*#include <osl/signal.h>*/
30 #include <osl/thread.h>
31 #include <osl/interlck.h>
32 
33 #include "sockimpl.h"
34 
35 #define PIPEDEFAULTPATH		"/tmp"
36 #define PIPEALTERNATEPATH	"/var/tmp"
37 
38 #define PIPENAMEMASK	"%s/OSL_PIPE_%s"
39 #define SECPIPENAMEMASK	"%s/OSL_PIPE_%s_%s"
40 
41 sal_Bool SAL_CALL osl_psz_getUserIdent(oslSecurity Security, sal_Char *pszIdent, sal_uInt32 nMax);
42 oslPipe SAL_CALL osl_psz_createPipe(const sal_Char *pszPipeName, oslPipeOptions Options, oslSecurity Security);
43 
44 /*#define DEBUG_OSL_PIPE*/
45 /*#define TRACE_OSL_PIPE*/
46 
47 
48 /*****************************************************************************/
49 /* enum oslPipeError */
50 /*****************************************************************************/
51 
52 static struct
53 {
54 	int            errcode;
55 	oslPipeError   error;
56 } PipeError[]= {
57 	{ 0,			   osl_Pipe_E_None		    	},	/* no error */
58 	{ EPROTOTYPE,	   osl_Pipe_E_NoProtocol	    },	/* Protocol wrong type for socket */
59 	{ ENOPROTOOPT,	   osl_Pipe_E_NoProtocol	    },	/* Protocol not available */
60 	{ EPROTONOSUPPORT, osl_Pipe_E_NoProtocol		},	/* Protocol not supported */
61 	{ ESOCKTNOSUPPORT, osl_Pipe_E_NoProtocol 		},	/* Socket type not supported */
62 	{ EPFNOSUPPORT,	   osl_Pipe_E_NoProtocol     	},	/* Protocol family not supported */
63 	{ EAFNOSUPPORT,	   osl_Pipe_E_NoProtocol     	},	/* Address family not supported by */
64 														/* protocol family */
65 	{ ENETRESET,	   osl_Pipe_E_NetworkReset 		},	/* Network dropped connection because */
66 											 			/* of reset */
67 	{ ECONNABORTED,	   osl_Pipe_E_ConnectionAbort 	},	/* Software caused connection abort */
68 	{ ECONNRESET,	   osl_Pipe_E_ConnectionReset 	},	/* Connection reset by peer */
69 	{ ENOBUFS,		   osl_Pipe_E_NoBufferSpace 	},	/* No buffer space available */
70 	{ ETIMEDOUT,	   osl_Pipe_E_TimedOut 			},	/* Connection timed out */
71 	{ ECONNREFUSED,	   osl_Pipe_E_ConnectionRefused	},	/* Connection refused */
72 	{ -1,		   	   osl_Pipe_E_invalidError 		}
73 };
74 
75 
76 /* map */
77 /* mfe: NOT USED
78    static int osl_NativeFromPipeError(oslPipeError errorCode)
79    {
80    int i = 0;
81 
82    while ((PipeError[i].error != osl_Pipe_E_invalidError) &&
83    (PipeError[i].error != errorCode)) i++;
84 
85    return PipeError[i].errcode;
86 
87    }
88 */
89 
90 /* reverse map */
osl_PipeErrorFromNative(int nativeType)91 static oslPipeError osl_PipeErrorFromNative(int nativeType)
92 {
93 	int i = 0;
94 
95 	while ((PipeError[i].error != osl_Pipe_E_invalidError) &&
96 		   (PipeError[i].errcode != nativeType)) i++;
97 
98 	return PipeError[i].error;
99 }
100 
101 
102 /* macros */
103 #define ERROR_TO_NATIVE(x)		osl_NativeFromPipeError(x)
104 #define ERROR_FROM_NATIVE(y)	osl_PipeErrorFromNative(y)
105 
106 
107 /*****************************************************************************/
108 /* osl_create/destroy-PipeImpl */
109 /*****************************************************************************/
110 
__osl_createPipeImpl()111 oslPipe __osl_createPipeImpl()
112 {
113 	oslPipe pPipeImpl;
114 
115 	pPipeImpl = (oslPipe)calloc(1, sizeof(struct oslPipeImpl));
116 	pPipeImpl->m_nRefCount =1;
117 	pPipeImpl->m_bClosed = sal_False;
118 #if CLOSESOCKET_DOESNT_WAKE_UP_ACCEPT
119 	pPipeImpl->m_bIsInShutdown = sal_False;
120 	pPipeImpl->m_bIsAccepting = sal_False;
121 #endif
122 	return pPipeImpl;
123 }
124 
__osl_destroyPipeImpl(oslPipe pImpl)125 void __osl_destroyPipeImpl(oslPipe pImpl)
126 {
127 	if (pImpl != NULL)
128 		free(pImpl);
129 }
130 
131 
132 /*****************************************************************************/
133 /* osl_createPipe  */
134 /*****************************************************************************/
osl_createPipe(rtl_uString * ustrPipeName,oslPipeOptions Options,oslSecurity Security)135 oslPipe SAL_CALL osl_createPipe(rtl_uString *ustrPipeName, oslPipeOptions Options, oslSecurity Security)
136 {
137     oslPipe pPipe=0;
138     rtl_String* strPipeName=NULL;
139     sal_Char* pszPipeName=NULL;
140 
141     if ( ustrPipeName != NULL )
142     {
143         rtl_uString2String( &strPipeName,
144                             rtl_uString_getStr(ustrPipeName),
145                             rtl_uString_getLength(ustrPipeName),
146                             osl_getThreadTextEncoding(),
147                             OUSTRING_TO_OSTRING_CVTFLAGS );
148         pszPipeName = rtl_string_getStr(strPipeName);
149         pPipe = osl_psz_createPipe(pszPipeName, Options, Security);
150 
151         if ( strPipeName != NULL )
152         {
153             rtl_string_release(strPipeName);
154         }
155     }
156 
157     return pPipe;
158 
159 }
160 
osl_psz_createPipe(const sal_Char * pszPipeName,oslPipeOptions Options,oslSecurity Security)161 oslPipe SAL_CALL osl_psz_createPipe(const sal_Char *pszPipeName, oslPipeOptions Options,
162                        oslSecurity Security)
163 {
164 	int    Flags;
165 	size_t	   len;
166 	struct sockaddr_un addr;
167 
168 	sal_Char  	 name[PATH_MAX + 1];
169 	const sal_Char 	 *pPath;
170 	oslPipe  pPipe;
171 
172 	if (access(PIPEDEFAULTPATH, R_OK|W_OK) == 0)
173 	{
174 		pPath = PIPEDEFAULTPATH;
175 	}
176 	else
177 	{
178 		pPath = PIPEALTERNATEPATH;
179 	}
180 
181 	if (Security)
182 	{
183 		sal_Char Ident[256];
184 
185 		Ident[0] = '\0';
186 
187 		OSL_VERIFY(osl_psz_getUserIdent(Security, Ident, sizeof(Ident)));
188 
189 		snprintf(name, sizeof(name), SECPIPENAMEMASK, pPath, Ident, pszPipeName);
190 	}
191 	else
192 	{
193 		snprintf(name, sizeof(name), PIPENAMEMASK, pPath, pszPipeName);
194 	}
195 
196 
197 	/* alloc memory */
198 	pPipe= __osl_createPipeImpl();
199 
200 	/* create socket */
201 	pPipe->m_Socket = socket(AF_UNIX, SOCK_STREAM, 0);
202 	if ( pPipe->m_Socket < 0 )
203 	{
204 		OSL_TRACE("osl_createPipe socket failed. Errno: %d; %s\n",errno, strerror(errno));
205 		__osl_destroyPipeImpl(pPipe);
206 		return NULL;
207 	}
208 
209 /*    OSL_TRACE("osl_createPipe : new Pipe on fd %i\n",pPipe->m_Socket);*/
210 
211 	/* set close-on-exec flag */
212 	if ((Flags = fcntl(pPipe->m_Socket, F_GETFD, 0)) != -1)
213 	{
214 		Flags |= FD_CLOEXEC;
215 		if (fcntl(pPipe->m_Socket, F_SETFD, Flags) == -1)
216 		{
217 			OSL_TRACE("osl_createPipe failed changing socket flags. Errno: %d; %s\n",errno,strerror(errno));
218 		}
219 	}
220 
221 	memset(&addr, 0, sizeof(addr));
222 
223     OSL_TRACE("osl_createPipe : Pipe Name '%s'",name);
224 
225 	addr.sun_family = AF_UNIX;
226 	strncpy(addr.sun_path, name, sizeof(addr.sun_path));
227 #if defined(FREEBSD)
228 	len = SUN_LEN(&addr);
229 #else
230 	len = sizeof(addr);
231 #endif
232 
233 	if ( Options & osl_Pipe_CREATE )
234 	{
235 		struct stat status;
236 
237 		/* check if there exists an orphan filesystem entry */
238 		if ( ( stat(name, &status) == 0) &&
239 			 ( S_ISSOCK(status.st_mode) || S_ISFIFO(status.st_mode) ) )
240 		{
241 			if ( connect(pPipe->m_Socket,(struct sockaddr *)&addr,len) >= 0 )
242 			{
243 				OSL_TRACE("osl_createPipe : Pipe already in use. Errno: %d; %s\n",errno,strerror(errno));
244 				close (pPipe->m_Socket);
245 				__osl_destroyPipeImpl(pPipe);
246 				return NULL;
247 			}
248 
249 			unlink(name);
250 		}
251 
252 		/* ok, fs clean */
253 		if ( bind(pPipe->m_Socket, (struct sockaddr *)&addr, len) < 0 )
254 		{
255 			OSL_TRACE("osl_createPipe : failed to bind socket. Errno: %d; %s\n",errno,strerror(errno));
256 			close (pPipe->m_Socket);
257 			__osl_destroyPipeImpl(pPipe);
258 			return NULL;
259 		}
260 
261 		/*	Only give access to all if no security handle was specified, otherwise security
262 			depends on umask */
263 
264 		if ( !Security )
265 			chmod(name,S_IRWXU | S_IRWXG |S_IRWXO);
266 
267 
268 		strncpy(pPipe->m_Name, name, sizeof(pPipe->m_Name));
269 
270 		if ( listen(pPipe->m_Socket, 5) < 0 )
271 		{
272 			OSL_TRACE("osl_createPipe failed to listen. Errno: %d; %s\n",errno,strerror(errno));
273 			unlink(name);	/* remove filesystem entry */
274 			close (pPipe->m_Socket);
275 			__osl_destroyPipeImpl(pPipe);
276 			return NULL;
277 		}
278 
279 		return (pPipe);
280 	}
281 	else
282 	{   /* osl_pipe_OPEN */
283 		if ( access(name, F_OK) != -1 )
284 		{
285 			if ( connect( pPipe->m_Socket, (struct sockaddr *)&addr, len) >= 0 )
286 			{
287 				return (pPipe);
288 			}
289 
290 			OSL_TRACE("osl_createPipe failed to connect. Errno: %d; %s\n",errno,strerror(errno));
291 		}
292 
293 		close (pPipe->m_Socket);
294 		__osl_destroyPipeImpl(pPipe);
295 		return NULL;
296 	}
297 }
298 
osl_acquirePipe(oslPipe pPipe)299 void SAL_CALL osl_acquirePipe( oslPipe pPipe )
300 {
301 	osl_incrementInterlockedCount( &(pPipe->m_nRefCount) );
302 }
303 
osl_releasePipe(oslPipe pPipe)304 void SAL_CALL osl_releasePipe( oslPipe pPipe )
305 {
306 
307 	if( 0 == pPipe )
308 		return;
309 
310 	if( 0 == osl_decrementInterlockedCount( &(pPipe->m_nRefCount) ) )
311 	{
312 		if( ! pPipe->m_bClosed )
313 			osl_closePipe( pPipe );
314 
315 		__osl_destroyPipeImpl( pPipe );
316 	}
317 }
318 
osl_closePipe(oslPipe pPipe)319 void SAL_CALL osl_closePipe( oslPipe pPipe )
320 {
321     int nRet;
322 #if CLOSESOCKET_DOESNT_WAKE_UP_ACCEPT
323     size_t	   len;
324 	struct sockaddr_un addr;
325     int fd;
326 #endif
327     int ConnFD;
328 
329 	if( ! pPipe )
330 	{
331 		return;
332 	}
333 
334 	if( pPipe->m_bClosed )
335 	{
336 		return;
337 	}
338 
339     ConnFD = pPipe->m_Socket;
340 
341 	/*
342 	  Thread does not return from accept on some operating systems, so
343 	  connect to the accepting pipe
344 	 */
345 #if CLOSESOCKET_DOESNT_WAKE_UP_ACCEPT
346     if ( pPipe->m_bIsAccepting )
347     {
348         pPipe->m_bIsInShutdown = sal_True;
349         pPipe->m_Socket = -1;
350         fd = socket(AF_UNIX, SOCK_STREAM, 0);
351         memset(&addr, 0, sizeof(addr));
352 
353         OSL_TRACE("osl_destroyPipe : Pipe Name '%s'",pPipe->m_Name);
354 
355         addr.sun_family = AF_UNIX;
356         strncpy(addr.sun_path, pPipe->m_Name, sizeof(addr.sun_path));
357 #if defined(FREEBSD)
358         len = SUN_LEN(&addr);
359 #else
360         len = sizeof(addr);
361 #endif
362 
363         nRet = connect( fd, (struct sockaddr *)&addr, len);
364 #if OSL_DEBUG_LEVEL > 1
365         if ( nRet < 0 )
366         {
367             perror("connect in osl_destroyPipe");
368         }
369 #endif /* OSL_DEBUG_LEVEL */
370         close(fd);
371     }
372 #endif /* CLOSESOCKET_DOESNT_WAKE_UP_ACCEPT */
373 
374 
375 	nRet = shutdown(ConnFD, 2);
376     if ( nRet < 0 )
377     {
378         OSL_TRACE("shutdown in destroyPipe failed : '%s'\n",strerror(errno));
379     }
380 
381 	nRet = close(ConnFD);
382     if ( nRet < 0 )
383     {
384         OSL_TRACE("close in destroyPipe failed : '%s'\n",strerror(errno));
385     }
386 	/* remove filesystem entry */
387 	if ( strlen(pPipe->m_Name) > 0 )
388 	{
389 		unlink(pPipe->m_Name);
390 	}
391 	pPipe->m_bClosed = sal_True;
392 
393 /*      OSL_TRACE("Out osl_destroyPipe");     */
394 }
395 
396 
397 /*****************************************************************************/
398 /* osl_acceptPipe  */
399 /*****************************************************************************/
osl_acceptPipe(oslPipe pPipe)400 oslPipe SAL_CALL osl_acceptPipe(oslPipe pPipe)
401 {
402 	int     s, flags;
403 	oslPipe pAcceptedPipe;
404 
405 	OSL_ASSERT(pPipe);
406 	if ( pPipe == 0 )
407 	{
408 		return NULL;
409 	}
410 
411 	OSL_ASSERT(strlen(pPipe->m_Name) > 0);
412 
413 #if CLOSESOCKET_DOESNT_WAKE_UP_ACCEPT
414     pPipe->m_bIsAccepting = sal_True;
415 #endif
416 
417     s = accept(pPipe->m_Socket, NULL, NULL);
418 
419 #if CLOSESOCKET_DOESNT_WAKE_UP_ACCEPT
420     pPipe->m_bIsAccepting = sal_False;
421 #endif
422 
423     if (s < 0)
424 	{
425         OSL_TRACE("osl_acceptPipe : accept error '%s'", strerror(errno));
426 		return NULL;
427 	}
428 
429 #if CLOSESOCKET_DOESNT_WAKE_UP_ACCEPT
430     if ( pPipe->m_bIsInShutdown  )
431     {
432         close(s);
433         return NULL;
434     }
435 #endif /* CLOSESOCKET_DOESNT_WAKE_UP_ACCEPT */
436     else
437 	{
438 		/* alloc memory */
439 		pAcceptedPipe= __osl_createPipeImpl();
440 
441 		OSL_ASSERT(pAcceptedPipe);
442 		if(pAcceptedPipe==NULL)
443 		{
444 			close(s);
445 			return NULL;
446 		}
447 
448 		/* set close-on-exec flag */
449 		if (!((flags = fcntl(s, F_GETFD, 0)) < 0))
450 		{
451 			flags |= FD_CLOEXEC;
452 			if (fcntl(s, F_SETFD, flags) < 0)
453 			{
454 				OSL_TRACE("osl_acceptPipe: error changing socket flags. "
455 						  "Errno: %d; %s",errno,strerror(errno));
456 			}
457 		}
458 
459 		pAcceptedPipe->m_Socket = s;
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     int nRet = 0;
473 
474 	OSL_ASSERT(pPipe);
475 
476 	if ( pPipe == 0 )
477 	{
478         OSL_TRACE("osl_receivePipe : Invalid socket");
479         errno=EINVAL;
480 		return -1;
481 	}
482 
483     nRet = recv(pPipe->m_Socket,
484   				(sal_Char*)pBuffer,
485   				BytesToRead, 0);
486 
487     if ( nRet < 0 )
488     {
489         OSL_TRACE("osl_receivePipe failed : %i '%s'",nRet,strerror(errno));
490     }
491 
492   	return nRet;
493 }
494 
495 
496 /*****************************************************************************/
497 /* osl_sendPipe  */
498 /*****************************************************************************/
osl_sendPipe(oslPipe pPipe,const void * pBuffer,sal_Int32 BytesToSend)499 sal_Int32 SAL_CALL osl_sendPipe(oslPipe pPipe,
500 				       const void* pBuffer,
501 				       sal_Int32 BytesToSend)
502 {
503     int nRet=0;
504 
505 	OSL_ASSERT(pPipe);
506 
507 	if ( pPipe == 0 )
508 	{
509         OSL_TRACE("osl_sendPipe : Invalid socket");
510         errno=EINVAL;
511 		return -1;
512 	}
513 
514     nRet = send(pPipe->m_Socket,
515   				(sal_Char*)pBuffer,
516   				BytesToSend, 0);
517 
518 
519     if ( nRet <= 0 )
520     {
521         OSL_TRACE("osl_sendPipe failed : %i '%s'",nRet,strerror(errno));
522     }
523 
524  	return nRet;
525 }
526 
527 
528 /*****************************************************************************/
529 /* osl_getLastPipeError  */
530 /*****************************************************************************/
osl_getLastPipeError(oslPipe pPipe)531 oslPipeError SAL_CALL osl_getLastPipeError(oslPipe pPipe)
532 {
533     (void) pPipe; /* unused */
534 	return ERROR_FROM_NATIVE(errno);
535 }
536 
537 
osl_writePipe(oslPipe pPipe,const void * pBuffer,sal_Int32 n)538 sal_Int32 SAL_CALL osl_writePipe( oslPipe pPipe, const void *pBuffer , sal_Int32 n )
539 {
540 	/* loop until all desired bytes were send or an error occurred */
541 	sal_Int32 BytesSend= 0;
542 	sal_Int32 BytesToSend= n;
543 
544 	OSL_ASSERT(pPipe);
545 	while (BytesToSend > 0)
546 	{
547 		sal_Int32 RetVal;
548 
549 		RetVal= osl_sendPipe(pPipe, pBuffer, BytesToSend);
550 
551 		/* error occurred? */
552 		if(RetVal <= 0)
553 		{
554 			break;
555 		}
556 
557 		BytesToSend -= RetVal;
558 		BytesSend += RetVal;
559 		pBuffer= (sal_Char*)pBuffer + RetVal;
560 	}
561 
562 	return BytesSend;
563 }
564 
osl_readPipe(oslPipe pPipe,void * pBuffer,sal_Int32 n)565 sal_Int32 SAL_CALL osl_readPipe( oslPipe pPipe, void *pBuffer , sal_Int32 n )
566 {
567 	/* loop until all desired bytes were read or an error occurred */
568 	sal_Int32 BytesRead= 0;
569 	sal_Int32 BytesToRead= n;
570 
571 	OSL_ASSERT( pPipe );
572 	while (BytesToRead > 0)
573 	{
574 		sal_Int32 RetVal;
575 		RetVal= osl_receivePipe(pPipe, pBuffer, BytesToRead);
576 
577 		/* error occurred? */
578 		if(RetVal <= 0)
579 		{
580 			break;
581 		}
582 
583 		BytesToRead -= RetVal;
584 		BytesRead += RetVal;
585 		pBuffer= (sal_Char*)pBuffer + RetVal;
586 	}
587 	return BytesRead;
588 }
589 
590 
591