Home | History | Annotate | Download | only in deutil
      1 /*-------------------------------------------------------------------------
      2  * drawElements Utility Library
      3  * ----------------------------
      4  *
      5  * Copyright 2014 The Android Open Source Project
      6  *
      7  * Licensed under the Apache License, Version 2.0 (the "License");
      8  * you may not use this file except in compliance with the License.
      9  * You may obtain a copy of the License at
     10  *
     11  *      http://www.apache.org/licenses/LICENSE-2.0
     12  *
     13  * Unless required by applicable law or agreed to in writing, software
     14  * distributed under the License is distributed on an "AS IS" BASIS,
     15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     16  * See the License for the specific language governing permissions and
     17  * limitations under the License.
     18  *
     19  *//*!
     20  * \file
     21  * \brief Socket abstraction.
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "deSocket.h"
     25 #include "deMemory.h"
     26 #include "deMutex.h"
     27 #include "deInt32.h"
     28 
     29 #if (DE_OS == DE_OS_WIN32)
     30 #	define DE_USE_WINSOCK
     31 #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)
     32 #	define DE_USE_BERKELEY_SOCKETS
     33 #else
     34 #	error Implement deSocket for your OS.
     35 #endif
     36 
     37 /* Common utilities. */
     38 
     39 const char* deGetSocketResultName (deSocketResult result)
     40 {
     41 	switch (result)
     42 	{
     43 		case DE_SOCKETRESULT_SUCCESS:				return "DE_SOCKETRESULT_SUCCESS";
     44 		case DE_SOCKETRESULT_WOULD_BLOCK:			return "DE_SOCKETRESULT_WOULD_BLOCK";
     45 		case DE_SOCKETRESULT_CONNECTION_CLOSED:		return "DE_SOCKETRESULT_CONNECTION_CLOSED";
     46 		case DE_SOCKETRESULT_CONNECTION_TERMINATED:	return "DE_SOCKETRESULT_CONNECTION_TERMINATED";
     47 		case DE_SOCKETRESULT_ERROR:					return "DE_SOCKETRESULT_ERROR";
     48 		default:									return DE_NULL;
     49 	}
     50 }
     51 
     52 const char* deGetSocketFamilyName (deSocketFamily family)
     53 {
     54 	switch (family)
     55 	{
     56 		case DE_SOCKETFAMILY_INET4:		return "DE_SOCKETFAMILY_INET4";
     57 		case DE_SOCKETFAMILY_INET6:		return "DE_SOCKETFAMILY_INET6";
     58 		default:						return DE_NULL;
     59 	}
     60 }
     61 
     62 #if defined(DE_USE_WINSOCK) || defined(DE_USE_BERKELEY_SOCKETS)
     63 
     64 /* Common deSocketAddress implementation. */
     65 
     66 struct deSocketAddress_s
     67 {
     68 	char*				host;
     69 	int					port;
     70 	deSocketFamily		family;
     71 	deSocketType		type;
     72 	deSocketProtocol	protocol;
     73 };
     74 
     75 deSocketAddress* deSocketAddress_create (void)
     76 {
     77 	deSocketAddress* addr = (deSocketAddress*)deCalloc(sizeof(deSocketAddress));
     78 	if (!addr)
     79 		return addr;
     80 
     81 	/* Sane defaults. */
     82 	addr->family	= DE_SOCKETFAMILY_INET4;
     83 	addr->type		= DE_SOCKETTYPE_STREAM;
     84 	addr->protocol	= DE_SOCKETPROTOCOL_TCP;
     85 
     86 	return addr;
     87 }
     88 
     89 deBool deSocketAddress_setFamily (deSocketAddress* address, deSocketFamily family)
     90 {
     91 	address->family = family;
     92 	return DE_TRUE;
     93 }
     94 
     95 deSocketFamily deSocketAddress_getFamily (const deSocketAddress* address)
     96 {
     97 	return address->family;
     98 }
     99 
    100 void deSocketAddress_destroy (deSocketAddress* address)
    101 {
    102 	deFree(address->host);
    103 	deFree(address);
    104 }
    105 
    106 deBool deSocketAddress_setPort (deSocketAddress* address, int port)
    107 {
    108 	address->port = port;
    109 	return DE_TRUE;
    110 }
    111 
    112 int deSocketAddress_getPort (const deSocketAddress* address)
    113 {
    114 	return address->port;
    115 }
    116 
    117 deBool deSocketAddress_setHost (deSocketAddress* address, const char* host)
    118 {
    119 	if (address->host)
    120 	{
    121 		deFree(address->host);
    122 		address->host = DE_NULL;
    123 	}
    124 
    125 	address->host = deStrdup(host);
    126 	return address->host != DE_NULL;
    127 }
    128 
    129 const char* deSocketAddress_getHost (const deSocketAddress* address)
    130 {
    131 	return address->host;
    132 }
    133 
    134 
    135 deBool deSocketAddress_setType (deSocketAddress* address, deSocketType type)
    136 {
    137 	address->type = type;
    138 	return DE_TRUE;
    139 }
    140 
    141 deSocketType deSocketAddress_getType (const deSocketAddress* address)
    142 {
    143 	return address->type;
    144 }
    145 
    146 deBool deSocketAddress_setProtocol (deSocketAddress* address, deSocketProtocol protocol)
    147 {
    148 	address->protocol = protocol;
    149 	return DE_TRUE;
    150 }
    151 
    152 deSocketProtocol deSocketAddress_getProtocol (const deSocketAddress* address)
    153 {
    154 	return address->protocol;
    155 }
    156 
    157 #endif
    158 
    159 #if defined(DE_USE_WINSOCK)
    160 
    161 	/* WinSock spesific. */
    162 #	include <WinSock2.h>
    163 #	include <WS2tcpip.h>
    164 #	include <WinDef.h>
    165 
    166 static deBool initWinsock (void)
    167 {
    168 	WSADATA wsaData;
    169 	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
    170 		return DE_FALSE;
    171 
    172 	return DE_TRUE;
    173 }
    174 
    175 #elif defined(DE_USE_BERKELEY_SOCKETS)
    176 
    177 	/* Berkeley Socket includes. */
    178 #	include <sys/socket.h>
    179 #	include <netinet/in.h>
    180 #	include <netinet/tcp.h>
    181 #	include <arpa/inet.h>
    182 #	include <netdb.h>
    183 #	include <unistd.h>
    184 #	include <fcntl.h>
    185 #	include <errno.h>
    186 
    187 #endif
    188 
    189 /* Socket type. */
    190 #if defined(DE_USE_WINSOCK)
    191 	/* \note SOCKET is unsigned type! */
    192 	typedef SOCKET					deSocketHandle;
    193 	typedef int						NativeSocklen;
    194 	typedef int						NativeSize;
    195 #	define DE_INVALID_SOCKET_HANDLE	INVALID_SOCKET
    196 #else
    197 	typedef int						deSocketHandle;
    198 	typedef socklen_t				NativeSocklen;
    199 	typedef size_t					NativeSize;
    200 #	define DE_INVALID_SOCKET_HANDLE	-1
    201 #endif
    202 
    203 DE_INLINE deBool deSocketHandleIsValid (deSocketHandle handle)
    204 {
    205 	return handle != DE_INVALID_SOCKET_HANDLE;
    206 }
    207 
    208 #if defined(DE_USE_WINSOCK) || defined(DE_USE_BERKELEY_SOCKETS)
    209 
    210 /* Shared berkeley and winsock implementation. */
    211 
    212 struct deSocket_s
    213 {
    214 	deSocketHandle			handle;
    215 
    216 	deMutex					stateLock;
    217 	volatile deSocketState	state;
    218 	volatile deUint32		openChannels;
    219 };
    220 
    221 /* Common socket functions. */
    222 
    223 static deUint16 deHostToNetworkOrder16 (deUint16 v)
    224 {
    225 #if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
    226 	return deReverseBytes16(v);
    227 #else
    228 	return v;
    229 #endif
    230 }
    231 
    232 static deUint16 deNetworkToHostOrder16 (deUint16 v)
    233 {
    234 #if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
    235 	return deReverseBytes16(v);
    236 #else
    237 	return v;
    238 #endif
    239 }
    240 
    241 DE_STATIC_ASSERT(sizeof(((struct sockaddr_in*)DE_NULL)->sin_port) == sizeof(deUint16));
    242 DE_STATIC_ASSERT(sizeof(((struct sockaddr_in6*)DE_NULL)->sin6_port) == sizeof(deUint16));
    243 
    244 static int deSocketFamilyToBsdFamily (deSocketFamily family)
    245 {
    246 	switch (family)
    247 	{
    248 		case DE_SOCKETFAMILY_INET4:	return AF_INET;
    249 		case DE_SOCKETFAMILY_INET6:	return AF_INET6;
    250 		default:
    251 			DE_ASSERT(DE_FALSE);
    252 			return 0;
    253 	}
    254 }
    255 
    256 static int deSocketTypeToBsdType (deSocketType type)
    257 {
    258 	switch (type)
    259 	{
    260 		case DE_SOCKETTYPE_STREAM:		return SOCK_STREAM;
    261 		case DE_SOCKETTYPE_DATAGRAM:	return SOCK_DGRAM;
    262 		default:
    263 			DE_ASSERT(DE_FALSE);
    264 			return 0;
    265 	}
    266 }
    267 
    268 static int deSocketProtocolToBsdProtocol (deSocketProtocol protocol)
    269 {
    270 	switch (protocol)
    271 	{
    272 		case DE_SOCKETPROTOCOL_TCP:	return IPPROTO_TCP;
    273 		case DE_SOCKETPROTOCOL_UDP:	return IPPROTO_UDP;
    274 		default:
    275 			DE_ASSERT(DE_FALSE);
    276 			return 0;
    277 	}
    278 }
    279 
    280 static deBool deSocketAddressToBsdAddress (const deSocketAddress* address, size_t bsdAddrBufSize, struct sockaddr* bsdAddr, NativeSocklen* bsdAddrLen)
    281 {
    282 	deMemset(bsdAddr, 0, bsdAddrBufSize);
    283 
    284 	/* Resolve host. */
    285 	if (address->host != DE_NULL)
    286 	{
    287 		struct addrinfo*	result	= DE_NULL;
    288 		struct addrinfo		hints;
    289 
    290 		deMemset(&hints, 0, sizeof(hints));
    291 		hints.ai_family		= deSocketFamilyToBsdFamily(address->family);
    292 		hints.ai_socktype	= deSocketTypeToBsdType(address->type);
    293 		hints.ai_protocol	= deSocketProtocolToBsdProtocol(address->protocol);
    294 
    295 		if (getaddrinfo(address->host, DE_NULL, &hints, &result) != 0 || !result)
    296 		{
    297 			if (result)
    298 				freeaddrinfo(result);
    299 			return DE_FALSE;
    300 		}
    301 
    302 		/* \note Always uses first address. */
    303 
    304 		if (bsdAddrBufSize < (size_t)result->ai_addrlen)
    305 		{
    306 			DE_FATAL("Too small bsdAddr buffer");
    307 			freeaddrinfo(result);
    308 			return DE_FALSE;
    309 		}
    310 
    311 		*bsdAddrLen	= (NativeSocklen)result->ai_addrlen;
    312 
    313 		deMemcpy(bsdAddr, result->ai_addr, (size_t)result->ai_addrlen);
    314 		freeaddrinfo(result);
    315 
    316 		/* Add port. */
    317 		if (bsdAddr->sa_family == AF_INET)
    318 		{
    319 			if (*bsdAddrLen < (NativeSocklen)sizeof(struct sockaddr_in))
    320 				return DE_FALSE;
    321 			((struct sockaddr_in*)bsdAddr)->sin_port = deHostToNetworkOrder16((deUint16)address->port);
    322 		}
    323 		else if (bsdAddr->sa_family == AF_INET6)
    324 		{
    325 			if (*bsdAddrLen < (NativeSocklen)sizeof(struct sockaddr_in6))
    326 				return DE_FALSE;
    327 			((struct sockaddr_in6*)bsdAddr)->sin6_port = deHostToNetworkOrder16((deUint16)address->port);
    328 		}
    329 		else
    330 			return DE_FALSE;
    331 
    332 		return DE_TRUE;
    333 	}
    334 	else if (address->family == DE_SOCKETFAMILY_INET4)
    335 	{
    336 		struct sockaddr_in* addr4 = (struct sockaddr_in*)bsdAddr;
    337 
    338 		if (bsdAddrBufSize < sizeof(struct sockaddr_in))
    339 		{
    340 			DE_FATAL("Too small bsdAddr buffer");
    341 			return DE_FALSE;
    342 		}
    343 
    344 		addr4->sin_port			= deHostToNetworkOrder16((deUint16)address->port);
    345 		addr4->sin_family		= AF_INET;
    346 		addr4->sin_addr.s_addr	= INADDR_ANY;
    347 
    348 		*bsdAddrLen	= (NativeSocklen)sizeof(struct sockaddr_in);
    349 
    350 		return DE_TRUE;
    351 	}
    352 	else if (address->family == DE_SOCKETFAMILY_INET6)
    353 	{
    354 		struct sockaddr_in6* addr6 = (struct sockaddr_in6*)bsdAddr;
    355 
    356 		if (bsdAddrBufSize < sizeof(struct sockaddr_in6))
    357 		{
    358 			DE_FATAL("Too small bsdAddr buffer");
    359 			return DE_FALSE;
    360 		}
    361 
    362 		addr6->sin6_port	= deHostToNetworkOrder16((deUint16)address->port);
    363 		addr6->sin6_family	= AF_INET6;
    364 
    365 		*bsdAddrLen	= (NativeSocklen)sizeof(struct sockaddr_in6);
    366 
    367 		return DE_TRUE;
    368 	}
    369 	else
    370 		return DE_FALSE;
    371 }
    372 
    373 void deBsdAddressToSocketAddress (deSocketAddress* address, const struct sockaddr* bsdAddr, int addrLen)
    374 {
    375 	/* Decode client address info. */
    376 	if (bsdAddr->sa_family == AF_INET)
    377 	{
    378 		const struct sockaddr_in* addr4 = (const struct sockaddr_in*)bsdAddr;
    379 		DE_ASSERT(addrLen >= (int)sizeof(struct sockaddr_in));
    380 		DE_UNREF(addrLen);
    381 
    382 		deSocketAddress_setFamily(address, DE_SOCKETFAMILY_INET4);
    383 		deSocketAddress_setPort(address, (int)deNetworkToHostOrder16((deUint16)addr4->sin_port));
    384 
    385 		{
    386 			char buf[16]; /* Max valid address takes 3*4 + 3 = 15 chars */
    387 			inet_ntop(AF_INET, (void*)&addr4->sin_addr, buf, sizeof(buf));
    388 			deSocketAddress_setHost(address, buf);
    389 		}
    390 	}
    391 	else if (bsdAddr->sa_family == AF_INET6)
    392 	{
    393 		const struct sockaddr_in6* addr6 = (const struct sockaddr_in6*)bsdAddr;
    394 		DE_ASSERT(addrLen >= (int)sizeof(struct sockaddr_in6));
    395 		DE_UNREF(addrLen);
    396 
    397 		deSocketAddress_setFamily(address, DE_SOCKETFAMILY_INET6);
    398 		deSocketAddress_setPort(address, (int)deNetworkToHostOrder16((deUint16)addr6->sin6_port));
    399 
    400 		{
    401 			char buf[40]; /* Max valid address takes 8*4 + 7 = 39 chars */
    402 			inet_ntop(AF_INET6, (void*)&addr6->sin6_addr, buf, sizeof(buf));
    403 			deSocketAddress_setHost(address, buf);
    404 		}
    405 	}
    406 	else
    407 		DE_ASSERT(DE_FALSE);
    408 }
    409 
    410 deSocket* deSocket_create (void)
    411 {
    412 	deSocket* sock = (deSocket*)deCalloc(sizeof(deSocket));
    413 	if (!sock)
    414 		return sock;
    415 
    416 #if defined(DE_USE_WINSOCK)
    417 	/* Make sure WSA is up. */
    418 	if (!initWinsock())
    419 		return DE_NULL;
    420 #endif
    421 
    422 	sock->stateLock	= deMutex_create(0);
    423 	sock->handle	= DE_INVALID_SOCKET_HANDLE;
    424 	sock->state		= DE_SOCKETSTATE_CLOSED;
    425 
    426 	return sock;
    427 }
    428 
    429 void deSocket_destroy (deSocket* sock)
    430 {
    431 	if (sock->state != DE_SOCKETSTATE_CLOSED)
    432 		deSocket_close(sock);
    433 
    434 	deMutex_destroy(sock->stateLock);
    435 	deFree(sock);
    436 }
    437 
    438 deSocketState deSocket_getState (const deSocket* sock)
    439 {
    440 	return sock->state;
    441 }
    442 
    443 deUint32 deSocket_getOpenChannels (const deSocket* sock)
    444 {
    445 	return sock->openChannels;
    446 }
    447 
    448 deBool deSocket_setFlags (deSocket* sock, deUint32 flags)
    449 {
    450 	deSocketHandle fd = sock->handle;
    451 
    452 	if (sock->state == DE_SOCKETSTATE_CLOSED)
    453 		return DE_FALSE;
    454 
    455 	/* Keepalive. */
    456 	{
    457 		int mode = (flags & DE_SOCKET_KEEPALIVE) ? 1 : 0;
    458 		if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (const char*)&mode, sizeof(mode)) != 0)
    459 			return DE_FALSE;
    460 	}
    461 
    462 	/* Nodelay. */
    463 	{
    464 		int mode = (flags & DE_SOCKET_NODELAY) ? 1 : 0;
    465 		if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const char*)&mode, sizeof(mode)) != 0)
    466 			return DE_FALSE;
    467 	}
    468 
    469 	/* Non-blocking. */
    470 	{
    471 #if defined(DE_USE_WINSOCK)
    472 		u_long mode = (flags & DE_SOCKET_NONBLOCKING) ? 1 : 0;
    473 		if (ioctlsocket(fd, FIONBIO, &mode) != 0)
    474 			return DE_FALSE;
    475 #else
    476 		int oldFlags	= fcntl(fd, F_GETFL, 0);
    477 		int newFlags	= (flags & DE_SOCKET_NONBLOCKING) ? (oldFlags | O_NONBLOCK) : (oldFlags & ~O_NONBLOCK);
    478 		if (fcntl(fd, F_SETFL, newFlags) != 0)
    479 			return DE_FALSE;
    480 #endif
    481 	}
    482 
    483 	/* Close on exec. */
    484 	{
    485 #if defined(DE_USE_BERKELEY_SOCKETS)
    486 		int oldFlags = fcntl(fd, F_GETFD, 0);
    487 		int newFlags = (flags & DE_SOCKET_CLOSE_ON_EXEC) ? (oldFlags | FD_CLOEXEC) : (oldFlags & ~FD_CLOEXEC);
    488 		if (fcntl(fd, F_SETFD, newFlags) != 0)
    489 			return DE_FALSE;
    490 #endif
    491 	}
    492 
    493 	return DE_TRUE;
    494 }
    495 
    496 deBool deSocket_listen (deSocket* sock, const deSocketAddress* address)
    497 {
    498 	const int			backlogSize	= 4;
    499 	deUint8				bsdAddrBuf[sizeof(struct sockaddr_in6)];
    500 	struct sockaddr*	bsdAddr		= (struct sockaddr*)&bsdAddrBuf[0];
    501 	NativeSocklen		bsdAddrLen;
    502 
    503 	if (sock->state != DE_SOCKETSTATE_CLOSED)
    504 		return DE_FALSE;
    505 
    506 	/* Resolve address. */
    507 	if (!deSocketAddressToBsdAddress(address, sizeof(bsdAddrBuf), bsdAddr, &bsdAddrLen))
    508 		return DE_FALSE;
    509 
    510 	/* Create socket. */
    511 	sock->handle = socket(bsdAddr->sa_family, deSocketTypeToBsdType(address->type), deSocketProtocolToBsdProtocol(address->protocol));
    512 	if (!deSocketHandleIsValid(sock->handle))
    513 		return DE_FALSE;
    514 
    515 	sock->state = DE_SOCKETSTATE_DISCONNECTED;
    516 
    517 	/* Allow re-using address. */
    518 	{
    519 		int reuseVal = 1;
    520 		setsockopt(sock->handle, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuseVal, (int)sizeof(reuseVal));
    521 	}
    522 
    523 	/* Bind to address. */
    524 	if (bind(sock->handle, bsdAddr, (NativeSocklen)bsdAddrLen) != 0)
    525 	{
    526 		deSocket_close(sock);
    527 		return DE_FALSE;
    528 	}
    529 
    530 	/* Start listening. */
    531 	if (listen(sock->handle, backlogSize) != 0)
    532 	{
    533 		deSocket_close(sock);
    534 		return DE_FALSE;
    535 	}
    536 
    537 	sock->state = DE_SOCKETSTATE_LISTENING;
    538 
    539 	return DE_TRUE;
    540 }
    541 
    542 deSocket* deSocket_accept (deSocket* sock, deSocketAddress* clientAddress)
    543 {
    544 	deSocketHandle		newFd		= DE_INVALID_SOCKET_HANDLE;
    545 	deSocket*			newSock		= DE_NULL;
    546 	deUint8				bsdAddrBuf[sizeof(struct sockaddr_in6)];
    547 	struct sockaddr*	bsdAddr		= (struct sockaddr*)&bsdAddrBuf[0];
    548 	NativeSocklen		bsdAddrLen	= (NativeSocklen)sizeof(bsdAddrBuf);
    549 
    550 	deMemset(bsdAddr, 0, (size_t)bsdAddrLen);
    551 
    552 	newFd = accept(sock->handle, bsdAddr, &bsdAddrLen);
    553 	if (!deSocketHandleIsValid(newFd))
    554 		return DE_NULL;
    555 
    556 	newSock = (deSocket*)deCalloc(sizeof(deSocket));
    557 	if (!newSock)
    558 	{
    559 #if defined(DE_USE_WINSOCK)
    560 		closesocket(newFd);
    561 #else
    562 		close(newFd);
    563 #endif
    564 		return DE_NULL;
    565 	}
    566 
    567 	newSock->stateLock		= deMutex_create(0);
    568 	newSock->handle			= newFd;
    569 	newSock->state			= DE_SOCKETSTATE_CONNECTED;
    570 	newSock->openChannels	= DE_SOCKETCHANNEL_BOTH;
    571 
    572 	if (clientAddress)
    573 		deBsdAddressToSocketAddress(clientAddress, bsdAddr, (int)bsdAddrLen);
    574 
    575 	return newSock;
    576 }
    577 
    578 deBool deSocket_connect (deSocket* sock, const deSocketAddress* address)
    579 {
    580 	deUint8				bsdAddrBuf[sizeof(struct sockaddr_in6)];
    581 	struct sockaddr*	bsdAddr		= (struct sockaddr*)&bsdAddrBuf[0];
    582 	NativeSocklen		bsdAddrLen;
    583 
    584 	/* Resolve address. */
    585 	if (!deSocketAddressToBsdAddress(address, sizeof(bsdAddrBuf), bsdAddr, &bsdAddrLen))
    586 		return DE_FALSE;
    587 
    588 	/* Create socket. */
    589 	sock->handle = socket(bsdAddr->sa_family, deSocketTypeToBsdType(address->type), deSocketProtocolToBsdProtocol(address->protocol));
    590 	if (!deSocketHandleIsValid(sock->handle))
    591 		return DE_FALSE;
    592 
    593 	/* Connect. */
    594 	if (connect(sock->handle, bsdAddr, bsdAddrLen) != 0)
    595 	{
    596 #if defined(DE_USE_WINSOCK)
    597 		closesocket(sock->handle);
    598 #else
    599 		close(sock->handle);
    600 #endif
    601 		sock->handle = DE_INVALID_SOCKET_HANDLE;
    602 		return DE_FALSE;
    603 	}
    604 
    605 	sock->state			= DE_SOCKETSTATE_CONNECTED;
    606 	sock->openChannels	= DE_SOCKETCHANNEL_BOTH;
    607 
    608 	return DE_TRUE;
    609 }
    610 
    611 deBool deSocket_shutdown (deSocket* sock, deUint32 channels)
    612 {
    613 	deUint32 closedChannels = 0;
    614 
    615 	deMutex_lock(sock->stateLock);
    616 
    617 	if (sock->state == DE_SOCKETSTATE_DISCONNECTED ||
    618 		sock->state == DE_SOCKETSTATE_CLOSED)
    619 	{
    620 		deMutex_unlock(sock->stateLock);
    621 		return DE_FALSE;
    622 	}
    623 
    624 	DE_ASSERT(channels != 0 && (channels & ~(deUint32)DE_SOCKETCHANNEL_BOTH) == 0);
    625 
    626 	/* Don't attempt to close already closed channels on partially open socket. */
    627 	channels &= sock->openChannels;
    628 
    629 	if (channels == 0)
    630 	{
    631 		deMutex_unlock(sock->stateLock);
    632 		return DE_FALSE;
    633 	}
    634 
    635 #if defined(DE_USE_WINSOCK)
    636 	{
    637 		int how = 0;
    638 
    639 		if ((channels & DE_SOCKETCHANNEL_BOTH) == DE_SOCKETCHANNEL_BOTH)
    640 			how = SD_BOTH;
    641 		else if (channels & DE_SOCKETCHANNEL_SEND)
    642 			how = SD_SEND;
    643 		else if (channels & DE_SOCKETCHANNEL_RECEIVE)
    644 			how = SD_RECEIVE;
    645 
    646 		if (shutdown(sock->handle, how) == 0)
    647 			closedChannels = channels;
    648 		else
    649 		{
    650 			int err = WSAGetLastError();
    651 
    652 			/* \note Due to asynchronous behavior certain errors are perfectly ok. */
    653 			if (err == WSAECONNABORTED || err == WSAECONNRESET || err == WSAENOTCONN)
    654 				closedChannels = DE_SOCKETCHANNEL_BOTH;
    655 			else
    656 			{
    657 				deMutex_unlock(sock->stateLock);
    658 				return DE_FALSE;
    659 			}
    660 		}
    661 	}
    662 #else
    663 	{
    664 		int how = 0;
    665 
    666 		if ((channels & DE_SOCKETCHANNEL_BOTH) == DE_SOCKETCHANNEL_BOTH)
    667 			how = SHUT_RDWR;
    668 		else if (channels & DE_SOCKETCHANNEL_SEND)
    669 			how = SHUT_WR;
    670 		else if (channels & DE_SOCKETCHANNEL_RECEIVE)
    671 			how = SHUT_RD;
    672 
    673 		if (shutdown(sock->handle, how) == 0)
    674 			closedChannels = channels;
    675 		else
    676 		{
    677 			if (errno == ENOTCONN)
    678 				closedChannels = DE_SOCKETCHANNEL_BOTH;
    679 			else
    680 			{
    681 				deMutex_unlock(sock->stateLock);
    682 				return DE_FALSE;
    683 			}
    684 		}
    685 	}
    686 #endif
    687 
    688 	sock->openChannels &= ~closedChannels;
    689 	if (sock->openChannels == 0)
    690 		sock->state = DE_SOCKETSTATE_DISCONNECTED;
    691 
    692 	deMutex_unlock(sock->stateLock);
    693 	return DE_TRUE;
    694 }
    695 
    696 deBool deSocket_close (deSocket* sock)
    697 {
    698 	deMutex_lock(sock->stateLock);
    699 
    700 	if (sock->state == DE_SOCKETSTATE_CLOSED)
    701 	{
    702 		deMutex_unlock(sock->stateLock);
    703 		return DE_FALSE;
    704 	}
    705 
    706 #if !defined(DE_USE_WINSOCK)
    707 	if (sock->state == DE_SOCKETSTATE_LISTENING)
    708 	{
    709 		/* There can be a thread blockin in accept(). Release it by calling shutdown. */
    710 		shutdown(sock->handle, SHUT_RDWR);
    711 	}
    712 #endif
    713 
    714 #if defined(DE_USE_WINSOCK)
    715 	if (closesocket(sock->handle) != 0)
    716 		return DE_FALSE;
    717 #else
    718 	if (close(sock->handle) != 0)
    719 		return DE_FALSE;
    720 #endif
    721 	sock->state			= DE_SOCKETSTATE_CLOSED;
    722 	sock->handle		= DE_INVALID_SOCKET_HANDLE;
    723 	sock->openChannels	= 0;
    724 
    725 	deMutex_unlock(sock->stateLock);
    726 	return DE_TRUE;
    727 }
    728 
    729 static deSocketResult mapSendRecvResult (int numBytes)
    730 {
    731 	if (numBytes > 0)
    732 		return DE_SOCKETRESULT_SUCCESS;
    733 	else if (numBytes == 0)
    734 		return DE_SOCKETRESULT_CONNECTION_CLOSED;
    735 	else
    736 	{
    737 		/* Other errors. */
    738 #if defined(DE_USE_WINSOCK)
    739 		int	error = WSAGetLastError();
    740 		switch (error)
    741 		{
    742 			case WSAEWOULDBLOCK:	return DE_SOCKETRESULT_WOULD_BLOCK;
    743 			case WSAENETDOWN:
    744 			case WSAENETRESET:
    745 			case WSAECONNABORTED:
    746 			case WSAECONNRESET:		return DE_SOCKETRESULT_CONNECTION_TERMINATED;
    747 			default:				return DE_SOCKETRESULT_ERROR;
    748 		}
    749 #else
    750 		switch (errno)
    751 		{
    752 			case EAGAIN:		return DE_SOCKETRESULT_WOULD_BLOCK;
    753 			case ECONNABORTED:
    754 			case ECONNRESET:	return DE_SOCKETRESULT_CONNECTION_TERMINATED;
    755 			default:			return DE_SOCKETRESULT_ERROR;
    756 		}
    757 #endif
    758 	}
    759 }
    760 
    761 DE_INLINE void deSocket_setChannelsClosed (deSocket* sock, deUint32 channels)
    762 {
    763 	deMutex_lock(sock->stateLock);
    764 
    765 	sock->openChannels &= ~channels;
    766 	if (sock->openChannels == 0)
    767 		sock->state = DE_SOCKETSTATE_DISCONNECTED;
    768 
    769 	deMutex_unlock(sock->stateLock);
    770 }
    771 
    772 deSocketResult deSocket_send (deSocket* sock, const void* buf, size_t bufSize, size_t* numSentPtr)
    773 {
    774 	int				numSent	= (int)send(sock->handle, (const char*)buf, (NativeSize)bufSize, 0);
    775 	deSocketResult	result	= mapSendRecvResult(numSent);
    776 
    777 	if (numSentPtr)
    778 		*numSentPtr = (numSent > 0) ? ((size_t)numSent) : (0);
    779 
    780 	/* Update state. */
    781 	if (result == DE_SOCKETRESULT_CONNECTION_CLOSED)
    782 		deSocket_setChannelsClosed(sock, DE_SOCKETCHANNEL_SEND);
    783 	else if (result == DE_SOCKETRESULT_CONNECTION_TERMINATED)
    784 		deSocket_setChannelsClosed(sock, DE_SOCKETCHANNEL_BOTH);
    785 
    786 	return result;
    787 }
    788 
    789 deSocketResult deSocket_receive (deSocket* sock, void* buf, size_t bufSize, size_t* numReceivedPtr)
    790 {
    791 	int				numRecv	= (int)recv(sock->handle, (char*)buf, (NativeSize)bufSize, 0);
    792 	deSocketResult	result	= mapSendRecvResult(numRecv);
    793 
    794 	if (numReceivedPtr)
    795 		*numReceivedPtr = (numRecv > 0) ? ((size_t)numRecv) : (0);
    796 
    797 	/* Update state. */
    798 	if (result == DE_SOCKETRESULT_CONNECTION_CLOSED)
    799 		deSocket_setChannelsClosed(sock, DE_SOCKETCHANNEL_RECEIVE);
    800 	else if (result == DE_SOCKETRESULT_CONNECTION_TERMINATED)
    801 		deSocket_setChannelsClosed(sock, DE_SOCKETCHANNEL_BOTH);
    802 
    803 	return result;
    804 }
    805 
    806 #endif
    807