summaryrefslogtreecommitdiffstats
path: root/sal/osl/unx/socket.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sal/osl/unx/socket.cxx')
-rw-r--r--sal/osl/unx/socket.cxx2046
1 files changed, 2046 insertions, 0 deletions
diff --git a/sal/osl/unx/socket.cxx b/sal/osl/unx/socket.cxx
new file mode 100644
index 000000000..535c1727c
--- /dev/null
+++ b/sal/osl/unx/socket.cxx
@@ -0,0 +1,2046 @@
+/* -*- 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 <osl/mutex.h>
+#include <osl/signal.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 <poll.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&0xffff);
+ 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
+{
+oslSocketResult lcl_getLocalHostname(rtl_uString **ustrLocalHostname, bool bUseFQDN)
+{
+ static auto const init = [bUseFQDN]() -> std::pair<oslSocketResult, OUString> {
+ 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()};
+ }();
+
+ rtl_uString_assign(ustrLocalHostname,init.second.pData);
+
+ return init.first;
+}
+}
+
+oslSocketResult SAL_CALL osl_getLocalHostname(rtl_uString **ustrLocalHostname)
+{
+ return lcl_getLocalHostname(ustrLocalHostname, false);
+}
+
+oslSocketResult osl_getLocalHostnameFQDN(rtl_uString **ustrLocalHostname)
+{
+ return lcl_getLocalHostname(ustrLocalHostname, true);
+}
+
+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: */