Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/LibreOffice/sal/osl/unx/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 15 kB image not shown  

Quelle  pipe.cxx   Sprache: C

 
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */


#include <o3tl/safeint.hxx>
#include <osl/pipe.h>
#include <osl/diagnose.h>
#include <osl/thread.h>
#include <osl/interlck.h>
#include <rtl/string.h>
#include <rtl/ustring.h>
#include <rtl/bootstrap.hxx>
#include <sal/log.hxx>

#include "sockimpl.hxx"
#include "secimpl.hxx"
#include "unixerrnostring.hxx"

#include <cassert>
#include <cstring>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>

constexpr OString PIPEDEFAULTPATH = "/tmp"_ostr;
constexpr OString PIPEALTERNATEPATH = "/var/tmp"_ostr;

static oslPipe osl_psz_createPipe(const char *pszPipeName, oslPipeOptions Options, oslSecurity Security);

struct
{
    int            errcode;
    oslPipeError   error;
const 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 */
#ifdef ESOCKTNOSUPPORT
    { ESOCKTNOSUPPORT, osl_Pipe_E_NoProtocol        },  /* Socket type not supported */
#endif
    { 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      }
};

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;
}

static oslPipe createPipeImpl()
{
    oslPipe pPipeImpl = new oslPipeImpl;

    pPipeImpl->m_Socket = 0;
    pPipeImpl->m_Name[0] = 0;
    pPipeImpl->m_nRefCount = 1;
    pPipeImpl->m_bClosed = false;
#if defined(CLOSESOCKET_DOESNT_WAKE_UP_ACCEPT)
    pPipeImpl->m_bIsInShutdown = false;
    pPipeImpl->m_bIsAccepting = false;
#endif

    return pPipeImpl;
}

static void destroyPipeImpl(oslPipe pImpl)
{
    delete pImpl;
}

oslPipe SAL_CALL osl_createPipe(rtl_uString *ustrPipeName, oslPipeOptions Options, oslSecurity Security)
{
    oslPipe pPipe = nullptr;
    rtl_String* strPipeName = nullptr;

    if (ustrPipeName)
    {
        rtl_uString2String(&strPipeName,
                           rtl_uString_getStr(ustrPipeName),
                           rtl_uString_getLength(ustrPipeName),
                           osl_getThreadTextEncoding(),
                           OUSTRING_TO_OSTRING_CVTFLAGS);
        char* pszPipeName = rtl_string_getStr(strPipeName);
        pPipe = osl_psz_createPipe(pszPipeName, Options, Security);

        if (strPipeName)
            rtl_string_release(strPipeName);
    }

    return pPipe;

}

static OString
getBootstrapSocketPath()
{
    OUString pValue;

    if (rtl::Bootstrap::get(u"OSL_SOCKET_PATH"_ustr, pValue))
    {
        return OUStringToOString(pValue, RTL_TEXTENCODING_UTF8);
    }
    return ""_ostr;
}

static oslPipe osl_psz_createPipe(const char *pszPipeName, oslPipeOptions Options,
                                    oslSecurity Security)
{
    int Flags;
    size_t len;
    struct sockaddr_un addr;

    OString name;
    oslPipe pPipe;

    if (access(PIPEDEFAULTPATH.getStr(), W_OK) == 0)
        name = PIPEDEFAULTPATH;
    else if (access(PIPEALTERNATEPATH.getStr(), W_OK) == 0)
        name = PIPEALTERNATEPATH;
    else {
        name = getBootstrapSocketPath ();
    }

    name += "/";

    if (Security)
    {
        char Ident[256];

        Ident[0] = '\0';

        OSL_VERIFY(osl_psz_getUserIdent(Security, Ident, sizeof(Ident)));

        name += OString::Concat("OSL_PIPE_") + Ident + "_" + pszPipeName;
    }
    else
    {
        name += OString::Concat("OSL_PIPE_") + pszPipeName;
    }

    if (o3tl::make_unsigned(name.getLength()) >= sizeof addr.sun_path)
    {
        SAL_WARN("sal.osl.pipe""osl_createPipe: pipe name too long");
        return nullptr;
    }

    /* alloc memory */
    pPipe = createPipeImpl();

    if (!pPipe)
        return nullptr;

    /* create socket */
    pPipe->m_Socket = socket(AF_UNIX, SOCK_STREAM, 0);
    if (pPipe->m_Socket < 0)
    {
        SAL_WARN("sal.osl.pipe""socket() failed: " << UnixErrnoString(errno));
        destroyPipeImpl(pPipe);
        return nullptr;
    }

    /* 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)
        {
            SAL_WARN("sal.osl.pipe""fcntl() failed: " << UnixErrnoString(errno));
        }
    }

    memset(&addr, 0, sizeof(addr));

    SAL_INFO("sal.osl.pipe""new pipe on fd " << pPipe->m_Socket << " '" << name << "'");

    addr.sun_family = AF_UNIX;
    // coverity[fixed_size_dest : FALSE] - safe, see check above
    strcpy(addr.sun_path, name.getStr());
#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.getStr(), &status) == 0) &&
            (S_ISSOCK(status.st_mode) || S_ISFIFO(status.st_mode)))
        {
            if (connect(pPipe->m_Socket, reinterpret_cast< sockaddr* >(&addr), len) >= 0)
            {
                close (pPipe->m_Socket);
                destroyPipeImpl(pPipe);
                return nullptr;
            }

            unlink(name.getStr());
        }

        /* ok, fs clean */
        if (bind(pPipe->m_Socket, reinterpret_cast< sockaddr* >(&addr), len) < 0)
        {
            SAL_WARN("sal.osl.pipe""bind() failed: " << UnixErrnoString(errno));
            close(pPipe->m_Socket);
            destroyPipeImpl(pPipe);
            return nullptr;
        }

        /*  Only give access to all if no security handle was specified, otherwise security
            depends on umask */


        if (!Security)
            (void)chmod(name.getStr(),S_IRWXU | S_IRWXG |S_IRWXO);

        strcpy(pPipe->m_Name, name.getStr()); // safe, see check above

        if (listen(pPipe->m_Socket, 5) < 0)
        {
            SAL_WARN("sal.osl.pipe""listen() failed: " << UnixErrnoString(errno));
            // cid#1255391 warns about unlink(name) after stat(name, &status)
            // above, but the intervening call to bind makes those two clearly
            // unrelated, as it would fail if name existed at that point in
            // time:
            // coverity[toctou] - this is bogus
            unlink(name.getStr());   /* remove filesystem entry */
            close(pPipe->m_Socket);
            destroyPipeImpl(pPipe);
            return nullptr;
        }

        return pPipe;
    }

    /* osl_pipe_OPEN */
    if (access(name.getStr(), F_OK) != -1)
    {
        if (connect(pPipe->m_Socket, reinterpret_cast< sockaddr* >(&addr), len) >= 0)
            return pPipe;

        SAL_WARN("sal.osl.pipe""connect() failed: " << UnixErrnoString(errno));
    }

    close (pPipe->m_Socket);
    destroyPipeImpl(pPipe);
    return nullptr;
}

void SAL_CALL osl_acquirePipe(oslPipe pPipe)
{
    osl_atomic_increment(&(pPipe->m_nRefCount));
}

void SAL_CALL osl_releasePipe(oslPipe pPipe)
{
    if (!pPipe)
        return;

    if (osl_atomic_decrement(&(pPipe->m_nRefCount)) == 0)
    {
        osl_closePipe(pPipe);

        destroyPipeImpl(pPipe);
    }
}

void SAL_CALL osl_closePipe(oslPipe pPipe)
{
    int nRet;
    int ConnFD;

    if (!pPipe)
        return;

    std::unique_lock aGuard(pPipe->m_Mutex);

    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(CLOSESOCKET_DOESNT_WAKE_UP_ACCEPT)
    struct sockaddr_un addr;

    if (pPipe->m_bIsAccepting)
    {
        pPipe->m_bIsInShutdown = true;
        pPipe->m_Socket = -1;

        int fd = socket(AF_UNIX, SOCK_STREAM, 0);
        if (fd < 0)
        {
            SAL_WARN("sal.osl.pipe""socket() failed: " << UnixErrnoString(errno));
            return;
        }

        memset(&addr, 0, sizeof(addr));

        SAL_INFO("sal.osl.pipe""osl_destroyPipe : Pipe Name '" << pPipe->m_Name << "'");

        addr.sun_family = AF_UNIX;
        strcpy(addr.sun_path, pPipe->m_Name); // safe, as both are same size

        nRet = connect(fd, reinterpret_cast< sockaddr* >(&addr), sizeof(addr));
        if (nRet < 0)
            SAL_WARN("sal.osl.pipe""connect() failed: " << UnixErrnoString(errno));

        close(fd);
    }
#endif /* CLOSESOCKET_DOESNT_WAKE_UP_ACCEPT */

    nRet = shutdown(ConnFD, 2);
    if (nRet < 0)
        SAL_WARN("sal.osl.pipe""shutdown() failed: " << UnixErrnoString(errno));

    nRet = close(ConnFD);
    if (nRet < 0)
        SAL_WARN("sal.osl.pipe""close() failed: " << UnixErrnoString(errno));

    /* remove filesystem entry */
    if (pPipe->m_Name[0] != '\0')
        unlink(pPipe->m_Name);

    pPipe->m_bClosed = true;
}

oslPipe SAL_CALL osl_acceptPipe(oslPipe pPipe)
{
    int s;
    oslPipe pAcceptedPipe;

    SAL_WARN_IF(!pPipe, "sal.osl.pipe""invalid pipe");
    if (!pPipe)
        return nullptr;

    int socket;
    {
        // don't hold lock while accepting, so it is possible to close a socket blocked in accept
        std::unique_lock aGuard(pPipe->m_Mutex);

        assert(pPipe->m_Name[0] != '\0');  // you cannot have an empty pipe name
#if defined(CLOSESOCKET_DOESNT_WAKE_UP_ACCEPT)
        pPipe->m_bIsAccepting = true;
#endif

        socket = pPipe->m_Socket;
    }


    s = accept(socket, nullptr, nullptr);

    std::unique_lock aGuard(pPipe->m_Mutex);

#if defined(CLOSESOCKET_DOESNT_WAKE_UP_ACCEPT)
    pPipe->m_bIsAccepting = false;
#endif

    if (s < 0)
    {
        SAL_WARN("sal.osl.pipe""accept() failed: " << UnixErrnoString(errno));
        return nullptr;
    }

#if defined(CLOSESOCKET_DOESNT_WAKE_UP_ACCEPT)
    if (pPipe->m_bIsInShutdown)
    {
        close(s);
        return nullptr;
    }
#endif /* CLOSESOCKET_DOESNT_WAKE_UP_ACCEPT */

    /* alloc memory */
    pAcceptedPipe = createPipeImpl();

    assert(pAcceptedPipe);  // should never be the case that an oslPipe cannot be initialized
    if (!pAcceptedPipe)
    {
        close(s);
        return nullptr;
    }

    /* set close-on-exec flag */
    int flags;
    if ((flags = fcntl(s, F_GETFD, 0)) >= 0)
    {
        flags |= FD_CLOEXEC;
        if (fcntl(s, F_SETFD, flags) < 0)
            SAL_WARN("sal.osl.pipe""fcntl() failed: " <<  UnixErrnoString(errno));
    }

    pAcceptedPipe->m_Socket = s;

    return pAcceptedPipe;
}

sal_Int32 SAL_CALL osl_receivePipe(oslPipe pPipe,
                        void* pBuffer,
                        sal_Int32 BytesToRead)
{
    SAL_WARN_IF(!pPipe, "sal.osl.pipe""osl_receivePipe: invalid pipe");
    if (!pPipe)
    {
        SAL_WARN("sal.osl.pipe""osl_receivePipe: Invalid socket");
        errno=EINVAL;
        return -1;
    }

    int socket;
    {
        // don't hold lock while receiving, so it is possible to close a socket blocked in recv
        std::unique_lock aGuard(pPipe->m_Mutex);
        socket = pPipe->m_Socket;
    }

    sal_Int32 nRet = recv(socket, pBuffer, BytesToRead, 0);

    SAL_WARN_IF(nRet < 0, "sal.osl.pipe""recv() failed: " << UnixErrnoString(errno));

    return nRet;
}

sal_Int32 SAL_CALL osl_sendPipe(oslPipe pPipe,
                       const void* pBuffer,
                       sal_Int32 BytesToSend)
{
    int nRet=0;

    SAL_WARN_IF(!pPipe, "sal.osl.pipe""osl_sendPipe: invalid pipe");
    if (!pPipe)
    {
        SAL_WARN("sal.osl.pipe""osl_sendPipe: Invalid socket");
        errno=EINVAL;
        return -1;
    }

    int socket;
    {
        // don't hold lock while sending, so it is possible to close a socket blocked in send
        std::unique_lock aGuard(pPipe->m_Mutex);
        socket = pPipe->m_Socket;
    }

    nRet = send(socket, pBuffer, BytesToSend, 0);

    if (nRet <= 0)
        SAL_WARN("sal.osl.pipe""send() failed: " << UnixErrnoString(errno));

    return nRet;
}

oslPipeError SAL_CALL osl_getLastPipeError(SAL_UNUSED_PARAMETER oslPipe)
{
    return osl_PipeErrorFromNative(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 occurred */
    sal_Int32 BytesSend = 0;
    sal_Int32 BytesToSend = n;

    SAL_WARN_IF(!pPipe, "sal.osl.pipe""osl_writePipe: invalid pipe"); // osl_sendPipe detects invalid pipe
    while (BytesToSend > 0)
    {
        // coverity[ tainted_data_return : FALSE ] version 2023.12.2
        sal_Int32 RetVal = osl_sendPipe(pPipe, pBuffer, BytesToSend);
        /* error occurred? */
        if (RetVal <= 0)
            break;

        BytesToSend -= RetVal;
        BytesSend += RetVal;
        pBuffer= static_castchar const* >(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 occurred */
    sal_Int32 BytesRead = 0;
    sal_Int32 BytesToRead = n;

    SAL_WARN_IF(!pPipe, "sal.osl.pipe""osl_readPipe: invalid pipe"); // osl_receivePipe detects invalid pipe
    while (BytesToRead > 0)
    {
        // coverity[ tainted_data_return : FALSE ] version 2023.12.2
        sal_Int32 RetVal = osl_receivePipe(pPipe, pBuffer, BytesToRead);
        /* error occurred? */
        if (RetVal <= 0)
            break;

        BytesToRead -= RetVal;
        BytesRead += RetVal;
        pBuffer= static_castchar* >(pBuffer) + RetVal;
    }

    return BytesRead;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Messung V0.5
C=90 H=97 G=93

¤ Dauer der Verarbeitung: 0.2 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.