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