542811291c
select() has the major drawback that it cannot handle file descriptor that are bigger than 1024. This patch makes use of poll() instead of select() when poll() support is available.
758 lines
14 KiB
C
758 lines
14 KiB
C
/**
|
|
* WinPR: Windows Portable Runtime
|
|
* Windows Sockets (Winsock)
|
|
*
|
|
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
|
*
|
|
* Licensed 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
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <winpr/crt.h>
|
|
|
|
#include <winpr/winsock.h>
|
|
|
|
/**
|
|
* ws2_32.dll:
|
|
*
|
|
* __WSAFDIsSet
|
|
* accept
|
|
* bind
|
|
* closesocket
|
|
* connect
|
|
* freeaddrinfo
|
|
* FreeAddrInfoEx
|
|
* FreeAddrInfoExW
|
|
* FreeAddrInfoW
|
|
* getaddrinfo
|
|
* GetAddrInfoExA
|
|
* GetAddrInfoExCancel
|
|
* GetAddrInfoExOverlappedResult
|
|
* GetAddrInfoExW
|
|
* GetAddrInfoW
|
|
* gethostbyaddr
|
|
* gethostbyname
|
|
* gethostname
|
|
* GetHostNameW
|
|
* getnameinfo
|
|
* GetNameInfoW
|
|
* getpeername
|
|
* getprotobyname
|
|
* getprotobynumber
|
|
* getservbyname
|
|
* getservbyport
|
|
* getsockname
|
|
* getsockopt
|
|
* htonl
|
|
* htons
|
|
* inet_addr
|
|
* inet_ntoa
|
|
* inet_ntop
|
|
* inet_pton
|
|
* InetNtopW
|
|
* InetPtonW
|
|
* ioctlsocket
|
|
* listen
|
|
* ntohl
|
|
* ntohs
|
|
* recv
|
|
* recvfrom
|
|
* select
|
|
* send
|
|
* sendto
|
|
* SetAddrInfoExA
|
|
* SetAddrInfoExW
|
|
* setsockopt
|
|
* shutdown
|
|
* socket
|
|
* WahCloseApcHelper
|
|
* WahCloseHandleHelper
|
|
* WahCloseNotificationHandleHelper
|
|
* WahCloseSocketHandle
|
|
* WahCloseThread
|
|
* WahCompleteRequest
|
|
* WahCreateHandleContextTable
|
|
* WahCreateNotificationHandle
|
|
* WahCreateSocketHandle
|
|
* WahDestroyHandleContextTable
|
|
* WahDisableNonIFSHandleSupport
|
|
* WahEnableNonIFSHandleSupport
|
|
* WahEnumerateHandleContexts
|
|
* WahInsertHandleContext
|
|
* WahNotifyAllProcesses
|
|
* WahOpenApcHelper
|
|
* WahOpenCurrentThread
|
|
* WahOpenHandleHelper
|
|
* WahOpenNotificationHandleHelper
|
|
* WahQueueUserApc
|
|
* WahReferenceContextByHandle
|
|
* WahRemoveHandleContext
|
|
* WahWaitForNotification
|
|
* WahWriteLSPEvent
|
|
* WEP
|
|
* WPUCompleteOverlappedRequest
|
|
* WPUGetProviderPathEx
|
|
* WSAAccept
|
|
* WSAAddressToStringA
|
|
* WSAAddressToStringW
|
|
* WSAAdvertiseProvider
|
|
* WSAAsyncGetHostByAddr
|
|
* WSAAsyncGetHostByName
|
|
* WSAAsyncGetProtoByName
|
|
* WSAAsyncGetProtoByNumber
|
|
* WSAAsyncGetServByName
|
|
* WSAAsyncGetServByPort
|
|
* WSAAsyncSelect
|
|
* WSACancelAsyncRequest
|
|
* WSACancelBlockingCall
|
|
* WSACleanup
|
|
* WSACloseEvent
|
|
* WSAConnect
|
|
* WSAConnectByList
|
|
* WSAConnectByNameA
|
|
* WSAConnectByNameW
|
|
* WSACreateEvent
|
|
* WSADuplicateSocketA
|
|
* WSADuplicateSocketW
|
|
* WSAEnumNameSpaceProvidersA
|
|
* WSAEnumNameSpaceProvidersExA
|
|
* WSAEnumNameSpaceProvidersExW
|
|
* WSAEnumNameSpaceProvidersW
|
|
* WSAEnumNetworkEvents
|
|
* WSAEnumProtocolsA
|
|
* WSAEnumProtocolsW
|
|
* WSAEventSelect
|
|
* WSAGetLastError
|
|
* WSAGetOverlappedResult
|
|
* WSAGetQOSByName
|
|
* WSAGetServiceClassInfoA
|
|
* WSAGetServiceClassInfoW
|
|
* WSAGetServiceClassNameByClassIdA
|
|
* WSAGetServiceClassNameByClassIdW
|
|
* WSAHtonl
|
|
* WSAHtons
|
|
* WSAInstallServiceClassA
|
|
* WSAInstallServiceClassW
|
|
* WSAIoctl
|
|
* WSAIsBlocking
|
|
* WSAJoinLeaf
|
|
* WSALookupServiceBeginA
|
|
* WSALookupServiceBeginW
|
|
* WSALookupServiceEnd
|
|
* WSALookupServiceNextA
|
|
* WSALookupServiceNextW
|
|
* WSANSPIoctl
|
|
* WSANtohl
|
|
* WSANtohs
|
|
* WSAPoll
|
|
* WSAProviderCompleteAsyncCall
|
|
* WSAProviderConfigChange
|
|
* WSApSetPostRoutine
|
|
* WSARecv
|
|
* WSARecvDisconnect
|
|
* WSARecvFrom
|
|
* WSARemoveServiceClass
|
|
* WSAResetEvent
|
|
* WSASend
|
|
* WSASendDisconnect
|
|
* WSASendMsg
|
|
* WSASendTo
|
|
* WSASetBlockingHook
|
|
* WSASetEvent
|
|
* WSASetLastError
|
|
* WSASetServiceA
|
|
* WSASetServiceW
|
|
* WSASocketA
|
|
* WSASocketW
|
|
* WSAStartup
|
|
* WSAStringToAddressA
|
|
* WSAStringToAddressW
|
|
* WSAUnadvertiseProvider
|
|
* WSAUnhookBlockingHook
|
|
* WSAWaitForMultipleEvents
|
|
* WSCDeinstallProvider
|
|
* WSCDeinstallProviderEx
|
|
* WSCEnableNSProvider
|
|
* WSCEnumProtocols
|
|
* WSCEnumProtocolsEx
|
|
* WSCGetApplicationCategory
|
|
* WSCGetApplicationCategoryEx
|
|
* WSCGetProviderInfo
|
|
* WSCGetProviderPath
|
|
* WSCInstallNameSpace
|
|
* WSCInstallNameSpaceEx
|
|
* WSCInstallNameSpaceEx2
|
|
* WSCInstallProvider
|
|
* WSCInstallProviderAndChains
|
|
* WSCInstallProviderEx
|
|
* WSCSetApplicationCategory
|
|
* WSCSetApplicationCategoryEx
|
|
* WSCSetProviderInfo
|
|
* WSCUnInstallNameSpace
|
|
* WSCUnInstallNameSpaceEx2
|
|
* WSCUpdateProvider
|
|
* WSCUpdateProviderEx
|
|
* WSCWriteNameSpaceOrder
|
|
* WSCWriteProviderOrder
|
|
* WSCWriteProviderOrderEx
|
|
*/
|
|
|
|
#ifdef _WIN32
|
|
|
|
#if (_WIN32_WINNT < 0x0600)
|
|
|
|
PCSTR inet_ntop(INT Family, PVOID pAddr, PSTR pStringBuf, size_t StringBufSize)
|
|
{
|
|
if (Family == AF_INET)
|
|
{
|
|
struct sockaddr_in in;
|
|
|
|
memset(&in, 0, sizeof(in));
|
|
in.sin_family = AF_INET;
|
|
memcpy(&in.sin_addr, pAddr, sizeof(struct in_addr));
|
|
getnameinfo((struct sockaddr*) &in, sizeof(struct sockaddr_in), pStringBuf, StringBufSize, NULL, 0, NI_NUMERICHOST);
|
|
|
|
return pStringBuf;
|
|
}
|
|
else if (Family == AF_INET6)
|
|
{
|
|
struct sockaddr_in6 in;
|
|
|
|
memset(&in, 0, sizeof(in));
|
|
in.sin6_family = AF_INET6;
|
|
memcpy(&in.sin6_addr, pAddr, sizeof(struct in_addr6));
|
|
getnameinfo((struct sockaddr*) &in, sizeof(struct sockaddr_in6), pStringBuf, StringBufSize, NULL, 0, NI_NUMERICHOST);
|
|
|
|
return pStringBuf;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
#endif /* (_WIN32_WINNT < 0x0600) */
|
|
|
|
#else /* _WIN32 */
|
|
|
|
#include <netdb.h>
|
|
#include <errno.h>
|
|
#include <unistd.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
#include <netinet/tcp.h>
|
|
#include <net/if.h>
|
|
|
|
#ifndef MSG_NOSIGNAL
|
|
#define MSG_NOSIGNAL 0
|
|
#endif
|
|
|
|
int WSAStartup(WORD wVersionRequired, LPWSADATA lpWSAData)
|
|
{
|
|
ZeroMemory(lpWSAData, sizeof(WSADATA));
|
|
|
|
lpWSAData->wVersion = wVersionRequired;
|
|
lpWSAData->wHighVersion = MAKEWORD(2, 2);
|
|
|
|
return 0; /* success */
|
|
}
|
|
|
|
int WSACleanup(void)
|
|
{
|
|
return 0; /* success */
|
|
}
|
|
|
|
void WSASetLastError(int iError)
|
|
{
|
|
|
|
}
|
|
|
|
int WSAGetLastError(void)
|
|
{
|
|
int iError = 0;
|
|
|
|
switch (errno)
|
|
{
|
|
/* Base error codes */
|
|
|
|
case EINTR:
|
|
iError = WSAEINTR;
|
|
break;
|
|
|
|
case EBADF:
|
|
iError = WSAEBADF;
|
|
break;
|
|
|
|
case EACCES:
|
|
iError = WSAEACCES;
|
|
break;
|
|
|
|
case EFAULT:
|
|
iError = WSAEFAULT;
|
|
break;
|
|
|
|
case EINVAL:
|
|
iError = WSAEINVAL;
|
|
break;
|
|
|
|
case EMFILE:
|
|
iError = WSAEMFILE;
|
|
break;
|
|
|
|
/* BSD sockets error codes */
|
|
|
|
case EWOULDBLOCK:
|
|
iError = WSAEWOULDBLOCK;
|
|
break;
|
|
case EINPROGRESS:
|
|
iError = WSAEINPROGRESS;
|
|
break;
|
|
case EALREADY:
|
|
iError = WSAEALREADY;
|
|
break;
|
|
case ENOTSOCK:
|
|
iError = WSAENOTSOCK;
|
|
break;
|
|
case EDESTADDRREQ:
|
|
iError = WSAEDESTADDRREQ;
|
|
break;
|
|
case EMSGSIZE:
|
|
iError = WSAEMSGSIZE;
|
|
break;
|
|
case EPROTOTYPE:
|
|
iError = WSAEPROTOTYPE;
|
|
break;
|
|
case ENOPROTOOPT:
|
|
iError = WSAENOPROTOOPT;
|
|
break;
|
|
case EPROTONOSUPPORT:
|
|
iError = WSAEPROTONOSUPPORT;
|
|
break;
|
|
case ESOCKTNOSUPPORT:
|
|
iError = WSAESOCKTNOSUPPORT;
|
|
break;
|
|
case EOPNOTSUPP:
|
|
iError = WSAEOPNOTSUPP;
|
|
break;
|
|
case EPFNOSUPPORT:
|
|
iError = WSAEPFNOSUPPORT;
|
|
break;
|
|
case EAFNOSUPPORT:
|
|
iError = WSAEAFNOSUPPORT;
|
|
break;
|
|
case EADDRINUSE:
|
|
iError = WSAEADDRINUSE;
|
|
break;
|
|
case EADDRNOTAVAIL:
|
|
iError = WSAEADDRNOTAVAIL;
|
|
break;
|
|
case ENETDOWN:
|
|
iError = WSAENETDOWN;
|
|
break;
|
|
case ENETUNREACH:
|
|
iError = WSAENETUNREACH;
|
|
break;
|
|
case ENETRESET:
|
|
iError = WSAENETRESET;
|
|
break;
|
|
case ECONNABORTED:
|
|
iError = WSAECONNABORTED;
|
|
break;
|
|
case ECONNRESET:
|
|
iError = WSAECONNRESET;
|
|
break;
|
|
case ENOBUFS:
|
|
iError = WSAENOBUFS;
|
|
break;
|
|
case EISCONN:
|
|
iError = WSAEISCONN;
|
|
break;
|
|
case ENOTCONN:
|
|
iError = WSAENOTCONN;
|
|
break;
|
|
case ESHUTDOWN:
|
|
iError = WSAESHUTDOWN;
|
|
break;
|
|
case ETOOMANYREFS:
|
|
iError = WSAETOOMANYREFS;
|
|
break;
|
|
case ETIMEDOUT:
|
|
iError = WSAETIMEDOUT;
|
|
break;
|
|
case ECONNREFUSED:
|
|
iError = WSAECONNREFUSED;
|
|
break;
|
|
case ELOOP:
|
|
iError = WSAELOOP;
|
|
break;
|
|
case ENAMETOOLONG:
|
|
iError = WSAENAMETOOLONG;
|
|
break;
|
|
case EHOSTDOWN:
|
|
iError = WSAEHOSTDOWN;
|
|
break;
|
|
case EHOSTUNREACH:
|
|
iError = WSAEHOSTUNREACH;
|
|
break;
|
|
case ENOTEMPTY:
|
|
iError = WSAENOTEMPTY;
|
|
break;
|
|
#ifdef EPROCLIM
|
|
case EPROCLIM:
|
|
iError = WSAEPROCLIM;
|
|
break;
|
|
#endif
|
|
case EUSERS:
|
|
iError = WSAEUSERS;
|
|
break;
|
|
case EDQUOT:
|
|
iError = WSAEDQUOT;
|
|
break;
|
|
case ESTALE:
|
|
iError = WSAESTALE;
|
|
break;
|
|
case EREMOTE:
|
|
iError = WSAEREMOTE;
|
|
break;
|
|
|
|
/* Special cases */
|
|
|
|
#if (EAGAIN != EWOULDBLOCK)
|
|
case EAGAIN:
|
|
iError = WSAEWOULDBLOCK;
|
|
break;
|
|
#endif
|
|
|
|
case EPROTO:
|
|
iError = WSAECONNRESET;
|
|
break;
|
|
}
|
|
|
|
/**
|
|
* Windows Sockets Extended Error Codes:
|
|
*
|
|
* WSASYSNOTREADY
|
|
* WSAVERNOTSUPPORTED
|
|
* WSANOTINITIALISED
|
|
* WSAEDISCON
|
|
* WSAENOMORE
|
|
* WSAECANCELLED
|
|
* WSAEINVALIDPROCTABLE
|
|
* WSAEINVALIDPROVIDER
|
|
* WSAEPROVIDERFAILEDINIT
|
|
* WSASYSCALLFAILURE
|
|
* WSASERVICE_NOT_FOUND
|
|
* WSATYPE_NOT_FOUND
|
|
* WSA_E_NO_MORE
|
|
* WSA_E_CANCELLED
|
|
* WSAEREFUSED
|
|
*/
|
|
|
|
return iError;
|
|
}
|
|
|
|
SOCKET _accept(SOCKET s, struct sockaddr* addr, int* addrlen)
|
|
{
|
|
int status;
|
|
int fd = (int) s;
|
|
socklen_t s_addrlen = (socklen_t) *addrlen;
|
|
|
|
status = accept(fd, addr, &s_addrlen);
|
|
*addrlen = (socklen_t) s_addrlen;
|
|
|
|
return status;
|
|
}
|
|
|
|
int _bind(SOCKET s, const struct sockaddr* addr, int namelen)
|
|
{
|
|
int status;
|
|
int fd = (int) s;
|
|
|
|
status = bind(fd, addr, (socklen_t) namelen);
|
|
|
|
return status;
|
|
}
|
|
|
|
int closesocket(SOCKET s)
|
|
{
|
|
int status;
|
|
int fd = (int) s;
|
|
|
|
status = close(fd);
|
|
|
|
return status;
|
|
}
|
|
|
|
int _connect(SOCKET s, const struct sockaddr* name, int namelen)
|
|
{
|
|
int status;
|
|
int fd = (int) s;
|
|
|
|
status = connect(fd, name, (socklen_t) namelen);
|
|
|
|
return status;
|
|
}
|
|
|
|
int _ioctlsocket(SOCKET s, long cmd, u_long* argp)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int _getpeername(SOCKET s, struct sockaddr* name, int* namelen)
|
|
{
|
|
int status;
|
|
int fd = (int) s;
|
|
socklen_t s_namelen = (socklen_t) *namelen;
|
|
|
|
status = getpeername(fd, name, &s_namelen);
|
|
*namelen = (int) s_namelen;
|
|
|
|
return status;
|
|
}
|
|
|
|
int _getsockname(SOCKET s, struct sockaddr* name, int* namelen)
|
|
{
|
|
int status;
|
|
int fd = (int) s;
|
|
socklen_t s_namelen = (socklen_t) *namelen;
|
|
|
|
status = getsockname(fd, name, &s_namelen);
|
|
*namelen = (int) s_namelen;
|
|
|
|
return status;
|
|
}
|
|
|
|
int _getsockopt(SOCKET s, int level, int optname, char* optval, int* optlen)
|
|
{
|
|
int status;
|
|
int fd = (int) s;
|
|
socklen_t s_optlen = (socklen_t) *optlen;
|
|
|
|
status = getsockopt(fd, level, optname, (void*) optval, &s_optlen);
|
|
*optlen = (socklen_t) s_optlen;
|
|
|
|
return status;
|
|
}
|
|
|
|
u_long _htonl(u_long hostlong)
|
|
{
|
|
return htonl(hostlong);
|
|
}
|
|
|
|
u_short _htons(u_short hostshort)
|
|
{
|
|
return htons(hostshort);
|
|
}
|
|
|
|
unsigned long _inet_addr(const char* cp)
|
|
{
|
|
return (long) inet_addr(cp);
|
|
}
|
|
|
|
char* _inet_ntoa(struct in_addr in)
|
|
{
|
|
return inet_ntoa(in);
|
|
}
|
|
|
|
int _listen(SOCKET s, int backlog)
|
|
{
|
|
int status;
|
|
int fd = (int) s;
|
|
|
|
status = listen(fd, backlog);
|
|
|
|
return status;
|
|
}
|
|
|
|
u_long _ntohl(u_long netlong)
|
|
{
|
|
return ntohl(netlong);
|
|
}
|
|
|
|
u_short _ntohs(u_short netshort)
|
|
{
|
|
return ntohs(netshort);
|
|
}
|
|
|
|
int _recv(SOCKET s, char* buf, int len, int flags)
|
|
{
|
|
int status;
|
|
int fd = (int) s;
|
|
|
|
status = (int) recv(fd, (void*) buf, (size_t) len, flags);
|
|
|
|
return status;
|
|
}
|
|
|
|
int _recvfrom(SOCKET s, char* buf, int len, int flags, struct sockaddr* from, int* fromlen)
|
|
{
|
|
int status;
|
|
int fd = (int) s;
|
|
socklen_t s_fromlen = (socklen_t) *fromlen;
|
|
|
|
status = (int) recvfrom(fd, (void*) buf, (size_t) len, flags, from, &s_fromlen);
|
|
*fromlen = (int) s_fromlen;
|
|
|
|
return status;
|
|
}
|
|
|
|
int _select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, const struct timeval* timeout)
|
|
{
|
|
int status;
|
|
|
|
do
|
|
{
|
|
status = select(nfds, readfds, writefds, exceptfds, (struct timeval*) timeout);
|
|
}
|
|
while ((status < 0) && (errno == EINTR));
|
|
|
|
return status;
|
|
}
|
|
|
|
int _send(SOCKET s, const char* buf, int len, int flags)
|
|
{
|
|
int status;
|
|
int fd = (int) s;
|
|
|
|
flags |= MSG_NOSIGNAL;
|
|
|
|
status = (int) send(fd, (void*) buf, (size_t) len, flags);
|
|
|
|
return status;
|
|
}
|
|
|
|
int _sendto(SOCKET s, const char* buf, int len, int flags, const struct sockaddr* to, int tolen)
|
|
{
|
|
int status;
|
|
int fd = (int) s;
|
|
|
|
status = (int) sendto(fd, (void*) buf, (size_t) len, flags, to, (socklen_t) tolen);
|
|
|
|
return status;
|
|
}
|
|
|
|
int _setsockopt(SOCKET s, int level, int optname, const char* optval, int optlen)
|
|
{
|
|
int status;
|
|
int fd = (int) s;
|
|
|
|
status = setsockopt(fd, level, optname, (void*) optval, (socklen_t) optlen);
|
|
|
|
return status;
|
|
}
|
|
|
|
int _shutdown(SOCKET s, int how)
|
|
{
|
|
int status;
|
|
int fd = (int) s;
|
|
int s_how = -1;
|
|
|
|
switch (how)
|
|
{
|
|
case SD_RECEIVE:
|
|
s_how = SHUT_RD;
|
|
break;
|
|
|
|
case SD_SEND:
|
|
s_how = SHUT_WR;
|
|
break;
|
|
|
|
case SD_BOTH:
|
|
s_how = SHUT_RDWR;
|
|
break;
|
|
}
|
|
|
|
if (s_how < 0)
|
|
return SOCKET_ERROR;
|
|
|
|
status = shutdown(fd, s_how);
|
|
|
|
return status;
|
|
}
|
|
|
|
SOCKET _socket(int af, int type, int protocol)
|
|
{
|
|
SOCKET s;
|
|
|
|
s = (SOCKET) socket(af, type, protocol);
|
|
|
|
return s;
|
|
}
|
|
|
|
struct hostent* _gethostbyaddr(const char* addr, int len, int type)
|
|
{
|
|
struct hostent* host;
|
|
|
|
host = gethostbyaddr((void*) addr, (socklen_t) len, type);
|
|
|
|
return host;
|
|
}
|
|
|
|
struct hostent* _gethostbyname(const char* name)
|
|
{
|
|
struct hostent* host;
|
|
|
|
host = gethostbyname(name);
|
|
|
|
return host;
|
|
}
|
|
|
|
int _gethostname(char* name, int namelen)
|
|
{
|
|
int status;
|
|
|
|
status = gethostname(name, (size_t) namelen);
|
|
|
|
return status;
|
|
}
|
|
|
|
struct servent* _getservbyport(int port, const char* proto)
|
|
{
|
|
struct servent* serv;
|
|
|
|
serv = getservbyport(port, proto);
|
|
|
|
return serv;
|
|
}
|
|
|
|
struct servent* _getservbyname(const char* name, const char* proto)
|
|
{
|
|
struct servent* serv;
|
|
|
|
serv = getservbyname(name, proto);
|
|
|
|
return serv;
|
|
}
|
|
|
|
struct protoent* _getprotobynumber(int number)
|
|
{
|
|
struct protoent* proto;
|
|
|
|
proto = getprotobynumber(number);
|
|
|
|
return proto;
|
|
}
|
|
|
|
struct protoent* _getprotobyname(const char* name)
|
|
{
|
|
struct protoent* proto;
|
|
|
|
proto = getprotobyname(name);
|
|
|
|
return proto;
|
|
}
|
|
|
|
#endif /* _WIN32 */
|