1 /* sim_sock.c: OS-dependent socket routines
2 
3    Copyright (c) 2001-2010 Robert M Supnik
4    Copyright (c) 2021 The DPS8M Development Team
5 
6    Permission is hereby granted, free of charge, to any person obtaining a
7    copy of this software and associated documentation files (the "Software"),
8    to deal in the Software without restriction, including without limitation
9    the rights to use, copy, modify, merge, publish, distribute, sublicense,
10    and/or sell copies of the Software, and to permit persons to whom the
11    Software is furnished to do so, subject to the following conditions:
12 
13    The above copyright notice and this permission notice shall be included in
14    all copies or substantial portions of the Software.
15 
16    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19    ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20    IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21    CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 
23    Except as contained in this notice, the name of Robert M Supnik shall not be
24    used in advertising or otherwise to promote the sale, use or other dealings
25    in this Software without prior written authorization from Robert M Supnik.
26 */
27 
28 #include "sim_sock.h"
29 #include <signal.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 
33 #if defined(AF_INET6) && defined(_WIN32)
34 # include <ws2tcpip.h>
35 #endif
36 
37 #ifndef WSAAPI
38 # define WSAAPI
39 #endif
40 
41 #if defined(SHUT_RDWR) && !defined(SD_BOTH)
42 # define SD_BOTH SHUT_RDWR
43 #endif
44 
45 #ifndef NI_MAXHOST
46 # define NI_MAXHOST 1025
47 #endif
48 
49 /* OS dependent routines
50 
51    sim_master_sock      create master socket
52    sim_connect_sock     connect a socket to a remote destination
53    sim_connect_sock_ex  connect a socket to a remote destination
54    sim_accept_conn      accept connection
55    sim_read_sock        read from socket
56    sim_write_sock       write from socket
57    sim_close_sock       close socket
58    sim_setnonblock      set socket non-blocking
59 */
60 
61 /* First, all the non-implemented versions */
62 
63 /* Standard Berkeley socket routines */
64 
65 static struct sock_errors {
66     int value;
67     const char *text;
68     } sock_errors[] = {
69         {WSAEWOULDBLOCK,  "Operation would block"},
70         {WSAENAMETOOLONG, "File name too long"},
71         {WSAEINPROGRESS,  "Operation now in progress "},
72         {WSAETIMEDOUT,    "Connection timed out"},
73         {WSAEISCONN,      "Transport endpoint is already connected"},
74         {WSAECONNRESET,   "Connection reset by peer"},
75         {WSAECONNREFUSED, "Connection refused"},
76         {WSAECONNABORTED, "Connection aborted"},
77         {WSAEHOSTUNREACH, "No route to host"},
78         {WSAEADDRINUSE,   "Address already in use"},
79 #if defined (WSAEAFNOSUPPORT)
80         {WSAEAFNOSUPPORT, "Address family not supported by protocol"},
81 #endif
82         {WSAEACCES,       "Permission denied"},
83         {0, NULL}
84     };
85 
sim_get_err_sock(const char * emsg)86 const char *sim_get_err_sock (const char *emsg)
87 {
88 int err = WSAGetLastError ();
89 int i;
90 static char err_buf[512];
91 
92 for (i=0; (sock_errors[i].text) && (sock_errors[i].value != err); i++)
93     ;
94 if (sock_errors[i].value == err)
95     sprintf (err_buf, "Sockets: %s error %d - %s\n", emsg, err, sock_errors[i].text);
96 else
97 #if defined(_WIN32)
98     sprintf (err_buf, "Sockets: %s error %d\n", emsg, err);
99 #else
100     sprintf (err_buf, "Sockets: %s error %d - %s\n", emsg, err, strerror(err));
101 #endif
102 return err_buf;
103 }
104 
sim_err_sock(SOCKET s,const char * emsg)105 SOCKET sim_err_sock (SOCKET s, const char *emsg)
106 {
107 sim_printf ("%s", sim_get_err_sock (emsg));
108 if (s != INVALID_SOCKET) {
109     int err = WSAGetLastError ();
110     sim_close_sock (s);
111     WSASetLastError (err);      /* Retain Original socket error value */
112     }
113 return INVALID_SOCKET;
114 }
115 
116 typedef void    (WSAAPI *freeaddrinfo_func) (struct addrinfo *ai);
117 static freeaddrinfo_func p_freeaddrinfo;
118 
119 typedef int     (WSAAPI *getaddrinfo_func) (const char *hostname,
120                                  const char *service,
121                                  const struct addrinfo *hints,
122                                  struct addrinfo **res);
123 static getaddrinfo_func p_getaddrinfo;
124 
125 typedef int (WSAAPI *getnameinfo_func) (const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags);
126 static getnameinfo_func p_getnameinfo;
127 
128 #if defined(_WIN32) || defined(__CYGWIN__)
s_freeaddrinfo(struct addrinfo * ai)129 static void    WSAAPI s_freeaddrinfo (struct addrinfo *ai)
130 {
131 struct addrinfo *a, *an;
132 
133 for (a=ai; a != NULL; a=an) {
134     an = a->ai_next;
135     free (a->ai_canonname);
136     free (a->ai_addr);
137     free (a);
138     }
139 }
140 
s_getaddrinfo(const char * hostname,const char * service,const struct addrinfo * hints,struct addrinfo ** res)141 static int     WSAAPI s_getaddrinfo (const char *hostname,
142                                      const char *service,
143                                      const struct addrinfo *hints,
144                                      struct addrinfo **res)
145 {
146 struct hostent *he;
147 struct servent *se = NULL;
148 struct sockaddr_in *sin;
149 struct addrinfo *result = NULL;
150 struct addrinfo *ai, *lai = NULL;
151 struct addrinfo dhints;
152 struct in_addr ipaddr;
153 struct in_addr *fixed[2];
154 struct in_addr **ips = NULL;
155 struct in_addr **ip;
156 const char *cname = NULL;
157 int port = 0;
158 
159 // Validate parameters
160 if ((hostname == NULL) && (service == NULL))
161     return EAI_NONAME;
162 
163 if (hints) {
164     if ((hints->ai_family != PF_INET) && (hints->ai_family != PF_UNSPEC))
165         return EAI_FAMILY;
166     switch (hints->ai_socktype)
167         {
168         default:
169             return EAI_SOCKTYPE;
170         case SOCK_DGRAM:
171         case SOCK_STREAM:
172         case 0:
173             break;
174         }
175     }
176 else {
177     hints = &dhints;
178     memset(&dhints, 0, sizeof(dhints));
179     dhints.ai_family = PF_UNSPEC;
180     }
181 if (service) {
182     char *c;
183 
184     port = strtoul(service, &c, 10);
185     if ((port == 0) || (*c != '\0')) {
186         switch (hints->ai_socktype)
187             {
188             case SOCK_DGRAM:
189                 se = getservbyname(service, "udp");
190                 break;
191             case SOCK_STREAM:
192             case 0:
193                 se = getservbyname(service, "tcp");
194                 break;
195             }
196         if (NULL == se)
197             return EAI_SERVICE;
198         port = se->s_port;
199         }
200     }
201 
202 if (hostname) {
203     if ((0xffffffff != (ipaddr.s_addr = inet_addr(hostname))) ||
204         (0 == strcmp("255.255.255.255", hostname))) {
205         fixed[0] = &ipaddr;
206         fixed[1] = NULL;
207         }
208     else {
209         if ((0xffffffff != (ipaddr.s_addr = inet_addr(hostname))) ||
210             (0 == strcmp("255.255.255.255", hostname))) {
211             fixed[0] = &ipaddr;
212             fixed[1] = NULL;
213             if ((hints->ai_flags & AI_CANONNAME) && !(hints->ai_flags & AI_NUMERICHOST)) {
214                 he = gethostbyaddr((char *)&ipaddr, 4, AF_INET);
215                 if (NULL != he)
216                     cname = he->h_name;
217                 else
218                     cname = hostname;
219                 }
220             ips = fixed;
221             }
222         else {
223             if (hints->ai_flags & AI_NUMERICHOST)
224                 return EAI_NONAME;
225             he = gethostbyname(hostname);
226             if (he) {
227                 ips = (struct in_addr **)he->h_addr_list;
228                 if (hints->ai_flags & AI_CANONNAME)
229                     cname = he->h_name;
230                 }
231             else {
232                 switch (h_errno)
233                     {
234                     case HOST_NOT_FOUND:
235                     case NO_DATA:
236                         return EAI_NONAME;
237                     case TRY_AGAIN:
238                         return EAI_AGAIN;
239                     default:
240                         return EAI_FAIL;
241                     }
242                 }
243             }
244         }
245     }
246 else {
247     if (hints->ai_flags & AI_PASSIVE)
248         ipaddr.s_addr = htonl(INADDR_ANY);
249     else
250         ipaddr.s_addr = htonl(INADDR_LOOPBACK);
251     fixed[0] = &ipaddr;
252     fixed[1] = NULL;
253     ips = fixed;
254     }
255 for (ip=ips; (ip != NULL) && (*ip != NULL); ++ip) {
256     ai = (struct addrinfo *)calloc(1, sizeof(*ai));
257     if (NULL == ai) {
258         s_freeaddrinfo(result);
259         return EAI_MEMORY;
260         }
261     ai->ai_family = PF_INET;
262     ai->ai_socktype = hints->ai_socktype;
263     ai->ai_protocol = hints->ai_protocol;
264     ai->ai_addr = NULL;
265     ai->ai_addrlen = sizeof(struct sockaddr_in);
266     ai->ai_canonname = NULL;
267     ai->ai_next = NULL;
268     ai->ai_addr = (struct sockaddr *)calloc(1, sizeof(struct sockaddr_in));
269     if (NULL == ai->ai_addr) {
270         free(ai);
271         s_freeaddrinfo(result);
272         return EAI_MEMORY;
273         }
274     sin = (struct sockaddr_in *)ai->ai_addr;
275     sin->sin_family = PF_INET;
276     sin->sin_port = (unsigned short)port;
277     memcpy(&sin->sin_addr, *ip, sizeof(sin->sin_addr));
278     if (NULL == result)
279         result = ai;
280     else
281         lai->ai_next = ai;
282     lai = ai;
283     }
284 if (cname) {
285     result->ai_canonname = (char *)calloc(1, strlen(cname)+1);
286     if (NULL == result->ai_canonname) {
287         s_freeaddrinfo(result);
288         return EAI_MEMORY;
289         }
290     strcpy(result->ai_canonname, cname);
291     }
292 *res = result;
293 return 0;
294 }
295 
296 # ifndef EAI_OVERFLOW
297 #  define EAI_OVERFLOW WSAENAMETOOLONG
298 # endif
299 
s_getnameinfo(const struct sockaddr * sa,socklen_t salen,char * host,size_t hostlen,char * serv,size_t servlen,int flags)300 static int     WSAAPI s_getnameinfo (const struct sockaddr *sa, socklen_t salen,
301                                      char *host, size_t hostlen,
302                                      char *serv, size_t servlen,
303                                      int flags)
304 {
305 struct hostent *he;
306 struct servent *se = NULL;
307 const struct sockaddr_in *sin = (const struct sockaddr_in *)sa;
308 
309 if (sin->sin_family != PF_INET)
310     return EAI_FAMILY;
311 if ((NULL == host) && (NULL == serv))
312     return EAI_NONAME;
313 if ((serv) && (servlen > 0)) {
314     if (flags & NI_NUMERICSERV)
315         se = NULL;
316     else
317         if (flags & NI_DGRAM)
318             se = getservbyport(sin->sin_port, "udp");
319         else
320             se = getservbyport(sin->sin_port, "tcp");
321     if (se) {
322         if (servlen <= strlen(se->s_name))
323             return EAI_OVERFLOW;
324         strcpy(serv, se->s_name);
325         }
326     else {
327         char buf[16];
328 
329         sprintf(buf, "%d", ntohs(sin->sin_port));
330         if (servlen <= strlen(buf))
331             return EAI_OVERFLOW;
332         strcpy(serv, buf);
333         }
334     }
335 if ((host) && (hostlen > 0)) {
336     if (flags & NI_NUMERICHOST)
337         he = NULL;
338     else
339         he = gethostbyaddr((const char *)&sin->sin_addr, 4, AF_INET);
340     if (he) {
341         if (hostlen < strlen(he->h_name)+1)
342             return EAI_OVERFLOW;
343         strcpy(host, he->h_name);
344         }
345     else {
346         if (flags & NI_NAMEREQD)
347             return EAI_NONAME;
348         if (hostlen < strlen(inet_ntoa(sin->sin_addr))+1)
349             return EAI_OVERFLOW;
350         strcpy(host, inet_ntoa(sin->sin_addr));
351         }
352     }
353 return 0;
354 }
355 
356 # if !defined(IPV6_V6ONLY)           /* Older environments may not define IPV6_V6ONLY */
357 #  define IPV6_V6ONLY          27    /* Treat wildcard bind as AF_INET6-only. */
358 # endif
359 /* Dynamic DLL load variables */
360 # ifdef _WIN32
361 static HINSTANCE hLib = 0;                      /* handle to DLL */
362 # else
363 static void *hLib = NULL;                       /* handle to Library */
364 # endif
365 static int lib_loaded = 0;                      /* 0=not loaded, 1=loaded, 2=library load failed, 3=Func load failed */
366 static const char* lib_name = "Ws2_32.dll";
367 
368 /* load function pointer from DLL */
369 typedef int (*_func)();
370 
load_function(const char * function,_func * func_ptr)371 static void load_function(const char* function, _func* func_ptr) {
372 # ifdef _WIN32
373     *func_ptr = (_func)GetProcAddress(hLib, function);
374 # else
375     *func_ptr = (_func)dlsym(hLib, function);
376 # endif
377     if (*func_ptr == 0) {
378     sim_printf ("Sockets: Failed to find function '%s' in %s\r\n", function, lib_name);
379     lib_loaded = 3;
380   }
381 }
382 
383 /* load Ws2_32.dll as required */
load_ws2(void)384 int load_ws2(void) {
385   switch(lib_loaded) {
386     case 0:                  /* not loaded */
387 # if defined(_WIN32) || defined(__CYGWIN__)
388       hLib = LoadLibraryA(lib_name);
389 # else
390       hLib = dlopen(lib_name, RTLD_NOW);
391 # endif
392       if (hLib == 0) {
393         /* failed to load DLL */
394         sim_printf ("Sockets: Failed to load %s\r\n", lib_name);
395         lib_loaded = 2;
396         break;
397       } else {
398         /* library loaded OK */
399         lib_loaded = 1;
400       }
401 
402       /* load required functions; sets dll_load=3 on error */
403       load_function("getaddrinfo",       (_func *) &p_getaddrinfo);
404       load_function("getnameinfo",       (_func *) &p_getnameinfo);
405       load_function("freeaddrinfo",      (_func *) &p_freeaddrinfo);
406 
407       if (lib_loaded != 1) {
408         /* unsuccessful load, connect stubs */
409         p_getaddrinfo = (getaddrinfo_func)s_getaddrinfo;
410         p_getnameinfo = (getnameinfo_func)s_getnameinfo;
411         p_freeaddrinfo = (freeaddrinfo_func)s_freeaddrinfo;
412       }
413       break;
414     default:                /* loaded or failed */
415       break;
416   }
417   return (lib_loaded == 1) ? 1 : 0;
418 }
419 #endif
420 
421 /* OS independent routines
422 
423    sim_parse_addr       parse a hostname/ipaddress from port and apply defaults and
424                         optionally validate an address match
425 */
426 
427 /* sim_parse_addr       host:port
428 
429    Presumption is that the input, if it doesn't contain a ':' character is a port specifier.
430    If the host field contains one or more colon characters (i.e. it is an IPv6 address),
431    the IPv6 address MUST be enclosed in square bracket characters (i.e. Domain Literal format)
432 
433    Inputs:
434         cptr    =       pointer to input string
435         default_host
436                 =       optional pointer to default host if none specified
437         host_len =      length of host buffer
438         default_port
439                 =       optional pointer to default port if none specified
440         port_len =      length of port buffer
441         validate_addr = optional name/addr which is checked to be equivalent
442                         to the host result of parsing the other input.  This
443                         address would usually be returned by sim_accept_conn.
444    Outputs:
445         host    =       pointer to buffer for IP address (may be NULL), 0 = none
446         port    =       pointer to buffer for IP port (may be NULL), 0 = none
447         result  =       status (0 on complete success or -1 if
448                         parsing can't happen due to bad syntax, a value is
449                         out of range, a result can't fit into a result buffer,
450                         a service name doesn't exist, or a validation name
451                         doesn't match the parsed host)
452 */
453 
sim_parse_addr(const char * cptr,char * host,size_t host_len,const char * default_host,char * port,size_t port_len,const char * default_port,const char * validate_addr)454 int sim_parse_addr (const char *cptr, char *host, size_t host_len, const char *default_host, char *port, size_t port_len, const char *default_port, const char *validate_addr)
455 {
456 char gbuf[CBUFSIZE], default_pbuf[CBUFSIZE];
457 const char *hostp;
458 char *portp;
459 char *endc;
460 unsigned long portval;
461 
462 if ((host != NULL) && (host_len != 0))
463     memset (host, 0, host_len);
464 if ((port != NULL) && (port_len != 0))
465     memset (port, 0, port_len);
466 if ((cptr == NULL) || (*cptr == 0)) {
467     if (((default_host == NULL) || (*default_host == 0)) || ((default_port == NULL) || (*default_port == 0)))
468         return -1;
469     if ((host == NULL) || (port == NULL))
470         return -1;                                  /* no place */
471     if ((strlen(default_host) >= host_len) || (strlen(default_port) >= port_len))
472         return -1;                                  /* no room */
473     strcpy (host, default_host);
474     strcpy (port, default_port);
475     return 0;
476     }
477 memset (default_pbuf, 0, sizeof(default_pbuf));
478 if (default_port)
479     strncpy (default_pbuf, default_port, sizeof(default_pbuf)-1);
480 gbuf[sizeof(gbuf)-1] = '\0';
481 strncpy (gbuf, cptr, sizeof(gbuf)-1);
482 hostp = gbuf;                                           /* default addr */
483 portp = NULL;
484 if ((portp = strrchr (gbuf, ':')) &&                    /* x:y? split */
485     (NULL == strchr (portp, ']'))) {
486     *portp++ = 0;
487     if (*portp == '\0')
488         portp = default_pbuf;
489     }
490 else {                                                  /* No colon in input */
491     portp = gbuf;                                       /* Input is the port specifier */
492     hostp = (const char *)default_host;                 /* host is defaulted if provided */
493     }
494 if (portp != NULL) {
495     portval = strtoul(portp, &endc, 10);
496     if ((*endc == '\0') && ((portval == 0) || (portval > 65535)))
497         return -1;                                      /* numeric value too big */
498     if (*endc != '\0') {
499         struct servent *se = getservbyname(portp, "tcp");
500 
501         if (se == NULL)
502             return -1;                                  /* invalid service name */
503         }
504     }
505 if (port)                                               /* port wanted? */
506     if (portp != NULL) {
507         if (strlen(portp) >= port_len)
508             return -1;                                  /* no room */
509         else
510             strcpy (port, portp);
511         }
512 if (hostp != NULL) {
513     if (']' == hostp[strlen(hostp)-1]) {
514         if ('[' != hostp[0])
515             return -1;                                  /* invalid domain literal */
516         /* host may be the const default_host so move to temp buffer before modifying */
517         strncpy(gbuf, hostp+1, sizeof(gbuf)-1);         /* remove brackets from domain literal host */
518         gbuf[strlen(gbuf)-1] = '\0';
519         hostp = gbuf;
520         }
521     }
522 if (host) {                                             /* host wanted? */
523     if (hostp != NULL) {
524         if (strlen(hostp) >= host_len)
525             return -1;                                  /* no room */
526         else
527             if (('\0' != hostp[0]) || (default_host == NULL))
528                 strcpy (host, hostp);
529             else
530                 if (strlen(default_host) >= host_len)
531                     return -1;                          /* no room */
532                 else
533                     strcpy (host, default_host);
534         }
535     else {
536         if (default_host) {
537             if (strlen(default_host) >= host_len)
538                 return -1;                              /* no room */
539             else
540                 strcpy (host, default_host);
541             }
542         }
543     }
544 if (validate_addr) {
545     struct addrinfo *ai_host, *ai_validate, *ai, *aiv;
546     int status;
547 
548     if (hostp == NULL)
549         return -1;
550     if (p_getaddrinfo(hostp, NULL, NULL, &ai_host))
551         return -1;
552     if (p_getaddrinfo(validate_addr, NULL, NULL, &ai_validate)) {
553         p_freeaddrinfo (ai_host);
554         return -1;
555         }
556     status = -1;
557     for (ai = ai_host; ai != NULL; ai = ai->ai_next) {
558         for (aiv = ai_validate; aiv != NULL; aiv = aiv->ai_next) {
559             if ((ai->ai_addrlen == aiv->ai_addrlen) &&
560                 (ai->ai_family == aiv->ai_family) &&
561                 (0 == memcmp (ai->ai_addr, aiv->ai_addr, ai->ai_addrlen))) {
562                 status = 0;
563                 break;
564                 }
565             }
566         }
567     if (status != 0) {
568         /* be generous and allow successful validations against variations of localhost addresses */
569         if (((0 == strcmp("127.0.0.1", hostp)) &&
570              (0 == strcmp("::1", validate_addr))) ||
571             ((0 == strcmp("127.0.0.1", validate_addr)) &&
572              (0 == strcmp("::1", hostp))))
573             status = 0;
574         }
575     p_freeaddrinfo (ai_host);
576     p_freeaddrinfo (ai_validate);
577     return status;
578     }
579 return 0;
580 }
581 
582 #ifdef UNUSED
583 /* sim_parse_addr_ex    localport:host:port
584 
585    Presumption is that the input, if it doesn't contain a ':' character is a port specifier.
586    If the host field contains one or more colon characters (i.e. it is an IPv6 address),
587    the IPv6 address MUST be enclosed in square bracket characters (i.e. Domain Literal format)
588 
589         llll:w.x.y.z:rrrr
590         llll:name.domain.com:rrrr
591         llll::rrrr
592         rrrr
593         w.x.y.z:rrrr
594         [w.x.y.z]:rrrr
595         name.domain.com:rrrr
596 
597    Inputs:
598         cptr    =       pointer to input string
599         default_host
600                 =       optional pointer to default host if none specified
601         host_len =      length of host buffer
602         default_port
603                 =       optional pointer to default port if none specified
604         port_len =      length of port buffer
605 
606    Outputs:
607         host    =       pointer to buffer for IP address (may be NULL), 0 = none
608         port    =       pointer to buffer for IP port (may be NULL), 0 = none
609         localport
610                 =       pointer to buffer for local IP port (may be NULL), 0 = none
611         result  =       status (SCPE_OK on complete success or SCPE_ARG if
612                         parsing can't happen due to bad syntax, a value is
613                         out of range, a result can't fit into a result buffer,
614                         a service name doesn't exist, or a validation name
615                         doesn't match the parsed host)
616 */
sim_parse_addr_ex(const char * cptr,char * host,size_t hostlen,const char * default_host,char * port,size_t port_len,char * localport,size_t localport_len,const char * default_port)617 int sim_parse_addr_ex (const char *cptr, char *host, size_t hostlen, const char *default_host, char *port, size_t port_len, char *localport, size_t localport_len, const char *default_port)
618 {
619 const char *hostp;
620 
621 if ((localport != NULL) && (localport_len != 0))
622     memset (localport, 0, localport_len);
623 hostp = strchr (cptr, ':');
624 if ((hostp != NULL) && ((hostp[1] == '[') || (NULL != strchr (hostp+1, ':')))) {
625     if ((localport != NULL) && (localport_len != 0)) {
626         localport_len -= 1;
627         if (localport_len > (size_t)(hostp-cptr))
628             localport_len = (size_t)(hostp-cptr);
629         memcpy (localport, cptr, localport_len);
630         }
631     return sim_parse_addr (hostp+1, host, hostlen, default_host, port, port_len, default_port, NULL);
632     }
633 return sim_parse_addr (cptr, host, hostlen, default_host, port, port_len, default_port, NULL);
634 }
635 #endif
636 
sim_init_sock(void)637 void sim_init_sock (void)
638 {
639 #if defined (_WIN32)
640 int err;
641 WORD wVersionRequested;
642 WSADATA wsaData;
643 wVersionRequested = MAKEWORD (2, 2);
644 
645 err = WSAStartup (wVersionRequested, &wsaData);         /* start Winsock */
646 if (err != 0)
647     sim_printf ("Winsock: startup error %d\n", err);
648 # if defined(AF_INET6)
649 load_ws2 ();
650 # endif                                                 /* endif AF_INET6 */
651 #else                                                   /* Use native addrinfo APIs */
652 # if defined(AF_INET6)
653     p_getaddrinfo = (getaddrinfo_func)getaddrinfo;
654     p_getnameinfo = (getnameinfo_func)getnameinfo;
655     p_freeaddrinfo = (freeaddrinfo_func)freeaddrinfo;
656 # else
657     /* Native APIs not available, connect stubs */
658     p_getaddrinfo = (getaddrinfo_func)s_getaddrinfo;
659     p_getnameinfo = (getnameinfo_func)s_getnameinfo;
660     p_freeaddrinfo = (freeaddrinfo_func)s_freeaddrinfo;
661 # endif                                                 /* endif AF_INET6 */
662 #endif                                                  /* endif _WIN32 */
663 #if defined (SIGPIPE)
664 signal (SIGPIPE, SIG_IGN);                              /* no pipe signals */
665 #endif
666 }
667 
sim_cleanup_sock(void)668 void sim_cleanup_sock (void)
669 {
670 #if defined (_WIN32)
671 WSACleanup ();
672 #endif
673 }
674 
675 #if defined (_WIN32)                                    /* Windows */
sim_setnonblock(SOCKET sock)676 static int sim_setnonblock (SOCKET sock)
677 {
678 unsigned long non_block = 1;
679 
680 return ioctlsocket (sock, FIONBIO, &non_block);         /* set nonblocking */
681 }
682 
683 #else                                                   /* Mac, Unix, OS/2 */
sim_setnonblock(SOCKET sock)684 static int sim_setnonblock (SOCKET sock)
685 {
686 int fl, sta;
687 
688 fl = fcntl (sock, F_GETFL,0);                           /* get flags */
689 if (fl == -1)
690     return SOCKET_ERROR;
691 sta = fcntl (sock, F_SETFL, fl | O_NONBLOCK);           /* set nonblock */
692 if (sta == -1)
693     return SOCKET_ERROR;
694 # if !defined (__HAIKU__)                               /* Unix only */
695 sta = fcntl (sock, F_SETOWN, getpid());                 /* set ownership */
696 if (sta == -1)
697     return SOCKET_ERROR;
698 # endif
699 return 0;
700 }
701 #endif                                                  /* endif !Win32 */
702 
sim_setnodelay(SOCKET sock)703 static int sim_setnodelay (SOCKET sock)
704 {
705 int nodelay = 1;
706 int sta;
707 
708 /* disable Nagle algorithm */
709 sta = setsockopt (sock, IPPROTO_TCP, TCP_NODELAY, (char *)&nodelay, sizeof(nodelay));
710 if (sta == -1)
711     return SOCKET_ERROR;
712 
713 #if defined(TCP_NODELAYACK)
714 /* disable delayed ack algorithm */
715 sta = setsockopt (sock, IPPROTO_TCP, TCP_NODELAYACK, (char *)&nodelay, sizeof(nodelay));
716 if (sta == -1)
717     return SOCKET_ERROR;
718 #endif
719 
720 #if defined(TCP_QUICKACK)
721 /* disable delayed ack algorithm */
722 sta = setsockopt (sock, IPPROTO_TCP, TCP_QUICKACK, (char *)&nodelay, sizeof(nodelay));
723 if (sta == -1)
724     return SOCKET_ERROR;
725 #endif
726 
727 return sta;
728 }
729 
sim_create_sock(int af,int opt_flags)730 static SOCKET sim_create_sock (int af, int opt_flags)
731 {
732 SOCKET newsock;
733 int err;
734 
735 newsock = socket (af, ((opt_flags & SIM_SOCK_OPT_DATAGRAM) ? SOCK_DGRAM : SOCK_STREAM), 0);/* create socket */
736 if (newsock == INVALID_SOCKET) {                        /* socket error? */
737 #if defined(WSAEAFNOSUPPORT)
738     err = WSAGetLastError ();
739     if (err == WSAEAFNOSUPPORT)                         /* expected error, just return */
740         return newsock;
741 #endif
742     return sim_err_sock (newsock, "socket");            /* report error and return */
743     }
744 return newsock;
745 }
746 
747 /*
748    Some platforms and/or network stacks have varying support for listening on
749    an IPv6 socket and receiving connections from both IPv4 and IPv6 client
750    connections.  This is known as IPv4-Mapped.  Some platforms claim such
751    support (i.e. some Windows versions), but it doesn't work in all cases.
752 */
753 
sim_master_sock_ex(const char * hostport,int * parse_status,int opt_flags)754 SOCKET sim_master_sock_ex (const char *hostport, int *parse_status, int opt_flags)
755 {
756 SOCKET newsock = INVALID_SOCKET;
757 int sta;
758 char host[CBUFSIZE], port[CBUFSIZE];
759 int r;
760 struct addrinfo hints;
761 struct addrinfo *result = NULL, *preferred;
762 
763 r = sim_parse_addr (hostport, host, sizeof(host), NULL, port, sizeof(port), NULL, NULL);
764 if (parse_status)
765     *parse_status = r;
766 if (r)
767     return newsock;
768 
769 memset(&hints, 0, sizeof(hints));
770 hints.ai_flags = AI_PASSIVE;
771 hints.ai_family = AF_UNSPEC;
772 hints.ai_protocol = IPPROTO_TCP;
773 hints.ai_socktype = SOCK_STREAM;
774 if (p_getaddrinfo(host[0] ? host : NULL, port[0] ? port : NULL, &hints, &result)) {
775     if (parse_status)
776         *parse_status = -1;
777     return newsock;
778     }
779 preferred = result;
780 #ifdef IPV6_V6ONLY
781 /*
782     When we can create a dual stack socket, be sure to find the IPv6 addrinfo
783     to bind to.
784 */
785 for (; preferred != NULL; preferred = preferred->ai_next) {
786     if (preferred->ai_family == AF_INET6)
787         break;
788     }
789 if (preferred == NULL)
790     preferred = result;
791 #endif
792 retry:
793 newsock = sim_create_sock (preferred->ai_family, 0);    /* create socket */
794 if (newsock == INVALID_SOCKET) {                        /* socket error? */
795 #ifndef IPV6_V6ONLY
796     if (preferred->ai_next) {
797         preferred = preferred->ai_next;
798         goto retry;
799         }
800 #else
801     if ((preferred->ai_family == AF_INET6) &&
802         (preferred != result)) {
803         preferred = result;
804         goto retry;
805         }
806 #endif
807     p_freeaddrinfo(result);
808     return newsock;
809     }
810 #ifdef IPV6_V6ONLY
811 if (preferred->ai_family == AF_INET6) {
812     int off = 0;
813     sta = setsockopt (newsock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&off, sizeof(off));
814     }
815 #endif
816 if (opt_flags & SIM_SOCK_OPT_REUSEADDR) {
817     int on = 1;
818 
819     sta = setsockopt (newsock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on));
820     }
821 #if defined (SO_EXCLUSIVEADDRUSE)
822 else {
823     int on = 1;
824 
825     sta = setsockopt (newsock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (char *)&on, sizeof(on));
826     }
827 #endif
828 sta = bind (newsock, preferred->ai_addr, preferred->ai_addrlen);
829 p_freeaddrinfo(result);
830 if (sta == SOCKET_ERROR)                                /* bind error? */
831     return sim_err_sock (newsock, "bind");
832 if (!(opt_flags & SIM_SOCK_OPT_BLOCKING)) {
833     sta = sim_setnonblock (newsock);                    /* set nonblocking */
834     if (sta == SOCKET_ERROR)                            /* fcntl error? */
835         return sim_err_sock (newsock, "setnonblock");
836     }
837 sta = listen (newsock, 1);                              /* listen on socket */
838 if (sta == SOCKET_ERROR)                                /* listen error? */
839     return sim_err_sock (newsock, "listen");
840 return newsock;                                         /* got it! */
841 }
842 
sim_connect_sock_ex(const char * sourcehostport,const char * hostport,const char * default_host,const char * default_port,int opt_flags)843 SOCKET sim_connect_sock_ex (const char *sourcehostport, const char *hostport, const char *default_host, const char *default_port, int opt_flags)
844 {
845 SOCKET newsock = INVALID_SOCKET;
846 int sta;
847 char host[CBUFSIZE], port[CBUFSIZE];
848 struct addrinfo hints;
849 struct addrinfo *result = NULL, *source = NULL;
850 
851 if (sim_parse_addr (hostport, host, sizeof(host), default_host, port, sizeof(port), default_port, NULL))
852     return INVALID_SOCKET;
853 
854 memset(&hints, 0, sizeof(hints));
855 hints.ai_family = AF_UNSPEC;
856 hints.ai_protocol = ((opt_flags & SIM_SOCK_OPT_DATAGRAM) ? IPPROTO_UDP : IPPROTO_TCP);
857 hints.ai_socktype = ((opt_flags & SIM_SOCK_OPT_DATAGRAM) ? SOCK_DGRAM : SOCK_STREAM);
858 if (p_getaddrinfo(host[0] ? host : NULL, port[0] ? port : NULL, &hints, &result))
859     return INVALID_SOCKET;
860 
861 if (sourcehostport) {
862 
863     /* Validate the local/source side address which we'll bind to */
864     if (sim_parse_addr (sourcehostport, host, sizeof(host), NULL, port, sizeof(port), NULL, NULL)) {
865         p_freeaddrinfo (result);
866         return INVALID_SOCKET;
867         }
868 
869     memset(&hints, 0, sizeof(hints));
870     hints.ai_flags = AI_PASSIVE;
871     hints.ai_family = result->ai_family;                /* Same family as connect destination */
872     hints.ai_protocol = ((opt_flags & SIM_SOCK_OPT_DATAGRAM) ? IPPROTO_UDP : IPPROTO_TCP);
873     hints.ai_socktype = ((opt_flags & SIM_SOCK_OPT_DATAGRAM) ? SOCK_DGRAM : SOCK_STREAM);
874     if (p_getaddrinfo(host[0] ? host : NULL, port[0] ? port : NULL, &hints, &source)) {
875         p_freeaddrinfo (result);
876         return INVALID_SOCKET;
877         }
878 
879     newsock = sim_create_sock (result->ai_family, opt_flags & SIM_SOCK_OPT_DATAGRAM);/* create socket */
880     if (newsock == INVALID_SOCKET) {                    /* socket error? */
881         p_freeaddrinfo (result);
882         p_freeaddrinfo (source);
883         return newsock;
884         }
885 
886     sta = bind (newsock, source->ai_addr, source->ai_addrlen);
887     p_freeaddrinfo(source);
888     source = NULL;
889     if (sta == SOCKET_ERROR) {                          /* bind error? */
890         p_freeaddrinfo (result);
891         return sim_err_sock (newsock, "bind");
892         }
893     }
894 
895 if (newsock == INVALID_SOCKET) {                        /* socket error? */
896     newsock = sim_create_sock (result->ai_family, opt_flags & SIM_SOCK_OPT_DATAGRAM);/* create socket */
897     if (newsock == INVALID_SOCKET) {                    /* socket error? */
898         p_freeaddrinfo (result);
899         return newsock;
900         }
901     }
902 
903 if (!(opt_flags & SIM_SOCK_OPT_BLOCKING)) {
904     sta = sim_setnonblock (newsock);                    /* set nonblocking */
905     if (sta == SOCKET_ERROR) {                          /* fcntl error? */
906         p_freeaddrinfo (result);
907         return sim_err_sock (newsock, "setnonblock");
908         }
909     }
910 if ((!(opt_flags & SIM_SOCK_OPT_DATAGRAM)) && (opt_flags & SIM_SOCK_OPT_NODELAY)) {
911     sta = sim_setnodelay (newsock);                     /* set nodelay */
912     if (sta == SOCKET_ERROR) {                          /* setsock error? */
913         p_freeaddrinfo (result);
914         return sim_err_sock (newsock, "setnodelay");
915         }
916     }
917 if (!(opt_flags & SIM_SOCK_OPT_DATAGRAM)) {
918     int keepalive = 1;
919 
920     /* enable TCP Keep Alives */
921     sta = setsockopt (newsock, SOL_SOCKET, SO_KEEPALIVE, (char *)&keepalive, sizeof(keepalive));
922     if (sta == -1)
923         return sim_err_sock (newsock, "setsockopt KEEPALIVE");
924     }
925 if (!(opt_flags & SIM_SOCK_OPT_BLOCKING)) {
926     sta = sim_setnonblock (newsock);                    /* set nonblocking */
927     if (sta == SOCKET_ERROR)                            /* fcntl error? */
928         return sim_err_sock (newsock, "setnonblock");
929     }
930 sta = connect (newsock, result->ai_addr, result->ai_addrlen);
931 p_freeaddrinfo (result);
932 if (sta == SOCKET_ERROR) {
933     if (opt_flags & SIM_SOCK_OPT_BLOCKING) {
934         if ((WSAGetLastError () == WSAETIMEDOUT)    ||  /* expected errors after a connect failure */
935             (WSAGetLastError () == WSAEHOSTUNREACH) ||
936             (WSAGetLastError () == WSAECONNREFUSED) ||
937             (WSAGetLastError () == WSAECONNABORTED) ||
938             (WSAGetLastError () == WSAECONNRESET)) {
939             sim_close_sock (newsock);
940             newsock = INVALID_SOCKET;
941             }
942         else
943             return sim_err_sock (newsock, "connect");
944         }
945     else    /* Non Blocking case won't return errors until some future read */
946         if ((WSAGetLastError () != WSAEWOULDBLOCK) &&
947             (WSAGetLastError () != WSAEINPROGRESS))
948             return sim_err_sock (newsock, "connect");
949     }
950 return newsock;                                         /* got it! */
951 }
952 
sim_accept_conn_ex(SOCKET master,char ** connectaddr,int opt_flags)953 SOCKET sim_accept_conn_ex (SOCKET master, char **connectaddr, int opt_flags)
954 {
955 int sta = 0, err;
956 int keepalive = 1;
957 #if defined (__linux)    || defined (__linux__)   || \
958     defined (__APPLE__)  || defined (__OpenBSD__) || \
959     defined (__NetBSD__) || defined(__FreeBSD__)  || \
960     defined (__FreeBSD_kernel__) || defined (__HAIKU__)
961 socklen_t size;
962 #elif defined (_WIN32)
963 int size;
964 #else
965 size_t size;
966 #endif
967 SOCKET newsock;
968 struct sockaddr_storage clientname;
969 
970 if (master == 0)                                        /* not attached? */
971     return INVALID_SOCKET;
972 size = sizeof (clientname);
973 memset (&clientname, 0, sizeof(clientname));
974 newsock = accept (master, (struct sockaddr *) &clientname, &size);
975 if (newsock == INVALID_SOCKET) {                        /* error? */
976     err = WSAGetLastError ();
977     if (err != WSAEWOULDBLOCK)
978         sim_err_sock(newsock, "accept");
979     return INVALID_SOCKET;
980     }
981 if (connectaddr != NULL) {
982     *connectaddr = (char *)calloc(1, NI_MAXHOST+1);
983 #ifdef AF_INET6
984     p_getnameinfo((struct sockaddr *)&clientname, size, *connectaddr, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
985     if (0 == memcmp("::ffff:", *connectaddr, 7))        /* is this a IPv4-mapped IPv6 address? */
986         memmove(*connectaddr, 7+*connectaddr,           /* prefer bare IPv4 address */
987                 strlen(*connectaddr) - 7 + 1);          /* length to include terminating \0 */
988 #else
989     strcpy(*connectaddr, inet_ntoa(((struct sockaddr_in *)&connectaddr)->s_addr));
990 #endif
991     }
992 
993 if (!(opt_flags & SIM_SOCK_OPT_BLOCKING)) {
994     sta = sim_setnonblock (newsock);                    /* set nonblocking */
995     if (sta == SOCKET_ERROR)                            /* fcntl error? */
996         return sim_err_sock (newsock, "setnonblock");
997     }
998 
999 if ((opt_flags & SIM_SOCK_OPT_NODELAY)) {
1000     sta = sim_setnodelay (newsock);                     /* set nonblocking */
1001     if (sta == SOCKET_ERROR)                            /* setsockopt error? */
1002         return sim_err_sock (newsock, "setnodelay");
1003     }
1004 
1005 /* enable TCP Keep Alives */
1006 sta = setsockopt (newsock, SOL_SOCKET, SO_KEEPALIVE, (char *)&keepalive, sizeof(keepalive));
1007 if (sta == -1)
1008     return sim_err_sock (newsock, "setsockopt KEEPALIVE");
1009 
1010 return newsock;
1011 }
1012 
sim_check_conn(SOCKET sock,int rd)1013 int sim_check_conn (SOCKET sock, int rd)
1014 {
1015 fd_set rw_set, er_set;
1016 fd_set *rw_p = &rw_set;
1017 fd_set *er_p = &er_set;
1018 struct timeval zero;
1019 struct sockaddr_storage peername;
1020 #if defined (__linux)    || defined (__linux__)   || \
1021     defined (__APPLE__)  || defined (__OpenBSD__) || \
1022     defined (__NetBSD__) || defined(__FreeBSD__)  || \
1023     defined (__FreeBSD_kernel__) || defined (__HAIKU__)
1024 socklen_t peernamesize = (socklen_t)sizeof(peername);
1025 #elif defined (_WIN32)
1026 int peernamesize = (int)sizeof(peername);
1027 #else
1028 size_t peernamesize = sizeof(peername);
1029 #endif
1030 
1031 memset (&zero, 0, sizeof(zero));
1032 FD_ZERO (rw_p);
1033 FD_ZERO (er_p);
1034 FD_SET (sock, rw_p);
1035 FD_SET (sock, er_p);
1036 if (rd)
1037     select ((int) sock + 1, rw_p, NULL, er_p, &zero);
1038 else
1039     select ((int) sock + 1, NULL, rw_p, er_p, &zero);
1040 if (FD_ISSET (sock, er_p))
1041     return -1;
1042 if (FD_ISSET (sock, rw_p)) {
1043     if (0 == getpeername (sock, (struct sockaddr *)&peername, &peernamesize))
1044         return 1;
1045     else
1046         return -1;
1047     }
1048 return 0;
1049 }
1050 
_sim_getaddrname(struct sockaddr * addr,size_t addrsize,char * hostnamebuf,char * portnamebuf)1051 static int _sim_getaddrname (struct sockaddr *addr, size_t addrsize, char *hostnamebuf, char *portnamebuf)
1052 {
1053 int ret = 0;
1054 
1055 #ifdef AF_INET6
1056 # if defined (__linux)    || defined (__linux__)   || \
1057      defined (__APPLE__)  || defined (__OpenBSD__) || \
1058      defined (__NetBSD__) || defined(__FreeBSD__)  || \
1059      defined (__FreeBSD_kernel__) || defined (__HAIKU__)
1060 socklen_t size = (socklen_t)addrsize;
1061 # elif defined (_WIN32)
1062 int size = (int)addrsize;
1063 # else
1064 size_t size = addrsize;
1065 # endif
1066 *hostnamebuf = '\0';
1067 *portnamebuf = '\0';
1068 ret = p_getnameinfo(addr, size, hostnamebuf, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
1069 if (0 == memcmp("::ffff:", hostnamebuf, 7))        /* is this a IPv4-mapped IPv6 address? */
1070     memmove(hostnamebuf, 7+hostnamebuf,            /* prefer bare IPv4 address */
1071             strlen(hostnamebuf) + 7 - 1);          /* length to include terminating \0 */
1072 if (!ret)
1073     ret = p_getnameinfo(addr, size, NULL, 0, portnamebuf, NI_MAXSERV, NI_NUMERICSERV);
1074 #else
1075 strcpy(hostnamebuf, inet_ntoa(((struct sockaddr_in *)addr)->s_addr));
1076 sprintf(portnamebuf, "%d", (int)ntohs(((struct sockaddr_in *)addr)->s_port));
1077 #endif
1078 return ret;
1079 }
1080 
sim_getnames_sock(SOCKET sock,char ** socknamebuf,char ** peernamebuf)1081 int sim_getnames_sock (SOCKET sock, char **socknamebuf, char **peernamebuf)
1082 {
1083 struct sockaddr_storage sockname, peername;
1084 #if defined (__linux)    || defined (__linux__)   || \
1085     defined (__APPLE__)  || defined (__OpenBSD__) || \
1086     defined (__NetBSD__) || defined(__FreeBSD__)  || \
1087     defined (__FreeBSD_kernel__) || defined (__HAIKU__)
1088 socklen_t socknamesize = (socklen_t)sizeof(sockname);
1089 socklen_t peernamesize = (socklen_t)sizeof(peername);
1090 #elif defined (_WIN32)
1091 int socknamesize = (int)sizeof(sockname);
1092 int peernamesize = (int)sizeof(peername);
1093 #else
1094 size_t socknamesize = sizeof(sockname);
1095 size_t peernamesize = sizeof(peername);
1096 #endif
1097 char hostbuf[NI_MAXHOST+1];
1098 char portbuf[NI_MAXSERV+1];
1099 
1100 if (socknamebuf)
1101     *socknamebuf = (char *)calloc(1, NI_MAXHOST+NI_MAXSERV+4);
1102 if (peernamebuf)
1103     *peernamebuf = (char *)calloc(1, NI_MAXHOST+NI_MAXSERV+4);
1104 getsockname (sock, (struct sockaddr *)&sockname, &socknamesize);
1105 getpeername (sock, (struct sockaddr *)&peername, &peernamesize);
1106 if (socknamebuf != NULL) {
1107     _sim_getaddrname ((struct sockaddr *)&sockname, (size_t)socknamesize, hostbuf, portbuf);
1108     sprintf(*socknamebuf, "[%s]:%s", hostbuf, portbuf);
1109     }
1110 if (peernamebuf != NULL) {
1111     _sim_getaddrname ((struct sockaddr *)&peername, (size_t)peernamesize, hostbuf, portbuf);
1112     sprintf(*peernamebuf, "[%s]:%s", hostbuf, portbuf);
1113     }
1114 return 0;
1115 }
1116 
sim_read_sock(SOCKET sock,char * buf,int nbytes)1117 int sim_read_sock (SOCKET sock, char *buf, int nbytes)
1118 {
1119 int rbytes, err;
1120 
1121 rbytes = recv (sock, buf, nbytes, 0);
1122 if (rbytes == 0)                                        /* disconnect */
1123     return -1;
1124 if (rbytes == SOCKET_ERROR) {
1125     err = WSAGetLastError ();
1126     if (err == WSAEWOULDBLOCK)                          /* no data */
1127         return 0;
1128 #if defined(EAGAIN)
1129     if (err == EAGAIN)                                  /* no data */
1130         return 0;
1131 #endif
1132     if ((err != WSAETIMEDOUT) &&                        /* expected errors after a connect failure */
1133         (err != WSAEHOSTUNREACH) &&
1134         (err != WSAECONNREFUSED) &&
1135         (err != WSAECONNABORTED) &&
1136         (err != WSAECONNRESET) &&
1137         (err != WSAEINTR))                              /* or a close of a blocking read */
1138         sim_err_sock (INVALID_SOCKET, "read");
1139     return -1;
1140     }
1141 return rbytes;
1142 }
1143 
sim_write_sock(SOCKET sock,const char * msg,int nbytes)1144 int sim_write_sock (SOCKET sock, const char *msg, int nbytes)
1145 {
1146 int err, sbytes = send (sock, msg, nbytes, 0);
1147 
1148 if (sbytes == SOCKET_ERROR) {
1149     err = WSAGetLastError ();
1150     if (err == WSAEWOULDBLOCK)                          /* no data */
1151         return 0;
1152 #if defined(EAGAIN)
1153     if (err == EAGAIN)                                  /* no data */
1154         return 0;
1155 #endif
1156     }
1157 return sbytes;
1158 }
1159 
sim_close_sock(SOCKET sock)1160 void sim_close_sock (SOCKET sock)
1161 {
1162 shutdown(sock, SD_BOTH);
1163 closesocket (sock);
1164 }
1165 
1166