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

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