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

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