Bump for 3.6-28
[LibreOffice.git] / sal / osl / unx / pipe.c
blobfd472fa18e4327d0898599e2a29e115241b32ab6
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 ************************************************************************/
29 #include "system.h"
31 #include <osl/pipe.h>
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>
39 #include "sockimpl.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 /*****************************************************************************/
55 static struct
57 int errcode;
58 oslPipeError error;
59 } PipeError[]= {
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 */
67 /* protocol family */
68 { ENETRESET, osl_Pipe_E_NetworkReset }, /* Network dropped connection because */
69 /* of reset */
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 }
79 /* map */
80 /* mfe: NOT USED
81 static int osl_NativeFromPipeError(oslPipeError errorCode)
83 int i = 0;
85 while ((PipeError[i].error != osl_Pipe_E_invalidError) &&
86 (PipeError[i].error != errorCode)) i++;
88 return PipeError[i].errcode;
93 /* reverse map */
94 static oslPipeError osl_PipeErrorFromNative(int nativeType)
96 int i = 0;
98 while ((PipeError[i].error != osl_Pipe_E_invalidError) &&
99 (PipeError[i].errcode != nativeType)) i++;
101 return PipeError[i].error;
105 /* macros */
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()
116 oslPipe pPipeImpl;
118 pPipeImpl = (oslPipe)calloc(1, sizeof(struct oslPipeImpl));
119 pPipeImpl->m_nRefCount =1;
120 pPipeImpl->m_bClosed = sal_False;
121 #if defined(LINUX)
122 pPipeImpl->m_bIsInShutdown = sal_False;
123 pPipeImpl->m_bIsAccepting = sal_False;
124 #endif
125 return pPipeImpl;
128 void __osl_destroyPipeImpl(oslPipe pImpl)
130 if (pImpl != NULL)
131 free(pImpl);
135 /*****************************************************************************/
136 /* osl_createPipe */
137 /*****************************************************************************/
138 oslPipe SAL_CALL osl_createPipe(rtl_uString *ustrPipeName, oslPipeOptions Options, oslSecurity Security)
140 oslPipe pPipe=0;
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);
160 return pPipe;
164 static sal_Bool
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);
184 name[nCopy] = '\0';
185 bRet = (size_t)pStrValue->length < len;
187 rtl_string_release(pStrValue);
189 rtl_uString_release(pName);
191 return bRet;
194 oslPipe SAL_CALL osl_psz_createPipe(const sal_Char *pszPipeName, oslPipeOptions Options,
195 oslSecurity Security)
197 int Flags;
198 size_t len;
199 struct sockaddr_un addr;
201 sal_Char name[PATH_MAX + 1];
202 size_t nNameLength = 0;
203 int bNameTooLong = 0;
204 oslPipe pPipe;
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)))
216 return NULL;
218 name[sizeof(name) - 1] = '\0'; // ensure the string is NULL-terminated
219 nNameLength = strlen(name);
220 bNameTooLong = nNameLength > sizeof(name) - 2;
222 if (!bNameTooLong)
224 size_t nRealLength = 0;
226 strcat(name, "/");
227 ++nNameLength;
229 if (Security)
231 sal_Char Ident[256];
233 Ident[0] = '\0';
235 OSL_VERIFY(osl_psz_getUserIdent(Security, Ident, sizeof(Ident)));
237 nRealLength = snprintf(&name[nNameLength], sizeof(name) - nNameLength, SECPIPENAMEMASK, Ident, pszPipeName);
239 else
241 nRealLength = snprintf(&name[nNameLength], sizeof(name) - nNameLength, PIPENAMEMASK, pszPipeName);
244 bNameTooLong = nRealLength > sizeof(name) - nNameLength - 1;
247 if (bNameTooLong)
249 OSL_TRACE("osl_createPipe: pipe name too long");
250 return NULL;
253 /* alloc memory */
254 pPipe= __osl_createPipeImpl();
256 /* create socket */
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);
262 return NULL;
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)
270 Flags |= FD_CLOEXEC;
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));
283 #if defined(FREEBSD)
284 len = SUN_LEN(&addr);
285 #else
286 len = sizeof(addr);
287 #endif
289 if ( Options & osl_Pipe_CREATE )
291 struct stat status;
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);
302 return NULL;
305 unlink(name);
308 /* ok, fs clean */
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);
314 return NULL;
317 /* Only give access to all if no security handle was specified, otherwise security
318 depends on umask */
320 if ( !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);
332 return NULL;
335 return (pPipe);
337 else
338 { /* osl_pipe_OPEN */
339 if ( access(name, F_OK) != -1 )
341 if ( connect( pPipe->m_Socket, (struct sockaddr *)&addr, len) >= 0 )
343 return (pPipe);
346 OSL_TRACE("osl_createPipe failed to connect. Errno: %d; %s",errno,strerror(errno));
349 close (pPipe->m_Socket);
350 __osl_destroyPipeImpl(pPipe);
351 return NULL;
355 void SAL_CALL osl_acquirePipe( oslPipe pPipe )
357 osl_incrementInterlockedCount( &(pPipe->m_nRefCount) );
360 void SAL_CALL osl_releasePipe( oslPipe pPipe )
363 if( 0 == pPipe )
364 return;
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 )
377 int nRet;
378 #if defined(LINUX)
379 size_t len;
380 struct sockaddr_un addr;
381 int fd;
382 #endif
383 int ConnFD;
385 if( ! pPipe )
387 return;
390 if( pPipe->m_bClosed )
392 return;
395 ConnFD = pPipe->m_Socket;
398 Thread does not return from accept on linux, so
399 connect to the accepting pipe
401 #if defined(LINUX)
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));
413 len = sizeof(addr);
415 nRet = connect( fd, (struct sockaddr *)&addr, len);
416 if ( nRet < 0 )
418 OSL_TRACE("connect in osl_destroyPipe failed with error: %s", strerror(errno));
420 close(fd);
422 #endif /* LINUX */
425 nRet = shutdown(ConnFD, 2);
426 if ( nRet < 0 )
428 OSL_TRACE("shutdown in destroyPipe failed : '%s'",strerror(errno));
431 nRet = close(ConnFD);
432 if ( nRet < 0 )
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 /*****************************************************************************/
448 /* osl_acceptPipe */
449 /*****************************************************************************/
450 oslPipe SAL_CALL osl_acceptPipe(oslPipe pPipe)
452 int s, flags;
453 oslPipe pAcceptedPipe;
455 OSL_ASSERT(pPipe);
456 if ( pPipe == 0 )
458 return NULL;
461 OSL_ASSERT(strlen(pPipe->m_Name) > 0);
463 #if defined(LINUX)
464 pPipe->m_bIsAccepting = sal_True;
465 #endif
467 s = accept(pPipe->m_Socket, NULL, NULL);
469 #if defined(LINUX)
470 pPipe->m_bIsAccepting = sal_False;
471 #endif
473 if (s < 0)
475 OSL_TRACE("osl_acceptPipe : accept error '%s'", strerror(errno));
476 return NULL;
479 #if defined(LINUX)
480 if ( pPipe->m_bIsInShutdown )
482 close(s);
483 return NULL;
485 #endif /* LINUX */
486 else
488 /* alloc memory */
489 pAcceptedPipe= __osl_createPipeImpl();
491 OSL_ASSERT(pAcceptedPipe);
492 if(pAcceptedPipe==NULL)
494 close(s);
495 return NULL;
498 /* set close-on-exec flag */
499 if (!((flags = fcntl(s, F_GETFD, 0)) < 0))
501 flags |= FD_CLOEXEC;
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,
519 void* pBuffer,
520 sal_Int32 BytesToRead)
522 int nRet = 0;
524 OSL_ASSERT(pPipe);
526 if ( pPipe == 0 )
528 OSL_TRACE("osl_receivePipe : Invalid socket");
529 errno=EINVAL;
530 return -1;
533 nRet = recv(pPipe->m_Socket,
534 (sal_Char*)pBuffer,
535 BytesToRead, 0);
537 if ( nRet < 0 )
539 OSL_TRACE("osl_receivePipe failed : %i '%s'",nRet,strerror(errno));
542 return nRet;
546 /*****************************************************************************/
547 /* osl_sendPipe */
548 /*****************************************************************************/
549 sal_Int32 SAL_CALL osl_sendPipe(oslPipe pPipe,
550 const void* pBuffer,
551 sal_Int32 BytesToSend)
553 int nRet=0;
555 OSL_ASSERT(pPipe);
557 if ( pPipe == 0 )
559 OSL_TRACE("osl_sendPipe : Invalid socket");
560 errno=EINVAL;
561 return -1;
564 nRet = send(pPipe->m_Socket,
565 (sal_Char*)pBuffer,
566 BytesToSend, 0);
569 if ( nRet <= 0 )
571 OSL_TRACE("osl_sendPipe failed : %i '%s'",nRet,strerror(errno));
574 return nRet;
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;
594 OSL_ASSERT(pPipe);
595 while (BytesToSend > 0)
597 sal_Int32 RetVal;
599 RetVal= osl_sendPipe(pPipe, pBuffer, BytesToSend);
601 /* error occurred? */
602 if(RetVal <= 0)
604 break;
607 BytesToSend -= RetVal;
608 BytesSend += RetVal;
609 pBuffer= (sal_Char*)pBuffer + RetVal;
612 return BytesSend;
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;
621 OSL_ASSERT( pPipe );
622 while (BytesToRead > 0)
624 sal_Int32 RetVal;
625 RetVal= osl_receivePipe(pPipe, pBuffer, BytesToRead);
627 /* error occurred? */
628 if(RetVal <= 0)
630 break;
633 BytesToRead -= RetVal;
634 BytesRead += RetVal;
635 pBuffer= (sal_Char*)pBuffer + RetVal;
637 return BytesRead;
640 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */