xref: /trunk/main/sal/osl/unx/pipe.c (revision cc2d236ef38d06aaf2de3a9ab3b8b9943bf13230)
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     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 
299 void SAL_CALL osl_acquirePipe( oslPipe pPipe )
300 {
301     osl_incrementInterlockedCount( &(pPipe->m_nRefCount) );
302 }
303 
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 
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 /*****************************************************************************/
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 /*****************************************************************************/
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 /*****************************************************************************/
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 /*****************************************************************************/
531 oslPipeError SAL_CALL osl_getLastPipeError(oslPipe pPipe)
532 {
533     (void) pPipe; /* unused */
534     return ERROR_FROM_NATIVE(errno);
535 }
536 
537 
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 
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