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