C++程序  |  807行  |  19.41 KB

/*-------------------------------------------------------------------------
 * 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