bump product version to 4.1.6.2
[LibreOffice.git] / sal / osl / unx / pipe.c
blobf0f91da98edcacc843f3a6a723f91f6e783c34b0
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
20 #include "system.h"
22 #include <osl/pipe.h>
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>
30 #include "sockimpl.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 /*****************************************************************************/
46 static struct
48 int errcode;
49 oslPipeError error;
50 } PipeError[]= {
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 */
58 /* protocol family */
59 { ENETRESET, osl_Pipe_E_NetworkReset }, /* Network dropped connection because */
60 /* of reset */
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 }
70 /* map */
71 /* mfe: NOT USED
72 static int osl_NativeFromPipeError(oslPipeError errorCode)
74 int i = 0;
76 while ((PipeError[i].error != osl_Pipe_E_invalidError) &&
77 (PipeError[i].error != errorCode)) i++;
79 return PipeError[i].errcode;
84 /* reverse map */
85 static oslPipeError osl_PipeErrorFromNative(int nativeType)
87 int i = 0;
89 while ((PipeError[i].error != osl_Pipe_E_invalidError) &&
90 (PipeError[i].errcode != nativeType)) i++;
92 return PipeError[i].error;
96 /* macros */
97 #define ERROR_FROM_NATIVE(y) osl_PipeErrorFromNative(y)
100 /*****************************************************************************/
101 /* osl_create/destroy-PipeImpl */
102 /*****************************************************************************/
104 oslPipe __osl_createPipeImpl()
106 oslPipe pPipeImpl;
108 pPipeImpl = (oslPipe)calloc(1, sizeof(struct oslPipeImpl));
109 pPipeImpl->m_nRefCount =1;
110 pPipeImpl->m_bClosed = sal_False;
111 #if defined(LINUX)
112 pPipeImpl->m_bIsInShutdown = sal_False;
113 pPipeImpl->m_bIsAccepting = sal_False;
114 #endif
115 return pPipeImpl;
118 void __osl_destroyPipeImpl(oslPipe pImpl)
120 if (pImpl != NULL)
121 free(pImpl);
125 /*****************************************************************************/
126 /* osl_createPipe */
127 /*****************************************************************************/
128 oslPipe SAL_CALL osl_createPipe(rtl_uString *ustrPipeName, oslPipeOptions Options, oslSecurity Security)
130 oslPipe pPipe=0;
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);
150 return pPipe;
154 static sal_Bool
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);
174 name[nCopy] = '\0';
175 bRet = (size_t)pStrValue->length < len;
177 rtl_string_release(pStrValue);
179 rtl_uString_release(pName);
181 return bRet;
184 oslPipe SAL_CALL osl_psz_createPipe(const sal_Char *pszPipeName, oslPipeOptions Options,
185 oslSecurity Security)
187 int Flags;
188 size_t len;
189 struct sockaddr_un addr;
191 sal_Char name[PATH_MAX + 1];
192 size_t nNameLength = 0;
193 int bNameTooLong = 0;
194 oslPipe pPipe;
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)))
206 return NULL;
208 name[sizeof(name) - 1] = '\0'; // ensure the string is NULL-terminated
209 nNameLength = strlen(name);
210 bNameTooLong = nNameLength > sizeof(name) - 2;
212 if (!bNameTooLong)
214 size_t nRealLength = 0;
216 strcat(name, "/");
217 ++nNameLength;
219 if (Security)
221 sal_Char Ident[256];
223 Ident[0] = '\0';
225 OSL_VERIFY(osl_psz_getUserIdent(Security, Ident, sizeof(Ident)));
227 nRealLength = snprintf(&name[nNameLength], sizeof(name) - nNameLength, SECPIPENAMEMASK, Ident, pszPipeName);
229 else
231 nRealLength = snprintf(&name[nNameLength], sizeof(name) - nNameLength, PIPENAMEMASK, pszPipeName);
234 bNameTooLong = nRealLength > sizeof(name) - nNameLength - 1;
237 if (bNameTooLong)
239 OSL_TRACE("osl_createPipe: pipe name too long");
240 return NULL;
243 /* alloc memory */
244 pPipe= __osl_createPipeImpl();
246 /* create socket */
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);
252 return NULL;
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)
260 Flags |= FD_CLOEXEC;
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);
273 #if defined(FREEBSD)
274 len = SUN_LEN(&addr);
275 #else
276 len = sizeof(addr);
277 #endif
279 if ( Options & osl_Pipe_CREATE )
281 struct stat status;
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);
292 return NULL;
295 unlink(name);
298 /* ok, fs clean */
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);
304 return NULL;
307 /* Only give access to all if no security handle was specified, otherwise security
308 depends on umask */
310 if ( !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);
322 return NULL;
325 return (pPipe);
327 else
328 { /* osl_pipe_OPEN */
329 if ( access(name, F_OK) != -1 )
331 if ( connect( pPipe->m_Socket, (struct sockaddr *)&addr, len) >= 0 )
333 return (pPipe);
336 OSL_TRACE("osl_createPipe failed to connect. Errno: %d; %s",errno,strerror(errno));
339 close (pPipe->m_Socket);
340 __osl_destroyPipeImpl(pPipe);
341 return NULL;
345 void SAL_CALL osl_acquirePipe( oslPipe pPipe )
347 osl_atomic_increment( &(pPipe->m_nRefCount) );
350 void SAL_CALL osl_releasePipe( oslPipe pPipe )
353 if( 0 == pPipe )
354 return;
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 )
367 int nRet;
368 #if defined(LINUX)
369 size_t len;
370 struct sockaddr_un addr;
371 int fd;
372 #endif
373 int ConnFD;
375 if( ! pPipe )
377 return;
380 if( pPipe->m_bClosed )
382 return;
385 ConnFD = pPipe->m_Socket;
388 Thread does not return from accept on linux, so
389 connect to the accepting pipe
391 #if defined(LINUX)
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);
403 len = sizeof(addr);
405 nRet = connect( fd, (struct sockaddr *)&addr, len);
406 if ( nRet < 0 )
408 OSL_TRACE("connect in osl_destroyPipe failed with error: %s", strerror(errno));
410 close(fd);
412 #endif /* LINUX */
415 nRet = shutdown(ConnFD, 2);
416 if ( nRet < 0 )
418 OSL_TRACE("shutdown in destroyPipe failed : '%s'",strerror(errno));
421 nRet = close(ConnFD);
422 if ( nRet < 0 )
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 /*****************************************************************************/
438 /* osl_acceptPipe */
439 /*****************************************************************************/
440 oslPipe SAL_CALL osl_acceptPipe(oslPipe pPipe)
442 int s, flags;
443 oslPipe pAcceptedPipe;
445 OSL_ASSERT(pPipe);
446 if ( pPipe == 0 )
448 return NULL;
451 OSL_ASSERT(strlen(pPipe->m_Name) > 0);
453 #if defined(LINUX)
454 pPipe->m_bIsAccepting = sal_True;
455 #endif
457 s = accept(pPipe->m_Socket, NULL, NULL);
459 #if defined(LINUX)
460 pPipe->m_bIsAccepting = sal_False;
461 #endif
463 if (s < 0)
465 OSL_TRACE("osl_acceptPipe : accept error '%s'", strerror(errno));
466 return NULL;
469 #if defined(LINUX)
470 if ( pPipe->m_bIsInShutdown )
472 close(s);
473 return NULL;
475 #endif /* LINUX */
476 else
478 /* alloc memory */
479 pAcceptedPipe= __osl_createPipeImpl();
481 OSL_ASSERT(pAcceptedPipe);
482 if(pAcceptedPipe==NULL)
484 close(s);
485 return NULL;
488 /* set close-on-exec flag */
489 if (!((flags = fcntl(s, F_GETFD, 0)) < 0))
491 flags |= FD_CLOEXEC;
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,
509 void* pBuffer,
510 sal_Int32 BytesToRead)
512 int nRet = 0;
514 OSL_ASSERT(pPipe);
516 if ( pPipe == 0 )
518 OSL_TRACE("osl_receivePipe : Invalid socket");
519 errno=EINVAL;
520 return -1;
523 nRet = recv(pPipe->m_Socket,
524 (sal_Char*)pBuffer,
525 BytesToRead, 0);
527 if ( nRet < 0 )
529 OSL_TRACE("osl_receivePipe failed : %i '%s'",nRet,strerror(errno));
532 return nRet;
536 /*****************************************************************************/
537 /* osl_sendPipe */
538 /*****************************************************************************/
539 sal_Int32 SAL_CALL osl_sendPipe(oslPipe pPipe,
540 const void* pBuffer,
541 sal_Int32 BytesToSend)
543 int nRet=0;
545 OSL_ASSERT(pPipe);
547 if ( pPipe == 0 )
549 OSL_TRACE("osl_sendPipe : Invalid socket");
550 errno=EINVAL;
551 return -1;
554 nRet = send(pPipe->m_Socket,
555 (sal_Char*)pBuffer,
556 BytesToSend, 0);
559 if ( nRet <= 0 )
561 OSL_TRACE("osl_sendPipe failed : %i '%s'",nRet,strerror(errno));
564 return nRet;
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;
584 OSL_ASSERT(pPipe);
585 while (BytesToSend > 0)
587 sal_Int32 RetVal;
589 RetVal= osl_sendPipe(pPipe, pBuffer, BytesToSend);
591 /* error occurred? */
592 if(RetVal <= 0)
594 break;
597 BytesToSend -= RetVal;
598 BytesSend += RetVal;
599 pBuffer= (sal_Char*)pBuffer + RetVal;
602 return BytesSend;
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;
611 OSL_ASSERT( pPipe );
612 while (BytesToRead > 0)
614 sal_Int32 RetVal;
615 RetVal= osl_receivePipe(pPipe, pBuffer, BytesToRead);
617 /* error occurred? */
618 if(RetVal <= 0)
620 break;
623 BytesToRead -= RetVal;
624 BytesRead += RetVal;
625 pBuffer= (sal_Char*)pBuffer + RetVal;
627 return BytesRead;
630 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */