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

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