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