/*------------------------------------------------------------------------- * drawElements Utility Library * ---------------------------- * * Copyright 2014 The Android Open Source Project * * 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. * *//*! * \file * \brief Socket abstraction. *//*--------------------------------------------------------------------*/ #include "deSocket.h" #include "deMemory.h" #include "deMutex.h" #include "deInt32.h" #if (DE_OS == DE_OS_WIN32) # define DE_USE_WINSOCK #elif (DE_OS == DE_OS_UNIX) || (DE_OS == DE_OS_OSX) || (DE_OS == DE_OS_IOS) || (DE_OS == DE_OS_ANDROID) || (DE_OS == DE_OS_SYMBIAN) || (DE_OS == DE_OS_QNX) # define DE_USE_BERKELEY_SOCKETS #else # error Implement deSocket for your OS. #endif /* Common utilities. */ const char* deGetSocketResultName (deSocketResult result) { switch (result) { case DE_SOCKETRESULT_SUCCESS: return "DE_SOCKETRESULT_SUCCESS"; case DE_SOCKETRESULT_WOULD_BLOCK: return "DE_SOCKETRESULT_WOULD_BLOCK"; case DE_SOCKETRESULT_CONNECTION_CLOSED: return "DE_SOCKETRESULT_CONNECTION_CLOSED"; case DE_SOCKETRESULT_CONNECTION_TERMINATED: return "DE_SOCKETRESULT_CONNECTION_TERMINATED"; case DE_SOCKETRESULT_ERROR: return "DE_SOCKETRESULT_ERROR"; default: return DE_NULL; } } const char* deGetSocketFamilyName (deSocketFamily family) { switch (family) { case DE_SOCKETFAMILY_INET4: return "DE_SOCKETFAMILY_INET4"; case DE_SOCKETFAMILY_INET6: return "DE_SOCKETFAMILY_INET6"; default: return DE_NULL; } } #if defined(DE_USE_WINSOCK) || defined(DE_USE_BERKELEY_SOCKETS) /* Common deSocketAddress implementation. */ struct deSocketAddress_s { char* host; int port; deSocketFamily family; deSocketType type; deSocketProtocol protocol; }; deSocketAddress* deSocketAddress_create (void) { deSocketAddress* addr = (deSocketAddress*)deCalloc(sizeof(deSocketAddress)); if (!addr) return addr; /* Sane defaults. */ addr->family = DE_SOCKETFAMILY_INET4; addr->type = DE_SOCKETTYPE_STREAM; addr->protocol = DE_SOCKETPROTOCOL_TCP; return addr; } deBool deSocketAddress_setFamily (deSocketAddress* address, deSocketFamily family) { address->family = family; return DE_TRUE; } deSocketFamily deSocketAddress_getFamily (const deSocketAddress* address) { return address->family; } void deSocketAddress_destroy (deSocketAddress* address) { deFree(address->host); deFree(address); } deBool deSocketAddress_setPort (deSocketAddress* address, int port) { address->port = port; return DE_TRUE; } int deSocketAddress_getPort (const deSocketAddress* address) { return address->port; } deBool deSocketAddress_setHost (deSocketAddress* address, const char* host) { if (address->host) { deFree(address->host); address->host = DE_NULL; } address->host = deStrdup(host); return address->host != DE_NULL; } const char* deSocketAddress_getHost (const deSocketAddress* address) { return address->host; } deBool deSocketAddress_setType (deSocketAddress* address, deSocketType type) { address->type = type; return DE_TRUE; } deSocketType deSocketAddress_getType (const deSocketAddress* address) { return address->type; } deBool deSocketAddress_setProtocol (deSocketAddress* address, deSocketProtocol protocol) { address->protocol = protocol; return DE_TRUE; } deSocketProtocol deSocketAddress_getProtocol (const deSocketAddress* address) { return address->protocol; } #endif #if defined(DE_USE_WINSOCK) /* WinSock spesific. */ # include <WinSock2.h> # include <WS2tcpip.h> # include <WinDef.h> static deBool initWinsock (void) { WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) return DE_FALSE; return DE_TRUE; } #elif defined(DE_USE_BERKELEY_SOCKETS) /* Berkeley Socket includes. */ # include <sys/socket.h> # include <netinet/in.h> # include <netinet/tcp.h> # include <arpa/inet.h> # include <netdb.h> # include <unistd.h> # include <fcntl.h> # include <errno.h> #endif /* Socket type. */ #if defined(DE_USE_WINSOCK) /* \note SOCKET is unsigned type! */ typedef SOCKET deSocketHandle; typedef int NativeSocklen; typedef int NativeSize; # define DE_INVALID_SOCKET_HANDLE INVALID_SOCKET #else typedef int deSocketHandle; typedef socklen_t NativeSocklen; typedef size_t NativeSize; # define DE_INVALID_SOCKET_HANDLE (-1) #endif DE_INLINE deBool deSocketHandleIsValid (deSocketHandle handle) { return handle != DE_INVALID_SOCKET_HANDLE; } #if defined(DE_USE_WINSOCK) || defined(DE_USE_BERKELEY_SOCKETS) /* Shared berkeley and winsock implementation. */ struct deSocket_s { deSocketHandle handle; deMutex stateLock; volatile deSocketState state; volatile deUint32 openChannels; }; /* Common socket functions. */ static deUint16 deHostToNetworkOrder16 (deUint16 v) { #if (DE_ENDIANNESS == DE_LITTLE_ENDIAN) return deReverseBytes16(v); #else return v; #endif } static deUint16 deNetworkToHostOrder16 (deUint16 v) { #if (DE_ENDIANNESS == DE_LITTLE_ENDIAN) return deReverseBytes16(v); #else return v; #endif } DE_STATIC_ASSERT(sizeof(((struct sockaddr_in*)DE_NULL)->sin_port) == sizeof(deUint16)); DE_STATIC_ASSERT(sizeof(((struct sockaddr_in6*)DE_NULL)->sin6_port) == sizeof(deUint16)); static int deSocketFamilyToBsdFamily (deSocketFamily family) { switch (family) { case DE_SOCKETFAMILY_INET4: return AF_INET; case DE_SOCKETFAMILY_INET6: return AF_INET6; default: DE_ASSERT(DE_FALSE); return 0; } } static int deSocketTypeToBsdType (deSocketType type) { switch (type) { case DE_SOCKETTYPE_STREAM: return SOCK_STREAM; case DE_SOCKETTYPE_DATAGRAM: return SOCK_DGRAM; default: DE_ASSERT(DE_FALSE); return 0; } } static int deSocketProtocolToBsdProtocol (deSocketProtocol protocol) { switch (protocol) { case DE_SOCKETPROTOCOL_TCP: return IPPROTO_TCP; case DE_SOCKETPROTOCOL_UDP: return IPPROTO_UDP; default: DE_ASSERT(DE_FALSE); return 0; } } static deBool deSocketAddressToBsdAddress (const deSocketAddress* address, size_t bsdAddrBufSize, struct sockaddr* bsdAddr, NativeSocklen* bsdAddrLen) { deMemset(bsdAddr, 0, bsdAddrBufSize); /* Resolve host. */ if (address->host != DE_NULL) { struct addrinfo* result = DE_NULL; struct addrinfo hints; deMemset(&hints, 0, sizeof(hints)); hints.ai_family = deSocketFamilyToBsdFamily(address->family); hints.ai_socktype = deSocketTypeToBsdType(address->type); hints.ai_protocol = deSocketProtocolToBsdProtocol(address->protocol); if (getaddrinfo(address->host, DE_NULL, &hints, &result) != 0 || !result) { if (result) freeaddrinfo(result); return DE_FALSE; } /* \note Always uses first address. */ if (bsdAddrBufSize < (size_t)result->ai_addrlen) { DE_FATAL("Too small bsdAddr buffer"); freeaddrinfo(result); return DE_FALSE; } *bsdAddrLen = (NativeSocklen)result->ai_addrlen; deMemcpy(bsdAddr, result->ai_addr, (size_t)result->ai_addrlen); freeaddrinfo(result); /* Add port. */ if (bsdAddr->sa_family == AF_INET) { if (*bsdAddrLen < (NativeSocklen)sizeof(struct sockaddr_in)) return DE_FALSE; ((struct sockaddr_in*)bsdAddr)->sin_port = deHostToNetworkOrder16((deUint16)address->port); } else if (bsdAddr->sa_family == AF_INET6) { if (*bsdAddrLen < (NativeSocklen)sizeof(struct sockaddr_in6)) return DE_FALSE; ((struct sockaddr_in6*)bsdAddr)->sin6_port = deHostToNetworkOrder16((deUint16)address->port); } else return DE_FALSE; return DE_TRUE; } else if (address->family == DE_SOCKETFAMILY_INET4) { struct sockaddr_in* addr4 = (struct sockaddr_in*)bsdAddr; if (bsdAddrBufSize < sizeof(struct sockaddr_in)) { DE_FATAL("Too small bsdAddr buffer"); return DE_FALSE; } addr4->sin_port = deHostToNetworkOrder16((deUint16)address->port); addr4->sin_family = AF_INET; addr4->sin_addr.s_addr = INADDR_ANY; *bsdAddrLen = (NativeSocklen)sizeof(struct sockaddr_in); return DE_TRUE; } else if (address->family == DE_SOCKETFAMILY_INET6) { struct sockaddr_in6* addr6 = (struct sockaddr_in6*)bsdAddr; if (bsdAddrBufSize < sizeof(struct sockaddr_in6)) { DE_FATAL("Too small bsdAddr buffer"); return DE_FALSE; } addr6->sin6_port = deHostToNetworkOrder16((deUint16)address->port); addr6->sin6_family = AF_INET6; *bsdAddrLen = (NativeSocklen)sizeof(struct sockaddr_in6); return DE_TRUE; } else return DE_FALSE; } void deBsdAddressToSocketAddress (deSocketAddress* address, const struct sockaddr* bsdAddr, int addrLen) { /* Decode client address info. */ if (bsdAddr->sa_family == AF_INET) { const struct sockaddr_in* addr4 = (const struct sockaddr_in*)bsdAddr; DE_ASSERT(addrLen >= (int)sizeof(struct sockaddr_in)); DE_UNREF(addrLen); deSocketAddress_setFamily(address, DE_SOCKETFAMILY_INET4); deSocketAddress_setPort(address, (int)deNetworkToHostOrder16((deUint16)addr4->sin_port)); { char buf[16]; /* Max valid address takes 3*4 + 3 = 15 chars */ inet_ntop(AF_INET, (void*)&addr4->sin_addr, buf, sizeof(buf)); deSocketAddress_setHost(address, buf); } } else if (bsdAddr->sa_family == AF_INET6) { const struct sockaddr_in6* addr6 = (const struct sockaddr_in6*)bsdAddr; DE_ASSERT(addrLen >= (int)sizeof(struct sockaddr_in6)); DE_UNREF(addrLen); deSocketAddress_setFamily(address, DE_SOCKETFAMILY_INET6); deSocketAddress_setPort(address, (int)deNetworkToHostOrder16((deUint16)addr6->sin6_port)); { char buf[40]; /* Max valid address takes 8*4 + 7 = 39 chars */ inet_ntop(AF_INET6, (void*)&addr6->sin6_addr, buf, sizeof(buf)); deSocketAddress_setHost(address, buf); } } else DE_ASSERT(DE_FALSE); } deSocket* deSocket_create (void) { deSocket* sock = (deSocket*)deCalloc(sizeof(deSocket)); if (!sock) return sock; #if defined(DE_USE_WINSOCK) /* Make sure WSA is up. */ if (!initWinsock()) return DE_NULL; #endif sock->stateLock = deMutex_create(0); sock->handle = DE_INVALID_SOCKET_HANDLE; sock->state = DE_SOCKETSTATE_CLOSED; return sock; } void deSocket_destroy (deSocket* sock) { if (sock->state != DE_SOCKETSTATE_CLOSED) deSocket_close(sock); deMutex_destroy(sock->stateLock); deFree(sock); } deSocketState deSocket_getState (const deSocket* sock) { return sock->state; } deUint32 deSocket_getOpenChannels (const deSocket* sock) { return sock->openChannels; } deBool deSocket_setFlags (deSocket* sock, deUint32 flags) { deSocketHandle fd = sock->handle; if (sock->state == DE_SOCKETSTATE_CLOSED) return DE_FALSE; /* Keepalive. */ { int mode = (flags & DE_SOCKET_KEEPALIVE) ? 1 : 0; if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (const char*)&mode, sizeof(mode)) != 0) return DE_FALSE; } /* Nodelay. */ { int mode = (flags & DE_SOCKET_NODELAY) ? 1 : 0; if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const char*)&mode, sizeof(mode)) != 0) return DE_FALSE; } /* Non-blocking. */ { #if defined(DE_USE_WINSOCK) u_long mode = (flags & DE_SOCKET_NONBLOCKING) ? 1 : 0; if (ioctlsocket(fd, FIONBIO, &mode) != 0) return DE_FALSE; #else int oldFlags = fcntl(fd, F_GETFL, 0); int newFlags = (flags & DE_SOCKET_NONBLOCKING) ? (oldFlags | O_NONBLOCK) : (oldFlags & ~O_NONBLOCK); if (fcntl(fd, F_SETFL, newFlags) != 0) return DE_FALSE; #endif } /* Close on exec. */ { #if defined(DE_USE_BERKELEY_SOCKETS) int oldFlags = fcntl(fd, F_GETFD, 0); int newFlags = (flags & DE_SOCKET_CLOSE_ON_EXEC) ? (oldFlags | FD_CLOEXEC) : (oldFlags & ~FD_CLOEXEC); if (fcntl(fd, F_SETFD, newFlags) != 0) return DE_FALSE; #endif } return DE_TRUE; } deBool deSocket_listen (deSocket* sock, const deSocketAddress* address) { const int backlogSize = 4; deUint8 bsdAddrBuf[sizeof(struct sockaddr_in6)]; struct sockaddr* bsdAddr = (struct sockaddr*)&bsdAddrBuf[0]; NativeSocklen bsdAddrLen; if (sock->state != DE_SOCKETSTATE_CLOSED) return DE_FALSE; /* Resolve address. */ if (!deSocketAddressToBsdAddress(address, sizeof(bsdAddrBuf), bsdAddr, &bsdAddrLen)) return DE_FALSE; /* Create socket. */ sock->handle = socket(bsdAddr->sa_family, deSocketTypeToBsdType(address->type), deSocketProtocolToBsdProtocol(address->protocol)); if (!deSocketHandleIsValid(sock->handle)) return DE_FALSE; sock->state = DE_SOCKETSTATE_DISCONNECTED; /* Allow re-using address. */ { int reuseVal = 1; setsockopt(sock->handle, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuseVal, (int)sizeof(reuseVal)); } /* Bind to address. */ if (bind(sock->handle, bsdAddr, (NativeSocklen)bsdAddrLen) != 0) { deSocket_close(sock); return DE_FALSE; } /* Start listening. */ if (listen(sock->handle, backlogSize) != 0) { deSocket_close(sock); return DE_FALSE; } sock->state = DE_SOCKETSTATE_LISTENING; return DE_TRUE; } deSocket* deSocket_accept (deSocket* sock, deSocketAddress* clientAddress) { deSocketHandle newFd = DE_INVALID_SOCKET_HANDLE; deSocket* newSock = DE_NULL; deUint8 bsdAddrBuf[sizeof(struct sockaddr_in6)]; struct sockaddr* bsdAddr = (struct sockaddr*)&bsdAddrBuf[0]; NativeSocklen bsdAddrLen = (NativeSocklen)sizeof(bsdAddrBuf); deMemset(bsdAddr, 0, (size_t)bsdAddrLen); newFd = accept(sock->handle, bsdAddr, &bsdAddrLen); if (!deSocketHandleIsValid(newFd)) return DE_NULL; newSock = (deSocket*)deCalloc(sizeof(deSocket)); if (!newSock) { #if defined(DE_USE_WINSOCK) closesocket(newFd); #else close(newFd); #endif return DE_NULL; } newSock->stateLock = deMutex_create(0); newSock->handle = newFd; newSock->state = DE_SOCKETSTATE_CONNECTED; newSock->openChannels = DE_SOCKETCHANNEL_BOTH; if (clientAddress) deBsdAddressToSocketAddress(clientAddress, bsdAddr, (int)bsdAddrLen); return newSock; } deBool deSocket_connect (deSocket* sock, const deSocketAddress* address) { deUint8 bsdAddrBuf[sizeof(struct sockaddr_in6)]; struct sockaddr* bsdAddr = (struct sockaddr*)&bsdAddrBuf[0]; NativeSocklen bsdAddrLen; /* Resolve address. */ if (!deSocketAddressToBsdAddress(address, sizeof(bsdAddrBuf), bsdAddr, &bsdAddrLen)) return DE_FALSE; /* Create socket. */ sock->handle = socket(bsdAddr->sa_family, deSocketTypeToBsdType(address->type), deSocketProtocolToBsdProtocol(address->protocol)); if (!deSocketHandleIsValid(sock->handle)) return DE_FALSE; /* Connect. */ if (connect(sock->handle, bsdAddr, bsdAddrLen) != 0) { #if defined(DE_USE_WINSOCK) closesocket(sock->handle); #else close(sock->handle); #endif sock->handle = DE_INVALID_SOCKET_HANDLE; return DE_FALSE; } sock->state = DE_SOCKETSTATE_CONNECTED; sock->openChannels = DE_SOCKETCHANNEL_BOTH; return DE_TRUE; } deBool deSocket_shutdown (deSocket* sock, deUint32 channels) { deUint32 closedChannels = 0; deMutex_lock(sock->stateLock); if (sock->state == DE_SOCKETSTATE_DISCONNECTED || sock->state == DE_SOCKETSTATE_CLOSED) { deMutex_unlock(sock->stateLock); return DE_FALSE; } DE_ASSERT(channels != 0 && (channels & ~(deUint32)DE_SOCKETCHANNEL_BOTH) == 0); /* Don't attempt to close already closed channels on partially open socket. */ channels &= sock->openChannels; if (channels == 0) { deMutex_unlock(sock->stateLock); return DE_FALSE; } #if defined(DE_USE_WINSOCK) { int how = 0; if ((channels & DE_SOCKETCHANNEL_BOTH) == DE_SOCKETCHANNEL_BOTH) how = SD_BOTH; else if (channels & DE_SOCKETCHANNEL_SEND) how = SD_SEND; else if (channels & DE_SOCKETCHANNEL_RECEIVE) how = SD_RECEIVE; if (shutdown(sock->handle, how) == 0) closedChannels = channels; else { int err = WSAGetLastError(); /* \note Due to asynchronous behavior certain errors are perfectly ok. */ if (err == WSAECONNABORTED || err == WSAECONNRESET || err == WSAENOTCONN) closedChannels = DE_SOCKETCHANNEL_BOTH; else { deMutex_unlock(sock->stateLock); return DE_FALSE; } } } #else { int how = 0; if ((channels & DE_SOCKETCHANNEL_BOTH) == DE_SOCKETCHANNEL_BOTH) how = SHUT_RDWR; else if (channels & DE_SOCKETCHANNEL_SEND) how = SHUT_WR; else if (channels & DE_SOCKETCHANNEL_RECEIVE) how = SHUT_RD; if (shutdown(sock->handle, how) == 0) closedChannels = channels; else { if (errno == ENOTCONN) closedChannels = DE_SOCKETCHANNEL_BOTH; else { deMutex_unlock(sock->stateLock); return DE_FALSE; } } } #endif sock->openChannels &= ~closedChannels; if (sock->openChannels == 0) sock->state = DE_SOCKETSTATE_DISCONNECTED; deMutex_unlock(sock->stateLock); return DE_TRUE; } deBool deSocket_close (deSocket* sock) { deMutex_lock(sock->stateLock); if (sock->state == DE_SOCKETSTATE_CLOSED) { deMutex_unlock(sock->stateLock); return DE_FALSE; } #if !defined(DE_USE_WINSOCK) if (sock->state == DE_SOCKETSTATE_LISTENING) { /* There can be a thread blockin in accept(). Release it by calling shutdown. */ shutdown(sock->handle, SHUT_RDWR); } #endif #if defined(DE_USE_WINSOCK) if (closesocket(sock->handle) != 0) return DE_FALSE; #else if (close(sock->handle) != 0) return DE_FALSE; #endif sock->state = DE_SOCKETSTATE_CLOSED; sock->handle = DE_INVALID_SOCKET_HANDLE; sock->openChannels = 0; deMutex_unlock(sock->stateLock); return DE_TRUE; } static deSocketResult mapSendRecvResult (int numBytes) { if (numBytes > 0) return DE_SOCKETRESULT_SUCCESS; else if (numBytes == 0) return DE_SOCKETRESULT_CONNECTION_CLOSED; else { /* Other errors. */ #if defined(DE_USE_WINSOCK) int error = WSAGetLastError(); switch (error) { case WSAEWOULDBLOCK: return DE_SOCKETRESULT_WOULD_BLOCK; case WSAENETDOWN: case WSAENETRESET: case WSAECONNABORTED: case WSAECONNRESET: return DE_SOCKETRESULT_CONNECTION_TERMINATED; default: return DE_SOCKETRESULT_ERROR; } #else switch (errno) { case EAGAIN: return DE_SOCKETRESULT_WOULD_BLOCK; case ECONNABORTED: case ECONNRESET: return DE_SOCKETRESULT_CONNECTION_TERMINATED; default: return DE_SOCKETRESULT_ERROR; } #endif } } DE_INLINE void deSocket_setChannelsClosed (deSocket* sock, deUint32 channels) { deMutex_lock(sock->stateLock); sock->openChannels &= ~channels; if (sock->openChannels == 0) sock->state = DE_SOCKETSTATE_DISCONNECTED; deMutex_unlock(sock->stateLock); } deSocketResult deSocket_send (deSocket* sock, const void* buf, size_t bufSize, size_t* numSentPtr) { int numSent = (int)send(sock->handle, (const char*)buf, (NativeSize)bufSize, 0); deSocketResult result = mapSendRecvResult(numSent); if (numSentPtr) *numSentPtr = (numSent > 0) ? ((size_t)numSent) : (0); /* Update state. */ if (result == DE_SOCKETRESULT_CONNECTION_CLOSED) deSocket_setChannelsClosed(sock, DE_SOCKETCHANNEL_SEND); else if (result == DE_SOCKETRESULT_CONNECTION_TERMINATED) deSocket_setChannelsClosed(sock, DE_SOCKETCHANNEL_BOTH); return result; } deSocketResult deSocket_receive (deSocket* sock, void* buf, size_t bufSize, size_t* numReceivedPtr) { int numRecv = (int)recv(sock->handle, (char*)buf, (NativeSize)bufSize, 0); deSocketResult result = mapSendRecvResult(numRecv); if (numReceivedPtr) *numReceivedPtr = (numRecv > 0) ? ((size_t)numRecv) : (0); /* Update state. */ if (result == DE_SOCKETRESULT_CONNECTION_CLOSED) deSocket_setChannelsClosed(sock, DE_SOCKETCHANNEL_RECEIVE); else if (result == DE_SOCKETRESULT_CONNECTION_TERMINATED) deSocket_setChannelsClosed(sock, DE_SOCKETCHANNEL_BOTH); return result; } #endif