ce8a1ddfa5a7d23f62ec5164ba70934d75c902f4
[platform/upstream/VK-GL-CTS.git] / framework / delibs / deutil / deSocket.c
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