9916c021b6
2008/03/31 13:23:44 rt 1.19.268.1: #i87441# Change license header to LPGL v3.
595 lines
16 KiB
C
595 lines
16 KiB
C
/*************************************************************************
|
|
*
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* Copyright 2008 by Sun Microsystems, Inc.
|
|
*
|
|
* OpenOffice.org - a multi-platform office productivity suite
|
|
*
|
|
* $RCSfile: pipe.c,v $
|
|
* $Revision: 1.20 $
|
|
*
|
|
* This file is part of OpenOffice.org.
|
|
*
|
|
* OpenOffice.org is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License version 3
|
|
* only, as published by the Free Software Foundation.
|
|
*
|
|
* OpenOffice.org is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Lesser General Public License version 3 for more details
|
|
* (a copy is included in the LICENSE file that accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* version 3 along with OpenOffice.org. If not, see
|
|
* <http://www.openoffice.org/license.html>
|
|
* for a copy of the LGPLv3 License.
|
|
*
|
|
************************************************************************/
|
|
|
|
|
|
#include "system.h"
|
|
|
|
#include <osl/pipe.h>
|
|
#include <osl/diagnose.h>
|
|
/*#include <osl/signal.h>*/
|
|
#include <osl/thread.h>
|
|
#include <osl/interlck.h>
|
|
|
|
#include "sockimpl.h"
|
|
|
|
#define PIPEDEFAULTPATH "/tmp"
|
|
#define PIPEALTERNATEPATH "/var/tmp"
|
|
|
|
#define PIPENAMEMASK "OSL_PIPE_%s"
|
|
#define SECPIPENAMEMASK "OSL_PIPE_%s_%s"
|
|
|
|
sal_Bool SAL_CALL osl_psz_getUserIdent(oslSecurity Security, sal_Char *pszIdent, sal_uInt32 nMax);
|
|
oslPipe SAL_CALL osl_psz_createPipe(const sal_Char *pszPipeName, oslPipeOptions Options, oslSecurity Security);
|
|
|
|
/*#define DEBUG_OSL_PIPE*/
|
|
/*#define TRACE_OSL_PIPE*/
|
|
|
|
|
|
/*****************************************************************************/
|
|
/* enum oslPipeError */
|
|
/*****************************************************************************/
|
|
|
|
static struct
|
|
{
|
|
int errcode;
|
|
oslPipeError error;
|
|
} PipeError[]= {
|
|
{ 0, osl_Pipe_E_None }, /* no error */
|
|
{ EPROTOTYPE, osl_Pipe_E_NoProtocol }, /* Protocol wrong type for socket */
|
|
{ ENOPROTOOPT, osl_Pipe_E_NoProtocol }, /* Protocol not available */
|
|
{ EPROTONOSUPPORT, osl_Pipe_E_NoProtocol }, /* Protocol not supported */
|
|
{ ESOCKTNOSUPPORT, osl_Pipe_E_NoProtocol }, /* Socket type not supported */
|
|
{ EPFNOSUPPORT, osl_Pipe_E_NoProtocol }, /* Protocol family not supported */
|
|
{ EAFNOSUPPORT, osl_Pipe_E_NoProtocol }, /* Address family not supported by */
|
|
/* protocol family */
|
|
{ ENETRESET, osl_Pipe_E_NetworkReset }, /* Network dropped connection because */
|
|
/* of reset */
|
|
{ ECONNABORTED, osl_Pipe_E_ConnectionAbort }, /* Software caused connection abort */
|
|
{ ECONNRESET, osl_Pipe_E_ConnectionReset }, /* Connection reset by peer */
|
|
{ ENOBUFS, osl_Pipe_E_NoBufferSpace }, /* No buffer space available */
|
|
{ ETIMEDOUT, osl_Pipe_E_TimedOut }, /* Connection timed out */
|
|
{ ECONNREFUSED, osl_Pipe_E_ConnectionRefused }, /* Connection refused */
|
|
{ -1, osl_Pipe_E_invalidError }
|
|
};
|
|
|
|
|
|
/* map */
|
|
/* mfe: NOT USED
|
|
static int osl_NativeFromPipeError(oslPipeError errorCode)
|
|
{
|
|
int i = 0;
|
|
|
|
while ((PipeError[i].error != osl_Pipe_E_invalidError) &&
|
|
(PipeError[i].error != errorCode)) i++;
|
|
|
|
return PipeError[i].errcode;
|
|
|
|
}
|
|
*/
|
|
|
|
/* reverse map */
|
|
static oslPipeError osl_PipeErrorFromNative(int nativeType)
|
|
{
|
|
int i = 0;
|
|
|
|
while ((PipeError[i].error != osl_Pipe_E_invalidError) &&
|
|
(PipeError[i].errcode != nativeType)) i++;
|
|
|
|
return PipeError[i].error;
|
|
}
|
|
|
|
|
|
/* macros */
|
|
#define ERROR_TO_NATIVE(x) osl_NativeFromPipeError(x)
|
|
#define ERROR_FROM_NATIVE(y) osl_PipeErrorFromNative(y)
|
|
|
|
|
|
/*****************************************************************************/
|
|
/* osl_create/destroy-PipeImpl */
|
|
/*****************************************************************************/
|
|
|
|
oslPipe __osl_createPipeImpl()
|
|
{
|
|
oslPipe pPipeImpl;
|
|
|
|
pPipeImpl = (oslPipe)calloc(1, sizeof(struct oslPipeImpl));
|
|
pPipeImpl->m_nRefCount =1;
|
|
pPipeImpl->m_bClosed = sal_False;
|
|
#if defined(LINUX)
|
|
pPipeImpl->m_bIsInShutdown = sal_False;
|
|
pPipeImpl->m_bIsAccepting = sal_False;
|
|
#endif
|
|
return pPipeImpl;
|
|
}
|
|
|
|
void __osl_destroyPipeImpl(oslPipe pImpl)
|
|
{
|
|
if (pImpl != NULL)
|
|
free(pImpl);
|
|
}
|
|
|
|
|
|
/*****************************************************************************/
|
|
/* osl_createPipe */
|
|
/*****************************************************************************/
|
|
oslPipe SAL_CALL osl_createPipe(rtl_uString *ustrPipeName, oslPipeOptions Options, oslSecurity Security)
|
|
{
|
|
oslPipe pPipe=0;
|
|
rtl_String* strPipeName=0;
|
|
sal_Char* pszPipeName=0;
|
|
|
|
if ( ustrPipeName != 0 )
|
|
{
|
|
rtl_uString2String( &strPipeName,
|
|
rtl_uString_getStr(ustrPipeName),
|
|
rtl_uString_getLength(ustrPipeName),
|
|
osl_getThreadTextEncoding(),
|
|
OUSTRING_TO_OSTRING_CVTFLAGS );
|
|
pszPipeName = rtl_string_getStr(strPipeName);
|
|
pPipe = osl_psz_createPipe(pszPipeName, Options, Security);
|
|
|
|
if ( strPipeName != 0 )
|
|
{
|
|
rtl_string_release(strPipeName);
|
|
}
|
|
}
|
|
|
|
return pPipe;
|
|
|
|
}
|
|
|
|
oslPipe SAL_CALL osl_psz_createPipe(const sal_Char *pszPipeName, oslPipeOptions Options,
|
|
oslSecurity Security)
|
|
{
|
|
int Flags;
|
|
size_t len;
|
|
struct sockaddr_un addr;
|
|
|
|
sal_Char name[PATH_MAX + 1];
|
|
oslPipe pPipe;
|
|
|
|
if (access(PIPEDEFAULTPATH, R_OK|W_OK) == 0)
|
|
{
|
|
strncpy(name, PIPEDEFAULTPATH, sizeof(name));
|
|
}
|
|
else
|
|
{
|
|
strncpy(name, PIPEALTERNATEPATH, sizeof(name));
|
|
}
|
|
|
|
|
|
strncat(name, "/", sizeof(name));
|
|
|
|
if (Security)
|
|
{
|
|
sal_Char Ident[256];
|
|
|
|
Ident[0] = '\0';
|
|
|
|
OSL_VERIFY(osl_psz_getUserIdent(Security, Ident, sizeof(Ident)));
|
|
|
|
snprintf(&name[strlen(name)], sizeof(name), SECPIPENAMEMASK, Ident, pszPipeName);
|
|
}
|
|
else
|
|
{
|
|
snprintf(&name[strlen(name)], sizeof(name), PIPENAMEMASK, pszPipeName);
|
|
}
|
|
|
|
|
|
/* alloc memory */
|
|
pPipe= __osl_createPipeImpl();
|
|
|
|
/* create socket */
|
|
pPipe->m_Socket = socket(AF_UNIX, SOCK_STREAM, 0);
|
|
if ( pPipe->m_Socket < 0 )
|
|
{
|
|
OSL_TRACE("osl_createPipe socket failed. Errno: %d; %s\n",errno, strerror(errno));
|
|
__osl_destroyPipeImpl(pPipe);
|
|
return NULL;
|
|
}
|
|
|
|
/* OSL_TRACE("osl_createPipe : new Pipe on fd %i\n",pPipe->m_Socket);*/
|
|
|
|
/* set close-on-exec flag */
|
|
if ((Flags = fcntl(pPipe->m_Socket, F_GETFD, 0)) != -1)
|
|
{
|
|
Flags |= FD_CLOEXEC;
|
|
if (fcntl(pPipe->m_Socket, F_SETFD, Flags) == -1)
|
|
{
|
|
OSL_TRACE("osl_createPipe failed changing socket flags. Errno: %d; %s\n",errno,strerror(errno));
|
|
}
|
|
}
|
|
|
|
memset(&addr, 0, sizeof(addr));
|
|
|
|
OSL_TRACE("osl_createPipe : Pipe Name '%s'",name);
|
|
|
|
addr.sun_family = AF_UNIX;
|
|
strncpy(addr.sun_path, name, sizeof(addr.sun_path));
|
|
#if defined(FREEBSD)
|
|
len = SUN_LEN(&addr);
|
|
#else
|
|
len = sizeof(addr);
|
|
#endif
|
|
|
|
if ( Options & osl_Pipe_CREATE )
|
|
{
|
|
struct stat status;
|
|
|
|
/* check if there exists an orphan filesystem entry */
|
|
if ( ( stat(name, &status) == 0) &&
|
|
( S_ISSOCK(status.st_mode) || S_ISFIFO(status.st_mode) ) )
|
|
{
|
|
if ( connect(pPipe->m_Socket,(struct sockaddr *)&addr,len) >= 0 )
|
|
{
|
|
OSL_TRACE("osl_createPipe : Pipe already in use. Errno: %d; %s\n",errno,strerror(errno));
|
|
close (pPipe->m_Socket);
|
|
__osl_destroyPipeImpl(pPipe);
|
|
return NULL;
|
|
}
|
|
|
|
unlink(name);
|
|
}
|
|
|
|
/* ok, fs clean */
|
|
if ( bind(pPipe->m_Socket, (struct sockaddr *)&addr, len) < 0 )
|
|
{
|
|
OSL_TRACE("osl_createPipe : failed to bind socket. Errno: %d; %s\n",errno,strerror(errno));
|
|
close (pPipe->m_Socket);
|
|
__osl_destroyPipeImpl(pPipe);
|
|
return NULL;
|
|
}
|
|
|
|
/* Only give access to all if no security handle was specified, otherwise security
|
|
depends on umask */
|
|
|
|
if ( !Security )
|
|
chmod(name,S_IRWXU | S_IRWXG |S_IRWXO);
|
|
|
|
|
|
strncpy(pPipe->m_Name, name, sizeof(pPipe->m_Name));
|
|
|
|
if ( listen(pPipe->m_Socket, 5) < 0 )
|
|
{
|
|
OSL_TRACE("osl_createPipe failed to listen. Errno: %d; %s\n",errno,strerror(errno));
|
|
unlink(name); /* remove filesystem entry */
|
|
close (pPipe->m_Socket);
|
|
__osl_destroyPipeImpl(pPipe);
|
|
return NULL;
|
|
}
|
|
|
|
return (pPipe);
|
|
}
|
|
else
|
|
{ /* osl_pipe_OPEN */
|
|
if ( access(name, F_OK) != -1 )
|
|
{
|
|
if ( connect( pPipe->m_Socket, (struct sockaddr *)&addr, len) >= 0 )
|
|
{
|
|
return (pPipe);
|
|
}
|
|
|
|
OSL_TRACE("osl_createPipe failed to connect. Errno: %d; %s\n",errno,strerror(errno));
|
|
}
|
|
|
|
close (pPipe->m_Socket);
|
|
__osl_destroyPipeImpl(pPipe);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
void SAL_CALL osl_acquirePipe( oslPipe pPipe )
|
|
{
|
|
osl_incrementInterlockedCount( &(pPipe->m_nRefCount) );
|
|
}
|
|
|
|
void SAL_CALL osl_releasePipe( oslPipe pPipe )
|
|
{
|
|
|
|
if( 0 == pPipe )
|
|
return;
|
|
|
|
if( 0 == osl_decrementInterlockedCount( &(pPipe->m_nRefCount) ) )
|
|
{
|
|
if( ! pPipe->m_bClosed )
|
|
osl_closePipe( pPipe );
|
|
|
|
__osl_destroyPipeImpl( pPipe );
|
|
}
|
|
}
|
|
|
|
void SAL_CALL osl_closePipe( oslPipe pPipe )
|
|
{
|
|
int nRet;
|
|
#if defined(LINUX)
|
|
size_t len;
|
|
struct sockaddr_un addr;
|
|
int fd;
|
|
#endif
|
|
int ConnFD;
|
|
|
|
if( ! pPipe )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if( pPipe->m_bClosed )
|
|
{
|
|
return;
|
|
}
|
|
|
|
ConnFD = pPipe->m_Socket;
|
|
|
|
/*
|
|
Thread does not return from accept on linux, so
|
|
connect to the accepting pipe
|
|
*/
|
|
#if defined(LINUX)
|
|
if ( pPipe->m_bIsAccepting )
|
|
{
|
|
pPipe->m_bIsInShutdown = sal_True;
|
|
pPipe->m_Socket = -1;
|
|
fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
|
memset(&addr, 0, sizeof(addr));
|
|
|
|
OSL_TRACE("osl_destroyPipe : Pipe Name '%s'",pPipe->m_Name);
|
|
|
|
addr.sun_family = AF_UNIX;
|
|
strncpy(addr.sun_path, pPipe->m_Name, sizeof(addr.sun_path));
|
|
len = sizeof(addr);
|
|
|
|
nRet = connect( fd, (struct sockaddr *)&addr, len);
|
|
#if OSL_DEBUG_LEVEL > 1
|
|
if ( nRet < 0 )
|
|
{
|
|
perror("connect in osl_destroyPipe");
|
|
}
|
|
#endif /* OSL_DEBUG_LEVEL */
|
|
close(fd);
|
|
}
|
|
#endif /* LINUX */
|
|
|
|
|
|
nRet = shutdown(ConnFD, 2);
|
|
if ( nRet < 0 )
|
|
{
|
|
OSL_TRACE("shutdown in destroyPipe failed : '%s'\n",strerror(errno));
|
|
}
|
|
|
|
nRet = close(ConnFD);
|
|
if ( nRet < 0 )
|
|
{
|
|
OSL_TRACE("close in destroyPipe failed : '%s'\n",strerror(errno));
|
|
}
|
|
/* remove filesystem entry */
|
|
if ( strlen(pPipe->m_Name) > 0 )
|
|
{
|
|
unlink(pPipe->m_Name);
|
|
}
|
|
pPipe->m_bClosed = sal_True;
|
|
|
|
/* OSL_TRACE("Out osl_destroyPipe"); */
|
|
}
|
|
|
|
|
|
/*****************************************************************************/
|
|
/* osl_acceptPipe */
|
|
/*****************************************************************************/
|
|
oslPipe SAL_CALL osl_acceptPipe(oslPipe pPipe)
|
|
{
|
|
int s, flags;
|
|
oslPipe pAcceptedPipe;
|
|
|
|
OSL_ASSERT(pPipe);
|
|
if ( pPipe == 0 )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
OSL_ASSERT(strlen(pPipe->m_Name) > 0);
|
|
|
|
#if defined(LINUX)
|
|
pPipe->m_bIsAccepting = sal_True;
|
|
#endif
|
|
|
|
s = accept(pPipe->m_Socket, NULL, NULL);
|
|
|
|
#if defined(LINUX)
|
|
pPipe->m_bIsAccepting = sal_False;
|
|
#endif
|
|
|
|
if (s < 0)
|
|
{
|
|
OSL_TRACE("osl_acceptPipe : accept error '%s'", strerror(errno));
|
|
return NULL;
|
|
}
|
|
|
|
#if defined(LINUX)
|
|
if ( pPipe->m_bIsInShutdown )
|
|
{
|
|
close(s);
|
|
return NULL;
|
|
}
|
|
#endif /* LINUX */
|
|
else
|
|
{
|
|
/* alloc memory */
|
|
pAcceptedPipe= __osl_createPipeImpl();
|
|
|
|
OSL_ASSERT(pAcceptedPipe);
|
|
if(pAcceptedPipe==NULL)
|
|
{
|
|
close(s);
|
|
return NULL;
|
|
}
|
|
|
|
/* set close-on-exec flag */
|
|
if (!((flags = fcntl(s, F_GETFD, 0)) < 0))
|
|
{
|
|
flags |= FD_CLOEXEC;
|
|
if (fcntl(s, F_SETFD, flags) < 0)
|
|
{
|
|
OSL_TRACE("osl_acceptPipe: error changing socket flags. "
|
|
"Errno: %d; %s",errno,strerror(errno));
|
|
}
|
|
}
|
|
|
|
pAcceptedPipe->m_Socket = s;
|
|
}
|
|
|
|
return pAcceptedPipe;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/* osl_receivePipe */
|
|
/*****************************************************************************/
|
|
sal_Int32 SAL_CALL osl_receivePipe(oslPipe pPipe,
|
|
void* pBuffer,
|
|
sal_Int32 BytesToRead)
|
|
{
|
|
int nRet = 0;
|
|
|
|
OSL_ASSERT(pPipe);
|
|
|
|
if ( pPipe == 0 )
|
|
{
|
|
OSL_TRACE("osl_receivePipe : Invalid socket");
|
|
errno=EINVAL;
|
|
return -1;
|
|
}
|
|
|
|
nRet = recv(pPipe->m_Socket,
|
|
(sal_Char*)pBuffer,
|
|
BytesToRead, 0);
|
|
|
|
if ( nRet <= 0 )
|
|
{
|
|
OSL_TRACE("osl_receivePipe failed : %i '%s'",nRet,strerror(errno));
|
|
}
|
|
|
|
return nRet;
|
|
}
|
|
|
|
|
|
/*****************************************************************************/
|
|
/* osl_sendPipe */
|
|
/*****************************************************************************/
|
|
sal_Int32 SAL_CALL osl_sendPipe(oslPipe pPipe,
|
|
const void* pBuffer,
|
|
sal_Int32 BytesToSend)
|
|
{
|
|
int nRet=0;
|
|
|
|
OSL_ASSERT(pPipe);
|
|
|
|
if ( pPipe == 0 )
|
|
{
|
|
OSL_TRACE("osl_sendPipe : Invalid socket");
|
|
errno=EINVAL;
|
|
return -1;
|
|
}
|
|
|
|
nRet = send(pPipe->m_Socket,
|
|
(sal_Char*)pBuffer,
|
|
BytesToSend, 0);
|
|
|
|
|
|
if ( nRet <= 0 )
|
|
{
|
|
OSL_TRACE("osl_sendPipe failed : %i '%s'",nRet,strerror(errno));
|
|
}
|
|
|
|
return nRet;
|
|
}
|
|
|
|
|
|
/*****************************************************************************/
|
|
/* osl_getLastPipeError */
|
|
/*****************************************************************************/
|
|
oslPipeError SAL_CALL osl_getLastPipeError(oslPipe pPipe)
|
|
{
|
|
(void) pPipe; /* unused */
|
|
return ERROR_FROM_NATIVE(errno);
|
|
}
|
|
|
|
|
|
sal_Int32 SAL_CALL osl_writePipe( oslPipe pPipe, const void *pBuffer , sal_Int32 n )
|
|
{
|
|
/* loop until all desired bytes were send or an error occured */
|
|
sal_Int32 BytesSend= 0;
|
|
sal_Int32 BytesToSend= n;
|
|
|
|
OSL_ASSERT(pPipe);
|
|
while (BytesToSend > 0)
|
|
{
|
|
sal_Int32 RetVal;
|
|
|
|
RetVal= osl_sendPipe(pPipe, pBuffer, BytesToSend);
|
|
|
|
/* error occured? */
|
|
if(RetVal <= 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
BytesToSend -= RetVal;
|
|
BytesSend += RetVal;
|
|
pBuffer= (sal_Char*)pBuffer + RetVal;
|
|
}
|
|
|
|
return BytesSend;
|
|
}
|
|
|
|
sal_Int32 SAL_CALL osl_readPipe( oslPipe pPipe, void *pBuffer , sal_Int32 n )
|
|
{
|
|
/* loop until all desired bytes were read or an error occured */
|
|
sal_Int32 BytesRead= 0;
|
|
sal_Int32 BytesToRead= n;
|
|
|
|
OSL_ASSERT( pPipe );
|
|
while (BytesToRead > 0)
|
|
{
|
|
sal_Int32 RetVal;
|
|
RetVal= osl_receivePipe(pPipe, pBuffer, BytesToRead);
|
|
|
|
/* error occured? */
|
|
if(RetVal <= 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
BytesToRead -= RetVal;
|
|
BytesRead += RetVal;
|
|
pBuffer= (sal_Char*)pBuffer + RetVal;
|
|
}
|
|
return BytesRead;
|
|
}
|
|
|
|
|