1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
32 #include <osl/diagnose.h>
33 #include <osl/thread.h>
34 #include <osl/interlck.h>
35 #include <rtl/string.h>
36 #include <rtl/ustring.h>
37 #include <rtl/bootstrap.h>
41 #define PIPEDEFAULTPATH "/tmp"
42 #define PIPEALTERNATEPATH "/var/tmp"
44 #define PIPENAMEMASK "OSL_PIPE_%s"
45 #define SECPIPENAMEMASK "OSL_PIPE_%s_%s"
47 sal_Bool SAL_CALL
osl_psz_getUserIdent(oslSecurity Security
, sal_Char
*pszIdent
, sal_uInt32 nMax
);
48 oslPipe SAL_CALL
osl_psz_createPipe(const sal_Char
*pszPipeName
, oslPipeOptions Options
, oslSecurity Security
);
51 /*****************************************************************************/
52 /* enum oslPipeError */
53 /*****************************************************************************/
60 { 0, osl_Pipe_E_None
}, /* no error */
61 { EPROTOTYPE
, osl_Pipe_E_NoProtocol
}, /* Protocol wrong type for socket */
62 { ENOPROTOOPT
, osl_Pipe_E_NoProtocol
}, /* Protocol not available */
63 { EPROTONOSUPPORT
, osl_Pipe_E_NoProtocol
}, /* Protocol not supported */
64 { ESOCKTNOSUPPORT
, osl_Pipe_E_NoProtocol
}, /* Socket type not supported */
65 { EPFNOSUPPORT
, osl_Pipe_E_NoProtocol
}, /* Protocol family not supported */
66 { EAFNOSUPPORT
, osl_Pipe_E_NoProtocol
}, /* Address family not supported by */
68 { ENETRESET
, osl_Pipe_E_NetworkReset
}, /* Network dropped connection because */
70 { ECONNABORTED
, osl_Pipe_E_ConnectionAbort
}, /* Software caused connection abort */
71 { ECONNRESET
, osl_Pipe_E_ConnectionReset
}, /* Connection reset by peer */
72 { ENOBUFS
, osl_Pipe_E_NoBufferSpace
}, /* No buffer space available */
73 { ETIMEDOUT
, osl_Pipe_E_TimedOut
}, /* Connection timed out */
74 { ECONNREFUSED
, osl_Pipe_E_ConnectionRefused
}, /* Connection refused */
75 { -1, osl_Pipe_E_invalidError
}
81 static int osl_NativeFromPipeError(oslPipeError errorCode)
85 while ((PipeError[i].error != osl_Pipe_E_invalidError) &&
86 (PipeError[i].error != errorCode)) i++;
88 return PipeError[i].errcode;
94 static oslPipeError
osl_PipeErrorFromNative(int nativeType
)
98 while ((PipeError
[i
].error
!= osl_Pipe_E_invalidError
) &&
99 (PipeError
[i
].errcode
!= nativeType
)) i
++;
101 return PipeError
[i
].error
;
106 #define ERROR_TO_NATIVE(x) osl_NativeFromPipeError(x)
107 #define ERROR_FROM_NATIVE(y) osl_PipeErrorFromNative(y)
110 /*****************************************************************************/
111 /* osl_create/destroy-PipeImpl */
112 /*****************************************************************************/
114 oslPipe
__osl_createPipeImpl()
118 pPipeImpl
= (oslPipe
)calloc(1, sizeof(struct oslPipeImpl
));
119 pPipeImpl
->m_nRefCount
=1;
120 pPipeImpl
->m_bClosed
= sal_False
;
122 pPipeImpl
->m_bIsInShutdown
= sal_False
;
123 pPipeImpl
->m_bIsAccepting
= sal_False
;
128 void __osl_destroyPipeImpl(oslPipe pImpl
)
135 /*****************************************************************************/
137 /*****************************************************************************/
138 oslPipe SAL_CALL
osl_createPipe(rtl_uString
*ustrPipeName
, oslPipeOptions Options
, oslSecurity Security
)
141 rtl_String
* strPipeName
=0;
142 sal_Char
* pszPipeName
=0;
144 if ( ustrPipeName
!= 0 )
146 rtl_uString2String( &strPipeName
,
147 rtl_uString_getStr(ustrPipeName
),
148 rtl_uString_getLength(ustrPipeName
),
149 osl_getThreadTextEncoding(),
150 OUSTRING_TO_OSTRING_CVTFLAGS
);
151 pszPipeName
= rtl_string_getStr(strPipeName
);
152 pPipe
= osl_psz_createPipe(pszPipeName
, Options
, Security
);
154 if ( strPipeName
!= 0 )
156 rtl_string_release(strPipeName
);
165 cpyBootstrapSocketPath(sal_Char
*name
, size_t len
)
167 sal_Bool bRet
= sal_False
;
168 rtl_uString
*pName
= 0, *pValue
= 0;
170 rtl_uString_newFromAscii(&pName
, "OSL_SOCKET_PATH");
172 if (rtl_bootstrap_get(pName
, &pValue
, NULL
))
174 rtl_String
*pStrValue
= 0;
175 if (pValue
&& pValue
->length
> 0)
177 rtl_uString2String(&pStrValue
, pValue
->buffer
,
178 pValue
->length
, RTL_TEXTENCODING_UTF8
,
179 OUSTRING_TO_OSTRING_CVTFLAGS
);
180 if (pStrValue
&& pStrValue
->length
> 0)
182 size_t nCopy
= SAL_MIN (len
-1, (size_t)pStrValue
->length
);
183 strncpy (name
, pStrValue
->buffer
, nCopy
);
185 bRet
= (size_t)pStrValue
->length
< len
;
187 rtl_string_release(pStrValue
);
189 rtl_uString_release(pName
);
194 oslPipe SAL_CALL
osl_psz_createPipe(const sal_Char
*pszPipeName
, oslPipeOptions Options
,
195 oslSecurity Security
)
199 struct sockaddr_un addr
;
201 sal_Char name
[PATH_MAX
+ 1];
202 size_t nNameLength
= 0;
203 int bNameTooLong
= 0;
206 if (access(PIPEDEFAULTPATH
, R_OK
|W_OK
) == 0)
208 strncpy(name
, PIPEDEFAULTPATH
, sizeof(name
));
210 else if (access(PIPEALTERNATEPATH
, R_OK
|W_OK
) == 0)
212 strncpy(name
, PIPEALTERNATEPATH
, sizeof(name
));
214 else if (!cpyBootstrapSocketPath (name
, sizeof (name
)))
218 name
[sizeof(name
) - 1] = '\0'; // ensure the string is NULL-terminated
219 nNameLength
= strlen(name
);
220 bNameTooLong
= nNameLength
> sizeof(name
) - 2;
224 size_t nRealLength
= 0;
235 OSL_VERIFY(osl_psz_getUserIdent(Security
, Ident
, sizeof(Ident
)));
237 nRealLength
= snprintf(&name
[nNameLength
], sizeof(name
) - nNameLength
, SECPIPENAMEMASK
, Ident
, pszPipeName
);
241 nRealLength
= snprintf(&name
[nNameLength
], sizeof(name
) - nNameLength
, PIPENAMEMASK
, pszPipeName
);
244 bNameTooLong
= nRealLength
> sizeof(name
) - nNameLength
- 1;
249 OSL_TRACE("osl_createPipe: pipe name too long");
254 pPipe
= __osl_createPipeImpl();
257 pPipe
->m_Socket
= socket(AF_UNIX
, SOCK_STREAM
, 0);
258 if ( pPipe
->m_Socket
< 0 )
260 OSL_TRACE("osl_createPipe socket failed. Errno: %d; %s",errno
, strerror(errno
));
261 __osl_destroyPipeImpl(pPipe
);
265 /* OSL_TRACE("osl_createPipe : new Pipe on fd %i\n",pPipe->m_Socket);*/
267 /* set close-on-exec flag */
268 if ((Flags
= fcntl(pPipe
->m_Socket
, F_GETFD
, 0)) != -1)
271 if (fcntl(pPipe
->m_Socket
, F_SETFD
, Flags
) == -1)
273 OSL_TRACE("osl_createPipe failed changing socket flags. Errno: %d; %s",errno
,strerror(errno
));
277 memset(&addr
, 0, sizeof(addr
));
279 OSL_TRACE("osl_createPipe : Pipe Name '%s'",name
);
281 addr
.sun_family
= AF_UNIX
;
282 strncpy(addr
.sun_path
, name
, sizeof(addr
.sun_path
));
284 len
= SUN_LEN(&addr
);
289 if ( Options
& osl_Pipe_CREATE
)
293 /* check if there exists an orphan filesystem entry */
294 if ( ( stat(name
, &status
) == 0) &&
295 ( S_ISSOCK(status
.st_mode
) || S_ISFIFO(status
.st_mode
) ) )
297 if ( connect(pPipe
->m_Socket
,(struct sockaddr
*)&addr
,len
) >= 0 )
299 OSL_TRACE("osl_createPipe : Pipe already in use. Errno: %d; %s",errno
,strerror(errno
));
300 close (pPipe
->m_Socket
);
301 __osl_destroyPipeImpl(pPipe
);
309 if ( bind(pPipe
->m_Socket
, (struct sockaddr
*)&addr
, len
) < 0 )
311 OSL_TRACE("osl_createPipe : failed to bind socket. Errno: %d; %s",errno
,strerror(errno
));
312 close (pPipe
->m_Socket
);
313 __osl_destroyPipeImpl(pPipe
);
317 /* Only give access to all if no security handle was specified, otherwise security
321 chmod(name
,S_IRWXU
| S_IRWXG
|S_IRWXO
);
324 strncpy(pPipe
->m_Name
, name
, sizeof(pPipe
->m_Name
));
326 if ( listen(pPipe
->m_Socket
, 5) < 0 )
328 OSL_TRACE("osl_createPipe failed to listen. Errno: %d; %s",errno
,strerror(errno
));
329 unlink(name
); /* remove filesystem entry */
330 close (pPipe
->m_Socket
);
331 __osl_destroyPipeImpl(pPipe
);
338 { /* osl_pipe_OPEN */
339 if ( access(name
, F_OK
) != -1 )
341 if ( connect( pPipe
->m_Socket
, (struct sockaddr
*)&addr
, len
) >= 0 )
346 OSL_TRACE("osl_createPipe failed to connect. Errno: %d; %s",errno
,strerror(errno
));
349 close (pPipe
->m_Socket
);
350 __osl_destroyPipeImpl(pPipe
);
355 void SAL_CALL
osl_acquirePipe( oslPipe pPipe
)
357 osl_incrementInterlockedCount( &(pPipe
->m_nRefCount
) );
360 void SAL_CALL
osl_releasePipe( oslPipe pPipe
)
366 if( 0 == osl_decrementInterlockedCount( &(pPipe
->m_nRefCount
) ) )
368 if( ! pPipe
->m_bClosed
)
369 osl_closePipe( pPipe
);
371 __osl_destroyPipeImpl( pPipe
);
375 void SAL_CALL
osl_closePipe( oslPipe pPipe
)
380 struct sockaddr_un addr
;
390 if( pPipe
->m_bClosed
)
395 ConnFD
= pPipe
->m_Socket
;
398 Thread does not return from accept on linux, so
399 connect to the accepting pipe
402 if ( pPipe
->m_bIsAccepting
)
404 pPipe
->m_bIsInShutdown
= sal_True
;
405 pPipe
->m_Socket
= -1;
406 fd
= socket(AF_UNIX
, SOCK_STREAM
, 0);
407 memset(&addr
, 0, sizeof(addr
));
409 OSL_TRACE("osl_destroyPipe : Pipe Name '%s'",pPipe
->m_Name
);
411 addr
.sun_family
= AF_UNIX
;
412 strncpy(addr
.sun_path
, pPipe
->m_Name
, sizeof(addr
.sun_path
));
415 nRet
= connect( fd
, (struct sockaddr
*)&addr
, len
);
418 OSL_TRACE("connect in osl_destroyPipe failed with error: %s", strerror(errno
));
425 nRet
= shutdown(ConnFD
, 2);
428 OSL_TRACE("shutdown in destroyPipe failed : '%s'",strerror(errno
));
431 nRet
= close(ConnFD
);
434 OSL_TRACE("close in destroyPipe failed : '%s'",strerror(errno
));
436 /* remove filesystem entry */
437 if ( strlen(pPipe
->m_Name
) > 0 )
439 unlink(pPipe
->m_Name
);
441 pPipe
->m_bClosed
= sal_True
;
443 /* OSL_TRACE("Out osl_destroyPipe"); */
447 /*****************************************************************************/
449 /*****************************************************************************/
450 oslPipe SAL_CALL
osl_acceptPipe(oslPipe pPipe
)
453 oslPipe pAcceptedPipe
;
461 OSL_ASSERT(strlen(pPipe
->m_Name
) > 0);
464 pPipe
->m_bIsAccepting
= sal_True
;
467 s
= accept(pPipe
->m_Socket
, NULL
, NULL
);
470 pPipe
->m_bIsAccepting
= sal_False
;
475 OSL_TRACE("osl_acceptPipe : accept error '%s'", strerror(errno
));
480 if ( pPipe
->m_bIsInShutdown
)
489 pAcceptedPipe
= __osl_createPipeImpl();
491 OSL_ASSERT(pAcceptedPipe
);
492 if(pAcceptedPipe
==NULL
)
498 /* set close-on-exec flag */
499 if (!((flags
= fcntl(s
, F_GETFD
, 0)) < 0))
502 if (fcntl(s
, F_SETFD
, flags
) < 0)
504 OSL_TRACE("osl_acceptPipe: error changing socket flags. "
505 "Errno: %d; %s",errno
,strerror(errno
));
509 pAcceptedPipe
->m_Socket
= s
;
512 return pAcceptedPipe
;
515 /*****************************************************************************/
516 /* osl_receivePipe */
517 /*****************************************************************************/
518 sal_Int32 SAL_CALL
osl_receivePipe(oslPipe pPipe
,
520 sal_Int32 BytesToRead
)
528 OSL_TRACE("osl_receivePipe : Invalid socket");
533 nRet
= recv(pPipe
->m_Socket
,
539 OSL_TRACE("osl_receivePipe failed : %i '%s'",nRet
,strerror(errno
));
546 /*****************************************************************************/
548 /*****************************************************************************/
549 sal_Int32 SAL_CALL
osl_sendPipe(oslPipe pPipe
,
551 sal_Int32 BytesToSend
)
559 OSL_TRACE("osl_sendPipe : Invalid socket");
564 nRet
= send(pPipe
->m_Socket
,
571 OSL_TRACE("osl_sendPipe failed : %i '%s'",nRet
,strerror(errno
));
578 /*****************************************************************************/
579 /* osl_getLastPipeError */
580 /*****************************************************************************/
581 oslPipeError SAL_CALL
osl_getLastPipeError(oslPipe pPipe
)
583 (void) pPipe
; /* unused */
584 return ERROR_FROM_NATIVE(errno
);
588 sal_Int32 SAL_CALL
osl_writePipe( oslPipe pPipe
, const void *pBuffer
, sal_Int32 n
)
590 /* loop until all desired bytes were send or an error occurred */
591 sal_Int32 BytesSend
= 0;
592 sal_Int32 BytesToSend
= n
;
595 while (BytesToSend
> 0)
599 RetVal
= osl_sendPipe(pPipe
, pBuffer
, BytesToSend
);
601 /* error occurred? */
607 BytesToSend
-= RetVal
;
609 pBuffer
= (sal_Char
*)pBuffer
+ RetVal
;
615 sal_Int32 SAL_CALL
osl_readPipe( oslPipe pPipe
, void *pBuffer
, sal_Int32 n
)
617 /* loop until all desired bytes were read or an error occurred */
618 sal_Int32 BytesRead
= 0;
619 sal_Int32 BytesToRead
= n
;
622 while (BytesToRead
> 0)
625 RetVal
= osl_receivePipe(pPipe
, pBuffer
, BytesToRead
);
627 /* error occurred? */
633 BytesToRead
-= RetVal
;
635 pBuffer
= (sal_Char
*)pBuffer
+ RetVal
;
640 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */