1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
23 #include <osl/diagnose.h>
24 #include <osl/thread.h>
25 #include <osl/interlck.h>
26 #include <rtl/string.h>
27 #include <rtl/ustring.h>
28 #include <rtl/bootstrap.h>
32 #define PIPEDEFAULTPATH "/tmp"
33 #define PIPEALTERNATEPATH "/var/tmp"
35 #define PIPENAMEMASK "OSL_PIPE_%s"
36 #define SECPIPENAMEMASK "OSL_PIPE_%s_%s"
38 sal_Bool SAL_CALL
osl_psz_getUserIdent(oslSecurity Security
, sal_Char
*pszIdent
, sal_uInt32 nMax
);
39 oslPipe SAL_CALL
osl_psz_createPipe(const sal_Char
*pszPipeName
, oslPipeOptions Options
, oslSecurity Security
);
47 { 0, osl_Pipe_E_None
}, /* no error */
48 { EPROTOTYPE
, osl_Pipe_E_NoProtocol
}, /* Protocol wrong type for socket */
49 { ENOPROTOOPT
, osl_Pipe_E_NoProtocol
}, /* Protocol not available */
50 { EPROTONOSUPPORT
, osl_Pipe_E_NoProtocol
}, /* Protocol not supported */
51 { ESOCKTNOSUPPORT
, osl_Pipe_E_NoProtocol
}, /* Socket type not supported */
52 { EPFNOSUPPORT
, osl_Pipe_E_NoProtocol
}, /* Protocol family not supported */
53 { EAFNOSUPPORT
, osl_Pipe_E_NoProtocol
}, /* Address family not supported by */
55 { ENETRESET
, osl_Pipe_E_NetworkReset
}, /* Network dropped connection because */
57 { ECONNABORTED
, osl_Pipe_E_ConnectionAbort
}, /* Software caused connection abort */
58 { ECONNRESET
, osl_Pipe_E_ConnectionReset
}, /* Connection reset by peer */
59 { ENOBUFS
, osl_Pipe_E_NoBufferSpace
}, /* No buffer space available */
60 { ETIMEDOUT
, osl_Pipe_E_TimedOut
}, /* Connection timed out */
61 { ECONNREFUSED
, osl_Pipe_E_ConnectionRefused
}, /* Connection refused */
62 { -1, osl_Pipe_E_invalidError
}
68 static int osl_NativeFromPipeError(oslPipeError errorCode)
72 while ((PipeError[i].error != osl_Pipe_E_invalidError) &&
73 (PipeError[i].error != errorCode)) i++;
75 return PipeError[i].errcode;
81 static oslPipeError
osl_PipeErrorFromNative(int nativeType
)
85 while ((PipeError
[i
].error
!= osl_Pipe_E_invalidError
) &&
86 (PipeError
[i
].errcode
!= nativeType
)) i
++;
88 return PipeError
[i
].error
;
93 #define ERROR_FROM_NATIVE(y) osl_PipeErrorFromNative(y)
96 oslPipe
__osl_createPipeImpl()
100 pPipeImpl
= (oslPipe
)calloc(1, sizeof(struct oslPipeImpl
));
101 pPipeImpl
->m_nRefCount
=1;
102 pPipeImpl
->m_bClosed
= sal_False
;
104 pPipeImpl
->m_bIsInShutdown
= sal_False
;
105 pPipeImpl
->m_bIsAccepting
= sal_False
;
110 void __osl_destroyPipeImpl(oslPipe pImpl
)
117 oslPipe SAL_CALL
osl_createPipe(rtl_uString
*ustrPipeName
, oslPipeOptions Options
, oslSecurity Security
)
120 rtl_String
* strPipeName
=0;
121 sal_Char
* pszPipeName
=0;
123 if ( ustrPipeName
!= 0 )
125 rtl_uString2String( &strPipeName
,
126 rtl_uString_getStr(ustrPipeName
),
127 rtl_uString_getLength(ustrPipeName
),
128 osl_getThreadTextEncoding(),
129 OUSTRING_TO_OSTRING_CVTFLAGS
);
130 pszPipeName
= rtl_string_getStr(strPipeName
);
131 pPipe
= osl_psz_createPipe(pszPipeName
, Options
, Security
);
133 if ( strPipeName
!= 0 )
135 rtl_string_release(strPipeName
);
144 cpyBootstrapSocketPath(sal_Char
*name
, size_t len
)
146 sal_Bool bRet
= sal_False
;
147 rtl_uString
*pName
= 0, *pValue
= 0;
149 rtl_uString_newFromAscii(&pName
, "OSL_SOCKET_PATH");
151 if (rtl_bootstrap_get(pName
, &pValue
, NULL
))
153 rtl_String
*pStrValue
= 0;
154 if (pValue
&& pValue
->length
> 0)
156 rtl_uString2String(&pStrValue
, pValue
->buffer
,
157 pValue
->length
, RTL_TEXTENCODING_UTF8
,
158 OUSTRING_TO_OSTRING_CVTFLAGS
);
159 if (pStrValue
&& pStrValue
->length
> 0)
161 size_t nCopy
= (len
-1 < (size_t)pStrValue
->length
) ? len
-1 : (size_t)pStrValue
->length
;
162 strncpy (name
, pStrValue
->buffer
, nCopy
);
164 bRet
= (size_t)pStrValue
->length
< len
;
166 rtl_string_release(pStrValue
);
168 rtl_uString_release(pName
);
173 oslPipe SAL_CALL
osl_psz_createPipe(const sal_Char
*pszPipeName
, oslPipeOptions Options
,
174 oslSecurity Security
)
178 struct sockaddr_un addr
;
180 sal_Char name
[PATH_MAX
+ 1];
181 size_t nNameLength
= 0;
182 int bNameTooLong
= 0;
185 if (access(PIPEDEFAULTPATH
, R_OK
|W_OK
) == 0)
187 strncpy(name
, PIPEDEFAULTPATH
, sizeof(name
));
189 else if (access(PIPEALTERNATEPATH
, R_OK
|W_OK
) == 0)
191 strncpy(name
, PIPEALTERNATEPATH
, sizeof(name
));
193 else if (!cpyBootstrapSocketPath (name
, sizeof (name
)))
197 name
[sizeof(name
) - 1] = '\0'; // ensure the string is NULL-terminated
198 nNameLength
= strlen(name
);
199 bNameTooLong
= nNameLength
> sizeof(name
) - 2;
203 size_t nRealLength
= 0;
214 OSL_VERIFY(osl_psz_getUserIdent(Security
, Ident
, sizeof(Ident
)));
216 nRealLength
= snprintf(&name
[nNameLength
], sizeof(name
) - nNameLength
, SECPIPENAMEMASK
, Ident
, pszPipeName
);
220 nRealLength
= snprintf(&name
[nNameLength
], sizeof(name
) - nNameLength
, PIPENAMEMASK
, pszPipeName
);
223 bNameTooLong
= nRealLength
> sizeof(name
) - nNameLength
- 1;
228 OSL_TRACE("osl_createPipe: pipe name too long");
233 pPipe
= __osl_createPipeImpl();
236 pPipe
->m_Socket
= socket(AF_UNIX
, SOCK_STREAM
, 0);
237 if ( pPipe
->m_Socket
< 0 )
239 OSL_TRACE("osl_createPipe socket failed. Errno: %d; %s",errno
, strerror(errno
));
240 __osl_destroyPipeImpl(pPipe
);
244 /* OSL_TRACE("osl_createPipe : new Pipe on fd %i\n",pPipe->m_Socket);*/
246 /* set close-on-exec flag */
247 if ((Flags
= fcntl(pPipe
->m_Socket
, F_GETFD
, 0)) != -1)
250 if (fcntl(pPipe
->m_Socket
, F_SETFD
, Flags
) == -1)
252 OSL_TRACE("osl_createPipe failed changing socket flags. Errno: %d; %s",errno
,strerror(errno
));
256 memset(&addr
, 0, sizeof(addr
));
258 OSL_TRACE("osl_createPipe : Pipe Name '%s'",name
);
260 addr
.sun_family
= AF_UNIX
;
261 strncpy(addr
.sun_path
, name
, sizeof(addr
.sun_path
) - 1);
263 len
= SUN_LEN(&addr
);
268 if ( Options
& osl_Pipe_CREATE
)
272 /* check if there exists an orphan filesystem entry */
273 if ( ( stat(name
, &status
) == 0) &&
274 ( S_ISSOCK(status
.st_mode
) || S_ISFIFO(status
.st_mode
) ) )
276 if ( connect(pPipe
->m_Socket
,(struct sockaddr
*)&addr
,len
) >= 0 )
278 OSL_TRACE("osl_createPipe : Pipe already in use. Errno: %d; %s",errno
,strerror(errno
));
279 close (pPipe
->m_Socket
);
280 __osl_destroyPipeImpl(pPipe
);
288 if ( bind(pPipe
->m_Socket
, (struct sockaddr
*)&addr
, len
) < 0 )
290 OSL_TRACE("osl_createPipe : failed to bind socket. Errno: %d; %s",errno
,strerror(errno
));
291 close (pPipe
->m_Socket
);
292 __osl_destroyPipeImpl(pPipe
);
296 /* Only give access to all if no security handle was specified, otherwise security
300 chmod(name
,S_IRWXU
| S_IRWXG
|S_IRWXO
);
303 strncpy(pPipe
->m_Name
, name
, sizeof(pPipe
->m_Name
) - 1);
305 if ( listen(pPipe
->m_Socket
, 5) < 0 )
307 OSL_TRACE("osl_createPipe failed to listen. Errno: %d; %s",errno
,strerror(errno
));
308 unlink(name
); /* remove filesystem entry */
309 close (pPipe
->m_Socket
);
310 __osl_destroyPipeImpl(pPipe
);
317 { /* osl_pipe_OPEN */
318 if ( access(name
, F_OK
) != -1 )
320 if ( connect( pPipe
->m_Socket
, (struct sockaddr
*)&addr
, len
) >= 0 )
325 OSL_TRACE("osl_createPipe failed to connect. Errno: %d; %s",errno
,strerror(errno
));
328 close (pPipe
->m_Socket
);
329 __osl_destroyPipeImpl(pPipe
);
334 void SAL_CALL
osl_acquirePipe( oslPipe pPipe
)
336 osl_atomic_increment( &(pPipe
->m_nRefCount
) );
339 void SAL_CALL
osl_releasePipe( oslPipe pPipe
)
345 if( 0 == osl_atomic_decrement( &(pPipe
->m_nRefCount
) ) )
347 if( ! pPipe
->m_bClosed
)
348 osl_closePipe( pPipe
);
350 __osl_destroyPipeImpl( pPipe
);
354 void SAL_CALL
osl_closePipe( oslPipe pPipe
)
359 struct sockaddr_un addr
;
369 if( pPipe
->m_bClosed
)
374 ConnFD
= pPipe
->m_Socket
;
377 Thread does not return from accept on linux, so
378 connect to the accepting pipe
381 if ( pPipe
->m_bIsAccepting
)
383 pPipe
->m_bIsInShutdown
= sal_True
;
384 pPipe
->m_Socket
= -1;
385 fd
= socket(AF_UNIX
, SOCK_STREAM
, 0);
386 memset(&addr
, 0, sizeof(addr
));
388 OSL_TRACE("osl_destroyPipe : Pipe Name '%s'",pPipe
->m_Name
);
390 addr
.sun_family
= AF_UNIX
;
391 strncpy(addr
.sun_path
, pPipe
->m_Name
, sizeof(addr
.sun_path
) - 1);
394 nRet
= connect( fd
, (struct sockaddr
*)&addr
, len
);
397 OSL_TRACE("connect in osl_destroyPipe failed with error: %s", strerror(errno
));
404 nRet
= shutdown(ConnFD
, 2);
407 OSL_TRACE("shutdown in destroyPipe failed : '%s'",strerror(errno
));
410 nRet
= close(ConnFD
);
413 OSL_TRACE("close in destroyPipe failed : '%s'",strerror(errno
));
415 /* remove filesystem entry */
416 if ( strlen(pPipe
->m_Name
) > 0 )
418 unlink(pPipe
->m_Name
);
420 pPipe
->m_bClosed
= sal_True
;
422 /* OSL_TRACE("Out osl_destroyPipe"); */
426 oslPipe SAL_CALL
osl_acceptPipe(oslPipe pPipe
)
429 oslPipe pAcceptedPipe
;
437 OSL_ASSERT(strlen(pPipe
->m_Name
) > 0);
440 pPipe
->m_bIsAccepting
= sal_True
;
443 s
= accept(pPipe
->m_Socket
, NULL
, NULL
);
446 pPipe
->m_bIsAccepting
= sal_False
;
451 OSL_TRACE("osl_acceptPipe : accept error '%s'", strerror(errno
));
456 if ( pPipe
->m_bIsInShutdown
)
465 pAcceptedPipe
= __osl_createPipeImpl();
467 OSL_ASSERT(pAcceptedPipe
);
468 if(pAcceptedPipe
==NULL
)
474 /* set close-on-exec flag */
475 if (!((flags
= fcntl(s
, F_GETFD
, 0)) < 0))
478 if (fcntl(s
, F_SETFD
, flags
) < 0)
480 OSL_TRACE("osl_acceptPipe: error changing socket flags. "
481 "Errno: %d; %s",errno
,strerror(errno
));
485 pAcceptedPipe
->m_Socket
= s
;
488 return pAcceptedPipe
;
491 sal_Int32 SAL_CALL
osl_receivePipe(oslPipe pPipe
,
493 sal_Int32 BytesToRead
)
501 OSL_TRACE("osl_receivePipe : Invalid socket");
506 nRet
= recv(pPipe
->m_Socket
,
512 OSL_TRACE("osl_receivePipe failed : %i '%s'",nRet
,strerror(errno
));
518 sal_Int32 SAL_CALL
osl_sendPipe(oslPipe pPipe
,
520 sal_Int32 BytesToSend
)
528 OSL_TRACE("osl_sendPipe : Invalid socket");
533 nRet
= send(pPipe
->m_Socket
,
540 OSL_TRACE("osl_sendPipe failed : %i '%s'",nRet
,strerror(errno
));
546 oslPipeError SAL_CALL
osl_getLastPipeError(oslPipe pPipe
)
548 (void) pPipe
; /* unused */
549 return ERROR_FROM_NATIVE(errno
);
553 sal_Int32 SAL_CALL
osl_writePipe( oslPipe pPipe
, const void *pBuffer
, sal_Int32 n
)
555 /* loop until all desired bytes were send or an error occurred */
556 sal_Int32 BytesSend
= 0;
557 sal_Int32 BytesToSend
= n
;
560 while (BytesToSend
> 0)
564 RetVal
= osl_sendPipe(pPipe
, pBuffer
, BytesToSend
);
566 /* error occurred? */
572 BytesToSend
-= RetVal
;
574 pBuffer
= (sal_Char
*)pBuffer
+ RetVal
;
580 sal_Int32 SAL_CALL
osl_readPipe( oslPipe pPipe
, void *pBuffer
, sal_Int32 n
)
582 /* loop until all desired bytes were read or an error occurred */
583 sal_Int32 BytesRead
= 0;
584 sal_Int32 BytesToRead
= n
;
587 while (BytesToRead
> 0)
590 RetVal
= osl_receivePipe(pPipe
, pBuffer
, BytesToRead
);
592 /* error occurred? */
598 BytesToRead
-= RetVal
;
600 pBuffer
= (sal_Char
*)pBuffer
+ RetVal
;
605 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */