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
39const 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
52const 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
66struct deSocketAddress_s
67{
68	char*				host;
69	int					port;
70	deSocketFamily		family;
71	deSocketType		type;
72	deSocketProtocol	protocol;
73};
74
75deSocketAddress* 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
89deBool deSocketAddress_setFamily (deSocketAddress* address, deSocketFamily family)
90{
91	address->family = family;
92	return DE_TRUE;
93}
94
95deSocketFamily deSocketAddress_getFamily (const deSocketAddress* address)
96{
97	return address->family;
98}
99
100void deSocketAddress_destroy (deSocketAddress* address)
101{
102	deFree(address->host);
103	deFree(address);
104}
105
106deBool deSocketAddress_setPort (deSocketAddress* address, int port)
107{
108	address->port = port;
109	return DE_TRUE;
110}
111
112int deSocketAddress_getPort (const deSocketAddress* address)
113{
114	return address->port;
115}
116
117deBool 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
129const char* deSocketAddress_getHost (const deSocketAddress* address)
130{
131	return address->host;
132}
133
134
135deBool deSocketAddress_setType (deSocketAddress* address, deSocketType type)
136{
137	address->type = type;
138	return DE_TRUE;
139}
140
141deSocketType deSocketAddress_getType (const deSocketAddress* address)
142{
143	return address->type;
144}
145
146deBool deSocketAddress_setProtocol (deSocketAddress* address, deSocketProtocol protocol)
147{
148	address->protocol = protocol;
149	return DE_TRUE;
150}
151
152deSocketProtocol 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
166static 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
203DE_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
212struct 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
223static 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
232static 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
241DE_STATIC_ASSERT(sizeof(((struct sockaddr_in*)DE_NULL)->sin_port) == sizeof(deUint16));
242DE_STATIC_ASSERT(sizeof(((struct sockaddr_in6*)DE_NULL)->sin6_port) == sizeof(deUint16));
243
244static 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
256static 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
268static 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
280static 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
373void 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
410deSocket* 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
429void 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
438deSocketState deSocket_getState (const deSocket* sock)
439{
440	return sock->state;
441}
442
443deUint32 deSocket_getOpenChannels (const deSocket* sock)
444{
445	return sock->openChannels;
446}
447
448deBool 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
496deBool 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
542deSocket* 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
578deBool 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
611deBool 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
696deBool 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
729static 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
761DE_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
772deSocketResult 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
789deSocketResult 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