root/src/simh/sim_sock.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sim_get_err_sock
  2. sim_err_sock
  3. s_freeaddrinfo
  4. s_getaddrinfo
  5. s_getnameinfo
  6. load_function
  7. load_ws2
  8. sim_init_sock
  9. sim_cleanup_sock
  10. sim_setnonblock
  11. sim_setnonblock
  12. sim_setnodelay
  13. sim_create_sock
  14. sim_master_sock_ex
  15. sim_accept_conn_ex
  16. sim_check_conn
  17. _sim_getaddrname
  18. sim_getnames_sock
  19. sim_read_sock
  20. sim_write_sock
  21. sim_close_sock

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

/* [previous][next][first][last][top][bottom][index][help] */