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