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
);
42 /*****************************************************************************/
43 /* enum oslPipeError */
44 /*****************************************************************************/
51 { 0, osl_Pipe_E_None
}, /* no error */
52 { EPROTOTYPE
, osl_Pipe_E_NoProtocol
}, /* Protocol wrong type for socket */
53 { ENOPROTOOPT
, osl_Pipe_E_NoProtocol
}, /* Protocol not available */
54 { EPROTONOSUPPORT
, osl_Pipe_E_NoProtocol
}, /* Protocol not supported */
55 { ESOCKTNOSUPPORT
, osl_Pipe_E_NoProtocol
}, /* Socket type not supported */
56 { EPFNOSUPPORT
, osl_Pipe_E_NoProtocol
}, /* Protocol family not supported */
57 { EAFNOSUPPORT
, osl_Pipe_E_NoProtocol
}, /* Address family not supported by */
59 { ENETRESET
, osl_Pipe_E_NetworkReset
}, /* Network dropped connection because */
61 { ECONNABORTED
, osl_Pipe_E_ConnectionAbort
}, /* Software caused connection abort */
62 { ECONNRESET
, osl_Pipe_E_ConnectionReset
}, /* Connection reset by peer */
63 { ENOBUFS
, osl_Pipe_E_NoBufferSpace
}, /* No buffer space available */
64 { ETIMEDOUT
, osl_Pipe_E_TimedOut
}, /* Connection timed out */
65 { ECONNREFUSED
, osl_Pipe_E_ConnectionRefused
}, /* Connection refused */
66 { -1, osl_Pipe_E_invalidError
}
72 static int osl_NativeFromPipeError(oslPipeError errorCode)
76 while ((PipeError[i].error != osl_Pipe_E_invalidError) &&
77 (PipeError[i].error != errorCode)) i++;
79 return PipeError[i].errcode;
85 static oslPipeError
osl_PipeErrorFromNative(int nativeType
)
89 while ((PipeError
[i
].error
!= osl_Pipe_E_invalidError
) &&
90 (PipeError
[i
].errcode
!= nativeType
)) i
++;
92 return PipeError
[i
].error
;
97 #define ERROR_FROM_NATIVE(y) osl_PipeErrorFromNative(y)
100 /*****************************************************************************/
101 /* osl_create/destroy-PipeImpl */
102 /*****************************************************************************/
104 oslPipe
__osl_createPipeImpl()
108 pPipeImpl
= (oslPipe
)calloc(1, sizeof(struct oslPipeImpl
));
109 pPipeImpl
->m_nRefCount
=1;
110 pPipeImpl
->m_bClosed
= sal_False
;
112 pPipeImpl
->m_bIsInShutdown
= sal_False
;
113 pPipeImpl
->m_bIsAccepting
= sal_False
;
118 void __osl_destroyPipeImpl(oslPipe pImpl
)
125 /*****************************************************************************/
127 /*****************************************************************************/
128 oslPipe SAL_CALL
osl_createPipe(rtl_uString
*ustrPipeName
, oslPipeOptions Options
, oslSecurity Security
)
131 rtl_String
* strPipeName
=0;
132 sal_Char
* pszPipeName
=0;
134 if ( ustrPipeName
!= 0 )
136 rtl_uString2String( &strPipeName
,
137 rtl_uString_getStr(ustrPipeName
),
138 rtl_uString_getLength(ustrPipeName
),
139 osl_getThreadTextEncoding(),
140 OUSTRING_TO_OSTRING_CVTFLAGS
);
141 pszPipeName
= rtl_string_getStr(strPipeName
);
142 pPipe
= osl_psz_createPipe(pszPipeName
, Options
, Security
);
144 if ( strPipeName
!= 0 )
146 rtl_string_release(strPipeName
);
155 cpyBootstrapSocketPath(sal_Char
*name
, size_t len
)
157 sal_Bool bRet
= sal_False
;
158 rtl_uString
*pName
= 0, *pValue
= 0;
160 rtl_uString_newFromAscii(&pName
, "OSL_SOCKET_PATH");
162 if (rtl_bootstrap_get(pName
, &pValue
, NULL
))
164 rtl_String
*pStrValue
= 0;
165 if (pValue
&& pValue
->length
> 0)
167 rtl_uString2String(&pStrValue
, pValue
->buffer
,
168 pValue
->length
, RTL_TEXTENCODING_UTF8
,
169 OUSTRING_TO_OSTRING_CVTFLAGS
);
170 if (pStrValue
&& pStrValue
->length
> 0)
172 size_t nCopy
= (len
-1 < (size_t)pStrValue
->length
) ? len
-1 : (size_t)pStrValue
->length
;
173 strncpy (name
, pStrValue
->buffer
, nCopy
);
175 bRet
= (size_t)pStrValue
->length
< len
;
177 rtl_string_release(pStrValue
);
179 rtl_uString_release(pName
);
184 oslPipe SAL_CALL
osl_psz_createPipe(const sal_Char
*pszPipeName
, oslPipeOptions Options
,
185 oslSecurity Security
)
189 struct sockaddr_un addr
;
191 sal_Char name
[PATH_MAX
+ 1];
192 size_t nNameLength
= 0;
193 int bNameTooLong
= 0;
196 if (access(PIPEDEFAULTPATH
, R_OK
|W_OK
) == 0)
198 strncpy(name
, PIPEDEFAULTPATH
, sizeof(name
));
200 else if (access(PIPEALTERNATEPATH
, R_OK
|W_OK
) == 0)
202 strncpy(name
, PIPEALTERNATEPATH
, sizeof(name
));
204 else if (!cpyBootstrapSocketPath (name
, sizeof (name
)))
208 name
[sizeof(name
) - 1] = '\0'; // ensure the string is NULL-terminated
209 nNameLength
= strlen(name
);
210 bNameTooLong
= nNameLength
> sizeof(name
) - 2;
214 size_t nRealLength
= 0;
225 OSL_VERIFY(osl_psz_getUserIdent(Security
, Ident
, sizeof(Ident
)));
227 nRealLength
= snprintf(&name
[nNameLength
], sizeof(name
) - nNameLength
, SECPIPENAMEMASK
, Ident
, pszPipeName
);
231 nRealLength
= snprintf(&name
[nNameLength
], sizeof(name
) - nNameLength
, PIPENAMEMASK
, pszPipeName
);
234 bNameTooLong
= nRealLength
> sizeof(name
) - nNameLength
- 1;
239 OSL_TRACE("osl_createPipe: pipe name too long");
244 pPipe
= __osl_createPipeImpl();
247 pPipe
->m_Socket
= socket(AF_UNIX
, SOCK_STREAM
, 0);
248 if ( pPipe
->m_Socket
< 0 )
250 OSL_TRACE("osl_createPipe socket failed. Errno: %d; %s",errno
, strerror(errno
));
251 __osl_destroyPipeImpl(pPipe
);
255 /* OSL_TRACE("osl_createPipe : new Pipe on fd %i\n",pPipe->m_Socket);*/
257 /* set close-on-exec flag */
258 if ((Flags
= fcntl(pPipe
->m_Socket
, F_GETFD
, 0)) != -1)
261 if (fcntl(pPipe
->m_Socket
, F_SETFD
, Flags
) == -1)
263 OSL_TRACE("osl_createPipe failed changing socket flags. Errno: %d; %s",errno
,strerror(errno
));
267 memset(&addr
, 0, sizeof(addr
));
269 OSL_TRACE("osl_createPipe : Pipe Name '%s'",name
);
271 addr
.sun_family
= AF_UNIX
;
272 strncpy(addr
.sun_path
, name
, sizeof(addr
.sun_path
) - 1);
274 len
= SUN_LEN(&addr
);
279 if ( Options
& osl_Pipe_CREATE
)
283 /* check if there exists an orphan filesystem entry */
284 if ( ( stat(name
, &status
) == 0) &&
285 ( S_ISSOCK(status
.st_mode
) || S_ISFIFO(status
.st_mode
) ) )
287 if ( connect(pPipe
->m_Socket
,(struct sockaddr
*)&addr
,len
) >= 0 )
289 OSL_TRACE("osl_createPipe : Pipe already in use. Errno: %d; %s",errno
,strerror(errno
));
290 close (pPipe
->m_Socket
);
291 __osl_destroyPipeImpl(pPipe
);
299 if ( bind(pPipe
->m_Socket
, (struct sockaddr
*)&addr
, len
) < 0 )
301 OSL_TRACE("osl_createPipe : failed to bind socket. Errno: %d; %s",errno
,strerror(errno
));
302 close (pPipe
->m_Socket
);
303 __osl_destroyPipeImpl(pPipe
);
307 /* Only give access to all if no security handle was specified, otherwise security
311 chmod(name
,S_IRWXU
| S_IRWXG
|S_IRWXO
);
314 strncpy(pPipe
->m_Name
, name
, sizeof(pPipe
->m_Name
) - 1);
316 if ( listen(pPipe
->m_Socket
, 5) < 0 )
318 OSL_TRACE("osl_createPipe failed to listen. Errno: %d; %s",errno
,strerror(errno
));
319 unlink(name
); /* remove filesystem entry */
320 close (pPipe
->m_Socket
);
321 __osl_destroyPipeImpl(pPipe
);
328 { /* osl_pipe_OPEN */
329 if ( access(name
, F_OK
) != -1 )
331 if ( connect( pPipe
->m_Socket
, (struct sockaddr
*)&addr
, len
) >= 0 )
336 OSL_TRACE("osl_createPipe failed to connect. Errno: %d; %s",errno
,strerror(errno
));
339 close (pPipe
->m_Socket
);
340 __osl_destroyPipeImpl(pPipe
);
345 void SAL_CALL
osl_acquirePipe( oslPipe pPipe
)
347 osl_atomic_increment( &(pPipe
->m_nRefCount
) );
350 void SAL_CALL
osl_releasePipe( oslPipe pPipe
)
356 if( 0 == osl_atomic_decrement( &(pPipe
->m_nRefCount
) ) )
358 if( ! pPipe
->m_bClosed
)
359 osl_closePipe( pPipe
);
361 __osl_destroyPipeImpl( pPipe
);
365 void SAL_CALL
osl_closePipe( oslPipe pPipe
)
370 struct sockaddr_un addr
;
380 if( pPipe
->m_bClosed
)
385 ConnFD
= pPipe
->m_Socket
;
388 Thread does not return from accept on linux, so
389 connect to the accepting pipe
392 if ( pPipe
->m_bIsAccepting
)
394 pPipe
->m_bIsInShutdown
= sal_True
;
395 pPipe
->m_Socket
= -1;
396 fd
= socket(AF_UNIX
, SOCK_STREAM
, 0);
397 memset(&addr
, 0, sizeof(addr
));
399 OSL_TRACE("osl_destroyPipe : Pipe Name '%s'",pPipe
->m_Name
);
401 addr
.sun_family
= AF_UNIX
;
402 strncpy(addr
.sun_path
, pPipe
->m_Name
, sizeof(addr
.sun_path
) - 1);
405 nRet
= connect( fd
, (struct sockaddr
*)&addr
, len
);
408 OSL_TRACE("connect in osl_destroyPipe failed with error: %s", strerror(errno
));
415 nRet
= shutdown(ConnFD
, 2);
418 OSL_TRACE("shutdown in destroyPipe failed : '%s'",strerror(errno
));
421 nRet
= close(ConnFD
);
424 OSL_TRACE("close in destroyPipe failed : '%s'",strerror(errno
));
426 /* remove filesystem entry */
427 if ( strlen(pPipe
->m_Name
) > 0 )
429 unlink(pPipe
->m_Name
);
431 pPipe
->m_bClosed
= sal_True
;
433 /* OSL_TRACE("Out osl_destroyPipe"); */
437 /*****************************************************************************/
439 /*****************************************************************************/
440 oslPipe SAL_CALL
osl_acceptPipe(oslPipe pPipe
)
443 oslPipe pAcceptedPipe
;
451 OSL_ASSERT(strlen(pPipe
->m_Name
) > 0);
454 pPipe
->m_bIsAccepting
= sal_True
;
457 s
= accept(pPipe
->m_Socket
, NULL
, NULL
);
460 pPipe
->m_bIsAccepting
= sal_False
;
465 OSL_TRACE("osl_acceptPipe : accept error '%s'", strerror(errno
));
470 if ( pPipe
->m_bIsInShutdown
)
479 pAcceptedPipe
= __osl_createPipeImpl();
481 OSL_ASSERT(pAcceptedPipe
);
482 if(pAcceptedPipe
==NULL
)
488 /* set close-on-exec flag */
489 if (!((flags
= fcntl(s
, F_GETFD
, 0)) < 0))
492 if (fcntl(s
, F_SETFD
, flags
) < 0)
494 OSL_TRACE("osl_acceptPipe: error changing socket flags. "
495 "Errno: %d; %s",errno
,strerror(errno
));
499 pAcceptedPipe
->m_Socket
= s
;
502 return pAcceptedPipe
;
505 /*****************************************************************************/
506 /* osl_receivePipe */
507 /*****************************************************************************/
508 sal_Int32 SAL_CALL
osl_receivePipe(oslPipe pPipe
,
510 sal_Int32 BytesToRead
)
518 OSL_TRACE("osl_receivePipe : Invalid socket");
523 nRet
= recv(pPipe
->m_Socket
,
529 OSL_TRACE("osl_receivePipe failed : %i '%s'",nRet
,strerror(errno
));
536 /*****************************************************************************/
538 /*****************************************************************************/
539 sal_Int32 SAL_CALL
osl_sendPipe(oslPipe pPipe
,
541 sal_Int32 BytesToSend
)
549 OSL_TRACE("osl_sendPipe : Invalid socket");
554 nRet
= send(pPipe
->m_Socket
,
561 OSL_TRACE("osl_sendPipe failed : %i '%s'",nRet
,strerror(errno
));
568 /*****************************************************************************/
569 /* osl_getLastPipeError */
570 /*****************************************************************************/
571 oslPipeError SAL_CALL
osl_getLastPipeError(oslPipe pPipe
)
573 (void) pPipe
; /* unused */
574 return ERROR_FROM_NATIVE(errno
);
578 sal_Int32 SAL_CALL
osl_writePipe( oslPipe pPipe
, const void *pBuffer
, sal_Int32 n
)
580 /* loop until all desired bytes were send or an error occurred */
581 sal_Int32 BytesSend
= 0;
582 sal_Int32 BytesToSend
= n
;
585 while (BytesToSend
> 0)
589 RetVal
= osl_sendPipe(pPipe
, pBuffer
, BytesToSend
);
591 /* error occurred? */
597 BytesToSend
-= RetVal
;
599 pBuffer
= (sal_Char
*)pBuffer
+ RetVal
;
605 sal_Int32 SAL_CALL
osl_readPipe( oslPipe pPipe
, void *pBuffer
, sal_Int32 n
)
607 /* loop until all desired bytes were read or an error occurred */
608 sal_Int32 BytesRead
= 0;
609 sal_Int32 BytesToRead
= n
;
612 while (BytesToRead
> 0)
615 RetVal
= osl_receivePipe(pPipe
, pBuffer
, BytesToRead
);
617 /* error occurred? */
623 BytesToRead
-= RetVal
;
625 pBuffer
= (sal_Char
*)pBuffer
+ RetVal
;
630 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */