Version 4.2.0.1, tag libreoffice-4.2.0.1
[LibreOffice.git] / sal / osl / unx / pipe.c
blobb3d108574dac7ad913bfddd8eac4d99600fde401
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 static struct
44 int errcode;
45 oslPipeError error;
46 } PipeError[]= {
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 */
54 /* protocol family */
55 { ENETRESET, osl_Pipe_E_NetworkReset }, /* Network dropped connection because */
56 /* of reset */
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 }
66 /* map */
67 /* mfe: NOT USED
68 static int osl_NativeFromPipeError(oslPipeError errorCode)
70 int i = 0;
72 while ((PipeError[i].error != osl_Pipe_E_invalidError) &&
73 (PipeError[i].error != errorCode)) i++;
75 return PipeError[i].errcode;
80 /* reverse map */
81 static oslPipeError osl_PipeErrorFromNative(int nativeType)
83 int i = 0;
85 while ((PipeError[i].error != osl_Pipe_E_invalidError) &&
86 (PipeError[i].errcode != nativeType)) i++;
88 return PipeError[i].error;
92 /* macros */
93 #define ERROR_FROM_NATIVE(y) osl_PipeErrorFromNative(y)
96 oslPipe __osl_createPipeImpl()
98 oslPipe pPipeImpl;
100 pPipeImpl = (oslPipe)calloc(1, sizeof(struct oslPipeImpl));
101 pPipeImpl->m_nRefCount =1;
102 pPipeImpl->m_bClosed = sal_False;
103 #if defined(LINUX)
104 pPipeImpl->m_bIsInShutdown = sal_False;
105 pPipeImpl->m_bIsAccepting = sal_False;
106 #endif
107 return pPipeImpl;
110 void __osl_destroyPipeImpl(oslPipe pImpl)
112 if (pImpl != NULL)
113 free(pImpl);
117 oslPipe SAL_CALL osl_createPipe(rtl_uString *ustrPipeName, oslPipeOptions Options, oslSecurity Security)
119 oslPipe pPipe=0;
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);
139 return pPipe;
143 static sal_Bool
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);
163 name[nCopy] = '\0';
164 bRet = (size_t)pStrValue->length < len;
166 rtl_string_release(pStrValue);
168 rtl_uString_release(pName);
170 return bRet;
173 oslPipe SAL_CALL osl_psz_createPipe(const sal_Char *pszPipeName, oslPipeOptions Options,
174 oslSecurity Security)
176 int Flags;
177 size_t len;
178 struct sockaddr_un addr;
180 sal_Char name[PATH_MAX + 1];
181 size_t nNameLength = 0;
182 int bNameTooLong = 0;
183 oslPipe pPipe;
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)))
195 return NULL;
197 name[sizeof(name) - 1] = '\0'; // ensure the string is NULL-terminated
198 nNameLength = strlen(name);
199 bNameTooLong = nNameLength > sizeof(name) - 2;
201 if (!bNameTooLong)
203 size_t nRealLength = 0;
205 strcat(name, "/");
206 ++nNameLength;
208 if (Security)
210 sal_Char Ident[256];
212 Ident[0] = '\0';
214 OSL_VERIFY(osl_psz_getUserIdent(Security, Ident, sizeof(Ident)));
216 nRealLength = snprintf(&name[nNameLength], sizeof(name) - nNameLength, SECPIPENAMEMASK, Ident, pszPipeName);
218 else
220 nRealLength = snprintf(&name[nNameLength], sizeof(name) - nNameLength, PIPENAMEMASK, pszPipeName);
223 bNameTooLong = nRealLength > sizeof(name) - nNameLength - 1;
226 if (bNameTooLong)
228 OSL_TRACE("osl_createPipe: pipe name too long");
229 return NULL;
232 /* alloc memory */
233 pPipe= __osl_createPipeImpl();
235 /* create socket */
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);
241 return NULL;
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)
249 Flags |= FD_CLOEXEC;
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);
262 #if defined(FREEBSD)
263 len = SUN_LEN(&addr);
264 #else
265 len = sizeof(addr);
266 #endif
268 if ( Options & osl_Pipe_CREATE )
270 struct stat status;
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);
281 return NULL;
284 unlink(name);
287 /* ok, fs clean */
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);
293 return NULL;
296 /* Only give access to all if no security handle was specified, otherwise security
297 depends on umask */
299 if ( !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);
311 return NULL;
314 return (pPipe);
316 else
317 { /* osl_pipe_OPEN */
318 if ( access(name, F_OK) != -1 )
320 if ( connect( pPipe->m_Socket, (struct sockaddr *)&addr, len) >= 0 )
322 return (pPipe);
325 OSL_TRACE("osl_createPipe failed to connect. Errno: %d; %s",errno,strerror(errno));
328 close (pPipe->m_Socket);
329 __osl_destroyPipeImpl(pPipe);
330 return NULL;
334 void SAL_CALL osl_acquirePipe( oslPipe pPipe )
336 osl_atomic_increment( &(pPipe->m_nRefCount) );
339 void SAL_CALL osl_releasePipe( oslPipe pPipe )
342 if( 0 == pPipe )
343 return;
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 )
356 int nRet;
357 #if defined(LINUX)
358 size_t len;
359 struct sockaddr_un addr;
360 int fd;
361 #endif
362 int ConnFD;
364 if( ! pPipe )
366 return;
369 if( pPipe->m_bClosed )
371 return;
374 ConnFD = pPipe->m_Socket;
377 Thread does not return from accept on linux, so
378 connect to the accepting pipe
380 #if defined(LINUX)
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);
392 len = sizeof(addr);
394 nRet = connect( fd, (struct sockaddr *)&addr, len);
395 if ( nRet < 0 )
397 OSL_TRACE("connect in osl_destroyPipe failed with error: %s", strerror(errno));
399 close(fd);
401 #endif /* LINUX */
404 nRet = shutdown(ConnFD, 2);
405 if ( nRet < 0 )
407 OSL_TRACE("shutdown in destroyPipe failed : '%s'",strerror(errno));
410 nRet = close(ConnFD);
411 if ( nRet < 0 )
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)
428 int s, flags;
429 oslPipe pAcceptedPipe;
431 OSL_ASSERT(pPipe);
432 if ( pPipe == 0 )
434 return NULL;
437 OSL_ASSERT(strlen(pPipe->m_Name) > 0);
439 #if defined(LINUX)
440 pPipe->m_bIsAccepting = sal_True;
441 #endif
443 s = accept(pPipe->m_Socket, NULL, NULL);
445 #if defined(LINUX)
446 pPipe->m_bIsAccepting = sal_False;
447 #endif
449 if (s < 0)
451 OSL_TRACE("osl_acceptPipe : accept error '%s'", strerror(errno));
452 return NULL;
455 #if defined(LINUX)
456 if ( pPipe->m_bIsInShutdown )
458 close(s);
459 return NULL;
461 #endif /* LINUX */
462 else
464 /* alloc memory */
465 pAcceptedPipe= __osl_createPipeImpl();
467 OSL_ASSERT(pAcceptedPipe);
468 if(pAcceptedPipe==NULL)
470 close(s);
471 return NULL;
474 /* set close-on-exec flag */
475 if (!((flags = fcntl(s, F_GETFD, 0)) < 0))
477 flags |= FD_CLOEXEC;
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,
492 void* pBuffer,
493 sal_Int32 BytesToRead)
495 int nRet = 0;
497 OSL_ASSERT(pPipe);
499 if ( pPipe == 0 )
501 OSL_TRACE("osl_receivePipe : Invalid socket");
502 errno=EINVAL;
503 return -1;
506 nRet = recv(pPipe->m_Socket,
507 (sal_Char*)pBuffer,
508 BytesToRead, 0);
510 if ( nRet < 0 )
512 OSL_TRACE("osl_receivePipe failed : %i '%s'",nRet,strerror(errno));
515 return nRet;
518 sal_Int32 SAL_CALL osl_sendPipe(oslPipe pPipe,
519 const void* pBuffer,
520 sal_Int32 BytesToSend)
522 int nRet=0;
524 OSL_ASSERT(pPipe);
526 if ( pPipe == 0 )
528 OSL_TRACE("osl_sendPipe : Invalid socket");
529 errno=EINVAL;
530 return -1;
533 nRet = send(pPipe->m_Socket,
534 (sal_Char*)pBuffer,
535 BytesToSend, 0);
538 if ( nRet <= 0 )
540 OSL_TRACE("osl_sendPipe failed : %i '%s'",nRet,strerror(errno));
543 return nRet;
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;
559 OSL_ASSERT(pPipe);
560 while (BytesToSend > 0)
562 sal_Int32 RetVal;
564 RetVal= osl_sendPipe(pPipe, pBuffer, BytesToSend);
566 /* error occurred? */
567 if(RetVal <= 0)
569 break;
572 BytesToSend -= RetVal;
573 BytesSend += RetVal;
574 pBuffer= (sal_Char*)pBuffer + RetVal;
577 return BytesSend;
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;
586 OSL_ASSERT( pPipe );
587 while (BytesToRead > 0)
589 sal_Int32 RetVal;
590 RetVal= osl_receivePipe(pPipe, pBuffer, BytesToRead);
592 /* error occurred? */
593 if(RetVal <= 0)
595 break;
598 BytesToRead -= RetVal;
599 BytesRead += RetVal;
600 pBuffer= (sal_Char*)pBuffer + RetVal;
602 return BytesRead;
605 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */