1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
35 #include <osl/diagnose.h>
36 /*#include <osl/signal.h>*/
37 #include <osl/thread.h>
38 #include <osl/interlck.h>
42 #define PIPEDEFAULTPATH "/tmp"
43 #define PIPEALTERNATEPATH "/var/tmp"
45 #define PIPENAMEMASK "OSL_PIPE_%s"
46 #define SECPIPENAMEMASK "OSL_PIPE_%s_%s"
48 sal_Bool SAL_CALL
osl_psz_getUserIdent(oslSecurity Security
, sal_Char
*pszIdent
, sal_uInt32 nMax
);
49 oslPipe SAL_CALL
osl_psz_createPipe(const sal_Char
*pszPipeName
, oslPipeOptions Options
, oslSecurity Security
);
51 /*#define DEBUG_OSL_PIPE*/
52 /*#define TRACE_OSL_PIPE*/
55 /*****************************************************************************/
56 /* enum oslPipeError */
57 /*****************************************************************************/
64 { 0, osl_Pipe_E_None
}, /* no error */
65 { EPROTOTYPE
, osl_Pipe_E_NoProtocol
}, /* Protocol wrong type for socket */
66 { ENOPROTOOPT
, osl_Pipe_E_NoProtocol
}, /* Protocol not available */
67 { EPROTONOSUPPORT
, osl_Pipe_E_NoProtocol
}, /* Protocol not supported */
68 { ESOCKTNOSUPPORT
, osl_Pipe_E_NoProtocol
}, /* Socket type not supported */
69 { EPFNOSUPPORT
, osl_Pipe_E_NoProtocol
}, /* Protocol family not supported */
70 { EAFNOSUPPORT
, osl_Pipe_E_NoProtocol
}, /* Address family not supported by */
72 { ENETRESET
, osl_Pipe_E_NetworkReset
}, /* Network dropped connection because */
74 { ECONNABORTED
, osl_Pipe_E_ConnectionAbort
}, /* Software caused connection abort */
75 { ECONNRESET
, osl_Pipe_E_ConnectionReset
}, /* Connection reset by peer */
76 { ENOBUFS
, osl_Pipe_E_NoBufferSpace
}, /* No buffer space available */
77 { ETIMEDOUT
, osl_Pipe_E_TimedOut
}, /* Connection timed out */
78 { ECONNREFUSED
, osl_Pipe_E_ConnectionRefused
}, /* Connection refused */
79 { -1, osl_Pipe_E_invalidError
}
85 static int osl_NativeFromPipeError(oslPipeError errorCode)
89 while ((PipeError[i].error != osl_Pipe_E_invalidError) &&
90 (PipeError[i].error != errorCode)) i++;
92 return PipeError[i].errcode;
98 static oslPipeError
osl_PipeErrorFromNative(int nativeType
)
102 while ((PipeError
[i
].error
!= osl_Pipe_E_invalidError
) &&
103 (PipeError
[i
].errcode
!= nativeType
)) i
++;
105 return PipeError
[i
].error
;
110 #define ERROR_TO_NATIVE(x) osl_NativeFromPipeError(x)
111 #define ERROR_FROM_NATIVE(y) osl_PipeErrorFromNative(y)
114 /*****************************************************************************/
115 /* osl_create/destroy-PipeImpl */
116 /*****************************************************************************/
118 oslPipe
__osl_createPipeImpl()
122 pPipeImpl
= (oslPipe
)calloc(1, sizeof(struct oslPipeImpl
));
123 pPipeImpl
->m_nRefCount
=1;
124 pPipeImpl
->m_bClosed
= sal_False
;
126 pPipeImpl
->m_bIsInShutdown
= sal_False
;
127 pPipeImpl
->m_bIsAccepting
= sal_False
;
132 void __osl_destroyPipeImpl(oslPipe pImpl
)
139 /*****************************************************************************/
141 /*****************************************************************************/
142 oslPipe SAL_CALL
osl_createPipe(rtl_uString
*ustrPipeName
, oslPipeOptions Options
, oslSecurity Security
)
145 rtl_String
* strPipeName
=0;
146 sal_Char
* pszPipeName
=0;
148 if ( ustrPipeName
!= 0 )
150 rtl_uString2String( &strPipeName
,
151 rtl_uString_getStr(ustrPipeName
),
152 rtl_uString_getLength(ustrPipeName
),
153 osl_getThreadTextEncoding(),
154 OUSTRING_TO_OSTRING_CVTFLAGS
);
155 pszPipeName
= rtl_string_getStr(strPipeName
);
156 pPipe
= osl_psz_createPipe(pszPipeName
, Options
, Security
);
158 if ( strPipeName
!= 0 )
160 rtl_string_release(strPipeName
);
168 oslPipe SAL_CALL
osl_psz_createPipe(const sal_Char
*pszPipeName
, oslPipeOptions Options
,
169 oslSecurity Security
)
173 struct sockaddr_un addr
;
175 sal_Char name
[PATH_MAX
+ 1];
178 if (access(PIPEDEFAULTPATH
, R_OK
|W_OK
) == 0)
180 strncpy(name
, PIPEDEFAULTPATH
, sizeof(name
));
184 strncpy(name
, PIPEALTERNATEPATH
, sizeof(name
));
188 strncat(name
, "/", sizeof(name
));
196 OSL_VERIFY(osl_psz_getUserIdent(Security
, Ident
, sizeof(Ident
)));
198 snprintf(&name
[strlen(name
)], sizeof(name
), SECPIPENAMEMASK
, Ident
, pszPipeName
);
202 snprintf(&name
[strlen(name
)], sizeof(name
), PIPENAMEMASK
, pszPipeName
);
207 pPipe
= __osl_createPipeImpl();
210 pPipe
->m_Socket
= socket(AF_UNIX
, SOCK_STREAM
, 0);
211 if ( pPipe
->m_Socket
< 0 )
213 OSL_TRACE("osl_createPipe socket failed. Errno: %d; %s\n",errno
, strerror(errno
));
214 __osl_destroyPipeImpl(pPipe
);
218 /* OSL_TRACE("osl_createPipe : new Pipe on fd %i\n",pPipe->m_Socket);*/
220 /* set close-on-exec flag */
221 if ((Flags
= fcntl(pPipe
->m_Socket
, F_GETFD
, 0)) != -1)
224 if (fcntl(pPipe
->m_Socket
, F_SETFD
, Flags
) == -1)
226 OSL_TRACE("osl_createPipe failed changing socket flags. Errno: %d; %s\n",errno
,strerror(errno
));
230 memset(&addr
, 0, sizeof(addr
));
232 OSL_TRACE("osl_createPipe : Pipe Name '%s'",name
);
234 addr
.sun_family
= AF_UNIX
;
235 strncpy(addr
.sun_path
, name
, sizeof(addr
.sun_path
));
237 len
= SUN_LEN(&addr
);
242 if ( Options
& osl_Pipe_CREATE
)
246 /* check if there exists an orphan filesystem entry */
247 if ( ( stat(name
, &status
) == 0) &&
248 ( S_ISSOCK(status
.st_mode
) || S_ISFIFO(status
.st_mode
) ) )
250 if ( connect(pPipe
->m_Socket
,(struct sockaddr
*)&addr
,len
) >= 0 )
252 OSL_TRACE("osl_createPipe : Pipe already in use. Errno: %d; %s\n",errno
,strerror(errno
));
253 close (pPipe
->m_Socket
);
254 __osl_destroyPipeImpl(pPipe
);
262 if ( bind(pPipe
->m_Socket
, (struct sockaddr
*)&addr
, len
) < 0 )
264 OSL_TRACE("osl_createPipe : failed to bind socket. Errno: %d; %s\n",errno
,strerror(errno
));
265 close (pPipe
->m_Socket
);
266 __osl_destroyPipeImpl(pPipe
);
270 /* Only give access to all if no security handle was specified, otherwise security
274 chmod(name
,S_IRWXU
| S_IRWXG
|S_IRWXO
);
277 strncpy(pPipe
->m_Name
, name
, sizeof(pPipe
->m_Name
));
279 if ( listen(pPipe
->m_Socket
, 5) < 0 )
281 OSL_TRACE("osl_createPipe failed to listen. Errno: %d; %s\n",errno
,strerror(errno
));
282 unlink(name
); /* remove filesystem entry */
283 close (pPipe
->m_Socket
);
284 __osl_destroyPipeImpl(pPipe
);
291 { /* osl_pipe_OPEN */
292 if ( access(name
, F_OK
) != -1 )
294 if ( connect( pPipe
->m_Socket
, (struct sockaddr
*)&addr
, len
) >= 0 )
299 OSL_TRACE("osl_createPipe failed to connect. Errno: %d; %s\n",errno
,strerror(errno
));
302 close (pPipe
->m_Socket
);
303 __osl_destroyPipeImpl(pPipe
);
308 void SAL_CALL
osl_acquirePipe( oslPipe pPipe
)
310 osl_incrementInterlockedCount( &(pPipe
->m_nRefCount
) );
313 void SAL_CALL
osl_releasePipe( oslPipe pPipe
)
319 if( 0 == osl_decrementInterlockedCount( &(pPipe
->m_nRefCount
) ) )
321 if( ! pPipe
->m_bClosed
)
322 osl_closePipe( pPipe
);
324 __osl_destroyPipeImpl( pPipe
);
328 void SAL_CALL
osl_closePipe( oslPipe pPipe
)
333 struct sockaddr_un addr
;
343 if( pPipe
->m_bClosed
)
348 ConnFD
= pPipe
->m_Socket
;
351 Thread does not return from accept on linux, so
352 connect to the accepting pipe
355 if ( pPipe
->m_bIsAccepting
)
357 pPipe
->m_bIsInShutdown
= sal_True
;
358 pPipe
->m_Socket
= -1;
359 fd
= socket(AF_UNIX
, SOCK_STREAM
, 0);
360 memset(&addr
, 0, sizeof(addr
));
362 OSL_TRACE("osl_destroyPipe : Pipe Name '%s'",pPipe
->m_Name
);
364 addr
.sun_family
= AF_UNIX
;
365 strncpy(addr
.sun_path
, pPipe
->m_Name
, sizeof(addr
.sun_path
));
368 nRet
= connect( fd
, (struct sockaddr
*)&addr
, len
);
369 #if OSL_DEBUG_LEVEL > 1
372 perror("connect in osl_destroyPipe");
374 #endif /* OSL_DEBUG_LEVEL */
380 nRet
= shutdown(ConnFD
, 2);
383 OSL_TRACE("shutdown in destroyPipe failed : '%s'\n",strerror(errno
));
386 nRet
= close(ConnFD
);
389 OSL_TRACE("close in destroyPipe failed : '%s'\n",strerror(errno
));
391 /* remove filesystem entry */
392 if ( strlen(pPipe
->m_Name
) > 0 )
394 unlink(pPipe
->m_Name
);
396 pPipe
->m_bClosed
= sal_True
;
398 /* OSL_TRACE("Out osl_destroyPipe"); */
402 /*****************************************************************************/
404 /*****************************************************************************/
405 oslPipe SAL_CALL
osl_acceptPipe(oslPipe pPipe
)
408 oslPipe pAcceptedPipe
;
416 OSL_ASSERT(strlen(pPipe
->m_Name
) > 0);
419 pPipe
->m_bIsAccepting
= sal_True
;
422 s
= accept(pPipe
->m_Socket
, NULL
, NULL
);
425 pPipe
->m_bIsAccepting
= sal_False
;
430 OSL_TRACE("osl_acceptPipe : accept error '%s'", strerror(errno
));
435 if ( pPipe
->m_bIsInShutdown
)
444 pAcceptedPipe
= __osl_createPipeImpl();
446 OSL_ASSERT(pAcceptedPipe
);
447 if(pAcceptedPipe
==NULL
)
453 /* set close-on-exec flag */
454 if (!((flags
= fcntl(s
, F_GETFD
, 0)) < 0))
457 if (fcntl(s
, F_SETFD
, flags
) < 0)
459 OSL_TRACE("osl_acceptPipe: error changing socket flags. "
460 "Errno: %d; %s",errno
,strerror(errno
));
464 pAcceptedPipe
->m_Socket
= s
;
467 return pAcceptedPipe
;
470 /*****************************************************************************/
471 /* osl_receivePipe */
472 /*****************************************************************************/
473 sal_Int32 SAL_CALL
osl_receivePipe(oslPipe pPipe
,
475 sal_Int32 BytesToRead
)
483 OSL_TRACE("osl_receivePipe : Invalid socket");
488 nRet
= recv(pPipe
->m_Socket
,
494 OSL_TRACE("osl_receivePipe failed : %i '%s'",nRet
,strerror(errno
));
501 /*****************************************************************************/
503 /*****************************************************************************/
504 sal_Int32 SAL_CALL
osl_sendPipe(oslPipe pPipe
,
506 sal_Int32 BytesToSend
)
514 OSL_TRACE("osl_sendPipe : Invalid socket");
519 nRet
= send(pPipe
->m_Socket
,
526 OSL_TRACE("osl_sendPipe failed : %i '%s'",nRet
,strerror(errno
));
533 /*****************************************************************************/
534 /* osl_getLastPipeError */
535 /*****************************************************************************/
536 oslPipeError SAL_CALL
osl_getLastPipeError(oslPipe pPipe
)
538 (void) pPipe
; /* unused */
539 return ERROR_FROM_NATIVE(errno
);
543 sal_Int32 SAL_CALL
osl_writePipe( oslPipe pPipe
, const void *pBuffer
, sal_Int32 n
)
545 /* loop until all desired bytes were send or an error occured */
546 sal_Int32 BytesSend
= 0;
547 sal_Int32 BytesToSend
= n
;
550 while (BytesToSend
> 0)
554 RetVal
= osl_sendPipe(pPipe
, pBuffer
, BytesToSend
);
562 BytesToSend
-= RetVal
;
564 pBuffer
= (sal_Char
*)pBuffer
+ RetVal
;
570 sal_Int32 SAL_CALL
osl_readPipe( oslPipe pPipe
, void *pBuffer
, sal_Int32 n
)
572 /* loop until all desired bytes were read or an error occured */
573 sal_Int32 BytesRead
= 0;
574 sal_Int32 BytesToRead
= n
;
577 while (BytesToRead
> 0)
580 RetVal
= osl_receivePipe(pPipe
, pBuffer
, BytesToRead
);
588 BytesToRead
-= RetVal
;
590 pBuffer
= (sal_Char
*)pBuffer
+ RetVal
;