/* -*- 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 <sal/config.h>
#include <utility>
#include "system.hxx"
#include <osl/socket.h>
#include <rtl/alloc.h>
#include <rtl/byteseq.h>
#include <rtl/ustring.hxx>
#include <assert.h>
#include <sal/types.h>
#include <sal/log.hxx>
#include "sockimpl.hxx"
#include "unixerrnostring.hxx"
#include <oslsocket.hxx>
#include <arpa/inet.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/tcp.h>
#include <poll.h>
#include <unistd.h>
/* defines for shutdown */
#define SD_RECEIVE 0
#define SD_SEND 1
#define SD_BOTH 2
/*
oslSocketAddr is a pointer to a Berkeley struct sockaddr .
I refrained from using sockaddr_in because of possible further
extensions of this socket - interface ( IP - NG ? ) .
The intention was to hide all Berkeley data - structures from
direct access past the osl - interface .
The current implementation is internet ( IP ) centered . All
the constructor - functions ( osl_create . . . ) take parameters
that will probably make sense only in the IP - environment
( e . g . because of using the dotted - address - format ) .
If the interface will be extended to host other protocol -
families , I expect no externally visible changes in the
existing functions . You ' ll probably need only new
constructor - functions who take the different address
formats into consideration ( maybe a long dotted address
or whatever ) .
*/
/* _Note_ that I rely on the fact that oslSocketAddr and struct sockaddr */
/* are the same! I don't like it very much but see no other easy way to */
/* conceal the struct sockaddr from the eyes of the user. */
#define OSL_INVALID_SOCKET -1
#define OSL_SOCKET_ERROR -1
/* Buffer size for getnameinfo */
#define MAX_HOSTBUFFER_SIZE 2048
const unsigned long FamilyMap[]= {
AF_INET, /* osl_Socket_FamilyInet */
AF_IPX, /* osl_Socket_FamilyIpx */
0 /* osl_Socket_FamilyInvalid */
};
static oslAddrFamily osl_AddrFamilyFromNative(sal_uInt32 nativeType)
{
oslAddrFamily i= oslAddrFamily(0 );
while (i != osl_Socket_FamilyInvalid)
{
if (FamilyMap[i] == nativeType)
return i;
i = static_cast <oslAddrFamily>( i + 1 );
}
return i;
}
#define FAMILY_FROM_NATIVE(y) osl_AddrFamilyFromNative(y)
#define FAMILY_TO_NATIVE(x) static_cast <short >(FamilyMap[x])
const sal_uInt32 ProtocolMap[]= {
0 , /* osl_Socket_ProtocolIp */
NSPROTO_IPX, /* osl_Socket_ProtocolIpx */
NSPROTO_SPX, /* osl_Socket_ProtocolSpx */
NSPROTO_SPXII, /* osl_Socket_ProtocolSpxII */
0 /* osl_Socket_ProtocolInvalid */
};
#define PROTOCOL_TO_NATIVE(x) ProtocolMap[x]
const sal_uInt32 TypeMap[]= {
SOCK_STREAM, /* osl_Socket_TypeStream */
SOCK_DGRAM, /* osl_Socket_TypeDgram */
SOCK_RAW, /* osl_Socket_TypeRaw */
SOCK_RDM, /* osl_Socket_TypeRdm */
SOCK_SEQPACKET, /* osl_Socket_TypeSeqPacket */
0 /* osl_Socket_TypeInvalid */
};
static oslSocketType osl_SocketTypeFromNative(sal_uInt32 nativeType)
{
oslSocketType i= oslSocketType(0 );
while (i != osl_Socket_TypeInvalid)
{
if (TypeMap[i] == nativeType)
return i;
i = static_cast <oslSocketType>(i + 1 );
}
return i;
}
#define TYPE_TO_NATIVE(x) TypeMap[x]
#define TYPE_FROM_NATIVE(y) osl_SocketTypeFromNative(y)
const sal_uInt32 OptionMap[]= {
SO_DEBUG, /* osl_Socket_OptionDebug */
SO_ACCEPTCONN, /* osl_Socket_OptionAcceptConn */
SO_REUSEADDR, /* osl_Socket_OptionReuseAddr */
SO_KEEPALIVE, /* osl_Socket_OptionKeepAlive */
SO_DONTROUTE, /* osl_Socket_OptionDontRoute */
SO_BROADCAST, /* osl_Socket_OptionBroadcast */
SO_USELOOPBACK, /* osl_Socket_OptionUseLoopback */
SO_LINGER, /* osl_Socket_OptionLinger */
SO_OOBINLINE, /* osl_Socket_OptionOOBinLine */
SO_SNDBUF, /* osl_Socket_OptionSndBuf */
SO_RCVBUF, /* osl_Socket_OptionRcvBuf */
SO_SNDLOWAT, /* osl_Socket_OptionSndLowat */
SO_RCVLOWAT, /* osl_Socket_OptionRcvLowat */
SO_SNDTIMEO, /* osl_Socket_OptionSndTimeo */
SO_RCVTIMEO, /* osl_Socket_OptionRcvTimeo */
SO_ERROR, /* osl_Socket_OptionError */
SO_TYPE, /* osl_Socket_OptionType */
TCP_NODELAY, /* osl_Socket_OptionTcpNoDelay */
0 /* osl_Socket_OptionInvalid */
};
#define OPTION_TO_NATIVE(x) OptionMap[x]
const sal_uInt32 OptionLevelMap[]= {
SOL_SOCKET, /* osl_Socket_LevelSocket */
IPPROTO_TCP, /* osl_Socket_LevelTcp */
0 /* osl_Socket_LevelInvalid */
};
#define OPTION_LEVEL_TO_NATIVE(x) OptionLevelMap[x]
const sal_uInt32 SocketMsgFlagMap[]= {
0 , /* osl_Socket_MsgNormal */
MSG_OOB, /* osl_Socket_MsgOOB */
MSG_PEEK, /* osl_Socket_MsgPeek */
MSG_DONTROUTE, /* osl_Socket_MsgDontRoute */
MSG_MAXIOVLEN, /* osl_Socket_MsgMaxIOVLen */
0 /* osl_Socket_MsgInvalid */
};
#define MSG_FLAG_TO_NATIVE(x) SocketMsgFlagMap[x]
const sal_uInt32 SocketDirection[]= {
SD_RECEIVE, /* osl_Socket_DirRead */
SD_SEND, /* osl_Socket_DirWrite */
SD_BOTH, /* osl_Socket_DirReadWrite */
0 /* osl_Socket_DirInvalid */
};
#define DIRECTION_TO_NATIVE(x) SocketDirection[x]
const struct
{
int errcode;
oslSocketError error;
} SocketError[]= {
{ 0 , osl_Socket_E_None }, /* no error */
{ ENOTSOCK, osl_Socket_E_NotSocket }, /* Socket operation on non-socket */
{ EDESTADDRREQ, osl_Socket_E_DestAddrReq }, /* Destination address required */
{ EMSGSIZE, osl_Socket_E_MsgSize }, /* Message too long */
{ EPROTOTYPE, osl_Socket_E_Prototype }, /* Protocol wrong type for socket */
{ ENOPROTOOPT, osl_Socket_E_NoProtocol }, /* Protocol not available */
{ EPROTONOSUPPORT, osl_Socket_E_ProtocolNoSupport }, /* Protocol not supported */
#ifdef ESOCKTNOSUPPORT
{ ESOCKTNOSUPPORT, osl_Socket_E_TypeNoSupport }, /* Socket type not supported */
#endif
{ EOPNOTSUPP, osl_Socket_E_OpNotSupport }, /* Operation not supported on socket */
{ EPFNOSUPPORT, osl_Socket_E_PfNoSupport }, /* Protocol family not supported */
{ EAFNOSUPPORT, osl_Socket_E_AfNoSupport }, /* Address family not supported by
protocol family */
{ EADDRINUSE, osl_Socket_E_AddrInUse }, /* Address already in use */
{ EADDRNOTAVAIL, osl_Socket_E_AddrNotAvail }, /* Can't assign requested address */
{ ENETDOWN, osl_Socket_E_NetDown }, /* Network is down */
{ ENETUNREACH, osl_Socket_E_NetUnreachable }, /* Network is unreachable */
{ ENETRESET, osl_Socket_E_NetReset }, /* Network dropped connection because
of reset */
{ ECONNABORTED, osl_Socket_E_ConnAborted }, /* Software caused connection abort */
{ ECONNRESET, osl_Socket_E_ConnReset }, /* Connection reset by peer */
{ ENOBUFS, osl_Socket_E_NoBufferSpace }, /* No buffer space available */
{ EISCONN, osl_Socket_E_IsConnected }, /* Socket is already connected */
{ ENOTCONN, osl_Socket_E_NotConnected }, /* Socket is not connected */
{ ESHUTDOWN, osl_Socket_E_Shutdown }, /* Can't send after socket shutdown */
#ifdef ETOOMANYREFS
{ ETOOMANYREFS, osl_Socket_E_TooManyRefs }, /* Too many references: can't splice */
#endif
{ ETIMEDOUT, osl_Socket_E_TimedOut }, /* Connection timed out */
{ ECONNREFUSED, osl_Socket_E_ConnRefused }, /* Connection refused */
{ EHOSTDOWN, osl_Socket_E_HostDown }, /* Host is down */
{ EHOSTUNREACH, osl_Socket_E_HostUnreachable }, /* No route to host */
{ EWOULDBLOCK, osl_Socket_E_WouldBlock }, /* call would block on non-blocking socket */
{ EALREADY, osl_Socket_E_Already }, /* operation already in progress */
{ EINPROGRESS, osl_Socket_E_InProgress }, /* operation now in progress */
{ EAGAIN, osl_Socket_E_WouldBlock }, /* same as EWOULDBLOCK */
{ -1 , osl_Socket_E_InvalidError }
};
static oslSocketError osl_SocketErrorFromNative(int nativeType)
{
int i = 0 ;
while ((SocketError[i].error != osl_Socket_E_InvalidError) &&
(SocketError[i].errcode != nativeType)) i++;
return SocketError[i].error;
}
#define ERROR_FROM_NATIVE(y) osl_SocketErrorFromNative(y)
static oslSocketAddr osl_psz_createInetSocketAddr (
const char * pszDottedAddr, sal_Int32 Port);
static oslHostAddr osl_psz_createHostAddr (
const char *pszHostname, const oslSocketAddr Addr);
static oslHostAddr osl_psz_createHostAddrByName (
const char *pszHostname);
static const char * osl_psz_getHostnameOfHostAddr (
const oslHostAddr Addr);
static oslSocketAddr osl_psz_resolveHostname (
const char * pszHostname);
static sal_Int32 osl_psz_getServicePort (
const char * pszServicename, const char * pszProtocol);
static void osl_psz_getLastSocketErrorDescription (
oslSocket Socket, char * pBuffer, sal_uInt32 BufferSize);
namespace {
int convertToMs(TimeValue const * value) {
return value->Seconds * 1000 + value->Nanosec / 1000000 ; //TODO: overflow
}
}
static oslSocket createSocketImpl()
{
oslSocket pSocket;
pSocket = static_cast <oslSocket>(calloc(1 , sizeof (struct oslSocketImpl)));
pSocket->m_Socket = OSL_INVALID_SOCKET;
pSocket->m_nLastError = 0 ;
pSocket->m_nRefCount = 1 ;
#if defined (CLOSESOCKET_DOESNT_WAKE_UP_ACCEPT)
pSocket->m_bIsAccepting = false ;
#endif
return pSocket;
}
static void destroySocketImpl(oslSocket Socket)
{
if ( Socket != nullptr)
free(Socket);
}
static oslSocketAddr createSocketAddr()
{
oslSocketAddr pAddr = static_cast <oslSocketAddr>(rtl_allocateZeroMemory( sizeof ( struct oslSocketAddrImpl )));
return pAddr;
}
static oslSocketAddr createSocketAddrWithFamily(
oslAddrFamily family, sal_Int32 port, sal_uInt32 nAddr )
{
oslSocketAddr pAddr;
SAL_WARN_IF( family != osl_Socket_FamilyInet, "sal.osl" , "creating socket for non-IP address family" );
pAddr = createSocketAddr();
switch ( family )
{
case osl_Socket_FamilyInet:
{
struct sockaddr_in* pInetAddr= reinterpret_cast <sockaddr_in*>(&pAddr->m_sockaddr);
pInetAddr->sin_family = FAMILY_TO_NATIVE(osl_Socket_FamilyInet);
pInetAddr->sin_addr.s_addr = nAddr;
pInetAddr->sin_port = static_cast <sal_uInt16>(port&0 xffff);
break ;
}
default :
pAddr->m_sockaddr.sa_family = FAMILY_TO_NATIVE(family);
}
return pAddr;
}
static oslSocketAddr createSocketAddrFromSystem( struct sockaddr *pSystemSockAddr )
{
oslSocketAddr pAddr = createSocketAddr();
memcpy( &(pAddr->m_sockaddr), pSystemSockAddr, sizeof ( struct sockaddr ) );
return pAddr;
}
static void destroySocketAddr( oslSocketAddr addr )
{
free( addr );
}
oslSocketAddr SAL_CALL osl_createEmptySocketAddr(oslAddrFamily Family)
{
oslSocketAddr pAddr = nullptr;
/* is it an internet-Addr? */
if (Family == osl_Socket_FamilyInet)
{
pAddr = createSocketAddrWithFamily(Family, 0 , htonl(INADDR_ANY) );
}
else
{
pAddr = createSocketAddrWithFamily( Family , 0 , 0 );
}
return pAddr;
}
oslSocketAddr SAL_CALL osl_copySocketAddr(oslSocketAddr Addr)
{
oslSocketAddr pCopy = nullptr;
if (Addr)
{
pCopy = createSocketAddr();
if (pCopy)
memcpy(&(pCopy->m_sockaddr),&(Addr->m_sockaddr), sizeof (struct sockaddr));
}
return pCopy;
}
sal_Bool SAL_CALL osl_isEqualSocketAddr (
oslSocketAddr Addr1,
oslSocketAddr Addr2)
{
struct sockaddr* pAddr1 = nullptr;
struct sockaddr* pAddr2 = nullptr;
assert(Addr1 && Addr2);
pAddr1 = &(Addr1->m_sockaddr);
pAddr2 = &(Addr2->m_sockaddr);
if (pAddr1 == pAddr2)
{
return true ;
}
if (pAddr1->sa_family == pAddr2->sa_family)
{
switch (pAddr1->sa_family)
{
case AF_INET:
{
struct sockaddr_in* pInetAddr1= reinterpret_cast <sockaddr_in*>(pAddr1);
struct sockaddr_in* pInetAddr2= reinterpret_cast <sockaddr_in*>(pAddr2);
if ((pInetAddr1->sin_family == pInetAddr2->sin_family) &&
(pInetAddr1->sin_addr.s_addr == pInetAddr2->sin_addr.s_addr) &&
(pInetAddr1->sin_port == pInetAddr2->sin_port))
return true ;
[[fallthrough]];
}
default :
{
return (memcmp(pAddr1, pAddr2, sizeof (struct sockaddr)) == 0 );
}
}
}
return false ;
}
oslSocketAddr SAL_CALL osl_createInetBroadcastAddr (
rtl_uString *strDottedAddr,
sal_Int32 Port)
{
sal_uInt32 nAddr = OSL_INADDR_NONE;
oslSocketAddr pAddr;
if (strDottedAddr && strDottedAddr->length)
{
/* Dotted host address for limited broadcast */
rtl_String *pDottedAddr = nullptr;
rtl_uString2String (
&pDottedAddr, strDottedAddr->buffer, strDottedAddr->length,
RTL_TEXTENCODING_UTF8, OUSTRING_TO_OSTRING_CVTFLAGS);
in_addr buf;
if (inet_pton (AF_INET, pDottedAddr->buffer, &buf) == 1 ) {
nAddr = buf.s_addr;
}
rtl_string_release (pDottedAddr);
}
if (nAddr != OSL_INADDR_NONE)
{
/* Limited broadcast */
nAddr = ntohl(nAddr);
if (IN_CLASSA(nAddr))
{
nAddr &= IN_CLASSA_NET;
nAddr |= IN_CLASSA_HOST;
}
else if (IN_CLASSB(nAddr))
{
nAddr &= IN_CLASSB_NET;
nAddr |= IN_CLASSB_HOST;
}
else if (IN_CLASSC(nAddr))
{
nAddr &= IN_CLASSC_NET;
nAddr |= IN_CLASSC_HOST;
}
else
{
/* No broadcast in class D */
return nullptr;
}
nAddr = htonl(nAddr);
}
pAddr = createSocketAddrWithFamily( osl_Socket_FamilyInet, htons(Port), nAddr );
return pAddr;
}
oslSocketAddr SAL_CALL osl_createInetSocketAddr (
rtl_uString *ustrDottedAddr,
sal_Int32 Port)
{
rtl_String* strDottedAddr=nullptr;
oslSocketAddr Addr;
char * pszDottedAddr=nullptr;
if ( ustrDottedAddr != nullptr )
{
rtl_uString2String( &strDottedAddr,
rtl_uString_getStr(ustrDottedAddr),
rtl_uString_getLength(ustrDottedAddr),
RTL_TEXTENCODING_UTF8,
OUSTRING_TO_OSTRING_CVTFLAGS);
pszDottedAddr = rtl_string_getStr(strDottedAddr);
}
Addr = pszDottedAddr ? osl_psz_createInetSocketAddr(pszDottedAddr, Port) : nullptr;
if ( strDottedAddr != nullptr )
{
rtl_string_release(strDottedAddr);
}
return Addr;
}
oslSocketAddr osl_psz_createInetSocketAddr (
const char * pszDottedAddr,
sal_Int32 Port)
{
oslSocketAddr pAddr = nullptr;
in_addr buf;
if (inet_pton(AF_INET, pszDottedAddr, &buf) == 1 )
{
/* valid dotted addr */
pAddr = createSocketAddrWithFamily( osl_Socket_FamilyInet, htons(Port) , buf.s_addr );
}
return pAddr;
}
oslSocketResult SAL_CALL osl_setAddrOfSocketAddr( oslSocketAddr pAddr, sal_Sequence *pByteSeq )
{
oslSocketResult res = osl_Socket_Error;
SAL_WARN_IF( !pAddr, "sal.osl" , "setting address of undefined socket address" );
SAL_WARN_IF( !pByteSeq, "sal.osl" , "setting undefined address for socket address" );
if ( pAddr && pByteSeq )
{
struct sockaddr_in * pSystemInetAddr;
assert( pAddr->m_sockaddr.sa_family == FAMILY_TO_NATIVE( osl_Socket_FamilyInet ) );
assert( pByteSeq->nElements == 4 );
pSystemInetAddr = reinterpret_cast <sockaddr_in *>(&pAddr->m_sockaddr);
memcpy( &(pSystemInetAddr->sin_addr) , pByteSeq->elements , 4 );
res = osl_Socket_Ok;
}
return res;
}
oslSocketResult SAL_CALL osl_getAddrOfSocketAddr( oslSocketAddr pAddr, sal_Sequence **ppByteSeq )
{
oslSocketResult res = osl_Socket_Error;
SAL_WARN_IF( !pAddr, "sal.osl" , "getting address of undefined socket address" );
SAL_WARN_IF( !ppByteSeq, "sal.osl" , "getting address to undefined address pointer" );
if ( pAddr && ppByteSeq )
{
struct sockaddr_in * pSystemInetAddr = reinterpret_cast <sockaddr_in *>(&pAddr->m_sockaddr);
rtl_byte_sequence_constructFromArray( ppByteSeq, reinterpret_cast <sal_Int8 *>(&pSystemInetAddr->sin_addr), 4 );
res = osl_Socket_Ok;
}
return res;
}
/** try to figure out a full-qualified hostname, by adding the current domain
as given by the domainname program to the given hostname .
This function MUST NOT call gethostbyname since pHostName already points
to data returned by gethostname and would be garbled : use gethostname_r
instead !
*/
namespace {
struct oslAddrInfo
{
addrinfo* pAddrInfoList = nullptr;
int nError;
oslAddrInfo(const char * name, bool isInet = false )
{
addrinfo aHints;
memset(&aHints, 0 , sizeof (addrinfo));
if (isInet)
aHints.ai_family = AF_INET;
aHints.ai_flags = AI_CANONNAME;
nError = getaddrinfo(name, nullptr, &aHints, &pAddrInfoList);
}
~oslAddrInfo()
{
if (nError == 0 )
freeaddrinfo(pAddrInfoList);
}
const char * getHostName() const
{
assert(pAddrInfoList);
return pAddrInfoList->ai_canonname;
}
};
}
static bool isFullQualifiedDomainName (const char *pHostName)
{
/* a FQDN (aka 'hostname.domain.top_level_domain' )
* is a name which contains a dot ' . ' in it ( would
* match as well for ' hostname . ' but is good enough
* for now )*/
return strchr( pHostName, int ('.' ) ) != nullptr;
}
static char * getFullQualifiedDomainName (const char *pHostName)
{
char *pFullQualifiedName = nullptr;
if (isFullQualifiedDomainName(pHostName))
{
pFullQualifiedName = strdup(pHostName);
}
else
{
oslAddrInfo aAddrInfo(pHostName);
if (aAddrInfo.nError == 0 )
pFullQualifiedName = strdup(aAddrInfo.getHostName());
}
return pFullQualifiedName;
}
struct oslHostAddrImpl
{
char *pHostName;
oslSocketAddr pSockAddr;
};
static oslHostAddr addrinfoToHostAddr (const addrinfo* ai)
{
if (!ai || !ai->ai_canonname || !ai->ai_addr)
return nullptr;
char * cn = getFullQualifiedDomainName(ai->ai_canonname);
SAL_WARN_IF( !cn, "sal.osl" , "couldn't get full qualified domain name" );
if (cn == nullptr)
return nullptr;
oslSocketAddr pSockAddr = createSocketAddr();
SAL_WARN_IF( !pSockAddr, "sal.osl" , "insufficient memory" );
if (pSockAddr == nullptr)
{
free(cn);
return nullptr;
}
if (ai->ai_family == FAMILY_TO_NATIVE(osl_Socket_FamilyInet))
{
memcpy (
&(pSockAddr->m_sockaddr),
ai->ai_addr,
ai->ai_addrlen);
}
else
{
/* unknown address family */
/* future extensions for new families might be implemented here */
SAL_WARN( "sal.osl" , "unknown address family" );
destroySocketAddr( pSockAddr );
free (cn);
return nullptr;
}
oslHostAddr pAddr = static_cast <oslHostAddr>(malloc(sizeof (struct oslHostAddrImpl)));
SAL_WARN_IF( !pAddr, "sal.osl" , "allocation error" );
if (pAddr == nullptr)
{
destroySocketAddr( pSockAddr );
free (cn);
return nullptr;
}
pAddr->pHostName= cn;
pAddr->pSockAddr= pSockAddr;
return pAddr;
}
oslHostAddr SAL_CALL osl_createHostAddr (
rtl_uString *ustrHostname,
const oslSocketAddr Addr)
{
oslHostAddr HostAddr;
rtl_String* strHostname=nullptr;
char * pszHostName=nullptr;
if ( ustrHostname != nullptr )
{
rtl_uString2String( &strHostname,
rtl_uString_getStr(ustrHostname),
rtl_uString_getLength(ustrHostname),
RTL_TEXTENCODING_UTF8,
OUSTRING_TO_OSTRING_CVTFLAGS );
pszHostName = rtl_string_getStr(strHostname);
}
HostAddr = osl_psz_createHostAddr(pszHostName,Addr);
if ( strHostname != nullptr )
{
rtl_string_release(strHostname);
}
return HostAddr;
}
oslHostAddr osl_psz_createHostAddr (
const char *pszHostname,
const oslSocketAddr pAddr)
{
oslHostAddr pHostAddr;
char *cn;
SAL_WARN_IF( !pszHostname, "sal.osl" , "undefined hostname" );
SAL_WARN_IF( !pAddr, "sal.osl" , "undefined address" );
if ((pszHostname == nullptr) || (pAddr == nullptr))
return nullptr;
cn = strdup(pszHostname);
SAL_WARN_IF( !cn, "sal.osl" , "insufficient memory" );
if (cn == nullptr)
return nullptr;
pHostAddr= static_cast <oslHostAddr>(malloc(sizeof (struct oslHostAddrImpl)));
SAL_WARN_IF( !pHostAddr, "sal.osl" , "allocation error" );
if (pHostAddr == nullptr)
{
free (cn);
return nullptr;
}
pHostAddr->pHostName= cn;
pHostAddr->pSockAddr= osl_copySocketAddr( pAddr );
return pHostAddr;
}
oslHostAddr SAL_CALL osl_createHostAddrByName(rtl_uString *ustrHostname)
{
oslHostAddr HostAddr;
rtl_String* strHostname=nullptr;
char * pszHostName=nullptr;
if ( ustrHostname != nullptr )
{
rtl_uString2String( &strHostname,
rtl_uString_getStr(ustrHostname),
rtl_uString_getLength(ustrHostname),
RTL_TEXTENCODING_UTF8,
OUSTRING_TO_OSTRING_CVTFLAGS );
pszHostName=rtl_string_getStr(strHostname);
}
HostAddr = osl_psz_createHostAddrByName(pszHostName);
if ( strHostname != nullptr )
{
rtl_string_release(strHostname);
}
return HostAddr;
}
oslHostAddr osl_psz_createHostAddrByName (const char *pszHostname)
{
oslAddrInfo aAddrInfo(pszHostname, /* isInet */ true);
return addrinfoToHostAddr (aAddrInfo.pAddrInfoList);
}
oslHostAddr SAL_CALL osl_createHostAddrByAddr (const oslSocketAddr pAddr)
{
SAL_WARN_IF( !pAddr, "sal.osl" , "undefined address" );
if (pAddr == nullptr)
return nullptr;
if (pAddr->m_sockaddr.sa_family == FAMILY_TO_NATIVE(osl_Socket_FamilyInet))
{
const struct sockaddr_in *sin = reinterpret_cast <sockaddr_in *>(&pAddr->m_sockaddr);
if (sin->sin_addr.s_addr == htonl(INADDR_ANY))
return nullptr;
char host[MAX_HOSTBUFFER_SIZE];
int res = getnameinfo(&pAddr->m_sockaddr, sizeof (struct sockaddr_in),
host, sizeof (host), nullptr, 0 , NI_NAMEREQD);
if (res != 0 )
return nullptr;
char *cn = getFullQualifiedDomainName(host);
SAL_WARN_IF( !cn, "sal.osl" , "couldn't get full qualified domain name" );
if (cn == nullptr)
return nullptr;
oslSocketAddr pSockAddr = createSocketAddr();
SAL_WARN_IF( !pSockAddr, "sal.osl" , "insufficient memory" );
if (pSockAddr == nullptr)
{
free(cn);
return nullptr;
}
memcpy(&pSockAddr->m_sockaddr, &pAddr->m_sockaddr, sizeof (pAddr->m_sockaddr));
oslHostAddr pHostAddr = static_cast <oslHostAddr>(malloc(sizeof (struct oslHostAddrImpl)));
SAL_WARN_IF( !pAddr, "sal.osl" , "allocation error" );
if (pHostAddr == nullptr)
{
destroySocketAddr(pSockAddr);
free(cn);
return nullptr;
}
pHostAddr->pHostName = cn;
pHostAddr->pSockAddr = pSockAddr;
return pHostAddr;
}
return nullptr;
}
oslHostAddr SAL_CALL osl_copyHostAddr (const oslHostAddr pAddr)
{
SAL_WARN_IF( !pAddr, "sal.osl" , "undefined address" );
if (pAddr)
return osl_psz_createHostAddr (pAddr->pHostName, pAddr->pSockAddr);
return nullptr;
}
void SAL_CALL osl_getHostnameOfHostAddr (
const oslHostAddr Addr,
rtl_uString **ustrHostname)
{
const char * pHostname = osl_psz_getHostnameOfHostAddr(Addr);
rtl_uString_newFromAscii (ustrHostname, pHostname);
}
const char * osl_psz_getHostnameOfHostAddr (const oslHostAddr pAddr)
{
if (pAddr)
return pAddr->pHostName;
return nullptr;
}
oslSocketAddr SAL_CALL osl_getSocketAddrOfHostAddr (const oslHostAddr pAddr)
{
SAL_WARN_IF( !pAddr, "sal.osl" , "undefined address" );
if (pAddr)
return pAddr->pSockAddr;
return nullptr;
}
void SAL_CALL osl_destroyHostAddr (oslHostAddr pAddr)
{
if (pAddr)
{
if (pAddr->pHostName)
free (pAddr->pHostName);
if (pAddr->pSockAddr)
osl_destroySocketAddr (pAddr->pSockAddr);
free (pAddr);
}
}
namespace
{
std::pair<oslSocketResult, OUString> lcl_getLocalHostname(bool bUseFQDN)
{
char LocalHostname[256 ] = "" ;
#ifdef SYSV
struct utsname uts;
if (uname(&uts) < 0 )
return {osl_Socket_Error, OUString()};
if ((strlen(uts.nodename) + 1 ) > nBufLen)
return {osl_Socket_Error, OUString()};
strncpy(LocalHostname, uts.nodename, sizeof ( LocalHostname ));
#else /* BSD compatible */
if (gethostname(LocalHostname, sizeof (LocalHostname)-1 ) != 0 )
return {osl_Socket_Error, OUString()};
#endif /* SYSV */
LocalHostname[sizeof (LocalHostname)-1 ] = 0 ;
/* check if we have an FQDN */
if (bUseFQDN && strchr(LocalHostname, '.' ) == nullptr)
{
oslHostAddr Addr;
/* no, determine it via dns */
Addr = osl_psz_createHostAddrByName(LocalHostname);
const char *pStr;
if ((pStr = osl_psz_getHostnameOfHostAddr(Addr)) != nullptr)
{
strncpy(LocalHostname, pStr, sizeof ( LocalHostname ));
LocalHostname[sizeof (LocalHostname)-1 ] = 0 ;
}
osl_destroyHostAddr(Addr);
}
if (LocalHostname[0 ] != '\0' )
{
return {osl_Socket_Ok, OUString::createFromAscii(LocalHostname)};
}
return {osl_Socket_Error, OUString()};
}
} // anonymous namespace
oslSocketResult SAL_CALL osl_getLocalHostname(rtl_uString **ustrLocalHostname)
{
static auto const init = lcl_getLocalHostname(/*bUseFQDN*/false);
rtl_uString_assign(ustrLocalHostname,init.second.pData);
return init.first;
}
oslSocketResult osl_getLocalHostnameFQDN(rtl_uString **ustrLocalHostname)
{
static auto const init = lcl_getLocalHostname(/*bUseFQDN*/true);
rtl_uString_assign(ustrLocalHostname,init.second.pData);
return init.first;
}
oslSocketAddr SAL_CALL osl_resolveHostname(rtl_uString *ustrHostname)
{
oslSocketAddr Addr;
rtl_String* strHostname=nullptr;
char * pszHostName=nullptr;
if ( ustrHostname != nullptr )
{
rtl_uString2String( &strHostname,
rtl_uString_getStr(ustrHostname),
rtl_uString_getLength(ustrHostname),
RTL_TEXTENCODING_UTF8,
OUSTRING_TO_OSTRING_CVTFLAGS );
pszHostName = rtl_string_getStr(strHostname);
}
Addr = osl_psz_resolveHostname(pszHostName);
if ( strHostname != nullptr )
{
rtl_string_release(strHostname);
}
return Addr;
}
oslSocketAddr osl_psz_resolveHostname(const char * pszHostname)
{
struct oslHostAddrImpl *pAddr = osl_psz_createHostAddrByName(pszHostname);
if (pAddr)
{
oslSocketAddr SockAddr = osl_copySocketAddr(pAddr->pSockAddr);
osl_destroyHostAddr(pAddr);
return SockAddr;
}
return nullptr;
}
sal_Int32 SAL_CALL osl_getServicePort(rtl_uString *ustrServicename, rtl_uString *ustrProtocol)
{
sal_Int32 nPort;
rtl_String* strServicename=nullptr;
rtl_String* strProtocol=nullptr;
char * pszServiceName=nullptr;
char * pszProtocol=nullptr;
if ( ustrServicename != nullptr )
{
rtl_uString2String( &strServicename,
rtl_uString_getStr(ustrServicename),
rtl_uString_getLength(ustrServicename),
RTL_TEXTENCODING_UTF8,
OUSTRING_TO_OSTRING_CVTFLAGS );
pszServiceName = rtl_string_getStr(strServicename);
}
if ( ustrProtocol != nullptr )
{
rtl_uString2String( &strProtocol,
rtl_uString_getStr(ustrProtocol),
rtl_uString_getLength(ustrProtocol),
RTL_TEXTENCODING_UTF8,
OUSTRING_TO_OSTRING_CVTFLAGS );
pszProtocol = rtl_string_getStr(strProtocol);
}
nPort = osl_psz_getServicePort(pszServiceName,pszProtocol);
if ( strServicename != nullptr )
{
rtl_string_release(strServicename);
}
if ( strProtocol != nullptr )
{
rtl_string_release(strProtocol);
}
return nPort;
}
sal_Int32 osl_psz_getServicePort(const char * pszServicename,
const char * pszProtocol)
{
struct servent* ps;
ps= getservbyname(pszServicename, pszProtocol);
if (ps != nullptr)
return ntohs(ps->s_port);
return OSL_INVALID_PORT;
}
void SAL_CALL osl_destroySocketAddr(oslSocketAddr pAddr)
{
destroySocketAddr( pAddr );
}
oslAddrFamily SAL_CALL osl_getFamilyOfSocketAddr(oslSocketAddr pAddr)
{
SAL_WARN_IF( !pAddr, "sal.osl" , "undefined address" );
if (pAddr)
return FAMILY_FROM_NATIVE(pAddr->m_sockaddr.sa_family);
return osl_Socket_FamilyInvalid;
}
sal_Int32 SAL_CALL osl_getInetPortOfSocketAddr(oslSocketAddr pAddr)
{
SAL_WARN_IF( !pAddr, "sal.osl" , "undefined address" );
if ( pAddr )
{
struct sockaddr_in* pSystemInetAddr= reinterpret_cast <sockaddr_in*>(&pAddr->m_sockaddr);
if ( pSystemInetAddr->sin_family == FAMILY_TO_NATIVE(osl_Socket_FamilyInet))
return ntohs(pSystemInetAddr->sin_port);
}
return OSL_INVALID_PORT;
}
sal_Bool SAL_CALL osl_setInetPortOfSocketAddr(oslSocketAddr pAddr, sal_Int32 Port)
{
SAL_WARN_IF( !pAddr, "sal.osl" , "undefined address" );
if ( pAddr )
{
struct sockaddr_in* pSystemInetAddr= reinterpret_cast <sockaddr_in*>(&pAddr->m_sockaddr);
if ( pSystemInetAddr->sin_family == FAMILY_TO_NATIVE(osl_Socket_FamilyInet))
{
pSystemInetAddr->sin_port= htons(static_cast <short >(Port));
return true ;
}
}
/* this is not a inet-addr => can't set port */
return false ;
}
oslSocketResult SAL_CALL osl_getHostnameOfSocketAddr(oslSocketAddr Addr, rtl_uString **ustrHostname)
{
oslHostAddr pHostAddr= osl_createHostAddrByAddr(Addr);
if (!pHostAddr)
{
return osl_Socket_Error;
}
rtl_uString_newFromAscii(ustrHostname,pHostAddr->pHostName);
osl_destroyHostAddr(pHostAddr);
return osl_Socket_Ok;
}
oslSocketResult SAL_CALL osl_getDottedInetAddrOfSocketAddr(oslSocketAddr Addr, rtl_uString **ustrDottedInetAddr)
{
if ( !Addr )
{
return osl_Socket_Error;
}
struct sockaddr_in* pSystemInetAddr = reinterpret_cast <sockaddr_in *>(&Addr->m_sockaddr);
if (pSystemInetAddr->sin_family != FAMILY_TO_NATIVE(osl_Socket_FamilyInet))
{
return osl_Socket_Error;
}
char buf[INET_ADDRSTRLEN];
auto const text = inet_ntop(AF_INET, &pSystemInetAddr->sin_addr, buf, INET_ADDRSTRLEN);
assert(text != nullptr);
rtl_uString_newFromAscii(ustrDottedInetAddr,text);
return osl_Socket_Ok;
}
oslSocket SAL_CALL osl_createSocket(
oslAddrFamily Family,
oslSocketType Type,
oslProtocol Protocol)
{
oslSocket pSocket;
/* alloc memory */
pSocket= createSocketImpl();
/* create socket */
pSocket->m_Socket= socket(FAMILY_TO_NATIVE(Family),
TYPE_TO_NATIVE(Type),
PROTOCOL_TO_NATIVE(Protocol));
/* creation failed => free memory */
if (pSocket->m_Socket == OSL_INVALID_SOCKET)
{
int nErrno = errno;
SAL_WARN( "sal.osl" , "socket creation failed: " << UnixErrnoString(nErrno) );
destroySocketImpl(pSocket);
pSocket= nullptr;
}
else
{
sal_Int32 nFlags=0 ;
/* set close-on-exec flag */
if ((nFlags = fcntl(pSocket->m_Socket, F_GETFD, 0 )) != -1 )
{
nFlags |= FD_CLOEXEC;
if (fcntl(pSocket->m_Socket, F_SETFD, nFlags) == -1 )
{
pSocket->m_nLastError=errno;
int nErrno = errno;
SAL_WARN( "sal.osl" , "failed changing socket flags: " << UnixErrnoString(nErrno) );
}
}
else
{
pSocket->m_nLastError=errno;
}
}
return pSocket;
}
void SAL_CALL osl_acquireSocket(oslSocket pSocket)
{
osl_atomic_increment(&(pSocket->m_nRefCount));
}
void SAL_CALL osl_releaseSocket(oslSocket pSocket)
{
if (pSocket && osl_atomic_decrement(&(pSocket->m_nRefCount)) == 0 )
{
#if defined (CLOSESOCKET_DOESNT_WAKE_UP_ACCEPT)
if (pSocket->m_bIsAccepting)
{
SAL_WARN( "sal.osl" , "attempt to destroy socket while accepting" );
return ;
}
#endif /* CLOSESOCKET_DOESNT_WAKE_UP_ACCEPT */
osl_closeSocket(pSocket);
destroySocketImpl(pSocket);
}
}
void SAL_CALL osl_closeSocket(oslSocket pSocket)
{
/* socket already invalid */
if (!pSocket)
return ;
pSocket->m_nLastError=0 ;
sal_Int32 nFD = pSocket->m_Socket;
if (nFD == OSL_INVALID_SOCKET)
return ;
pSocket->m_Socket = OSL_INVALID_SOCKET;
sal_Int32 nRet=0 ;
#if defined (CLOSESOCKET_DOESNT_WAKE_UP_ACCEPT)
pSocket->m_bIsInShutdown = true ;
if (pSocket->m_bIsAccepting)
{
union {
struct sockaddr aSockAddr;
struct sockaddr_in aSockAddrIn;
} s;
socklen_t nSockLen = sizeof (s.aSockAddr);
nRet = getsockname(nFD, &s.aSockAddr, &nSockLen);
if (nRet < 0 )
{
int nErrno = errno;
SAL_WARN( "sal.osl" , "getsockname call failed: " << UnixErrnoString(nErrno) );
}
if (s.aSockAddr.sa_family == AF_INET)
{
if (s.aSockAddrIn.sin_addr.s_addr == htonl(INADDR_ANY))
{
s.aSockAddrIn.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
}
int nConnFD = socket(AF_INET, SOCK_STREAM, 0 );
if (nConnFD < 0 )
{
int nErrno = errno;
SAL_WARN( "sal.osl" , "socket call failed: " << UnixErrnoString(nErrno) );
}
else
{
nRet = connect(nConnFD, &s.aSockAddr, sizeof (s.aSockAddr));
if (nRet < 0 )
{
int nErrno = errno;
SAL_WARN( "sal.osl" , "connect call failed: " << UnixErrnoString(nErrno) );
}
close(nConnFD);
}
}
pSocket->m_bIsAccepting = false ;
}
#endif /* CLOSESOCKET_DOESNT_WAKE_UP_ACCEPT */
nRet=close(nFD);
if (nRet != 0 )
{
pSocket->m_nLastError=errno;
int nErrno = errno;
SAL_WARN( "sal.osl" , "closeSocket close failed: " << UnixErrnoString(nErrno) );
}
pSocket->m_Socket = OSL_INVALID_SOCKET;
}
/* Note from function creator: I rely on the fact that oslSocketAddr and struct sockaddr
are the same ! I don ' t like it very much but see no other easy way to conceal
the struct sockaddr from the eyes of the user. */
oslSocketAddr SAL_CALL osl_getLocalAddrOfSocket(oslSocket pSocket)
{
socklen_t AddrLen;
struct sockaddr Addr;
oslSocketAddr pAddr;
if (pSocket == nullptr) /* ENOTSOCK */
return nullptr;
AddrLen= sizeof (struct sockaddr);
if (getsockname(pSocket->m_Socket, &Addr, &AddrLen) == OSL_SOCKET_ERROR)
return nullptr;
pAddr = createSocketAddrFromSystem( &Addr );
return pAddr;
}
oslSocketAddr SAL_CALL osl_getPeerAddrOfSocket(oslSocket pSocket)
{
socklen_t AddrLen;
struct sockaddr Addr;
SAL_WARN_IF( !pSocket, "sal.osl" , "undefined socket" );
if ( pSocket == nullptr )
{
return nullptr;
}
pSocket->m_nLastError=0 ;
AddrLen= sizeof (struct sockaddr);
if (getpeername(pSocket->m_Socket, &Addr, &AddrLen) == OSL_SOCKET_ERROR)
{
pSocket->m_nLastError=errno;
return nullptr;
}
return createSocketAddrFromSystem( &Addr );
}
sal_Bool SAL_CALL osl_bindAddrToSocket(oslSocket pSocket,
oslSocketAddr pAddr)
{
int nRet;
SAL_WARN_IF( !pSocket, "sal.osl" , "undefined socket" );
SAL_WARN_IF( !pAddr, "sal.osl" , "undefined address" );
if ( pSocket == nullptr || pAddr == nullptr )
{
return false ;
}
pSocket->m_nLastError=0 ;
nRet = bind(pSocket->m_Socket, &(pAddr->m_sockaddr), sizeof (struct sockaddr));
if ( nRet == OSL_SOCKET_ERROR)
{
pSocket->m_nLastError=errno;
return false ;
}
return true ;
}
sal_Bool SAL_CALL osl_listenOnSocket(oslSocket pSocket,
sal_Int32 MaxPendingConnections)
{
int nRet;
SAL_WARN_IF( !pSocket, "sal.osl" , "undefined socket" );
if ( pSocket == nullptr )
{
return false ;
}
pSocket->m_nLastError=0 ;
nRet = listen(pSocket->m_Socket,
MaxPendingConnections == -1 ?
SOMAXCONN :
MaxPendingConnections);
if ( nRet == OSL_SOCKET_ERROR)
{
pSocket->m_nLastError=errno;
return false ;
}
return true ;
}
oslSocketResult SAL_CALL osl_connectSocketTo(oslSocket pSocket,
oslSocketAddr pAddr,
const TimeValue* pTimeout)
{
int ReadyHandles;
SAL_WARN_IF( !pSocket, "sal.osl" , "undefined socket" );
if ( pSocket == nullptr )
{
return osl_Socket_Error;
}
pSocket->m_nLastError=0 ;
if (osl_isNonBlockingMode(pSocket))
{
if (connect(pSocket->m_Socket,
&(pAddr->m_sockaddr),
sizeof (struct sockaddr)) != OSL_SOCKET_ERROR)
return osl_Socket_Ok;
if (errno == EWOULDBLOCK || errno == EINPROGRESS)
{
pSocket->m_nLastError=EINPROGRESS;
return osl_Socket_InProgress;
}
pSocket->m_nLastError=errno;
int nErrno = errno;
SAL_WARN( "sal.osl" , "connection failed: " << UnixErrnoString(nErrno) );
return osl_Socket_Error;
}
/* set socket temporarily to non-blocking */
if ( !osl_enableNonBlockingMode(pSocket, true ) )
SAL_WARN( "sal.osl" , "failed to enable non-blocking mode" );
/* initiate connect */
if (connect(pSocket->m_Socket,
&(pAddr->m_sockaddr),
sizeof (struct sockaddr)) != OSL_SOCKET_ERROR)
{
/* immediate connection */
osl_enableNonBlockingMode(pSocket, false );
return osl_Socket_Ok;
}
/* really an error or just delayed? */
if (errno != EINPROGRESS)
{
pSocket->m_nLastError=errno;
int nErrno = errno;
SAL_WARN( "sal.osl" , "connection failed: " << UnixErrnoString(nErrno) );
osl_enableNonBlockingMode(pSocket, false );
return osl_Socket_Error;
}
/* prepare poll set for socket */
pollfd Set = {pSocket->m_Socket, POLLPRI | POLLOUT, 0 };
/* poll */
ReadyHandles= poll(&Set, 1 ,
pTimeout ? convertToMs(pTimeout) : -1 );
if (ReadyHandles > 0 ) /* connected */
{
if ( (Set.revents & POLLOUT) != 0 )
{
int nErrorCode = 0 ;
socklen_t nErrorSize = sizeof ( nErrorCode );
int nSockOpt;
nSockOpt = getsockopt ( pSocket->m_Socket, SOL_SOCKET, SO_ERROR,
&nErrorCode, &nErrorSize );
if ( (nSockOpt == 0 ) && (nErrorCode == 0 ))
{
osl_enableNonBlockingMode(pSocket, false );
return osl_Socket_Ok;
}
else
{
pSocket->m_nLastError = (nSockOpt == 0 ) ? nErrorCode : errno;
return osl_Socket_Error;
}
}
else
{
return osl_Socket_Error;
}
}
else if (ReadyHandles < 0 ) /* error */
{
if (errno == EBADF) /* most probably interrupted by close() */
{
/* do not access pSockImpl because it is about to be or */
/* already destroyed */
return osl_Socket_Interrupted;
}
pSocket->m_nLastError=errno;
return osl_Socket_Error;
}
else /* timeout */
{
pSocket->m_nLastError=errno;
return osl_Socket_TimedOut;
}
}
oslSocket SAL_CALL osl_acceptConnectionOnSocket(oslSocket pSocket,
oslSocketAddr* ppAddr)
{
struct sockaddr Addr;
int Connection, Flags;
oslSocket pConnectionSockImpl;
socklen_t AddrLen = sizeof (struct sockaddr);
SAL_WARN_IF( !pSocket, "sal.osl" , "undefined socket" );
if ( pSocket == nullptr )
{
return nullptr;
}
pSocket->m_nLastError=0 ;
#if defined (CLOSESOCKET_DOESNT_WAKE_UP_ACCEPT)
pSocket->m_bIsAccepting = true ;
#endif /* CLOSESOCKET_DOESNT_WAKE_UP_ACCEPT */
if ( ppAddr && *ppAddr )
{
osl_destroySocketAddr( *ppAddr );
*ppAddr = nullptr;
}
/* prevent Linux EINTR behaviour */
do
{
Connection = accept(pSocket->m_Socket, &Addr, &AddrLen);
} while (Connection == -1 && errno == EINTR);
/* accept failed? */
if ( Connection == OSL_SOCKET_ERROR )
{
pSocket->m_nLastError=errno;
int nErrno = errno;
SAL_WARN( "sal.osl" , "accept connection failed: " << UnixErrnoString(nErrno) );
#if defined (CLOSESOCKET_DOESNT_WAKE_UP_ACCEPT)
pSocket->m_bIsAccepting = false ;
#endif /* CLOSESOCKET_DOESNT_WAKE_UP_ACCEPT */
return nullptr;
}
assert(AddrLen == sizeof (struct sockaddr));
#if defined (CLOSESOCKET_DOESNT_WAKE_UP_ACCEPT)
if ( pSocket->m_bIsInShutdown )
{
close(Connection);
SAL_WARN( "sal.osl" , "close while accept" );
return nullptr;
}
#endif /* CLOSESOCKET_DOESNT_WAKE_UP_ACCEPT */
if (ppAddr)
{
*ppAddr= createSocketAddrFromSystem(&Addr);
}
/* alloc memory */
pConnectionSockImpl= createSocketImpl();
/* set close-on-exec flag */
if ((Flags = fcntl(Connection, F_GETFD, 0 )) != -1 )
{
Flags |= FD_CLOEXEC;
if (fcntl(Connection, F_SETFD, Flags) == -1 )
{
pSocket->m_nLastError=errno;
int nErrno = errno;
SAL_WARN( "sal.osl" , "fcntl failed: " << UnixErrnoString(nErrno) );
}
}
pConnectionSockImpl->m_Socket = Connection;
pConnectionSockImpl->m_nLastError = 0 ;
#if defined (CLOSESOCKET_DOESNT_WAKE_UP_ACCEPT)
pConnectionSockImpl->m_bIsAccepting = false ;
pSocket->m_bIsAccepting = false ;
#endif /* CLOSESOCKET_DOESNT_WAKE_UP_ACCEPT */
return pConnectionSockImpl;
}
sal_Int32 SAL_CALL osl_receiveSocket(oslSocket pSocket,
void * pBuffer,
sal_uInt32 BytesToRead,
oslSocketMsgFlag Flag)
{
int nRead;
SAL_WARN_IF( !pSocket, "sal.osl" , "undefined socket" );
if ( pSocket == nullptr )
{
return -1 ;
}
pSocket->m_nLastError=0 ;
do
{
nRead = recv(pSocket->m_Socket,
pBuffer,
BytesToRead,
MSG_FLAG_TO_NATIVE(Flag));
} while ( nRead < 0 && errno == EINTR );
if ( nRead < 0 )
{
pSocket->m_nLastError=errno;
int nErrno = errno;
SAL_WARN( "sal.osl" , "receive socket [" << nRead << "] failed: " << UnixErrnoString(nErrno) );
}
else if ( nRead == 0 )
{
SAL_WARN( "sal.osl" , "receive socket [" << nRead << "] failed: EOL" );
}
return nRead;
}
sal_Int32 SAL_CALL osl_receiveFromSocket(oslSocket pSocket,
oslSocketAddr pSenderAddr,
void * pBuffer,
sal_uInt32 BufferSize,
oslSocketMsgFlag Flag)
{
int nRead;
struct sockaddr *pSystemSockAddr = nullptr;
socklen_t AddrLen = 0 ;
if ( pSenderAddr )
{
AddrLen = sizeof ( struct sockaddr );
pSystemSockAddr = &(pSenderAddr->m_sockaddr);
}
SAL_WARN_IF( !pSocket, "sal.osl" , "undefined socket" );
if ( pSocket == nullptr )
{
return -1 ;
}
pSocket->m_nLastError=0 ;
nRead = recvfrom(pSocket->m_Socket,
pBuffer,
BufferSize,
MSG_FLAG_TO_NATIVE(Flag),
pSystemSockAddr,
&AddrLen);
if ( nRead < 0 )
{
pSocket->m_nLastError=errno;
int nErrno = errno;
SAL_WARN( "sal.osl" , "receive socket [" << nRead << "] failed: " << UnixErrnoString(nErrno) );
}
else if ( nRead == 0 )
{
SAL_WARN( "sal.osl" , "receive socket [" << nRead << "] failed: EOL" );
}
return nRead;
}
sal_Int32 SAL_CALL osl_sendSocket(oslSocket pSocket,
const void * pBuffer,
sal_uInt32 BytesToSend,
oslSocketMsgFlag Flag)
{
int nWritten;
SAL_WARN_IF( !pSocket, "sal.osl" , "undefined socket" );
if ( pSocket == nullptr )
{
return -1 ;
}
pSocket->m_nLastError=0 ;
do
{
nWritten = send(pSocket->m_Socket,
pBuffer,
BytesToSend,
MSG_FLAG_TO_NATIVE(Flag));
} while ( nWritten < 0 && errno == EINTR );
if ( nWritten < 0 )
{
pSocket->m_nLastError=errno;
int nErrno = errno;
SAL_WARN( "sal.osl" , "send socket [" << nWritten << "] failed: " << UnixErrnoString(nErrno) );
}
else if ( nWritten == 0 )
{
SAL_WARN( "sal.osl" , "send socket [" << nWritten << "] failed: EOL" );
}
return nWritten;
}
sal_Int32 SAL_CALL osl_sendToSocket(oslSocket pSocket,
oslSocketAddr ReceiverAddr,
const void * pBuffer,
sal_uInt32 BytesToSend,
oslSocketMsgFlag Flag)
{
int nWritten;
struct sockaddr *pSystemSockAddr = nullptr;
int AddrLen = 0 ;
if ( ReceiverAddr )
{
pSystemSockAddr = &(ReceiverAddr->m_sockaddr);
AddrLen = sizeof ( struct sockaddr );
}
SAL_WARN_IF( !pSocket, "sal.osl" , "undefined socket" );
if ( pSocket == nullptr )
{
return -1 ;
}
pSocket->m_nLastError=0 ;
/* ReceiverAddr might be 0 when used on a connected socket. */
/* Then sendto should behave like send. */
nWritten = sendto(pSocket->m_Socket,
pBuffer,
BytesToSend,
MSG_FLAG_TO_NATIVE(Flag),
pSystemSockAddr,
AddrLen);
if ( nWritten < 0 )
{
pSocket->m_nLastError=errno;
int nErrno = errno;
SAL_WARN( "sal.osl" , "send socket [" << nWritten << "] failed: " << UnixErrnoString(nErrno) );
}
else if ( nWritten == 0 )
{
SAL_WARN( "sal.osl" , "send socket [" << nWritten << "] failed: EOL" );
}
return nWritten;
}
sal_Int32 SAL_CALL osl_readSocket (
oslSocket pSocket, void *pBuffer, sal_Int32 n )
{
sal_uInt8 * Ptr = static_cast <sal_uInt8 *>(pBuffer);
sal_uInt32 BytesRead= 0 ;
sal_uInt32 BytesToRead= n;
SAL_WARN_IF( !pSocket, "sal.osl" , "undefined socket" );
/* loop until all desired bytes were read or an error occurred */
while (BytesToRead > 0 )
{
sal_Int32 RetVal;
RetVal= osl_receiveSocket(pSocket,
Ptr,
BytesToRead,
osl_Socket_MsgNormal);
/* error occurred? */
if (RetVal <= 0 )
{
break ;
}
BytesToRead -= RetVal;
BytesRead += RetVal;
Ptr += RetVal;
}
return BytesRead;
}
sal_Int32 SAL_CALL osl_writeSocket(
oslSocket pSocket, const void *pBuffer, sal_Int32 n )
{
/* loop until all desired bytes were send or an error occurred */
sal_uInt32 BytesSend= 0 ;
sal_uInt32 BytesToSend= n;
sal_uInt8 const *Ptr = static_cast <sal_uInt8 const *>(pBuffer);
SAL_WARN_IF( !pSocket, "sal.osl" , "undefined socket" );
while (BytesToSend > 0 )
{
sal_Int32 RetVal;
RetVal= osl_sendSocket( pSocket,Ptr,BytesToSend,osl_Socket_MsgNormal);
/* error occurred? */
if (RetVal <= 0 )
{
break ;
}
BytesToSend -= RetVal;
BytesSend += RetVal;
Ptr += RetVal;
}
return BytesSend;
}
static bool socket_poll (
oslSocket pSocket,
const TimeValue* pTimeout,
short nEvent)
{
struct pollfd fds;
int timeout;
int result;
SAL_WARN_IF( !pSocket, "sal.osl" , "undefined socket" );
if (pSocket == nullptr)
return false ; /* EINVAL */
pSocket->m_nLastError = 0 ;
fds.fd = pSocket->m_Socket;
fds.events = nEvent;
fds.revents = 0 ;
timeout = -1 ;
if (pTimeout)
{
timeout = convertToMs(pTimeout);
}
result = poll (&fds, 1 , timeout);
if (result < 0 )
{
pSocket->m_nLastError = errno;
int nErrno = errno;
SAL_WARN( "sal.osl" , "poll failed: " << UnixErrnoString(nErrno) );
return false ;
}
if (result == 0 )
{
/* Timeout */
return false ;
}
return ((fds.revents & nEvent) == nEvent);
}
sal_Bool SAL_CALL osl_isReceiveReady (
oslSocket pSocket, const TimeValue* pTimeout)
{
SAL_WARN_IF( !pSocket, "sal.osl" , "undefined socket" );
if (pSocket == nullptr)
{
/* ENOTSOCK */
return false ;
}
return socket_poll (pSocket, pTimeout, POLLIN);
}
sal_Bool SAL_CALL osl_isSendReady (
oslSocket pSocket, const TimeValue* pTimeout)
{
SAL_WARN_IF( !pSocket, "sal.osl" , "undefined socket" );
if (pSocket == nullptr)
{
/* ENOTSOCK */
return false ;
}
return socket_poll (pSocket, pTimeout, POLLOUT);
}
sal_Bool SAL_CALL osl_isExceptionPending (
oslSocket pSocket, const TimeValue* pTimeout)
{
SAL_WARN_IF( !pSocket, "sal.osl" , "undefined socket" );
if (pSocket == nullptr)
{
/* ENOTSOCK */
return false ;
}
return socket_poll (pSocket, pTimeout, POLLPRI);
}
sal_Bool SAL_CALL osl_shutdownSocket(oslSocket pSocket,
oslSocketDirection Direction)
{
int nRet;
SAL_WARN_IF( !pSocket, "sal.osl" , "undefined socket" );
if ( pSocket == nullptr )
{
return false ;
}
pSocket->m_nLastError=0 ;
nRet=shutdown(pSocket->m_Socket, DIRECTION_TO_NATIVE(Direction));
if (nRet != 0 )
{
pSocket->m_nLastError=errno;
int nErrno = errno;
SAL_WARN( "sal.osl" , "shutdown failed: " << UnixErrnoString(nErrno) );
}
return (nRet==0 );
}
sal_Int32 SAL_CALL osl_getSocketOption(oslSocket pSocket,
oslSocketOptionLevel Level,
oslSocketOption Option,
void * pBuffer,
sal_uInt32 BufferLen)
{
socklen_t nOptLen = static_cast <socklen_t>(BufferLen);
SAL_WARN_IF( !pSocket, "sal.osl" , "undefined socket" );
if ( pSocket == nullptr )
{
return -1 ;
}
pSocket->m_nLastError=0 ;
if (getsockopt(pSocket->m_Socket,
OPTION_LEVEL_TO_NATIVE(Level),
OPTION_TO_NATIVE(Option),
pBuffer,
&nOptLen) == -1 )
{
pSocket->m_nLastError=errno;
return -1 ;
}
return nOptLen;
}
sal_Bool SAL_CALL osl_setSocketOption(oslSocket pSocket,
oslSocketOptionLevel Level,
oslSocketOption Option,
void * pBuffer,
sal_uInt32 BufferLen)
{
int nRet;
SAL_WARN_IF( !pSocket, "sal.osl" , "undefined socket" );
if ( pSocket == nullptr )
{
return false ;
}
pSocket->m_nLastError=0 ;
nRet = setsockopt(pSocket->m_Socket,
OPTION_LEVEL_TO_NATIVE(Level),
OPTION_TO_NATIVE(Option),
pBuffer,
BufferLen);
if ( nRet < 0 )
{
pSocket->m_nLastError=errno;
return false ;
}
return true ;
}
sal_Bool SAL_CALL osl_enableNonBlockingMode(oslSocket pSocket,
sal_Bool On)
{
int flags;
int nRet;
SAL_WARN_IF( !pSocket, "sal.osl" , "undefined socket" );
if ( pSocket == nullptr )
{
return false ;
}
pSocket->m_nLastError=0 ;
flags = fcntl(pSocket->m_Socket, F_GETFL, 0 );
if (On)
flags |= O_NONBLOCK;
else
flags &= ~(O_NONBLOCK);
nRet = fcntl(pSocket->m_Socket, F_SETFL, flags);
if ( nRet < 0 )
{
pSocket->m_nLastError=errno;
return false ;
}
return true ;
}
sal_Bool SAL_CALL osl_isNonBlockingMode(oslSocket pSocket)
{
int flags;
SAL_WARN_IF( !pSocket, "sal.osl" , "undefined socket" );
if ( pSocket == nullptr )
{
return false ;
}
pSocket->m_nLastError=0 ;
flags = fcntl(pSocket->m_Socket, F_GETFL, 0 );
if (flags == -1 || !(flags & O_NONBLOCK))
return false ;
return true ;
}
oslSocketType SAL_CALL osl_getSocketType(oslSocket pSocket)
{
int Type=0 ;
socklen_t TypeSize= sizeof (Type);
SAL_WARN_IF( !pSocket, "sal.osl" , "undefined socket" );
if ( pSocket == nullptr )
{
return osl_Socket_TypeInvalid;
}
pSocket->m_nLastError=0 ;
if (getsockopt(pSocket->m_Socket,
OPTION_LEVEL_TO_NATIVE(osl_Socket_LevelSocket),
OPTION_TO_NATIVE(osl_Socket_OptionType),
&Type,
&TypeSize) == -1 )
{
/* error */
pSocket->m_nLastError=errno;
return osl_Socket_TypeInvalid;
}
return TYPE_FROM_NATIVE(Type);
}
void SAL_CALL osl_getLastSocketErrorDescription(oslSocket Socket, rtl_uString **ustrError)
{
char pszError[1024 ];
pszError[0 ] = '\0' ;
osl_psz_getLastSocketErrorDescription(Socket,pszError,sizeof (pszError));
rtl_uString_newFromAscii(ustrError,pszError);
}
void osl_psz_getLastSocketErrorDescription(oslSocket pSocket, char * pBuffer, sal_uInt32 BufferSize)
{
/* make sure pBuffer will be a zero-terminated string even when strncpy has to cut */
pBuffer[BufferSize-1 ]= '\0' ;
if ( pSocket == nullptr )
{
strncpy(pBuffer, strerror(EINVAL), BufferSize-1 );
return ;
}
strncpy(pBuffer, strerror(pSocket->m_nLastError), BufferSize-1 );
}
oslSocketError SAL_CALL osl_getLastSocketError(oslSocket pSocket)
{
if ( pSocket == nullptr )
{
return ERROR_FROM_NATIVE(EINVAL);
}
return ERROR_FROM_NATIVE(pSocket->m_nLastError);
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Messung V0.5 in Prozent C=93 H=96 G=94
¤ Dauer der Verarbeitung: 0.27 Sekunden
(vorverarbeitet am 2026-09-29)
¤
*© Formatika GbR, Deutschland