xref: /aoo42x/main/sal/osl/unx/pipe.c (revision 0618ff6b)
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 */
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 
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 
125 void __osl_destroyPipeImpl(oslPipe pImpl)
126 {
127 	if (pImpl != NULL)
128 		free(pImpl);
129 }
130 
131 
132 /*****************************************************************************/
133 /* osl_createPipe  */
134 /*****************************************************************************/
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 
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     union
167     {
168 	    struct sockaddr addr;
169 	    struct sockaddr_un addr_un;
170     } s;
171 
172 	sal_Char  	 name[PATH_MAX + 1];
173 	const sal_Char 	 *pPath;
174 	oslPipe  pPipe;
175 
176 	if (access(PIPEDEFAULTPATH, R_OK|W_OK) == 0)
177 	{
178 		pPath = PIPEDEFAULTPATH;
179 	}
180 	else
181 	{
182 		pPath = PIPEALTERNATEPATH;
183 	}
184 
185 	if (Security)
186 	{
187 		sal_Char Ident[256];
188 
189 		Ident[0] = '\0';
190 
191 		OSL_VERIFY(osl_psz_getUserIdent(Security, Ident, sizeof(Ident)));
192 
193 		snprintf(name, sizeof(name), SECPIPENAMEMASK, pPath, Ident, pszPipeName);
194 	}
195 	else
196 	{
197 		snprintf(name, sizeof(name), PIPENAMEMASK, pPath, pszPipeName);
198 	}
199 
200 
201 	/* alloc memory */
202 	pPipe= __osl_createPipeImpl();
203 
204 	/* create socket */
205 	pPipe->m_Socket = socket(AF_UNIX, SOCK_STREAM, 0);
206 	if ( pPipe->m_Socket < 0 )
207 	{
208 		OSL_TRACE("osl_createPipe socket failed. Errno: %d; %s\n",errno, strerror(errno));
209 		__osl_destroyPipeImpl(pPipe);
210 		return NULL;
211 	}
212 
213 /*    OSL_TRACE("osl_createPipe : new Pipe on fd %i\n",pPipe->m_Socket);*/
214 
215 	/* set close-on-exec flag */
216 	if ((Flags = fcntl(pPipe->m_Socket, F_GETFD, 0)) != -1)
217 	{
218 		Flags |= FD_CLOEXEC;
219 		if (fcntl(pPipe->m_Socket, F_SETFD, Flags) == -1)
220 		{
221 			OSL_TRACE("osl_createPipe failed changing socket flags. Errno: %d; %s\n",errno,strerror(errno));
222 		}
223 	}
224 
225 	memset(&s.addr_un, 0, sizeof(s.addr_un));
226 
227     OSL_TRACE("osl_createPipe : Pipe Name '%s'",name);
228 
229 	s.addr_un.sun_family = AF_UNIX;
230 	strncpy(s.addr_un.sun_path, name, sizeof(s.addr_un.sun_path));
231 #if defined(FREEBSD)
232 	len = SUN_LEN(&s.addr_un);
233 #else
234 	len = sizeof(s.addr_un);
235 #endif
236 
237 	if ( Options & osl_Pipe_CREATE )
238 	{
239 		struct stat status;
240 
241 		/* check if there exists an orphan filesystem entry */
242 		if ( ( stat(name, &status) == 0) &&
243 			 ( S_ISSOCK(status.st_mode) || S_ISFIFO(status.st_mode) ) )
244 		{
245 			if ( connect(pPipe->m_Socket,&s.addr,len) >= 0 )
246 			{
247 				OSL_TRACE("osl_createPipe : Pipe already in use. Errno: %d; %s\n",errno,strerror(errno));
248 				close (pPipe->m_Socket);
249 				__osl_destroyPipeImpl(pPipe);
250 				return NULL;
251 			}
252 
253 			unlink(name);
254 		}
255 
256 		/* ok, fs clean */
257 		if ( bind(pPipe->m_Socket, &s.addr, len) < 0 )
258 		{
259 			OSL_TRACE("osl_createPipe : failed to bind socket. Errno: %d; %s\n",errno,strerror(errno));
260 			close (pPipe->m_Socket);
261 			__osl_destroyPipeImpl(pPipe);
262 			return NULL;
263 		}
264 
265 		/*	Only give access to all if no security handle was specified, otherwise security
266 			depends on umask */
267 
268 		if ( !Security )
269 			chmod(name,S_IRWXU | S_IRWXG |S_IRWXO);
270 
271 
272 		strncpy(pPipe->m_Name, name, sizeof(pPipe->m_Name));
273 
274 		if ( listen(pPipe->m_Socket, 5) < 0 )
275 		{
276 			OSL_TRACE("osl_createPipe failed to listen. Errno: %d; %s\n",errno,strerror(errno));
277 			unlink(name);	/* remove filesystem entry */
278 			close (pPipe->m_Socket);
279 			__osl_destroyPipeImpl(pPipe);
280 			return NULL;
281 		}
282 
283 		return (pPipe);
284 	}
285 	else
286 	{   /* osl_pipe_OPEN */
287 		if ( access(name, F_OK) != -1 )
288 		{
289 			if ( connect( pPipe->m_Socket, &s.addr, len) >= 0 )
290 			{
291 				return (pPipe);
292 			}
293 
294 			OSL_TRACE("osl_createPipe failed to connect. Errno: %d; %s\n",errno,strerror(errno));
295 		}
296 
297 		close (pPipe->m_Socket);
298 		__osl_destroyPipeImpl(pPipe);
299 		return NULL;
300 	}
301 }
302 
303 void SAL_CALL osl_acquirePipe( oslPipe pPipe )
304 {
305 	osl_incrementInterlockedCount( &(pPipe->m_nRefCount) );
306 }
307 
308 void SAL_CALL osl_releasePipe( oslPipe pPipe )
309 {
310 
311 	if( 0 == pPipe )
312 		return;
313 
314 	if( 0 == osl_decrementInterlockedCount( &(pPipe->m_nRefCount) ) )
315 	{
316 		if( ! pPipe->m_bClosed )
317 			osl_closePipe( pPipe );
318 
319 		__osl_destroyPipeImpl( pPipe );
320 	}
321 }
322 
323 void SAL_CALL osl_closePipe( oslPipe pPipe )
324 {
325     int nRet;
326 #if CLOSESOCKET_DOESNT_WAKE_UP_ACCEPT
327     size_t	   len;
328     union
329     {
330 	    struct sockaddr_un addr_un;
331 	    struct sockaddr addr;
332     } s;
333     int fd;
334 #endif
335     int ConnFD;
336 
337 	if( ! pPipe )
338 	{
339 		return;
340 	}
341 
342 	if( pPipe->m_bClosed )
343 	{
344 		return;
345 	}
346 
347     ConnFD = pPipe->m_Socket;
348 
349 	/*
350 	  Thread does not return from accept on some operating systems, so
351 	  connect to the accepting pipe
352 	 */
353 #if CLOSESOCKET_DOESNT_WAKE_UP_ACCEPT
354     if ( pPipe->m_bIsAccepting )
355     {
356         pPipe->m_bIsInShutdown = sal_True;
357         pPipe->m_Socket = -1;
358         fd = socket(AF_UNIX, SOCK_STREAM, 0);
359         memset(&s.addr_un, 0, sizeof(s.addr_un));
360 
361         OSL_TRACE("osl_destroyPipe : Pipe Name '%s'",pPipe->m_Name);
362 
363         s.addr_un.sun_family = AF_UNIX;
364         strncpy(s.addr_un.sun_path, pPipe->m_Name, sizeof(s.addr_un.sun_path));
365 #if defined(FREEBSD)
366         len = SUN_LEN(&s.addr_un);
367 #else
368         len = sizeof(s.addr_un);
369 #endif
370 
371         nRet = connect( fd, &s.addr, len);
372 #if OSL_DEBUG_LEVEL > 1
373         if ( nRet < 0 )
374         {
375             perror("connect in osl_destroyPipe");
376         }
377 #endif /* OSL_DEBUG_LEVEL */
378         close(fd);
379     }
380 #endif /* CLOSESOCKET_DOESNT_WAKE_UP_ACCEPT */
381 
382 
383 	nRet = shutdown(ConnFD, 2);
384     if ( nRet < 0 )
385     {
386         OSL_TRACE("shutdown in destroyPipe failed : '%s'\n",strerror(errno));
387     }
388 
389 	nRet = close(ConnFD);
390     if ( nRet < 0 )
391     {
392         OSL_TRACE("close in destroyPipe failed : '%s'\n",strerror(errno));
393     }
394 	/* remove filesystem entry */
395 	if ( strlen(pPipe->m_Name) > 0 )
396 	{
397 		unlink(pPipe->m_Name);
398 	}
399 	pPipe->m_bClosed = sal_True;
400 
401 /*      OSL_TRACE("Out osl_destroyPipe");     */
402 }
403 
404 
405 /*****************************************************************************/
406 /* osl_acceptPipe  */
407 /*****************************************************************************/
408 oslPipe SAL_CALL osl_acceptPipe(oslPipe pPipe)
409 {
410 	int     s, flags;
411 	oslPipe pAcceptedPipe;
412 
413 	OSL_ASSERT(pPipe);
414 	if ( pPipe == 0 )
415 	{
416 		return NULL;
417 	}
418 
419 	OSL_ASSERT(strlen(pPipe->m_Name) > 0);
420 
421 #if CLOSESOCKET_DOESNT_WAKE_UP_ACCEPT
422     pPipe->m_bIsAccepting = sal_True;
423 #endif
424 
425     s = accept(pPipe->m_Socket, NULL, NULL);
426 
427 #if CLOSESOCKET_DOESNT_WAKE_UP_ACCEPT
428     pPipe->m_bIsAccepting = sal_False;
429 #endif
430 
431     if (s < 0)
432 	{
433         OSL_TRACE("osl_acceptPipe : accept error '%s'", strerror(errno));
434 		return NULL;
435 	}
436 
437 #if CLOSESOCKET_DOESNT_WAKE_UP_ACCEPT
438     if ( pPipe->m_bIsInShutdown  )
439     {
440         close(s);
441         return NULL;
442     }
443 #endif /* CLOSESOCKET_DOESNT_WAKE_UP_ACCEPT */
444     else
445 	{
446 		/* alloc memory */
447 		pAcceptedPipe= __osl_createPipeImpl();
448 
449 		OSL_ASSERT(pAcceptedPipe);
450 		if(pAcceptedPipe==NULL)
451 		{
452 			close(s);
453 			return NULL;
454 		}
455 
456 		/* set close-on-exec flag */
457 		if (!((flags = fcntl(s, F_GETFD, 0)) < 0))
458 		{
459 			flags |= FD_CLOEXEC;
460 			if (fcntl(s, F_SETFD, flags) < 0)
461 			{
462 				OSL_TRACE("osl_acceptPipe: error changing socket flags. "
463 						  "Errno: %d; %s",errno,strerror(errno));
464 			}
465 		}
466 
467 		pAcceptedPipe->m_Socket = s;
468 	}
469 
470 	return pAcceptedPipe;
471 }
472 
473 /*****************************************************************************/
474 /* osl_receivePipe  */
475 /*****************************************************************************/
476 sal_Int32 SAL_CALL osl_receivePipe(oslPipe pPipe,
477 					    void* pBuffer,
478 					    sal_Int32 BytesToRead)
479 {
480     int nRet = 0;
481 
482 	OSL_ASSERT(pPipe);
483 
484 	if ( pPipe == 0 )
485 	{
486         OSL_TRACE("osl_receivePipe : Invalid socket");
487         errno=EINVAL;
488 		return -1;
489 	}
490 
491     nRet = recv(pPipe->m_Socket,
492   				(sal_Char*)pBuffer,
493   				BytesToRead, 0);
494 
495     if ( nRet < 0 )
496     {
497         OSL_TRACE("osl_receivePipe failed : %i '%s'",nRet,strerror(errno));
498     }
499 
500   	return nRet;
501 }
502 
503 
504 /*****************************************************************************/
505 /* osl_sendPipe  */
506 /*****************************************************************************/
507 sal_Int32 SAL_CALL osl_sendPipe(oslPipe pPipe,
508 				       const void* pBuffer,
509 				       sal_Int32 BytesToSend)
510 {
511     int nRet=0;
512 
513 	OSL_ASSERT(pPipe);
514 
515 	if ( pPipe == 0 )
516 	{
517         OSL_TRACE("osl_sendPipe : Invalid socket");
518         errno=EINVAL;
519 		return -1;
520 	}
521 
522     nRet = send(pPipe->m_Socket,
523   				(sal_Char*)pBuffer,
524   				BytesToSend, 0);
525 
526 
527     if ( nRet <= 0 )
528     {
529         OSL_TRACE("osl_sendPipe failed : %i '%s'",nRet,strerror(errno));
530     }
531 
532  	return nRet;
533 }
534 
535 
536 /*****************************************************************************/
537 /* osl_getLastPipeError  */
538 /*****************************************************************************/
539 oslPipeError SAL_CALL osl_getLastPipeError(oslPipe pPipe)
540 {
541     (void) pPipe; /* unused */
542 	return ERROR_FROM_NATIVE(errno);
543 }
544 
545 
546 sal_Int32 SAL_CALL osl_writePipe( oslPipe pPipe, const void *pBuffer , sal_Int32 n )
547 {
548 	/* loop until all desired bytes were send or an error occurred */
549 	sal_Int32 BytesSend= 0;
550 	sal_Int32 BytesToSend= n;
551 
552 	OSL_ASSERT(pPipe);
553 	while (BytesToSend > 0)
554 	{
555 		sal_Int32 RetVal;
556 
557 		RetVal= osl_sendPipe(pPipe, pBuffer, BytesToSend);
558 
559 		/* error occurred? */
560 		if(RetVal <= 0)
561 		{
562 			break;
563 		}
564 
565 		BytesToSend -= RetVal;
566 		BytesSend += RetVal;
567 		pBuffer= (sal_Char*)pBuffer + RetVal;
568 	}
569 
570 	return BytesSend;
571 }
572 
573 sal_Int32 SAL_CALL osl_readPipe( oslPipe pPipe, void *pBuffer , sal_Int32 n )
574 {
575 	/* loop until all desired bytes were read or an error occurred */
576 	sal_Int32 BytesRead= 0;
577 	sal_Int32 BytesToRead= n;
578 
579 	OSL_ASSERT( pPipe );
580 	while (BytesToRead > 0)
581 	{
582 		sal_Int32 RetVal;
583 		RetVal= osl_receivePipe(pPipe, pBuffer, BytesToRead);
584 
585 		/* error occurred? */
586 		if(RetVal <= 0)
587 		{
588 			break;
589 		}
590 
591 		BytesToRead -= RetVal;
592 		BytesRead += RetVal;
593 		pBuffer= (sal_Char*)pBuffer + RetVal;
594 	}
595 	return BytesRead;
596 }
597 
598 
599