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