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

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