/*------------------------------------------------------------------------- * 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" #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) # 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 <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; # define DE_INVALID_SOCKET_HANDLE INVALID_SOCKET #else typedef int deSocketHandle; # 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 int deSocketFamilyToBsdProtocolFamily (deSocketFamily family) { switch (family) { case DE_SOCKETFAMILY_INET4: return PF_INET; case DE_SOCKETFAMILY_INET6: return PF_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, struct sockaddr* bsdAddr, int* bsdAddrSize, deSocketFamily* family) { deBool hasHost = address->host != DE_NULL; deUint8 hostAddr[16]; /*!< Binary representation. */ deMemset(bsdAddr, 0, sizeof(struct sockaddr)); *family = address->family; /* If host is supplied, use gethostbyname() to determine actual family. */ if (hasHost) { struct hostent* host = gethostbyname(address->host); if (!host) return DE_FALSE; if (host->h_addrtype == AF_INET) *family = DE_SOCKETFAMILY_INET4; else if (host->h_addrtype == AF_INET6) *family = DE_SOCKETFAMILY_INET6; else return DE_FALSE; DE_ASSERT((host->h_addrtype == AF_INET && host->h_length == 4) || (host->h_addrtype == AF_INET6 && host->h_length == 16)); /* Use first address. */ if (host->h_addr_list[0] != 0) deMemcpy(hostAddr, host->h_addr_list[0], host->h_length); else return DE_FALSE; } if (*family == DE_SOCKETFAMILY_INET4) { struct sockaddr_in* addr4 = (struct sockaddr_in*)bsdAddr; addr4->sin_port = htons((deUint16)address->port); addr4->sin_family = AF_INET; if (hasHost) deMemcpy(&addr4->sin_addr, hostAddr, 4); else addr4->sin_addr.s_addr = INADDR_ANY; *bsdAddrSize = sizeof(struct sockaddr_in); return DE_TRUE; } else if (*family == DE_SOCKETFAMILY_INET6) { DE_ASSERT(!"TODO"); return DE_FALSE; } 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, ntohs(addr4->sin_port)); #if defined(DE_USE_WINSOCK) deSocketAddress_setHost(address, inet_ntoa(addr4->sin_addr)); #else { char buf[16]; inet_ntop(AF_INET, &addr4->sin_addr, buf, sizeof(buf)); deSocketAddress_setHost(address, buf); } #endif } 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 0; #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; struct sockaddr bsdAddr; int bsdAddrLen; deSocketFamily family; if (sock->state != DE_SOCKETSTATE_CLOSED) return DE_FALSE; /* Resolve address. */ if (!deSocketAddressToBsdAddress(address, &bsdAddr, &bsdAddrLen, &family)) return DE_FALSE; /* Create socket. */ sock->handle = socket(deSocketFamilyToBsdProtocolFamily(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, 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; struct sockaddr addr; int addrLen = (int)sizeof(addr); deMemset(&addr, 0, sizeof(addr)); #if defined(DE_USE_WINSOCK) newFd = accept(sock->handle, (struct sockaddr*)&addr, &addrLen); #else newFd = accept(sock->handle, (struct sockaddr*)&addr, (socklen_t*)&addrLen); #endif 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, &addr, addrLen); return newSock; } deBool deSocket_connect (deSocket* sock, const deSocketAddress* address) { struct sockaddr bsdAddr; int bsdAddrLen; deSocketFamily family; /* Resolve address. */ if (!deSocketAddressToBsdAddress(address, &bsdAddr, &bsdAddrLen, &family)) return DE_FALSE; /* Create socket. */ sock->handle = socket(deSocketFamilyToBsdProtocolFamily(family), deSocketTypeToBsdType(address->type), deSocketProtocolToBsdProtocol(address->protocol)); if (!deSocketHandleIsValid(sock->handle)) return DE_FALSE; /* Connect. */ if (connect(sock->handle, &bsdAddr, bsdAddrLen) != 0) 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 & ~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, int bufSize, int* numSentPtr) { int numSent = (int)send(sock->handle, (const char*)buf, bufSize, 0); deSocketResult result = mapSendRecvResult(numSent); if (numSentPtr) *numSentPtr = numSent; /* 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, int bufSize, int* numReceivedPtr) { int numRecv = (int)recv(sock->handle, (char*)buf, bufSize, 0); deSocketResult result = mapSendRecvResult(numRecv); if (numReceivedPtr) *numReceivedPtr = numRecv; /* 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