/* -*- 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 #include #include "system.h" #include #include #include #include #include #include #include #include #include #include "sockimpl.hxx" /* 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-Addr-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 Addr formats into consideration (maybe a long dotted Addr 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 INVALID_SOCKET /* WIN32 */ #define OSL_SOCKET_ERROR SOCKET_ERROR /* WIN32 */ static DWORD FamilyMap[]= { AF_INET, /* osl_Socket_FamilyInet */ AF_IPX, /* osl_Socket_FamilyIpx */ 0 /* osl_Socket_FamilyInvalid */ }; static oslAddrFamily osl_AddrFamilyFromNative(DWORD nativeType) { oslAddrFamily i= oslAddrFamily(0); while(i != osl_Socket_FamilyInvalid) { if(FamilyMap[i] == nativeType) return i; i = static_cast( static_cast(i) + 1); } return i; } #define FAMILY_FROM_NATIVE(y) osl_AddrFamilyFromNative(y) #define FAMILY_TO_NATIVE(x) static_cast(FamilyMap[x]) static DWORD ProtocolMap[]= { 0, /* osl_Socket_FamilyInet */ NSPROTO_IPX, /* osl_Socket_FamilyIpx */ NSPROTO_SPX, /* osl_Socket_ProtocolSpx */ NSPROTO_SPXII, /* osl_Socket_ProtocolSpx_ii */ 0 /* osl_Socket_ProtocolInvalid */ }; #define PROTOCOL_TO_NATIVE(x) ProtocolMap[x] static DWORD 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(DWORD nativeType) { oslSocketType i= oslSocketType(0); while(i != osl_Socket_TypeInvalid) { if(TypeMap[i] == nativeType) return i; i = static_cast(static_cast(i)+1); } return i; } #define TYPE_TO_NATIVE(x) TypeMap[x] #define TYPE_FROM_NATIVE(y) osl_SocketTypeFromNative(y) static DWORD 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] static DWORD OptionLevelMap[]= { SOL_SOCKET, /* osl_Socket_LevelSocket */ IPPROTO_TCP, /* osl_Socket_LevelTcp */ 0 /* osl_invalid_SocketLevel */ }; #define OPTION_LEVEL_TO_NATIVE(x) OptionLevelMap[x] static DWORD 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 */ }; #define MSG_FLAG_TO_NATIVE(x) SocketMsgFlagMap[x] static DWORD SocketDirection[]= { SD_RECEIVE, /* osl_Socket_DirRead */ SD_SEND, /* osl_Socket_DirWrite */ SD_BOTH /* osl_Socket_DirReadwrite */ }; #define DIRECTION_TO_NATIVE(x) SocketDirection[x] static int SocketError[]= { 0, /* no error */ WSAENOTSOCK, /* Socket operation on non-socket */ WSAEDESTADDRREQ, /* Destination address required */ WSAEMSGSIZE, /* Message too long */ WSAEPROTOTYPE, /* Protocol wrong type for socket */ WSAENOPROTOOPT, /* Protocol not available */ WSAEPROTONOSUPPORT, /* Protocol not supported */ WSAESOCKTNOSUPPORT, /* Socket type not supported */ WSAEOPNOTSUPP, /* Operation not supported on socket */ WSAEPFNOSUPPORT, /* Protocol family not supported */ WSAEAFNOSUPPORT, /* Address family not supported by protocol family */ WSAEADDRINUSE, /* Address already in use */ WSAEADDRNOTAVAIL, /* Can't assign requested address */ WSAENETDOWN, /* Network is down */ WSAENETUNREACH, /* Network is unreachable */ WSAENETRESET, /* Network dropped connection because of reset */ WSAECONNABORTED, /* Software caused connection abort */ WSAECONNRESET, /* Connection reset by peer */ WSAENOBUFS, /* No buffer space available */ WSAEISCONN, /* Socket is already connected */ WSAENOTCONN, /* Socket is not connected */ WSAESHUTDOWN, /* Can't send after socket shutdown */ WSAETOOMANYREFS, /* Too many references: can't splice */ WSAETIMEDOUT, /* Connection timed out */ WSAECONNREFUSED, /* Connection refused */ WSAEHOSTDOWN, /* Host is down */ WSAEHOSTUNREACH, /* No route to host */ WSAEWOULDBLOCK, /* call would block on non-blocking socket */ WSAEALREADY, /* operation already in progress */ WSAEINPROGRESS /* operation now in progress */ }; static oslSocketError osl_SocketErrorFromNative(int nativeType) { oslSocketError i= oslSocketError(0); while(i != osl_Socket_E_InvalidError) { if(SocketError[i] == nativeType) return i; i = static_cast( static_cast(i) + 1); } return i; } #define ERROR_FROM_NATIVE(y) osl_SocketErrorFromNative(y) #if OSL_DEBUG_LEVEL > 0 static sal_uInt32 g_nSocketAddr = 0; namespace { struct LeakWarning { ~LeakWarning() { SAL_WARN_IF( g_nSocketAddr, "sal.osl", "sal_socket: " << g_nSocketAddr << " socket address instances leak" ); } }; } static LeakWarning socketWarning; #endif static oslSocket createSocketImpl(SOCKET Socket) { oslSocket pSockImpl = static_cast(rtl_allocateZeroMemory( sizeof(struct oslSocketImpl))); pSockImpl->m_Socket = Socket; pSockImpl->m_nRefCount = 1; return pSockImpl; } static void destroySocketImpl(oslSocketImpl *pImpl) { if (pImpl) { free (pImpl); } } static oslSocketAddr createSocketAddr( ) { oslSocketAddr pAddr = static_cast(rtl_allocateZeroMemory( sizeof( struct oslSocketAddrImpl ))); pAddr->m_nRefCount = 1; #if OSL_DEBUG_LEVEL > 0 g_nSocketAddr ++; #endif return pAddr; } static oslSocketAddr createSocketAddrWithFamily( oslAddrFamily family, sal_Int32 port, sal_uInt32 nAddr ) { OSL_ASSERT( family == osl_Socket_FamilyInet ); oslSocketAddr pAddr = createSocketAddr(); switch( family ) { case osl_Socket_FamilyInet: { struct sockaddr_in* pInetAddr= reinterpret_cast(&pAddr->m_sockaddr); pInetAddr->sin_family = FAMILY_TO_NATIVE(osl_Socket_FamilyInet); pInetAddr->sin_addr.s_addr = nAddr; pInetAddr->sin_port = static_cast(port&0xffff); break; } default: pAddr->m_sockaddr.sa_family = FAMILY_TO_NATIVE(family); } return pAddr; } static oslSocketAddr createSocketAddFromSystem( struct sockaddr *pSystemSockAddr ) { oslSocketAddr pAddr = createSocketAddr(); memcpy( &(pAddr->m_sockaddr), pSystemSockAddr, sizeof( sockaddr ) ); return pAddr; } static void destroySocketAddr( oslSocketAddr addr ) { #if OSL_DEBUG_LEVEL > 0 g_nSocketAddr --; #endif 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; } /** @deprecated, to be removed */ 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) { assert(Addr1); assert(Addr2); struct sockaddr* pAddr1= &(Addr1->m_sockaddr); struct sockaddr* pAddr2= &(Addr2->m_sockaddr); assert(pAddr1); assert(pAddr2); if (pAddr1->sa_family == pAddr2->sa_family) { switch (pAddr1->sa_family) { case AF_INET: { struct sockaddr_in* pInetAddr1= reinterpret_cast(pAddr1); struct sockaddr_in* pInetAddr2= reinterpret_cast(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; if (strDottedAddr && strDottedAddr->length) { IN_ADDR addr; INT ret = InetPtonW(AF_INET, o3tl::toW(strDottedAddr->buffer), & addr); if (1 == ret) { nAddr = addr.S_un.S_addr; } } 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); } oslSocketAddr pAddr = createSocketAddrWithFamily( osl_Socket_FamilyInet, htons( static_cast(Port)), nAddr ); return pAddr; } oslSocketAddr SAL_CALL osl_createInetSocketAddr ( rtl_uString *strDottedAddr, sal_Int32 Port) { sal_uInt32 Addr; IN_ADDR addr; INT ret = InetPtonW(AF_INET, o3tl::toW(strDottedAddr->buffer), & addr); Addr = ret == 1 ? addr.S_un.S_addr : OSL_INADDR_NONE; oslSocketAddr pAddr = nullptr; if(Addr != OSL_INADDR_NONE) { pAddr = createSocketAddrWithFamily( osl_Socket_FamilyInet, htons( static_cast(Port)), Addr ); } return pAddr; } oslSocketResult SAL_CALL osl_setAddrOfSocketAddr( oslSocketAddr pAddr, sal_Sequence *pByteSeq ) { OSL_ASSERT( pAddr ); OSL_ASSERT( pByteSeq ); oslSocketResult res = osl_Socket_Error; if( pAddr && pByteSeq ) { OSL_ASSERT( pAddr->m_sockaddr.sa_family == FAMILY_TO_NATIVE( osl_Socket_FamilyInet ) ); OSL_ASSERT( pByteSeq->nElements == 4 ); struct sockaddr_in * pSystemInetAddr = reinterpret_cast(&pAddr->m_sockaddr); memcpy( &(pSystemInetAddr->sin_addr) , pByteSeq->elements , 4 ); res = osl_Socket_Ok; } return res; } /** Returns the addr field in the struct sockaddr. ppByteSeq is in network byteorder. *ppByteSeq may either be 0 or contain a constructed sal_Sequence. */ oslSocketResult SAL_CALL osl_getAddrOfSocketAddr( oslSocketAddr pAddr, sal_Sequence **ppByteSeq ) { OSL_ASSERT( pAddr ); OSL_ASSERT( ppByteSeq ); oslSocketResult res = osl_Socket_Error; if( pAddr && ppByteSeq ) { struct sockaddr_in * pSystemInetAddr = reinterpret_cast(&pAddr->m_sockaddr); rtl_byte_sequence_constructFromArray( ppByteSeq , reinterpret_cast(&pSystemInetAddr->sin_addr),4); res = osl_Socket_Ok; } return res; } struct oslHostAddrImpl { rtl_uString *pHostName; oslSocketAddr pSockAddr; } ; oslHostAddr SAL_CALL osl_createHostAddr ( rtl_uString *strHostname, const oslSocketAddr pSocketAddr) { oslHostAddr pAddr; rtl_uString *cn= nullptr; if ((strHostname == nullptr) || (strHostname->length == 0) || (pSocketAddr == nullptr)) return nullptr; rtl_uString_newFromString( &cn, strHostname); pAddr= static_cast(malloc (sizeof (struct oslHostAddrImpl))); if (pAddr == nullptr) { rtl_uString_release(cn); return nullptr; } pAddr->pHostName= cn; pAddr->pSockAddr= osl_copySocketAddr( pSocketAddr ); return pAddr; } oslHostAddr SAL_CALL osl_createHostAddrByName(rtl_uString *strHostname) { if ((strHostname == nullptr) || (strHostname->length == 0)) return nullptr; PADDRINFOW pAddrInfo = nullptr; int ret = GetAddrInfoW( o3tl::toW(strHostname->buffer), nullptr, nullptr, & pAddrInfo); if (0 != ret) { SAL_INFO("sal.osl", "GetAddrInfoW failed: " << WSAGetLastError()); return nullptr; } oslHostAddr pRet = nullptr; for (PADDRINFOW pIter = pAddrInfo; pIter; pIter = pIter->ai_next) { if (AF_INET == pIter->ai_family) { pRet = static_cast( rtl_allocateZeroMemory(sizeof(struct oslHostAddrImpl))); if (pIter->ai_canonname == nullptr) { rtl_uString_new(&pRet->pHostName); } else { rtl_uString_newFromStr(&pRet->pHostName, o3tl::toU(pIter->ai_canonname)); } pRet->pSockAddr = createSocketAddr(); memcpy(& pRet->pSockAddr->m_sockaddr, pIter->ai_addr, pIter->ai_addrlen); break; // ignore other results } } FreeAddrInfoW(pAddrInfo); return pRet; } oslHostAddr SAL_CALL osl_createHostAddrByAddr(const oslSocketAddr pAddr) { if (pAddr == nullptr) return nullptr; if (pAddr->m_sockaddr.sa_family != FAMILY_TO_NATIVE(osl_Socket_FamilyInet)) return nullptr; const struct sockaddr_in *sin= reinterpret_cast(&pAddr->m_sockaddr); if (sin->sin_addr.s_addr == htonl(INADDR_ANY)) return nullptr; WCHAR buf[NI_MAXHOST]; int ret = GetNameInfoW( & pAddr->m_sockaddr, sizeof(struct sockaddr), buf, NI_MAXHOST, nullptr, 0, 0); if (0 != ret) { SAL_INFO("sal.osl", "GetNameInfoW failed: " << WSAGetLastError()); return nullptr; } oslHostAddr pRet = static_cast( rtl_allocateZeroMemory(sizeof(struct oslHostAddrImpl))); rtl_uString_newFromStr(&pRet->pHostName, o3tl::toU(buf)); pRet->pSockAddr = createSocketAddr(); memcpy(& pRet->pSockAddr->m_sockaddr, & pAddr->m_sockaddr, sizeof(struct sockaddr)); return pRet; } oslHostAddr SAL_CALL osl_copyHostAddr(const oslHostAddr Addr) { oslHostAddr pAddr = Addr; if (pAddr) return osl_createHostAddr (pAddr->pHostName, pAddr->pSockAddr); else return nullptr; } void SAL_CALL osl_getHostnameOfHostAddr( const oslHostAddr pAddr, rtl_uString **strHostname) { if (pAddr) rtl_uString_assign (strHostname, pAddr->pHostName); else rtl_uString_new (strHostname); } oslSocketAddr SAL_CALL osl_getSocketAddrOfHostAddr(const oslHostAddr pAddr) { if (pAddr) return pAddr->pSockAddr; else return nullptr; } void SAL_CALL osl_destroyHostAddr(oslHostAddr pAddr) { if (pAddr) { if (pAddr->pHostName) rtl_uString_release (pAddr->pHostName); if (pAddr->pSockAddr) osl_destroySocketAddr( pAddr->pSockAddr ); free (pAddr); } } oslSocketResult SAL_CALL osl_getLocalHostname (rtl_uString **strLocalHostname) { static auto const init = []() -> std::pair { sal_Unicode LocalHostname[256] = {0}; char Host[256]= ""; if (gethostname(Host, sizeof(Host)) == 0) { OUString u; if (rtl_convertStringToUString( &u.pData, Host, strlen(Host), osl_getThreadTextEncoding(), (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)) && o3tl::make_unsigned(u.getLength()) < SAL_N_ELEMENTS(LocalHostname)) { memcpy(LocalHostname, u.getStr(), (u.getLength() + 1) * sizeof (sal_Unicode)); } } if (rtl_ustr_getLength(LocalHostname) > 0) { return {osl_Socket_Ok, OUString(LocalHostname)}; } return {osl_Socket_Error, OUString()}; }(); rtl_uString_assign (strLocalHostname, init.second.pData); return init.first; } oslSocketAddr SAL_CALL osl_resolveHostname(rtl_uString* strHostname) { oslHostAddr pAddr = osl_createHostAddrByName (strHostname); if (pAddr) { oslSocketAddr SockAddr = osl_copySocketAddr( pAddr->pSockAddr ); osl_destroyHostAddr(pAddr); return SockAddr; } return nullptr; } sal_Int32 SAL_CALL osl_getServicePort ( rtl_uString* strServicename, rtl_uString* strProtocol) { struct servent* ps; rtl_String *str_Servicename=nullptr; rtl_String *str_Protocol=nullptr; rtl_uString2String( &str_Servicename, rtl_uString_getStr(strServicename), rtl_uString_getLength(strServicename), RTL_TEXTENCODING_UTF8, OUSTRING_TO_OSTRING_CVTFLAGS); rtl_uString2String( &str_Protocol, rtl_uString_getStr(strProtocol), rtl_uString_getLength(strProtocol), RTL_TEXTENCODING_UTF8, OUSTRING_TO_OSTRING_CVTFLAGS); ps= getservbyname( rtl_string_getStr(str_Servicename), rtl_string_getStr(str_Protocol)); rtl_string_release( str_Servicename ); rtl_string_release( str_Protocol ); 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) { if (pAddr) return FAMILY_FROM_NATIVE(pAddr->m_sockaddr.sa_family); else return osl_Socket_FamilyInvalid; } sal_Int32 SAL_CALL osl_getInetPortOfSocketAddr(oslSocketAddr pAddr) { if( pAddr ) { struct sockaddr_in* pSystemInetAddr= reinterpret_cast(&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) { if (pAddr == nullptr) return false; struct sockaddr_in* pSystemInetAddr= reinterpret_cast(&pAddr->m_sockaddr); if (pSystemInetAddr->sin_family != FAMILY_TO_NATIVE(osl_Socket_FamilyInet)) return false; pSystemInetAddr->sin_port= htons(static_cast(Port)); return true; } oslSocketResult SAL_CALL osl_getHostnameOfSocketAddr ( oslSocketAddr Addr, rtl_uString **strHostName) { oslHostAddr pAddr= osl_createHostAddrByAddr (Addr); if (pAddr) { rtl_uString_newFromString(strHostName, pAddr->pHostName); osl_destroyHostAddr(pAddr); return osl_Socket_Ok; } return osl_Socket_Error; } oslSocketResult SAL_CALL osl_getDottedInetAddrOfSocketAddr ( oslSocketAddr pAddr, rtl_uString **strDottedInetAddr) { if (pAddr == nullptr) return osl_Socket_Error; struct sockaddr_in *pSystemInetAddr = reinterpret_cast(&pAddr->m_sockaddr); if (pSystemInetAddr->sin_family != FAMILY_TO_NATIVE(osl_Socket_FamilyInet)) return osl_Socket_Error; *strDottedInetAddr = nullptr; WCHAR buf[16]; // 16 for IPV4, 46 for IPV6 PCWSTR ret = InetNtopW( AF_INET, & pSystemInetAddr->sin_addr, buf, SAL_N_ELEMENTS(buf)); if (nullptr == ret) { SAL_INFO("sal.osl", "InetNtopW failed: " << WSAGetLastError()); return osl_Socket_Error; } rtl_uString_newFromStr(strDottedInetAddr, o3tl::toU(ret)); OSL_ASSERT(*strDottedInetAddr != nullptr); return osl_Socket_Ok; } oslSocket SAL_CALL osl_createSocket( oslAddrFamily Family, oslSocketType Type, oslProtocol Protocol) { /* alloc memory */ oslSocket pSocket = createSocketImpl(0); if (pSocket == nullptr) return nullptr; /* 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 = WSAGetLastError(); SAL_WARN("sal.osl", "socket creation failed: (" << nErrno << "): " << WindowsErrorString(nErrno)); destroySocketImpl(pSocket); pSocket = nullptr; } else { pSocket->m_Flags = 0; } 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) { osl_closeSocket(pSocket); destroySocketImpl(pSocket); } } void SAL_CALL osl_closeSocket(oslSocket pSocket) { /* socket already invalid */ if (!pSocket) return; /* close */ closesocket(pSocket->m_Socket); pSocket->m_Socket = OSL_INVALID_SOCKET; } /** 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. */ oslSocketAddr SAL_CALL osl_getLocalAddrOfSocket(oslSocket pSocket) { struct sockaddr Addr; int AddrLen; if (pSocket == nullptr) /* ENOTSOCK */ return nullptr; AddrLen= sizeof(struct sockaddr); if (getsockname(pSocket->m_Socket, &Addr, &AddrLen) == OSL_SOCKET_ERROR) return nullptr; oslSocketAddr pAddr = createSocketAddFromSystem( &Addr ); return pAddr; } oslSocketAddr SAL_CALL osl_getPeerAddrOfSocket(oslSocket pSocket) { struct sockaddr Addr; int AddrLen; if (pSocket == nullptr) /* ENOTSOCK */ return nullptr; AddrLen= sizeof(struct sockaddr); if (getpeername(pSocket->m_Socket, &Addr, &AddrLen) == OSL_SOCKET_ERROR) return nullptr; oslSocketAddr pAddr = createSocketAddFromSystem( &Addr ); return pAddr; } sal_Bool SAL_CALL osl_bindAddrToSocket ( oslSocket pSocket, oslSocketAddr pAddr) { assert(pAddr); if (pSocket == nullptr) /* ENOTSOCK */ return false; return (bind(pSocket->m_Socket, &(pAddr->m_sockaddr), sizeof(struct sockaddr)) != OSL_SOCKET_ERROR); } oslSocketResult SAL_CALL osl_connectSocketTo ( oslSocket pSocket, oslSocketAddr pAddr, const TimeValue* pTimeout) { if (pSocket == nullptr) /* ENOTSOCK */ return osl_Socket_Error; if (pAddr == nullptr) /* EDESTADDRREQ */ return osl_Socket_Error; if (pTimeout == nullptr) { if(connect(pSocket->m_Socket, &(pAddr->m_sockaddr), sizeof(struct sockaddr)) == OSL_SOCKET_ERROR) return osl_Socket_Error; else return osl_Socket_Ok; } else { fd_set fds; int error; struct timeval tv; unsigned long Param; oslSocketResult Result= osl_Socket_Ok; if (pSocket->m_Flags & OSL_SOCKET_FLAGS_NONBLOCKING) { if (connect(pSocket->m_Socket, &(pAddr->m_sockaddr), sizeof(struct sockaddr)) == OSL_SOCKET_ERROR) { switch (WSAGetLastError()) { case WSAEWOULDBLOCK: case WSAEINPROGRESS: return osl_Socket_InProgress; default: return osl_Socket_Error; } } else return osl_Socket_Ok; } /* set socket temporarily to non-blocking */ Param= 1; OSL_VERIFY(ioctlsocket( pSocket->m_Socket, FIONBIO, &Param) != OSL_SOCKET_ERROR); /* initiate connect */ if (connect(pSocket->m_Socket, &(pAddr->m_sockaddr), sizeof(struct sockaddr)) != OSL_SOCKET_ERROR) { /* immediate connection */ Param= 0; ioctlsocket(pSocket->m_Socket, FIONBIO, &Param); return osl_Socket_Ok; } else { error = WSAGetLastError(); /* really an error or just delayed? */ if (error != WSAEWOULDBLOCK && error != WSAEINPROGRESS) { Param= 0; ioctlsocket(pSocket->m_Socket, FIONBIO, &Param); return osl_Socket_Error; } } /* prepare select set for socket */ FD_ZERO(&fds); FD_SET(pSocket->m_Socket, &fds); /* divide milliseconds into seconds and microseconds */ tv.tv_sec= pTimeout->Seconds; tv.tv_usec= pTimeout->Nanosec / 1000L; /* select */ error= select(pSocket->m_Socket+1, nullptr, &fds, nullptr, &tv); if (error > 0) /* connected */ { SAL_WARN_IF( !FD_ISSET(pSocket->m_Socket, &fds), "sal.osl", "osl_connectSocketTo(): select returned but socket not set"); Result= osl_Socket_Ok; } else if(error < 0) /* error */ { /* errno == EBADF: most probably interrupted by close() */ if(WSAGetLastError() == WSAEBADF) { /* do not access pSockImpl because it is about to be or */ /* already destroyed */ return osl_Socket_Interrupted; } else Result= osl_Socket_Error; } else /* timeout */ Result= osl_Socket_TimedOut; /* clean up */ Param= 0; ioctlsocket(pSocket->m_Socket, FIONBIO, &Param); return Result; } } sal_Bool SAL_CALL osl_listenOnSocket ( oslSocket pSocket, sal_Int32 MaxPendingConnections) { if (pSocket == nullptr) /* ENOTSOCK */ return false; return (listen(pSocket->m_Socket, MaxPendingConnections == -1 ? SOMAXCONN : MaxPendingConnections) != OSL_SOCKET_ERROR); } oslSocket SAL_CALL osl_acceptConnectionOnSocket ( oslSocket pSocket, oslSocketAddr* ppAddr) { if (pSocket == nullptr) /* ENOTSOCK */ return nullptr; SOCKET Connection; if(ppAddr) { if( *ppAddr ) { osl_destroySocketAddr( *ppAddr ); *ppAddr = nullptr; } int AddrLen= sizeof(struct sockaddr); /* user wants to know peer Addr */ struct sockaddr Addr; Connection= accept(pSocket->m_Socket, &Addr, &AddrLen); OSL_ASSERT(AddrLen == sizeof(struct sockaddr)); if(Connection != static_cast(OSL_SOCKET_ERROR)) *ppAddr= createSocketAddFromSystem(&Addr); else *ppAddr = nullptr; } else { /* user is not interested in peer-addr */ Connection= accept(pSocket->m_Socket, nullptr, nullptr); } /* accept failed? */ if(Connection == static_cast(OSL_SOCKET_ERROR)) return nullptr; /* alloc memory */ oslSocket pConnectionSocket; pConnectionSocket= createSocketImpl(Connection); pConnectionSocket->m_Flags = 0; return pConnectionSocket; } sal_Int32 SAL_CALL osl_receiveSocket ( oslSocket pSocket, void* pBuffer, sal_uInt32 BytesToRead, oslSocketMsgFlag Flag) { if (pSocket == nullptr) /* ENOTSOCK */ return osl_Socket_Error; return recv(pSocket->m_Socket, static_cast(pBuffer), BytesToRead, MSG_FLAG_TO_NATIVE(Flag)); } sal_Int32 SAL_CALL osl_receiveFromSocket ( oslSocket pSocket, oslSocketAddr SenderAddr, void* pBuffer, sal_uInt32 BufferSize, oslSocketMsgFlag Flag) { struct sockaddr *pSystemSockAddr = nullptr; int AddrLen = 0; if( SenderAddr ) { AddrLen = sizeof( struct sockaddr ); pSystemSockAddr = &(SenderAddr->m_sockaddr); } if (pSocket == nullptr) /* ENOTSOCK */ return osl_Socket_Error; return recvfrom(pSocket->m_Socket, static_cast(pBuffer), BufferSize, MSG_FLAG_TO_NATIVE(Flag), pSystemSockAddr, &AddrLen); } sal_Int32 SAL_CALL osl_sendSocket ( oslSocket pSocket, const void* pBuffer, sal_uInt32 BytesToSend, oslSocketMsgFlag Flag) { if (pSocket == nullptr) /* ENOTSOCK */ return osl_Socket_Error; return send(pSocket->m_Socket, static_cast(pBuffer), BytesToSend, MSG_FLAG_TO_NATIVE(Flag)); } sal_Int32 SAL_CALL osl_sendToSocket ( oslSocket pSocket, oslSocketAddr ReceiverAddr, const void* pBuffer, sal_uInt32 BytesToSend, oslSocketMsgFlag Flag) { if (pSocket == nullptr) /* ENOTSOCK */ return osl_Socket_Error; /* ReceiverAddr might be 0 when used on a connected socket. */ /* Then sendto should behave like send. */ struct sockaddr *pSystemSockAddr = nullptr; if( ReceiverAddr ) pSystemSockAddr = &(ReceiverAddr->m_sockaddr); return sendto(pSocket->m_Socket, static_cast(pBuffer), BytesToSend, MSG_FLAG_TO_NATIVE(Flag), pSystemSockAddr, pSystemSockAddr == nullptr ? 0 : sizeof(struct sockaddr)); } sal_Int32 SAL_CALL osl_readSocket( oslSocket pSocket, void *pBuffer, sal_Int32 n ) { sal_uInt8 * Ptr = static_cast(pBuffer); OSL_ASSERT( pSocket); /* loop until all desired bytes were read or an error occurred */ sal_uInt32 BytesRead= 0; sal_uInt32 BytesToRead= n; 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 ) { OSL_ASSERT( pSocket ); /* 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(pBuffer); 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; } sal_Bool SAL_CALL osl_isReceiveReady ( oslSocket pSocket, const TimeValue* pTimeout) { fd_set fds; struct timeval tv; if (pSocket == nullptr) /* ENOTSOCK */ return false; FD_ZERO(&fds); FD_SET(pSocket->m_Socket, &fds); if (pTimeout) { tv.tv_sec = pTimeout->Seconds; tv.tv_usec = pTimeout->Nanosec / 1000L; } return (select(pSocket->m_Socket + 1, /* no of sockets to monitor */ &fds, /* check read operations */ nullptr, /* check write ops */ nullptr, /* check for OOB */ pTimeout ? &tv : nullptr)==1); /* use timeout? */ } /*****************************************************************************/ /* osl_isSendReady */ /*****************************************************************************/ sal_Bool SAL_CALL osl_isSendReady ( oslSocket pSocket, const TimeValue* pTimeout) { fd_set fds; struct timeval tv; if (pSocket == nullptr) /* ENOTSOCK */ return false; FD_ZERO(&fds); FD_SET(pSocket->m_Socket, &fds); if (pTimeout) { tv.tv_sec = pTimeout->Seconds; tv.tv_usec = pTimeout->Nanosec / 1000L; } return (select(pSocket->m_Socket + 1, /* no of sockets to monitor */ nullptr, /* check read operations */ &fds, /* check write ops */ nullptr, /* check for OOB */ pTimeout ? &tv : nullptr)==1); /* use timeout? */ } sal_Bool SAL_CALL osl_isExceptionPending ( oslSocket pSocket, const TimeValue* pTimeout) { fd_set fds; struct timeval tv; if (pSocket == nullptr) /* ENOTSOCK */ return false; FD_ZERO(&fds); FD_SET(pSocket->m_Socket, &fds); if (pTimeout) { tv.tv_sec = pTimeout->Seconds; tv.tv_usec = pTimeout->Nanosec / 1000L; } return (select(pSocket->m_Socket + 1, /* no of sockets to monitor */ nullptr, /* check read operations */ nullptr, /* check write ops */ &fds, /* check for OOB */ pTimeout ? &tv : nullptr)==1); /* use timeout? */ } sal_Bool SAL_CALL osl_shutdownSocket ( oslSocket pSocket, oslSocketDirection Direction) { if (pSocket == nullptr) /* ENOTSOCK */ return false; return (shutdown(pSocket->m_Socket, DIRECTION_TO_NATIVE(Direction))==0); } sal_Int32 SAL_CALL osl_getSocketOption ( oslSocket pSocket, oslSocketOptionLevel Level, oslSocketOption Option, void* pBuffer, sal_uInt32 BufferLen) { if (pSocket == nullptr) /* ENOTSOCK */ return osl_Socket_Error; int len = BufferLen; if (getsockopt(pSocket->m_Socket, OPTION_LEVEL_TO_NATIVE(Level), OPTION_TO_NATIVE(Option), static_cast(pBuffer), &len) == -1) { return -1; } return len; } sal_Bool SAL_CALL osl_setSocketOption ( oslSocket pSocket, oslSocketOptionLevel Level, oslSocketOption Option, void* pBuffer, sal_uInt32 BufferLen) { if (pSocket == nullptr) /* ENOTSOCK */ return false; return(setsockopt(pSocket->m_Socket, OPTION_LEVEL_TO_NATIVE(Level), OPTION_TO_NATIVE(Option), static_cast(pBuffer), BufferLen) == 0); } sal_Bool SAL_CALL osl_enableNonBlockingMode ( oslSocket pSocket, sal_Bool On) { unsigned long Param= On ? 1 : 0; if (pSocket == nullptr) /* ENOTSOCK */ return false; pSocket->m_Flags = Param ? (pSocket->m_Flags | OSL_SOCKET_FLAGS_NONBLOCKING) : (pSocket->m_Flags & ~OSL_SOCKET_FLAGS_NONBLOCKING) ; return ( ioctlsocket(pSocket->m_Socket, FIONBIO, &Param) != OSL_SOCKET_ERROR); } sal_Bool SAL_CALL osl_isNonBlockingMode(oslSocket pSocket) { if (pSocket == nullptr) /* ENOTSOCK */ return false; return (pSocket->m_Flags & OSL_SOCKET_FLAGS_NONBLOCKING) != 0; } oslSocketType SAL_CALL osl_getSocketType(oslSocket pSocket) { int Type=0; int TypeSize= sizeof(Type); if (pSocket == nullptr) /* ENOTSOCK */ return osl_Socket_TypeInvalid; if(getsockopt(pSocket->m_Socket, OPTION_LEVEL_TO_NATIVE(osl_Socket_LevelSocket), OPTION_TO_NATIVE(osl_Socket_OptionType), reinterpret_cast(&Type), &TypeSize) == -1) { /* error */ return osl_Socket_TypeInvalid; } return TYPE_FROM_NATIVE(Type); } void SAL_CALL osl_getLastSocketErrorDescription ( oslSocket /*Socket*/, rtl_uString **strError) { int error; switch(error = WSAGetLastError()) { case WSAENOTSOCK: rtl_uString_newFromAscii (strError, "WSAENOTSOCK, Socket operation on non-socket. A socket created in one process is used by another process."); break; case WSAEDESTADDRREQ: rtl_uString_newFromAscii (strError, "WSAEDESTADDRREQ, Destination Addr required"); break; case WSAEMSGSIZE: rtl_uString_newFromAscii (strError, "WSAEMSGSIZE, Message too long"); break; case WSAEPROTOTYPE: rtl_uString_newFromAscii (strError, "WSAEPROTOTYPE, Protocol wrong type for socket"); break; case WSAENOPROTOOPT: rtl_uString_newFromAscii (strError, "WSAENOPROTOOPT, Protocol not available"); break; case WSAEPROTONOSUPPORT: rtl_uString_newFromAscii (strError, "WSAEPROTONOSUPPORT, Protocol not supported"); break; case WSAESOCKTNOSUPPORT: rtl_uString_newFromAscii (strError, "WSAESOCKTNOSUPPORT, Socket type not supported"); break; case WSAEOPNOTSUPP: rtl_uString_newFromAscii (strError, "WSAEOPNOTSUPP, Operation not supported on socket"); break; case WSAEPFNOSUPPORT: rtl_uString_newFromAscii (strError, "WSAEPFNOSUPPORT, Protocol family not supported"); break; case WSAEAFNOSUPPORT: rtl_uString_newFromAscii (strError, "WSEAFNOSUPPORT, Addr family not supported by protocol family"); break; case WSAEADDRINUSE: rtl_uString_newFromAscii (strError, "WSAEADDRINUSE, Triggered by bind() because a process went down without closing a socket."); break; case WSAEADDRNOTAVAIL: rtl_uString_newFromAscii (strError, "WSAEADDRNOTAVAIL, Can't assign requested Addr"); break; case WSAENETDOWN: rtl_uString_newFromAscii (strError, "WSAENETDOWN, Network is down"); break; case WSAENETUNREACH: rtl_uString_newFromAscii (strError, "WSAENETUNREACH, Network is unreachable"); break; case WSAENETRESET: rtl_uString_newFromAscii (strError, "WSAENETRESET, Network dropped connection or reset"); break; case WSAECONNABORTED: rtl_uString_newFromAscii (strError, "WSAECONNABORTED, Software caused connection abort"); break; case WSAECONNRESET: rtl_uString_newFromAscii (strError, "WSAECONNRESET, Connection reset by peer"); break; case WSAENOBUFS: rtl_uString_newFromAscii (strError, "WSAENOBUFS, No buffer space available."); break; case WSAEISCONN: rtl_uString_newFromAscii (strError, "WSAEISCONN, Socket is already connected"); break; case WSAENOTCONN: rtl_uString_newFromAscii (strError, "WSAENOTCONN, Socket is not connected"); break; case WSAESHUTDOWN: rtl_uString_newFromAscii (strError, "WSAESHUTDOWN, Can't send after socket shutdown"); break; case WSAETIMEDOUT: rtl_uString_newFromAscii (strError, "WSAETIMEDOUT, Connection timed out"); break; case WSAECONNREFUSED: rtl_uString_newFromAscii (strError, "WSAECONNREFUSED, Connection refused"); break; case WSAEHOSTDOWN: rtl_uString_newFromAscii (strError, "WSAEHOSTDOWN, Networking subsystem not started"); break; case WSAEHOSTUNREACH: rtl_uString_newFromAscii (strError, "WSAEHOSTUNREACH, No route to host"); break; case WSAEWOULDBLOCK: rtl_uString_newFromAscii (strError, "WSAEWOULDBLOCK, Operation would block"); break; case WSAEINPROGRESS: rtl_uString_newFromAscii (strError, "WSAEINPROGRESS, Operation now in progress"); break; case WSAEALREADY: rtl_uString_newFromAscii (strError, "WSAEALREADY, Operation already in progress"); break; case WSAEINTR: rtl_uString_newFromAscii (strError, "WSAEALREADY, Operation was interrupted"); break; case WSAEBADF: rtl_uString_newFromAscii (strError, "WSAEBADF, Bad file number"); break; case WSAEACCES: rtl_uString_newFromAscii (strError, "WSAEACCES, Access is denied"); break; case WSAEFAULT: rtl_uString_newFromAscii (strError, "WSAEFAULT, Bad memory Addr"); break; case WSAEINVAL: rtl_uString_newFromAscii (strError, "WSAEINVAL, The socket has not been bound with bind() or is already connected"); break; case WSAEMFILE: rtl_uString_newFromAscii (strError, "WSAEMFILE, No more file descriptors are available"); break; case WSAETOOMANYREFS: rtl_uString_newFromAscii (strError, "WSAETOOMANYREFS, Undocumented WinSock error"); break; case WSAENAMETOOLONG: rtl_uString_newFromAscii (strError, "WSAENAMETOOLONG, Undocumented WinSock error"); break; case WSAENOTEMPTY: rtl_uString_newFromAscii (strError, "WSAENOTEMPTY, Undocumented WinSock error"); break; case WSAEPROCLIM: rtl_uString_newFromAscii (strError, "WSAEPROCLIM, Undocumented WinSock error"); break; case WSAEUSERS: rtl_uString_newFromAscii (strError, "WSAEUSERS, Undocumented WinSock error"); break; case WSAEDQUOT: rtl_uString_newFromAscii (strError, "WSAEDQUOT, Undocumented WinSock error"); break; case WSAESTALE: rtl_uString_newFromAscii (strError, "WSAESTALE, Undocumented WinSock error"); break; case WSAEREMOTE: rtl_uString_newFromAscii (strError, "WSAEREMOTE, Undocumented WinSock error"); break; case WSAEDISCON: rtl_uString_newFromAscii (strError, "WSAEDISCON, Circuit was gracefully terminated"); break; case WSASYSNOTREADY: rtl_uString_newFromAscii (strError, "WSASYSNOTREADY, The underlying network subsystem is not ready for network communication"); break; case WSAVERNOTSUPPORTED: rtl_uString_newFromAscii (strError, "WSAVERNOTSUPPORTED, The version of Windows Sockets API support requested is not provided by this particular Windows Sockets implementation"); break; case WSANOTINITIALISED: rtl_uString_newFromAscii (strError, "WSANOTINITIALISED, WSAStartup() has not been called"); break; case WSAHOST_NOT_FOUND: rtl_uString_newFromAscii (strError, "WSAHOST_NOT_FOUND, Authoritative answer host not found"); break; case WSATRY_AGAIN: rtl_uString_newFromAscii (strError, "WSATRY_AGAIN, Non-authoritative answer host not found or SERVERFAIL"); break; case WSANO_RECOVERY: rtl_uString_newFromAscii (strError, "WSANO_RECOVERY, Non recoverable errors, FORMERR, REFUSED, NOTIMP"); break; case WSANO_DATA: rtl_uString_newFromAscii (strError, "WSANO_DATA or WSANO_ADDRESS, Valid name, no data record of requested type"); break; default: { sal_Unicode message[128]; wsprintfW(o3tl::toW(message), L"Unknown WinSock Error Number %d", error); rtl_uString_newFromStr (strError, message); } return; } } oslSocketError SAL_CALL osl_getLastSocketError(oslSocket /*Socket*/) { return ERROR_FROM_NATIVE(WSAGetLastError()); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */