From 1fb209c275e356d16402f0cfe0ad89810517c6a1 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Wed, 11 Feb 2015 09:41:18 -0800 Subject: [PATCH] SOCKETS: Cleanup, simplify and extend the sim_sock API set. Cleanup/Simplification by: 1) removing irrelevant master flag variable from sim_close_sock and thus sim_err_sock 2) change previous boolean feature arguments (datagram, nodelay, reuseaddr) to flag bits in a single option argument. This allows for features to be added by new flag bits which don't change the calling signatures. 3) changed all status returns to be int (vs t_stat) with success being 0 and error being -1 4) removed unneeded simh specific type references to allow sim_sock to be used by n Extended API by providing flags to influence socket setup/behavior: SIM_SOCK_OPT_REUSEADDR Retains prior behavior when sim_switches had -U set SIM_SOCK_OPT_DATAGRAM UDP socket setup provided for when prior datagram argument was specified SIM_SOCK_OPT_NODELAY TCP Nagle disable provided for when prior nodelay argument was specified SIM_SOCK_OPT_BLOCKING Blocking socket mode (detault is non blocking) --- AltairZ80/altairz80_net.c | 9 +- H316/h316_udp.c | 4 +- HP2100/hp2100_ipl.c | 11 +- Ibm1130/ibm1130_sca.c | 18 ++- PDP11/pdp11_dmc.c | 8 +- sim_ether.c | 6 +- sim_sock.c | 274 +++++++++++++++++++------------------- sim_sock.h | 42 ++++-- 8 files changed, 192 insertions(+), 180 deletions(-) diff --git a/AltairZ80/altairz80_net.c b/AltairZ80/altairz80_net.c index 4714f3c5..d845958f 100644 --- a/AltairZ80/altairz80_net.c +++ b/AltairZ80/altairz80_net.c @@ -154,8 +154,7 @@ static t_stat net_attach(UNIT *uptr, char *cptr) { char host[CBUFSIZE], port[CBUFSIZE]; t_stat r; - r = sim_parse_addr (cptr, host, sizeof(host), "localhost", port, sizeof(port), "3000", NULL); - if (r != SCPE_OK) + if (sim_parse_addr (cptr, host, sizeof(host), "localhost", port, sizeof(port), "3000", NULL)) return SCPE_ARG; net_reset(&net_dev); for (i = 0; i <= MAX_CONNECTIONS; i++) @@ -185,10 +184,10 @@ static t_stat net_detach(UNIT *uptr) { if (!(net_unit.flags & UNIT_ATT)) return SCPE_OK; /* if not attached simply return */ if (net_unit.flags & UNIT_SERVER) - sim_close_sock(serviceDescriptor[1].masterSocket, TRUE); + sim_close_sock(serviceDescriptor[1].masterSocket); for (i = 0; i <= MAX_CONNECTIONS; i++) if (serviceDescriptor[i].ioSocket) - sim_close_sock(serviceDescriptor[i].ioSocket, FALSE); + sim_close_sock(serviceDescriptor[i].ioSocket); free(net_unit.filename); /* free port string */ net_unit.filename = NULL; net_unit.flags &= ~UNIT_ATT; /* not attached */ @@ -226,7 +225,7 @@ static t_stat net_svc(UNIT *uptr) { BUFFER_LENGTH - serviceDescriptor[i].inputSize); if (r == -1) { sim_debug(DROP_MSG, &net_dev, "NET: " ADDRESS_FORMAT " Drop connection %i with socket %i.\n", PCX, i, serviceDescriptor[i].ioSocket); - sim_close_sock(serviceDescriptor[i].ioSocket, FALSE); + sim_close_sock(serviceDescriptor[i].ioSocket); serviceDescriptor[i].ioSocket = 0; serviceDescriptor_reset(i); continue; diff --git a/H316/h316_udp.c b/H316/h316_udp.c index ad49c10b..79e11f06 100644 --- a/H316/h316_udp.c +++ b/H316/h316_udp.c @@ -235,8 +235,8 @@ t_stat udp_parse_remote (int32 link, char *premote) premote = end+1; } - ret = sim_parse_addr (premote, host, sizeof(host), "localhost", port, sizeof(port), NULL, NULL); - if (ret != SCPE_OK) return SCPE_ARG; + if (sim_parse_addr (premote, host, sizeof(host), "localhost", port, sizeof(port), NULL, NULL)) + return SCPE_ARG; sprintf (udp_links[link].rhostport, "%s:%s", host, port); if (udp_links[link].lport[0] == '\0') strcpy (udp_links[link].lport, port); diff --git a/HP2100/hp2100_ipl.c b/HP2100/hp2100_ipl.c index 8d16be61..27d4391a 100644 --- a/HP2100/hp2100_ipl.c +++ b/HP2100/hp2100_ipl.c @@ -613,8 +613,7 @@ if ((sim_switches & SWMASK ('C')) || /* connecting? */ } else { - r = sim_parse_addr (cptr, host, sizeof(host), NULL, port, sizeof(port), NULL, NULL); - if (r != SCPE_OK) + if (sim_parse_addr (cptr, host, sizeof(host), NULL, port, sizeof(port), NULL, NULL)) return SCPE_ARG; sprintf(hostport, "%s%s%s%s%s", strchr(host, ':') ? "[" : "", host, strchr(host, ':') ? "]" : "", host [0] ? ":" : "", port); newsock = sim_master_sock (hostport, &r); @@ -662,12 +661,12 @@ if (!(uptr->flags & UNIT_ATT)) /* attached? */ return SCPE_OK; if (uptr->flags & UNIT_ACTV) - sim_close_sock (uptr->DSOCKET, 1); + sim_close_sock (uptr->DSOCKET); else { if (uptr->flags & UNIT_ESTB) /* if established, */ - sim_close_sock (uptr->DSOCKET, 0); /* close data socket */ - sim_close_sock (uptr->LSOCKET, 1); /* closen listen socket */ + sim_close_sock (uptr->DSOCKET); /* close data socket */ + sim_close_sock (uptr->LSOCKET); /* closen listen socket */ } free (uptr->filename); /* free string */ @@ -689,7 +688,7 @@ if (((uptr->flags & UNIT_ATT) == 0) || (uptr->flags & UNIT_ACTV) || ((uptr->flags & UNIT_ESTB) == 0)) return SCPE_NOFNC; -sim_close_sock (uptr->DSOCKET, 0); +sim_close_sock (uptr->DSOCKET); uptr->DSOCKET = 0; uptr->flags = uptr->flags & ~UNIT_ESTB; return SCPE_OK; diff --git a/Ibm1130/ibm1130_sca.c b/Ibm1130/ibm1130_sca.c index e9927185..b58cc194 100644 --- a/Ibm1130/ibm1130_sca.c +++ b/Ibm1130/ibm1130_sca.c @@ -305,7 +305,7 @@ static void sca_socket_error (void) if (sca_sock != INVALID_SOCKET) { /* close socket, prepare to listen again if in listen mode. It's a "master" socket if it was an outgoing connection */ - sim_close_sock(sca_sock, (sca_unit.flags & UNIT_LISTEN) == 0); + sim_close_sock(sca_sock); sca_sock = INVALID_SOCKET; if (sca_unit.filename != NULL) /* reset filename string in unit record */ @@ -460,9 +460,8 @@ static t_stat sca_attach (UNIT *uptr, char *cptr) detach_unit(&sca_unit); if (do_listen) { /* if listen mode, string specifies port number (only; otherwise it's a dummy argument) */ - r = sim_parse_addr (cptr, host, sizeof(host), NULL, port, sizeof(port), SCA_DEFAULT_PORT, NULL); - if (r != SCPE_OK) - return r; + if (sim_parse_addr (cptr, host, sizeof(host), NULL, port, sizeof(port), SCA_DEFAULT_PORT, NULL)) + return SCPE_ARG; if ((0 == strcmp(port, cptr)) && (0 == strcmp(port, "dummy"))) strcpy(port, SCA_DEFAULT_PORT); @@ -491,9 +490,8 @@ static t_stat sca_attach (UNIT *uptr, char *cptr) if (! *cptr) return SCPE_2FARG; - r = sim_parse_addr (cptr, host, sizeof(host), NULL, port, sizeof(port), SCA_DEFAULT_PORT, NULL); - if (r != SCPE_OK) - return r; + if (sim_parse_addr (cptr, host, sizeof(host), NULL, port, sizeof(port), SCA_DEFAULT_PORT, NULL)) + return SCPE_ARG; if ((0 == strcmp(cptr, port)) && (0 == strcmp(host, ""))) { strcpy(host, port); strcpy(port, SCA_DEFAULT_PORT); @@ -518,7 +516,7 @@ static t_stat sca_attach (UNIT *uptr, char *cptr) SETBIT(sca_dsw, SCA_DSW_READY); } else { /* sca_sock appears in "error" set -- connect failed */ - sim_close_sock(sca_sock, TRUE); + sim_close_sock(sca_sock); sca_sock = INVALID_SOCKET; return SCPE_OPENERR; } @@ -559,11 +557,11 @@ static t_stat sca_detach (UNIT *uptr) CLRBIT(sca_dsw, SCA_DSW_READY); /* indicate offline */ if (sca_sock != INVALID_SOCKET) { /* close connected socket */ - sim_close_sock(sca_sock, (sca_unit.flags & UNIT_LISTEN) == 0); + sim_close_sock(sca_sock); sca_sock = INVALID_SOCKET; } if (sca_lsock != INVALID_SOCKET) { /* close listening socket */ - sim_close_sock(sca_lsock, TRUE); + sim_close_sock(sca_lsock); sca_lsock = INVALID_SOCKET; } diff --git a/PDP11/pdp11_dmc.c b/PDP11/pdp11_dmc.c index 998af139..06d78cee 100644 --- a/PDP11/pdp11_dmc.c +++ b/PDP11/pdp11_dmc.c @@ -1258,20 +1258,18 @@ t_stat dmc_setpeer (UNIT* uptr, int32 val, char* cptr, void* desc) DEVICE *dptr = (UNIBUS) ? ((&dmc_dev == find_dev_from_unit(uptr)) ? &dmc_dev : &dmp_dev) : &dmv_dev; int32 dmc = (int32)(uptr-dptr->units); char *peer = ((dptr == &dmc_dev)? &dmc_peer[dmc][0] : &dmp_peer[dmc][0]); -t_stat status = SCPE_OK; char host[CBUFSIZE], port[CBUFSIZE]; if ((!cptr) || (!*cptr)) return SCPE_ARG; if (dmc_is_attached(uptr)) return SCPE_ALATT; -status = sim_parse_addr (cptr, host, sizeof(host), NULL, port, sizeof(port), NULL, NULL); -if (status != SCPE_OK) - return status; +if (sim_parse_addr (cptr, host, sizeof(host), NULL, port, sizeof(port), NULL, NULL)) + return SCPE_ARG; if (host[0] == '\0') return SCPE_ARG; strncpy(peer, cptr, CBUFSIZE-1); -return status; +return SCPE_OK; } t_stat dmc_showspeed (FILE* st, UNIT* uptr, int32 val, void* desc) diff --git a/sim_ether.c b/sim_ether.c index f5d9b8cb..f7ec4c3f 100644 --- a/sim_ether.c +++ b/sim_ether.c @@ -1906,7 +1906,7 @@ else sim_printf ("Eth: Must specify different udp localhost ports\r\n"); return SCPE_OPENERR; } - *fd_handle = sim_connect_sock_ex (localport, hostport, NULL, NULL, TRUE, FALSE); + *fd_handle = sim_connect_sock_ex (localport, hostport, NULL, NULL, SIM_SOCK_OPT_DATAGRAM); if (INVALID_SOCKET == *fd_handle) return SCPE_OPENERR; *eth_api = ETH_API_UDP; @@ -2101,7 +2101,7 @@ switch (eth_api) { break; #endif case ETH_API_UDP: - sim_close_sock(pcap_fd, TRUE); + sim_close_sock(pcap_fd); break; #ifdef USE_SLIRP_NETWORK case ETH_API_NAT: @@ -2363,7 +2363,7 @@ switch (dev->eth_api) { break; #endif default: - sim_err_sock (INVALID_SOCKET, msg, 0); + sim_err_sock (INVALID_SOCKET, msg); break; } #ifdef USE_READER_THREAD diff --git a/sim_sock.c b/sim_sock.c index 94df8414..b42590a0 100644 --- a/sim_sock.c +++ b/sim_sock.c @@ -42,9 +42,10 @@ 02-Sep-01 RMS Fixed UNIX bugs found by Mirian Lennox and Tom Markson */ -#include "sim_defs.h" #include "sim_sock.h" #include +#include +#include #if defined(AF_INET6) && defined(_WIN32) #include @@ -76,7 +77,6 @@ sim_write_sock write from socket sim_close_sock close socket sim_setnonblock set socket non-blocking - sim_msg_sock send message to socket */ /* First, all the non-implemented versions */ @@ -91,17 +91,12 @@ void sim_cleanup_sock (void) { } -SOCKET sim_master_sock (const char *hostport, t_stat *parse_status) +SOCKET sim_master_sock_ex (const char *hostport, int *parse_status, int opt_flags) { return INVALID_SOCKET; } -SOCKET sim_connect_sock (const char *hostport, const char *default_host, const char *default_port) -{ -return INVALID_SOCKET; -} - -SOCKET sim_connect_sock_ex (const char *sourcehostport, const char *hostport, const char *default_host, const char *default_port, t_bool datagram, t_bool nodelay) +SOCKET sim_connect_sock_ex (const char *sourcehostport, const char *hostport, const char *default_host, const char *default_port, int opt_flags) { return INVALID_SOCKET; } @@ -111,17 +106,17 @@ SOCKET sim_accept_conn (SOCKET master, char **connectaddr); return INVALID_SOCKET; } -int32 sim_read_sock (SOCKET sock, char *buf, int32 nbytes) +int sim_read_sock (SOCKET sock, char *buf, int nbytes) { return -1; } -int32 sim_write_sock (SOCKET sock, char *msg, int32 nbytes) +int sim_write_sock (SOCKET sock, char *msg, int nbytes) { return 0; } -void sim_close_sock (SOCKET sock, t_bool master) +void sim_close_sock (SOCKET sock) { return; } @@ -131,7 +126,7 @@ return; /* UNIX, Win32, Macintosh, VMS, OS2 (Berkeley socket) routines */ static struct sock_errors { - int32 value; + int value; char *text; } sock_errors[] = { {WSAEWOULDBLOCK, "Operation would block"}, @@ -152,26 +147,33 @@ static struct sock_errors { }; - - -SOCKET sim_err_sock (SOCKET s, const char *emsg, int32 flg) +char *sim_get_err_sock (const char *emsg) { -int32 err = WSAGetLastError (); -int32 i; +int err = WSAGetLastError (); +int i; +static char err_buf[512]; for (i=0; (sock_errors[i].text) && (sock_errors[i].value != err); i++) ; - if (sock_errors[i].value == err) - sim_printf ("Sockets: %s error %d - %s\n", emsg, err, sock_errors[i].text); + sprintf (err_buf, "Sockets: %s error %d - %s\n", emsg, err, sock_errors[i].text); else #if defined(_WIN32) - sim_printf ("Sockets: %s error %d\n", emsg, err); + sprintf (err_buf, "Sockets: %s error %d\n", emsg, err); #else - sim_printf ("Sockets: %s error %d - %s\n", emsg, err, strerror(err)); + sprintf (err_buf, "Sockets: %s error %d - %s\n", emsg, err, strerror(err)); #endif -if (s != INVALID_SOCKET) - sim_close_sock (s, flg); +return err_buf; +} + +SOCKET sim_err_sock (SOCKET s, const char *emsg) +{ +sim_printf ("%s", sim_get_err_sock (emsg)); +if (s != INVALID_SOCKET) { + int err = WSAGetLastError (); + sim_close_sock (s); + WSASetLastError (err); /* Retain Original socket error value */ + } return INVALID_SOCKET; } @@ -525,14 +527,14 @@ int load_ws2(void) { Outputs: host = pointer to buffer for IP address (may be NULL), 0 = none port = pointer to buffer for IP port (may be NULL), 0 = none - result = status (SCPE_OK on complete success or SCPE_ARG if + result = status (0 on complete success or -1 if parsing can't happen due to bad syntax, a value is out of range, a result can't fit into a result buffer, a service name doesn't exist, or a validation name doesn't match the parsed host) */ -t_stat 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) +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) { char gbuf[CBUFSIZE]; char *hostp, *portp; @@ -545,14 +547,14 @@ if ((port != NULL) && (port_len != 0)) memset (port, 0, port_len); if ((cptr == NULL) || (*cptr == 0)) { if (((default_host == NULL) || (*default_host == 0)) || ((default_port == NULL) || (*default_port == 0))) - return SCPE_ARG; + return -1; if ((host == NULL) || (port == NULL)) - return SCPE_ARG; /* no place */ + return -1; /* no place */ if ((strlen(default_host) >= host_len) || (strlen(default_port) >= port_len)) - return SCPE_ARG; /* no room */ + return -1; /* no room */ strcpy (host, default_host); strcpy (port, default_port); - return SCPE_OK; + return 0; } gbuf[sizeof(gbuf)-1] = '\0'; strncpy (gbuf, cptr, sizeof(gbuf)-1); @@ -571,25 +573,25 @@ else { /* No colon in input */ if (portp != NULL) { portval = strtoul(portp, &endc, 10); if ((*endc == '\0') && ((portval == 0) || (portval > 65535))) - return SCPE_ARG; /* numeric value too big */ + return -1; /* numeric value too big */ if (*endc != '\0') { struct servent *se = getservbyname(portp, "tcp"); if (se == NULL) - return SCPE_ARG; /* invalid service name */ + return -1; /* invalid service name */ } } if (port) /* port wanted? */ if (portp != NULL) { if (strlen(portp) >= port_len) - return SCPE_ARG; /* no room */ + return -1; /* no room */ else strcpy (port, portp); } if (hostp != NULL) { if (']' == hostp[strlen(hostp)-1]) { if ('[' != hostp[0]) - return SCPE_ARG; /* invalid domain literal */ + return -1; /* invalid domain literal */ /* host may be the const default_host so move to temp buffer before modifying */ strncpy(gbuf, hostp+1, sizeof(gbuf)-1); /* remove brackets from domain literal host */ hostp = gbuf; @@ -599,20 +601,20 @@ if (hostp != NULL) { if (host) { /* host wanted? */ if (hostp != NULL) { if (strlen(hostp) >= host_len) - return SCPE_ARG; /* no room */ + return -1; /* no room */ else if (('\0' != hostp[0]) || (default_host == NULL)) strcpy (host, hostp); else if (strlen(default_host) >= host_len) - return SCPE_ARG; /* no room */ + return -1; /* no room */ else strcpy (host, default_host); } else { if (default_host) { if (strlen(default_host) >= host_len) - return SCPE_ARG; /* no room */ + return -1; /* no room */ else strcpy (host, default_host); } @@ -620,40 +622,40 @@ if (host) { /* host wanted? */ } if (validate_addr) { struct addrinfo *ai_host, *ai_validate, *ai, *aiv; - t_stat status; + int status; if (hostp == NULL) - return SCPE_ARG; + return -1; if (p_getaddrinfo(hostp, NULL, NULL, &ai_host)) - return SCPE_ARG; + return -1; if (p_getaddrinfo(validate_addr, NULL, NULL, &ai_validate)) { p_freeaddrinfo (ai_host); - return SCPE_ARG; + return -1; } - status = SCPE_ARG; + status = -1; for (ai = ai_host; ai != NULL; ai = ai->ai_next) { for (aiv = ai_validate; aiv != NULL; aiv = aiv->ai_next) { if ((ai->ai_addrlen == aiv->ai_addrlen) && (ai->ai_family == aiv->ai_family) && (0 == memcmp (ai->ai_addr, aiv->ai_addr, ai->ai_addrlen))) { - status = SCPE_OK; + status = 0; break; } } } - if (status != SCPE_OK) { + if (status != 0) { /* be generous and allow successful validations against variations of localhost addresses */ if (((0 == strcmp("127.0.0.1", hostp)) && (0 == strcmp("::1", validate_addr))) || ((0 == strcmp("127.0.0.1", validate_addr)) && (0 == strcmp("::1", hostp)))) - status = SCPE_OK; + status = 0; } p_freeaddrinfo (ai_host); p_freeaddrinfo (ai_validate); return status; } -return SCPE_OK; +return 0; } /* sim_parse_addr_ex localport:host:port @@ -690,7 +692,7 @@ return SCPE_OK; a service name doesn't exist, or a validation name doesn't match the parsed host) */ -t_stat 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) +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) { char *hostp; @@ -749,7 +751,7 @@ WSACleanup (); } #if defined (_WIN32) /* Windows */ -static int32 sim_setnonblock (SOCKET sock) +static int sim_setnonblock (SOCKET sock) { unsigned long non_block = 1; @@ -757,7 +759,7 @@ return ioctlsocket (sock, FIONBIO, &non_block); /* set nonblocking */ } #elif defined (VMS) /* VMS */ -static int32 sim_setnonblock (SOCKET sock) +static int sim_setnonblock (SOCKET sock) { int non_block = 1; @@ -765,9 +767,9 @@ return ioctl (sock, FIONBIO, &non_block); /* set nonblocking */ } #else /* Mac, Unix, OS/2 */ -static int32 sim_setnonblock (SOCKET sock) +static int sim_setnonblock (SOCKET sock) { -int32 fl, sta; +int fl, sta; fl = fcntl (sock, F_GETFL,0); /* get flags */ if (fl == -1) @@ -786,7 +788,7 @@ return 0; #endif /* endif !Win32 && !VMS */ -static int32 sim_setnodelay (SOCKET sock) +static int sim_setnodelay (SOCKET sock) { int nodelay = 1; int sta; @@ -813,28 +815,23 @@ if (sta == -1) return sta; } -static SOCKET sim_create_sock_ex (int af, t_bool datagram) +static SOCKET sim_create_sock (int af, int opt_flags) { SOCKET newsock; -int32 err; +int err; -newsock = socket (af, (datagram ? SOCK_DGRAM : SOCK_STREAM), 0);/* create socket */ +newsock = socket (af, ((opt_flags & SIM_SOCK_OPT_DATAGRAM) ? SOCK_DGRAM : SOCK_STREAM), 0);/* create socket */ if (newsock == INVALID_SOCKET) { /* socket error? */ err = WSAGetLastError (); #if defined(WSAEAFNOSUPPORT) if (err == WSAEAFNOSUPPORT) /* expected error, just return */ return newsock; #endif - return sim_err_sock (newsock, "socket", 0); /* report error and return */ + return sim_err_sock (newsock, "socket"); /* report error and return */ } return newsock; } -static SOCKET sim_create_sock (int af) -{ -return sim_create_sock_ex (af, FALSE); -} - /* Some platforms and/or network stacks have varying support for listening on an IPv6 socket and receiving connections from both IPv4 and IPv6 client @@ -842,19 +839,19 @@ return sim_create_sock_ex (af, FALSE); support (i.e. some Windows versions), but it doesn't work in all cases. */ -SOCKET sim_master_sock (const char *hostport, t_stat *parse_status) +SOCKET sim_master_sock_ex (const char *hostport, int *parse_status, int opt_flags) { SOCKET newsock = INVALID_SOCKET; -int32 sta; +int sta; char host[CBUFSIZE], port[CBUFSIZE]; -t_stat r; +int r; struct addrinfo hints; struct addrinfo *result = NULL, *preferred; r = sim_parse_addr (hostport, host, sizeof(host), NULL, port, sizeof(port), NULL, NULL); if (parse_status) *parse_status = r; -if (r != SCPE_OK) +if (r) return newsock; memset(&hints, 0, sizeof(hints)); @@ -864,7 +861,7 @@ hints.ai_protocol = IPPROTO_TCP; hints.ai_socktype = SOCK_STREAM; if (p_getaddrinfo(host[0] ? host : NULL, port[0] ? port : NULL, &hints, &result)) { if (parse_status) - *parse_status = SCPE_ARG; + *parse_status = -1; return newsock; } preferred = result; @@ -881,7 +878,7 @@ if (preferred == NULL) preferred = result; #endif retry: -newsock = sim_create_sock (preferred->ai_family); /* create socket */ +newsock = sim_create_sock (preferred->ai_family, 0); /* create socket */ if (newsock == INVALID_SOCKET) { /* socket error? */ #ifndef IPV6_V6ONLY if (preferred->ai_next) { @@ -900,18 +897,18 @@ if (newsock == INVALID_SOCKET) { /* socket error? */ } #ifdef IPV6_V6ONLY if (preferred->ai_family == AF_INET6) { - int off = FALSE; + int off = 0; sta = setsockopt (newsock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&off, sizeof(off)); } #endif -if (sim_switches & SWMASK ('U')) { - int on = TRUE; +if (opt_flags & SIM_SOCK_OPT_REUSEADDR) { + int on = 1; sta = setsockopt (newsock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)); } #if defined (SO_EXCLUSIVEADDRUSE) else { - int on = TRUE; + int on = 1; sta = setsockopt (newsock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (char *)&on, sizeof(on)); } @@ -919,46 +916,40 @@ else { sta = bind (newsock, preferred->ai_addr, preferred->ai_addrlen); p_freeaddrinfo(result); if (sta == SOCKET_ERROR) /* bind error? */ - return sim_err_sock (newsock, "bind", 1); -sta = sim_setnonblock (newsock); /* set nonblocking */ -if (sta == SOCKET_ERROR) /* fcntl error? */ - return sim_err_sock (newsock, "fcntl", 1); + return sim_err_sock (newsock, "bind"); +if (!(opt_flags & SIM_SOCK_OPT_BLOCKING)) { + sta = sim_setnonblock (newsock); /* set nonblocking */ + if (sta == SOCKET_ERROR) /* fcntl error? */ + return sim_err_sock (newsock, "fcntl"); + } sta = listen (newsock, 1); /* listen on socket */ if (sta == SOCKET_ERROR) /* listen error? */ - return sim_err_sock (newsock, "listen", 1); + return sim_err_sock (newsock, "listen"); return newsock; /* got it! */ } -SOCKET sim_connect_sock (const char *hostport, const char *default_host, const char *default_port) -{ -return sim_connect_sock_ex (NULL, hostport, default_host, default_port, FALSE, FALSE); -} - -SOCKET sim_connect_sock_ex (const char *sourcehostport, const char *hostport, const char *default_host, const char *default_port, t_bool datagram, t_bool nodelay) +SOCKET sim_connect_sock_ex (const char *sourcehostport, const char *hostport, const char *default_host, const char *default_port, int opt_flags) { SOCKET newsock = INVALID_SOCKET; -int32 sta; +int sta; char host[CBUFSIZE], port[CBUFSIZE]; -t_stat r; struct addrinfo hints; struct addrinfo *result = NULL, *source = NULL; -r = sim_parse_addr (hostport, host, sizeof(host), default_host, port, sizeof(port), default_port, NULL); -if (r != SCPE_OK) +if (sim_parse_addr (hostport, host, sizeof(host), default_host, port, sizeof(port), default_port, NULL)) return INVALID_SOCKET; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; -hints.ai_protocol = (datagram ? IPPROTO_UDP : IPPROTO_TCP); -hints.ai_socktype = (datagram ? SOCK_DGRAM : SOCK_STREAM); +hints.ai_protocol = ((opt_flags & SIM_SOCK_OPT_DATAGRAM) ? IPPROTO_UDP : IPPROTO_TCP); +hints.ai_socktype = ((opt_flags & SIM_SOCK_OPT_DATAGRAM) ? SOCK_DGRAM : SOCK_STREAM); if (p_getaddrinfo(host[0] ? host : NULL, port[0] ? port : NULL, &hints, &result)) return INVALID_SOCKET; if (sourcehostport) { /* Validate the local/source side address which we'll bind to */ - r = sim_parse_addr (sourcehostport, host, sizeof(host), NULL, port, sizeof(port), NULL, NULL); - if (r != SCPE_OK) { + if (sim_parse_addr (sourcehostport, host, sizeof(host), NULL, port, sizeof(port), NULL, NULL)) { p_freeaddrinfo (result); return INVALID_SOCKET; } @@ -966,14 +957,14 @@ if (sourcehostport) { memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_PASSIVE; hints.ai_family = result->ai_family; /* Same family as connect destination */ - hints.ai_protocol = (datagram ? IPPROTO_UDP : IPPROTO_TCP); - hints.ai_socktype = (datagram ? SOCK_DGRAM : SOCK_STREAM); + hints.ai_protocol = ((opt_flags & SIM_SOCK_OPT_DATAGRAM) ? IPPROTO_UDP : IPPROTO_TCP); + hints.ai_socktype = ((opt_flags & SIM_SOCK_OPT_DATAGRAM) ? SOCK_DGRAM : SOCK_STREAM); if (p_getaddrinfo(host[0] ? host : NULL, port[0] ? port : NULL, &hints, &source)) { p_freeaddrinfo (result); return INVALID_SOCKET; } - newsock = sim_create_sock_ex (result->ai_family, datagram);/* create socket */ + newsock = sim_create_sock (result->ai_family, opt_flags & SIM_SOCK_OPT_DATAGRAM);/* create socket */ if (newsock == INVALID_SOCKET) { /* socket error? */ p_freeaddrinfo (result); p_freeaddrinfo (source); @@ -985,55 +976,66 @@ if (sourcehostport) { source = NULL; if (sta == SOCKET_ERROR) { /* bind error? */ p_freeaddrinfo (result); - return sim_err_sock (newsock, "bind", 1); + return sim_err_sock (newsock, "bind"); } } if (newsock == INVALID_SOCKET) { /* socket error? */ - newsock = sim_create_sock_ex (result->ai_family, datagram);/* create socket */ + newsock = sim_create_sock (result->ai_family, opt_flags & SIM_SOCK_OPT_DATAGRAM);/* create socket */ if (newsock == INVALID_SOCKET) { /* socket error? */ p_freeaddrinfo (result); return newsock; } } -sta = sim_setnonblock (newsock); /* set nonblocking */ -if (sta == SOCKET_ERROR) { /* fcntl error? */ - p_freeaddrinfo (result); - return sim_err_sock (newsock, "fcntl", 1); +if (!(opt_flags & SIM_SOCK_OPT_BLOCKING)) { + sta = sim_setnonblock (newsock); /* set nonblocking */ + if (sta == SOCKET_ERROR) { /* fcntl error? */ + p_freeaddrinfo (result); + return sim_err_sock (newsock, "fcntl"); + } } -if ((!datagram) && (nodelay)) { +if ((!(opt_flags & SIM_SOCK_OPT_DATAGRAM)) && (opt_flags & SIM_SOCK_OPT_NODELAY)) { sta = sim_setnodelay (newsock); /* set nodelay */ if (sta == SOCKET_ERROR) { /* setsock error? */ p_freeaddrinfo (result); - return sim_err_sock (newsock, "setnodelay", 1); + return sim_err_sock (newsock, "setnodelay"); } } -sta = connect (newsock, result->ai_addr, result->ai_addrlen); -p_freeaddrinfo (result); -if ((sta == SOCKET_ERROR) && - (WSAGetLastError () != WSAEWOULDBLOCK) && - (WSAGetLastError () != WSAEINPROGRESS)) - return sim_err_sock (newsock, "connect", 1); -if (!datagram) { +if (!(opt_flags & SIM_SOCK_OPT_DATAGRAM)) { int keepalive = 1; /* enable TCP Keep Alives */ sta = setsockopt (newsock, SOL_SOCKET, SO_KEEPALIVE, (char *)&keepalive, sizeof(keepalive)); if (sta == -1) - return sim_err_sock (newsock, "setsockopt KEEPALIVE", 1); + return sim_err_sock (newsock, "setsockopt KEEPALIVE"); + } +sta = connect (newsock, result->ai_addr, result->ai_addrlen); +p_freeaddrinfo (result); +if (sta == SOCKET_ERROR) { + if (opt_flags & SIM_SOCK_OPT_BLOCKING) { + if ((sta == WSAETIMEDOUT) || /* expected errors after a connect failure */ + (sta == WSAEHOSTUNREACH) || + (sta == WSAECONNREFUSED) || + (sta == WSAECONNABORTED) || + (sta == WSAECONNRESET)) { + sim_close_sock (newsock); + newsock = INVALID_SOCKET; + } + else + return sim_err_sock (newsock, "connect"); + } + else /* Non Blocking case won't return errors until some future read */ + if ((WSAGetLastError () != WSAEWOULDBLOCK) && + (WSAGetLastError () != WSAEINPROGRESS)) + return sim_err_sock (newsock, "connect"); } return newsock; /* got it! */ } -SOCKET sim_accept_conn (SOCKET master, char **connectaddr) +SOCKET sim_accept_conn_ex (SOCKET master, char **connectaddr, int opt_flags) { -return sim_accept_conn_ex (master, connectaddr, FALSE); -} - -SOCKET sim_accept_conn_ex (SOCKET master, char **connectaddr, t_bool nodelay) -{ -int32 sta, err; +int sta = 0, err; int keepalive = 1; #if defined (macintosh) || defined (__linux) || defined (__linux__) || \ defined (__APPLE__) || defined (__OpenBSD__) || \ @@ -1059,7 +1061,7 @@ newsock = accept (master, (struct sockaddr *) &clientname, &size); if (newsock == INVALID_SOCKET) { /* error? */ err = WSAGetLastError (); if (err != WSAEWOULDBLOCK) - sim_err_sock(newsock, "accept", 0); + sim_err_sock(newsock, "accept"); return INVALID_SOCKET; } if (connectaddr != NULL) { @@ -1074,25 +1076,27 @@ if (connectaddr != NULL) { #endif } -sta = sim_setnonblock (newsock); /* set nonblocking */ -if (sta == SOCKET_ERROR) /* fcntl error? */ - return sim_err_sock (newsock, "fcntl", 0); +if (!(opt_flags & SIM_SOCK_OPT_BLOCKING)) { + sta = sim_setnonblock (newsock); /* set nonblocking */ + if (sta == SOCKET_ERROR) /* fcntl error? */ + return sim_err_sock (newsock, "fcntl"); + } -if (nodelay) { - sta = sim_setnodelay (newsock); /* set nonblocking */ - if (sta == SOCKET_ERROR) /* setsockopt error? */ - return sim_err_sock (newsock, "setnodelay", 0); +if ((opt_flags & SIM_SOCK_OPT_NODELAY)) { + sta = sim_setnodelay (newsock); /* set nonblocking */ + if (sta == SOCKET_ERROR) /* setsockopt error? */ + return sim_err_sock (newsock, "setnodelay"); } /* enable TCP Keep Alives */ sta = setsockopt (newsock, SOL_SOCKET, SO_KEEPALIVE, (char *)&keepalive, sizeof(keepalive)); if (sta == -1) - return sim_err_sock (newsock, "setsockopt KEEPALIVE", 1); + return sim_err_sock (newsock, "setsockopt KEEPALIVE"); return newsock; } -int32 sim_check_conn (SOCKET sock, t_bool rd) +int sim_check_conn (SOCKET sock, int rd) { fd_set rw_set, er_set; fd_set *rw_p = &rw_set; @@ -1132,7 +1136,7 @@ if (FD_ISSET (sock, rw_p)) { return 0; } -static int32 _sim_getaddrname (struct sockaddr *addr, size_t addrsize, char *hostnamebuf, char *portnamebuf) +static int _sim_getaddrname (struct sockaddr *addr, size_t addrsize, char *hostnamebuf, char *portnamebuf) { #if defined (macintosh) || defined (__linux) || defined (__linux__) || \ defined (__APPLE__) || defined (__OpenBSD__) || \ @@ -1147,7 +1151,7 @@ int size = (int)addrsize; #else size_t size = addrsize; #endif -int32 ret = 0; +int ret = 0; #ifdef AF_INET6 *hostnamebuf = '\0'; @@ -1165,7 +1169,7 @@ sprintf(portnamebuf, "%d", (int)ntohs(((struct sockaddr_in *)addr)->s_port))); return ret; } -int32 sim_getnames_sock (SOCKET sock, char **socknamebuf, char **peernamebuf) +int sim_getnames_sock (SOCKET sock, char **socknamebuf, char **peernamebuf) { struct sockaddr_storage sockname, peername; #if defined (macintosh) || defined (__linux) || defined (__linux__) || \ @@ -1205,9 +1209,9 @@ return 0; } -int32 sim_read_sock (SOCKET sock, char *buf, int32 nbytes) +int sim_read_sock (SOCKET sock, char *buf, int nbytes) { -int32 rbytes, err; +int rbytes, err; rbytes = recv (sock, buf, nbytes, 0); if (rbytes == 0) /* disconnect */ @@ -1225,15 +1229,15 @@ if (rbytes == SOCKET_ERROR) { (err != WSAECONNREFUSED) && (err != WSAECONNABORTED) && (err != WSAECONNRESET)) - sim_err_sock (INVALID_SOCKET, "read", 0); + sim_err_sock (INVALID_SOCKET, "read"); return -1; } return rbytes; } -int32 sim_write_sock (SOCKET sock, const char *msg, int32 nbytes) +int sim_write_sock (SOCKET sock, const char *msg, int nbytes) { -int32 err, sbytes = send (sock, msg, nbytes, 0); +int err, sbytes = send (sock, msg, nbytes, 0); if (sbytes == SOCKET_ERROR) { err = WSAGetLastError (); @@ -1247,7 +1251,7 @@ if (sbytes == SOCKET_ERROR) { return sbytes; } -void sim_close_sock (SOCKET sock, t_bool master) +void sim_close_sock (SOCKET sock) { shutdown(sock, SD_BOTH); closesocket (sock); diff --git a/sim_sock.h b/sim_sock.h index 0dcb8273..6d063194 100644 --- a/sim_sock.h +++ b/sim_sock.h @@ -51,8 +51,9 @@ #elif !defined (__OS2__) || defined (__EMX__) /* VMS, Mac, Unix, OS/2 EMX */ #define WSAGetLastError() errno /* Windows macros */ +#define WSASetLastError(err) errno = err #define closesocket close -#define SOCKET int32 +#define SOCKET int #if defined(__hpux) #define WSAEWOULDBLOCK EAGAIN #else @@ -75,6 +76,8 @@ #define SOCKET_ERROR -1 #include /* for fcntl, getpid */ #include /* for sockets */ +#include +#include #include #include #include /* for sockaddr_in */ @@ -102,19 +105,30 @@ #endif #endif -t_stat sim_parse_addr (const char *cptr, char *host, size_t hostlen, const char *default_host, char *port, size_t port_len, const char *default_port, const char *validate_addr); -t_stat 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 local_port_len, const char *default_port); -SOCKET sim_master_sock (const char *hostport, t_stat *parse_status); -SOCKET sim_connect_sock (const char *hostport, const char *default_host, const char *default_port); -SOCKET sim_connect_sock_ex (const char *sourcehostport, const char *hostport, const char *default_host, const char *default_port, t_bool datagram, t_bool nodelay); -SOCKET sim_accept_conn (SOCKET master, char **connectaddr); -SOCKET sim_accept_conn_ex (SOCKET master, char **connectaddr, t_bool nodelay); -int32 sim_check_conn (SOCKET sock, t_bool rd); -int32 sim_read_sock (SOCKET sock, char *buf, int32 nbytes); -int32 sim_write_sock (SOCKET sock, const char *msg, int32 nbytes); -void sim_close_sock (SOCKET sock, t_bool master); -SOCKET sim_err_sock (SOCKET sock, const char *emsg, int32 flg); -int32 sim_getnames_sock (SOCKET sock, char **socknamebuf, char **peernamebuf); +#if !defined(CBUFSIZE) +#define CBUFSIZE 1024 +#define sim_printf printf +#endif + +int sim_parse_addr (const char *cptr, char *host, size_t hostlen, const char *default_host, char *port, size_t port_len, const char *default_port, const char *validate_addr); +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 local_port_len, const char *default_port); +#define SIM_SOCK_OPT_REUSEADDR 0x0001 +#define SIM_SOCK_OPT_DATAGRAM 0x0002 +#define SIM_SOCK_OPT_NODELAY 0x0004 +#define SIM_SOCK_OPT_BLOCKING 0x0008 +SOCKET sim_master_sock_ex (const char *hostport, int *parse_status, int opt_flags); +#define sim_master_sock(hostport, parse_status) sim_master_sock_ex(hostport, parse_status, ((sim_switches & SWMASK ('U')) ? SIM_SOCK_OPT_REUSEADDR : 0)) +SOCKET sim_connect_sock_ex (const char *sourcehostport, const char *hostport, const char *default_host, const char *default_port, int opt_flags); +#define sim_connect_sock(hostport, default_host, default_port) sim_connect_sock_ex(NULL, hostport, default_host, default_port, 0) +SOCKET sim_accept_conn_ex (SOCKET master, char **connectaddr, int opt_flags); +#define sim_accept_conn(master, connectaddr) sim_accept_conn_ex(master, connectaddr, 0) +int sim_check_conn (SOCKET sock, int rd); +int sim_read_sock (SOCKET sock, char *buf, int nbytes); +int sim_write_sock (SOCKET sock, const char *msg, int nbytes); +void sim_close_sock (SOCKET sock); +char *sim_get_err_sock (const char *emsg); +SOCKET sim_err_sock (SOCKET sock, const char *emsg); +int sim_getnames_sock (SOCKET sock, char **socknamebuf, char **peernamebuf); void sim_init_sock (void); void sim_cleanup_sock (void);