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