Fix couple of trivial warnings reported by MSVC
[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
28 #if (DE_OS == DE_OS_WIN32)
29 #       define DE_USE_WINSOCK
30 #elif (DE_OS == DE_OS_UNIX) || (DE_OS == DE_OS_OSX) || (DE_OS == DE_OS_IOS) || (DE_OS == DE_OS_ANDROID) || (DE_OS == DE_OS_SYMBIAN)
31 #       define DE_USE_BERKELEY_SOCKETS
32 #else
33 #       error Implement deSocket for your OS.
34 #endif
35
36 /* Common utilities. */
37
38 const char* deGetSocketResultName (deSocketResult result)
39 {
40         switch (result)
41         {
42                 case DE_SOCKETRESULT_SUCCESS:                           return "DE_SOCKETRESULT_SUCCESS";
43                 case DE_SOCKETRESULT_WOULD_BLOCK:                       return "DE_SOCKETRESULT_WOULD_BLOCK";
44                 case DE_SOCKETRESULT_CONNECTION_CLOSED:         return "DE_SOCKETRESULT_CONNECTION_CLOSED";
45                 case DE_SOCKETRESULT_CONNECTION_TERMINATED:     return "DE_SOCKETRESULT_CONNECTION_TERMINATED";
46                 case DE_SOCKETRESULT_ERROR:                                     return "DE_SOCKETRESULT_ERROR";
47                 default:                                                                        return DE_NULL;
48         }
49 }
50
51 const char* deGetSocketFamilyName (deSocketFamily family)
52 {
53         switch (family)
54         {
55                 case DE_SOCKETFAMILY_INET4:             return "DE_SOCKETFAMILY_INET4";
56                 case DE_SOCKETFAMILY_INET6:             return "DE_SOCKETFAMILY_INET6";
57                 default:                                                return DE_NULL;
58         }
59 }
60
61 #if defined(DE_USE_WINSOCK) || defined(DE_USE_BERKELEY_SOCKETS)
62
63 /* Common deSocketAddress implementation. */
64
65 struct deSocketAddress_s
66 {
67         char*                           host;
68         int                                     port;
69         deSocketFamily          family;
70         deSocketType            type;
71         deSocketProtocol        protocol;
72 };
73
74 deSocketAddress* deSocketAddress_create (void)
75 {
76         deSocketAddress* addr = (deSocketAddress*)deCalloc(sizeof(deSocketAddress));
77         if (!addr)
78                 return addr;
79
80         /* Sane defaults. */
81         addr->family    = DE_SOCKETFAMILY_INET4;
82         addr->type              = DE_SOCKETTYPE_STREAM;
83         addr->protocol  = DE_SOCKETPROTOCOL_TCP;
84
85         return addr;
86 }
87
88 deBool deSocketAddress_setFamily (deSocketAddress* address, deSocketFamily family)
89 {
90         address->family = family;
91         return DE_TRUE;
92 }
93
94 deSocketFamily deSocketAddress_getFamily (const deSocketAddress* address)
95 {
96         return address->family;
97 }
98
99 void deSocketAddress_destroy (deSocketAddress* address)
100 {
101         deFree(address->host);
102         deFree(address);
103 }
104
105 deBool deSocketAddress_setPort (deSocketAddress* address, int port)
106 {
107         address->port = port;
108         return DE_TRUE;
109 }
110
111 int deSocketAddress_getPort (const deSocketAddress* address)
112 {
113         return address->port;
114 }
115
116 deBool deSocketAddress_setHost (deSocketAddress* address, const char* host)
117 {
118         if (address->host)
119         {
120                 deFree(address->host);
121                 address->host = DE_NULL;
122         }
123
124         address->host = deStrdup(host);
125         return address->host != DE_NULL;
126 }
127
128 const char* deSocketAddress_getHost (const deSocketAddress* address)
129 {
130         return address->host;
131 }
132
133
134 deBool deSocketAddress_setType (deSocketAddress* address, deSocketType type)
135 {
136         address->type = type;
137         return DE_TRUE;
138 }
139
140 deSocketType deSocketAddress_getType (const deSocketAddress* address)
141 {
142         return address->type;
143 }
144
145 deBool deSocketAddress_setProtocol (deSocketAddress* address, deSocketProtocol protocol)
146 {
147         address->protocol = protocol;
148         return DE_TRUE;
149 }
150
151 deSocketProtocol deSocketAddress_getProtocol (const deSocketAddress* address)
152 {
153         return address->protocol;
154 }
155
156 #endif
157
158 #if defined(DE_USE_WINSOCK)
159
160         /* WinSock spesific. */
161 #       include <WinSock2.h>
162 #       include <WS2tcpip.h>
163 #       include <WinDef.h>
164
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
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
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
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
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
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
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
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
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
412 deSocketState deSocket_getState (const deSocket* sock)
413 {
414         return sock->state;
415 }
416
417 deUint32 deSocket_getOpenChannels (const deSocket* sock)
418 {
419         return sock->openChannels;
420 }
421
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
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
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
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
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
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
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
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
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
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