merged tag ooo/DEV300_m102
[LibreOffice.git] / sal / osl / unx / pipe.c
blob069ea9990951d09ca15cad84c46c24e9b3063b6b
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
29 #include "system.h"
31 #include <osl/pipe.h>
32 #include <osl/diagnose.h>
33 /*#include <osl/signal.h>*/
34 #include <osl/thread.h>
35 #include <osl/interlck.h>
37 #include "sockimpl.h"
39 #define PIPEDEFAULTPATH "/tmp"
40 #define PIPEALTERNATEPATH "/var/tmp"
42 #define PIPENAMEMASK "OSL_PIPE_%s"
43 #define SECPIPENAMEMASK "OSL_PIPE_%s_%s"
45 sal_Bool SAL_CALL osl_psz_getUserIdent(oslSecurity Security, sal_Char *pszIdent, sal_uInt32 nMax);
46 oslPipe SAL_CALL osl_psz_createPipe(const sal_Char *pszPipeName, oslPipeOptions Options, oslSecurity Security);
48 /*#define DEBUG_OSL_PIPE*/
49 /*#define TRACE_OSL_PIPE*/
52 /*****************************************************************************/
53 /* enum oslPipeError */
54 /*****************************************************************************/
56 static struct
58 int errcode;
59 oslPipeError error;
60 } PipeError[]= {
61 { 0, osl_Pipe_E_None }, /* no error */
62 { EPROTOTYPE, osl_Pipe_E_NoProtocol }, /* Protocol wrong type for socket */
63 { ENOPROTOOPT, osl_Pipe_E_NoProtocol }, /* Protocol not available */
64 { EPROTONOSUPPORT, osl_Pipe_E_NoProtocol }, /* Protocol not supported */
65 { ESOCKTNOSUPPORT, osl_Pipe_E_NoProtocol }, /* Socket type not supported */
66 { EPFNOSUPPORT, osl_Pipe_E_NoProtocol }, /* Protocol family not supported */
67 { EAFNOSUPPORT, osl_Pipe_E_NoProtocol }, /* Address family not supported by */
68 /* protocol family */
69 { ENETRESET, osl_Pipe_E_NetworkReset }, /* Network dropped connection because */
70 /* of reset */
71 { ECONNABORTED, osl_Pipe_E_ConnectionAbort }, /* Software caused connection abort */
72 { ECONNRESET, osl_Pipe_E_ConnectionReset }, /* Connection reset by peer */
73 { ENOBUFS, osl_Pipe_E_NoBufferSpace }, /* No buffer space available */
74 { ETIMEDOUT, osl_Pipe_E_TimedOut }, /* Connection timed out */
75 { ECONNREFUSED, osl_Pipe_E_ConnectionRefused }, /* Connection refused */
76 { -1, osl_Pipe_E_invalidError }
80 /* map */
81 /* mfe: NOT USED
82 static int osl_NativeFromPipeError(oslPipeError errorCode)
84 int i = 0;
86 while ((PipeError[i].error != osl_Pipe_E_invalidError) &&
87 (PipeError[i].error != errorCode)) i++;
89 return PipeError[i].errcode;
94 /* reverse map */
95 static oslPipeError osl_PipeErrorFromNative(int nativeType)
97 int i = 0;
99 while ((PipeError[i].error != osl_Pipe_E_invalidError) &&
100 (PipeError[i].errcode != nativeType)) i++;
102 return PipeError[i].error;
106 /* macros */
107 #define ERROR_TO_NATIVE(x) osl_NativeFromPipeError(x)
108 #define ERROR_FROM_NATIVE(y) osl_PipeErrorFromNative(y)
111 /*****************************************************************************/
112 /* osl_create/destroy-PipeImpl */
113 /*****************************************************************************/
115 oslPipe __osl_createPipeImpl()
117 oslPipe pPipeImpl;
119 pPipeImpl = (oslPipe)calloc(1, sizeof(struct oslPipeImpl));
120 pPipeImpl->m_nRefCount =1;
121 pPipeImpl->m_bClosed = sal_False;
122 #if defined(LINUX)
123 pPipeImpl->m_bIsInShutdown = sal_False;
124 pPipeImpl->m_bIsAccepting = sal_False;
125 #endif
126 return pPipeImpl;
129 void __osl_destroyPipeImpl(oslPipe pImpl)
131 if (pImpl != NULL)
132 free(pImpl);
136 /*****************************************************************************/
137 /* osl_createPipe */
138 /*****************************************************************************/
139 oslPipe SAL_CALL osl_createPipe(rtl_uString *ustrPipeName, oslPipeOptions Options, oslSecurity Security)
141 oslPipe pPipe=0;
142 rtl_String* strPipeName=0;
143 sal_Char* pszPipeName=0;
145 if ( ustrPipeName != 0 )
147 rtl_uString2String( &strPipeName,
148 rtl_uString_getStr(ustrPipeName),
149 rtl_uString_getLength(ustrPipeName),
150 osl_getThreadTextEncoding(),
151 OUSTRING_TO_OSTRING_CVTFLAGS );
152 pszPipeName = rtl_string_getStr(strPipeName);
153 pPipe = osl_psz_createPipe(pszPipeName, Options, Security);
155 if ( strPipeName != 0 )
157 rtl_string_release(strPipeName);
161 return pPipe;
165 oslPipe SAL_CALL osl_psz_createPipe(const sal_Char *pszPipeName, oslPipeOptions Options,
166 oslSecurity Security)
168 int Flags;
169 size_t len;
170 struct sockaddr_un addr;
172 sal_Char name[PATH_MAX + 1];
173 oslPipe pPipe;
175 if (access(PIPEDEFAULTPATH, R_OK|W_OK) == 0)
177 strncpy(name, PIPEDEFAULTPATH, sizeof(name));
179 else
181 strncpy(name, PIPEALTERNATEPATH, sizeof(name));
185 strncat(name, "/", sizeof(name));
187 if (Security)
189 sal_Char Ident[256];
191 Ident[0] = '\0';
193 OSL_VERIFY(osl_psz_getUserIdent(Security, Ident, sizeof(Ident)));
195 snprintf(&name[strlen(name)], sizeof(name), SECPIPENAMEMASK, Ident, pszPipeName);
197 else
199 snprintf(&name[strlen(name)], sizeof(name), PIPENAMEMASK, pszPipeName);
203 /* alloc memory */
204 pPipe= __osl_createPipeImpl();
206 /* create socket */
207 pPipe->m_Socket = socket(AF_UNIX, SOCK_STREAM, 0);
208 if ( pPipe->m_Socket < 0 )
210 OSL_TRACE("osl_createPipe socket failed. Errno: %d; %s\n",errno, strerror(errno));
211 __osl_destroyPipeImpl(pPipe);
212 return NULL;
215 /* OSL_TRACE("osl_createPipe : new Pipe on fd %i\n",pPipe->m_Socket);*/
217 /* set close-on-exec flag */
218 if ((Flags = fcntl(pPipe->m_Socket, F_GETFD, 0)) != -1)
220 Flags |= FD_CLOEXEC;
221 if (fcntl(pPipe->m_Socket, F_SETFD, Flags) == -1)
223 OSL_TRACE("osl_createPipe failed changing socket flags. Errno: %d; %s\n",errno,strerror(errno));
227 memset(&addr, 0, sizeof(addr));
229 OSL_TRACE("osl_createPipe : Pipe Name '%s'",name);
231 addr.sun_family = AF_UNIX;
232 strncpy(addr.sun_path, name, sizeof(addr.sun_path));
233 #if defined(FREEBSD)
234 len = SUN_LEN(&addr);
235 #else
236 len = sizeof(addr);
237 #endif
239 if ( Options & osl_Pipe_CREATE )
241 struct stat status;
243 /* check if there exists an orphan filesystem entry */
244 if ( ( stat(name, &status) == 0) &&
245 ( S_ISSOCK(status.st_mode) || S_ISFIFO(status.st_mode) ) )
247 if ( connect(pPipe->m_Socket,(struct sockaddr *)&addr,len) >= 0 )
249 OSL_TRACE("osl_createPipe : Pipe already in use. Errno: %d; %s\n",errno,strerror(errno));
250 close (pPipe->m_Socket);
251 __osl_destroyPipeImpl(pPipe);
252 return NULL;
255 unlink(name);
258 /* ok, fs clean */
259 if ( bind(pPipe->m_Socket, (struct sockaddr *)&addr, len) < 0 )
261 OSL_TRACE("osl_createPipe : failed to bind socket. Errno: %d; %s\n",errno,strerror(errno));
262 close (pPipe->m_Socket);
263 __osl_destroyPipeImpl(pPipe);
264 return NULL;
267 /* Only give access to all if no security handle was specified, otherwise security
268 depends on umask */
270 if ( !Security )
271 chmod(name,S_IRWXU | S_IRWXG |S_IRWXO);
274 strncpy(pPipe->m_Name, name, sizeof(pPipe->m_Name));
276 if ( listen(pPipe->m_Socket, 5) < 0 )
278 OSL_TRACE("osl_createPipe failed to listen. Errno: %d; %s\n",errno,strerror(errno));
279 unlink(name); /* remove filesystem entry */
280 close (pPipe->m_Socket);
281 __osl_destroyPipeImpl(pPipe);
282 return NULL;
285 return (pPipe);
287 else
288 { /* osl_pipe_OPEN */
289 if ( access(name, F_OK) != -1 )
291 if ( connect( pPipe->m_Socket, (struct sockaddr *)&addr, len) >= 0 )
293 return (pPipe);
296 OSL_TRACE("osl_createPipe failed to connect. Errno: %d; %s\n",errno,strerror(errno));
299 close (pPipe->m_Socket);
300 __osl_destroyPipeImpl(pPipe);
301 return NULL;
305 void SAL_CALL osl_acquirePipe( oslPipe pPipe )
307 osl_incrementInterlockedCount( &(pPipe->m_nRefCount) );
310 void SAL_CALL osl_releasePipe( oslPipe pPipe )
313 if( 0 == pPipe )
314 return;
316 if( 0 == osl_decrementInterlockedCount( &(pPipe->m_nRefCount) ) )
318 if( ! pPipe->m_bClosed )
319 osl_closePipe( pPipe );
321 __osl_destroyPipeImpl( pPipe );
325 void SAL_CALL osl_closePipe( oslPipe pPipe )
327 int nRet;
328 #if defined(LINUX)
329 size_t len;
330 struct sockaddr_un addr;
331 int fd;
332 #endif
333 int ConnFD;
335 if( ! pPipe )
337 return;
340 if( pPipe->m_bClosed )
342 return;
345 ConnFD = pPipe->m_Socket;
348 Thread does not return from accept on linux, so
349 connect to the accepting pipe
351 #if defined(LINUX)
352 if ( pPipe->m_bIsAccepting )
354 pPipe->m_bIsInShutdown = sal_True;
355 pPipe->m_Socket = -1;
356 fd = socket(AF_UNIX, SOCK_STREAM, 0);
357 memset(&addr, 0, sizeof(addr));
359 OSL_TRACE("osl_destroyPipe : Pipe Name '%s'",pPipe->m_Name);
361 addr.sun_family = AF_UNIX;
362 strncpy(addr.sun_path, pPipe->m_Name, sizeof(addr.sun_path));
363 len = sizeof(addr);
365 nRet = connect( fd, (struct sockaddr *)&addr, len);
366 #if OSL_DEBUG_LEVEL > 1
367 if ( nRet < 0 )
369 perror("connect in osl_destroyPipe");
371 #endif /* OSL_DEBUG_LEVEL */
372 close(fd);
374 #endif /* LINUX */
377 nRet = shutdown(ConnFD, 2);
378 if ( nRet < 0 )
380 OSL_TRACE("shutdown in destroyPipe failed : '%s'\n",strerror(errno));
383 nRet = close(ConnFD);
384 if ( nRet < 0 )
386 OSL_TRACE("close in destroyPipe failed : '%s'\n",strerror(errno));
388 /* remove filesystem entry */
389 if ( strlen(pPipe->m_Name) > 0 )
391 unlink(pPipe->m_Name);
393 pPipe->m_bClosed = sal_True;
395 /* OSL_TRACE("Out osl_destroyPipe"); */
399 /*****************************************************************************/
400 /* osl_acceptPipe */
401 /*****************************************************************************/
402 oslPipe SAL_CALL osl_acceptPipe(oslPipe pPipe)
404 int s, flags;
405 oslPipe pAcceptedPipe;
407 OSL_ASSERT(pPipe);
408 if ( pPipe == 0 )
410 return NULL;
413 OSL_ASSERT(strlen(pPipe->m_Name) > 0);
415 #if defined(LINUX)
416 pPipe->m_bIsAccepting = sal_True;
417 #endif
419 s = accept(pPipe->m_Socket, NULL, NULL);
421 #if defined(LINUX)
422 pPipe->m_bIsAccepting = sal_False;
423 #endif
425 if (s < 0)
427 OSL_TRACE("osl_acceptPipe : accept error '%s'", strerror(errno));
428 return NULL;
431 #if defined(LINUX)
432 if ( pPipe->m_bIsInShutdown )
434 close(s);
435 return NULL;
437 #endif /* LINUX */
438 else
440 /* alloc memory */
441 pAcceptedPipe= __osl_createPipeImpl();
443 OSL_ASSERT(pAcceptedPipe);
444 if(pAcceptedPipe==NULL)
446 close(s);
447 return NULL;
450 /* set close-on-exec flag */
451 if (!((flags = fcntl(s, F_GETFD, 0)) < 0))
453 flags |= FD_CLOEXEC;
454 if (fcntl(s, F_SETFD, flags) < 0)
456 OSL_TRACE("osl_acceptPipe: error changing socket flags. "
457 "Errno: %d; %s",errno,strerror(errno));
461 pAcceptedPipe->m_Socket = s;
464 return pAcceptedPipe;
467 /*****************************************************************************/
468 /* osl_receivePipe */
469 /*****************************************************************************/
470 sal_Int32 SAL_CALL osl_receivePipe(oslPipe pPipe,
471 void* pBuffer,
472 sal_Int32 BytesToRead)
474 int nRet = 0;
476 OSL_ASSERT(pPipe);
478 if ( pPipe == 0 )
480 OSL_TRACE("osl_receivePipe : Invalid socket");
481 errno=EINVAL;
482 return -1;
485 nRet = recv(pPipe->m_Socket,
486 (sal_Char*)pBuffer,
487 BytesToRead, 0);
489 if ( nRet < 0 )
491 OSL_TRACE("osl_receivePipe failed : %i '%s'",nRet,strerror(errno));
494 return nRet;
498 /*****************************************************************************/
499 /* osl_sendPipe */
500 /*****************************************************************************/
501 sal_Int32 SAL_CALL osl_sendPipe(oslPipe pPipe,
502 const void* pBuffer,
503 sal_Int32 BytesToSend)
505 int nRet=0;
507 OSL_ASSERT(pPipe);
509 if ( pPipe == 0 )
511 OSL_TRACE("osl_sendPipe : Invalid socket");
512 errno=EINVAL;
513 return -1;
516 nRet = send(pPipe->m_Socket,
517 (sal_Char*)pBuffer,
518 BytesToSend, 0);
521 if ( nRet <= 0 )
523 OSL_TRACE("osl_sendPipe failed : %i '%s'",nRet,strerror(errno));
526 return nRet;
530 /*****************************************************************************/
531 /* osl_getLastPipeError */
532 /*****************************************************************************/
533 oslPipeError SAL_CALL osl_getLastPipeError(oslPipe pPipe)
535 (void) pPipe; /* unused */
536 return ERROR_FROM_NATIVE(errno);
540 sal_Int32 SAL_CALL osl_writePipe( oslPipe pPipe, const void *pBuffer , sal_Int32 n )
542 /* loop until all desired bytes were send or an error occured */
543 sal_Int32 BytesSend= 0;
544 sal_Int32 BytesToSend= n;
546 OSL_ASSERT(pPipe);
547 while (BytesToSend > 0)
549 sal_Int32 RetVal;
551 RetVal= osl_sendPipe(pPipe, pBuffer, BytesToSend);
553 /* error occured? */
554 if(RetVal <= 0)
556 break;
559 BytesToSend -= RetVal;
560 BytesSend += RetVal;
561 pBuffer= (sal_Char*)pBuffer + RetVal;
564 return BytesSend;
567 sal_Int32 SAL_CALL osl_readPipe( oslPipe pPipe, void *pBuffer , sal_Int32 n )
569 /* loop until all desired bytes were read or an error occured */
570 sal_Int32 BytesRead= 0;
571 sal_Int32 BytesToRead= n;
573 OSL_ASSERT( pPipe );
574 while (BytesToRead > 0)
576 sal_Int32 RetVal;
577 RetVal= osl_receivePipe(pPipe, pBuffer, BytesToRead);
579 /* error occured? */
580 if(RetVal <= 0)
582 break;
585 BytesToRead -= RetVal;
586 BytesRead += RetVal;
587 pBuffer= (sal_Char*)pBuffer + RetVal;
589 return BytesRead;