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)
This commit is contained in:
Mark Pizzolato 2015-02-11 09:41:18 -08:00
parent 5b4e9d5891
commit 1fb209c275
8 changed files with 192 additions and 180 deletions

View file

@ -154,8 +154,7 @@ static t_stat net_attach(UNIT *uptr, char *cptr) {
char host[CBUFSIZE], port[CBUFSIZE]; char host[CBUFSIZE], port[CBUFSIZE];
t_stat r; t_stat r;
r = sim_parse_addr (cptr, host, sizeof(host), "localhost", port, sizeof(port), "3000", NULL); if (sim_parse_addr (cptr, host, sizeof(host), "localhost", port, sizeof(port), "3000", NULL))
if (r != SCPE_OK)
return SCPE_ARG; return SCPE_ARG;
net_reset(&net_dev); net_reset(&net_dev);
for (i = 0; i <= MAX_CONNECTIONS; i++) for (i = 0; i <= MAX_CONNECTIONS; i++)
@ -185,10 +184,10 @@ static t_stat net_detach(UNIT *uptr) {
if (!(net_unit.flags & UNIT_ATT)) if (!(net_unit.flags & UNIT_ATT))
return SCPE_OK; /* if not attached simply return */ return SCPE_OK; /* if not attached simply return */
if (net_unit.flags & UNIT_SERVER) 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++) for (i = 0; i <= MAX_CONNECTIONS; i++)
if (serviceDescriptor[i].ioSocket) if (serviceDescriptor[i].ioSocket)
sim_close_sock(serviceDescriptor[i].ioSocket, FALSE); sim_close_sock(serviceDescriptor[i].ioSocket);
free(net_unit.filename); /* free port string */ free(net_unit.filename); /* free port string */
net_unit.filename = NULL; net_unit.filename = NULL;
net_unit.flags &= ~UNIT_ATT; /* not attached */ net_unit.flags &= ~UNIT_ATT; /* not attached */
@ -226,7 +225,7 @@ static t_stat net_svc(UNIT *uptr) {
BUFFER_LENGTH - serviceDescriptor[i].inputSize); BUFFER_LENGTH - serviceDescriptor[i].inputSize);
if (r == -1) { 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_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[i].ioSocket = 0;
serviceDescriptor_reset(i); serviceDescriptor_reset(i);
continue; continue;

View file

@ -235,8 +235,8 @@ t_stat udp_parse_remote (int32 link, char *premote)
premote = end+1; premote = end+1;
} }
ret = sim_parse_addr (premote, host, sizeof(host), "localhost", port, sizeof(port), NULL, NULL); if (sim_parse_addr (premote, host, sizeof(host), "localhost", port, sizeof(port), NULL, NULL))
if (ret != SCPE_OK) return SCPE_ARG; return SCPE_ARG;
sprintf (udp_links[link].rhostport, "%s:%s", host, port); sprintf (udp_links[link].rhostport, "%s:%s", host, port);
if (udp_links[link].lport[0] == '\0') if (udp_links[link].lport[0] == '\0')
strcpy (udp_links[link].lport, port); strcpy (udp_links[link].lport, port);

View file

@ -613,8 +613,7 @@ if ((sim_switches & SWMASK ('C')) || /* connecting? */
} }
else { else {
r = sim_parse_addr (cptr, host, sizeof(host), NULL, port, sizeof(port), NULL, NULL); if (sim_parse_addr (cptr, host, sizeof(host), NULL, port, sizeof(port), NULL, NULL))
if (r != SCPE_OK)
return SCPE_ARG; return SCPE_ARG;
sprintf(hostport, "%s%s%s%s%s", strchr(host, ':') ? "[" : "", host, strchr(host, ':') ? "]" : "", host [0] ? ":" : "", port); sprintf(hostport, "%s%s%s%s%s", strchr(host, ':') ? "[" : "", host, strchr(host, ':') ? "]" : "", host [0] ? ":" : "", port);
newsock = sim_master_sock (hostport, &r); newsock = sim_master_sock (hostport, &r);
@ -662,12 +661,12 @@ if (!(uptr->flags & UNIT_ATT)) /* attached? */
return SCPE_OK; return SCPE_OK;
if (uptr->flags & UNIT_ACTV) if (uptr->flags & UNIT_ACTV)
sim_close_sock (uptr->DSOCKET, 1); sim_close_sock (uptr->DSOCKET);
else { else {
if (uptr->flags & UNIT_ESTB) /* if established, */ if (uptr->flags & UNIT_ESTB) /* if established, */
sim_close_sock (uptr->DSOCKET, 0); /* close data socket */ sim_close_sock (uptr->DSOCKET); /* close data socket */
sim_close_sock (uptr->LSOCKET, 1); /* closen listen socket */ sim_close_sock (uptr->LSOCKET); /* closen listen socket */
} }
free (uptr->filename); /* free string */ free (uptr->filename); /* free string */
@ -689,7 +688,7 @@ if (((uptr->flags & UNIT_ATT) == 0) ||
(uptr->flags & UNIT_ACTV) || (uptr->flags & UNIT_ACTV) ||
((uptr->flags & UNIT_ESTB) == 0)) ((uptr->flags & UNIT_ESTB) == 0))
return SCPE_NOFNC; return SCPE_NOFNC;
sim_close_sock (uptr->DSOCKET, 0); sim_close_sock (uptr->DSOCKET);
uptr->DSOCKET = 0; uptr->DSOCKET = 0;
uptr->flags = uptr->flags & ~UNIT_ESTB; uptr->flags = uptr->flags & ~UNIT_ESTB;
return SCPE_OK; return SCPE_OK;

View file

@ -305,7 +305,7 @@ static void sca_socket_error (void)
if (sca_sock != INVALID_SOCKET) { 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 */ /* 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; sca_sock = INVALID_SOCKET;
if (sca_unit.filename != NULL) /* reset filename string in unit record */ 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); detach_unit(&sca_unit);
if (do_listen) { /* if listen mode, string specifies port number (only; otherwise it's a dummy argument) */ 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 (sim_parse_addr (cptr, host, sizeof(host), NULL, port, sizeof(port), SCA_DEFAULT_PORT, NULL))
if (r != SCPE_OK) return SCPE_ARG;
return r;
if ((0 == strcmp(port, cptr)) && (0 == strcmp(port, "dummy"))) if ((0 == strcmp(port, cptr)) && (0 == strcmp(port, "dummy")))
strcpy(port, SCA_DEFAULT_PORT); strcpy(port, SCA_DEFAULT_PORT);
@ -491,9 +490,8 @@ static t_stat sca_attach (UNIT *uptr, char *cptr)
if (! *cptr) if (! *cptr)
return SCPE_2FARG; return SCPE_2FARG;
r = sim_parse_addr (cptr, host, sizeof(host), NULL, port, sizeof(port), SCA_DEFAULT_PORT, NULL); if (sim_parse_addr (cptr, host, sizeof(host), NULL, port, sizeof(port), SCA_DEFAULT_PORT, NULL))
if (r != SCPE_OK) return SCPE_ARG;
return r;
if ((0 == strcmp(cptr, port)) && (0 == strcmp(host, ""))) { if ((0 == strcmp(cptr, port)) && (0 == strcmp(host, ""))) {
strcpy(host, port); strcpy(host, port);
strcpy(port, SCA_DEFAULT_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); SETBIT(sca_dsw, SCA_DSW_READY);
} }
else { /* sca_sock appears in "error" set -- connect failed */ else { /* sca_sock appears in "error" set -- connect failed */
sim_close_sock(sca_sock, TRUE); sim_close_sock(sca_sock);
sca_sock = INVALID_SOCKET; sca_sock = INVALID_SOCKET;
return SCPE_OPENERR; return SCPE_OPENERR;
} }
@ -559,11 +557,11 @@ static t_stat sca_detach (UNIT *uptr)
CLRBIT(sca_dsw, SCA_DSW_READY); /* indicate offline */ CLRBIT(sca_dsw, SCA_DSW_READY); /* indicate offline */
if (sca_sock != INVALID_SOCKET) { /* close connected socket */ 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; sca_sock = INVALID_SOCKET;
} }
if (sca_lsock != INVALID_SOCKET) { /* close listening socket */ if (sca_lsock != INVALID_SOCKET) { /* close listening socket */
sim_close_sock(sca_lsock, TRUE); sim_close_sock(sca_lsock);
sca_lsock = INVALID_SOCKET; sca_lsock = INVALID_SOCKET;
} }

View file

@ -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; DEVICE *dptr = (UNIBUS) ? ((&dmc_dev == find_dev_from_unit(uptr)) ? &dmc_dev : &dmp_dev) : &dmv_dev;
int32 dmc = (int32)(uptr-dptr->units); int32 dmc = (int32)(uptr-dptr->units);
char *peer = ((dptr == &dmc_dev)? &dmc_peer[dmc][0] : &dmp_peer[dmc][0]); char *peer = ((dptr == &dmc_dev)? &dmc_peer[dmc][0] : &dmp_peer[dmc][0]);
t_stat status = SCPE_OK;
char host[CBUFSIZE], port[CBUFSIZE]; char host[CBUFSIZE], port[CBUFSIZE];
if ((!cptr) || (!*cptr)) if ((!cptr) || (!*cptr))
return SCPE_ARG; return SCPE_ARG;
if (dmc_is_attached(uptr)) if (dmc_is_attached(uptr))
return SCPE_ALATT; return SCPE_ALATT;
status = sim_parse_addr (cptr, host, sizeof(host), NULL, port, sizeof(port), NULL, NULL); if (sim_parse_addr (cptr, host, sizeof(host), NULL, port, sizeof(port), NULL, NULL))
if (status != SCPE_OK) return SCPE_ARG;
return status;
if (host[0] == '\0') if (host[0] == '\0')
return SCPE_ARG; return SCPE_ARG;
strncpy(peer, cptr, CBUFSIZE-1); strncpy(peer, cptr, CBUFSIZE-1);
return status; return SCPE_OK;
} }
t_stat dmc_showspeed (FILE* st, UNIT* uptr, int32 val, void* desc) t_stat dmc_showspeed (FILE* st, UNIT* uptr, int32 val, void* desc)

View file

@ -1906,7 +1906,7 @@ else
sim_printf ("Eth: Must specify different udp localhost ports\r\n"); sim_printf ("Eth: Must specify different udp localhost ports\r\n");
return SCPE_OPENERR; 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) if (INVALID_SOCKET == *fd_handle)
return SCPE_OPENERR; return SCPE_OPENERR;
*eth_api = ETH_API_UDP; *eth_api = ETH_API_UDP;
@ -2101,7 +2101,7 @@ switch (eth_api) {
break; break;
#endif #endif
case ETH_API_UDP: case ETH_API_UDP:
sim_close_sock(pcap_fd, TRUE); sim_close_sock(pcap_fd);
break; break;
#ifdef USE_SLIRP_NETWORK #ifdef USE_SLIRP_NETWORK
case ETH_API_NAT: case ETH_API_NAT:
@ -2363,7 +2363,7 @@ switch (dev->eth_api) {
break; break;
#endif #endif
default: default:
sim_err_sock (INVALID_SOCKET, msg, 0); sim_err_sock (INVALID_SOCKET, msg);
break; break;
} }
#ifdef USE_READER_THREAD #ifdef USE_READER_THREAD

View file

@ -42,9 +42,10 @@
02-Sep-01 RMS Fixed UNIX bugs found by Mirian Lennox and Tom Markson 02-Sep-01 RMS Fixed UNIX bugs found by Mirian Lennox and Tom Markson
*/ */
#include "sim_defs.h"
#include "sim_sock.h" #include "sim_sock.h"
#include <signal.h> #include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#if defined(AF_INET6) && defined(_WIN32) #if defined(AF_INET6) && defined(_WIN32)
#include <ws2tcpip.h> #include <ws2tcpip.h>
@ -76,7 +77,6 @@
sim_write_sock write from socket sim_write_sock write from socket
sim_close_sock close socket sim_close_sock close socket
sim_setnonblock set socket non-blocking sim_setnonblock set socket non-blocking
sim_msg_sock send message to socket
*/ */
/* First, all the non-implemented versions */ /* 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; return INVALID_SOCKET;
} }
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, int opt_flags)
{
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)
{ {
return INVALID_SOCKET; return INVALID_SOCKET;
} }
@ -111,17 +106,17 @@ SOCKET sim_accept_conn (SOCKET master, char **connectaddr);
return INVALID_SOCKET; 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; return -1;
} }
int32 sim_write_sock (SOCKET sock, char *msg, int32 nbytes) int sim_write_sock (SOCKET sock, char *msg, int nbytes)
{ {
return 0; return 0;
} }
void sim_close_sock (SOCKET sock, t_bool master) void sim_close_sock (SOCKET sock)
{ {
return; return;
} }
@ -131,7 +126,7 @@ return;
/* UNIX, Win32, Macintosh, VMS, OS2 (Berkeley socket) routines */ /* UNIX, Win32, Macintosh, VMS, OS2 (Berkeley socket) routines */
static struct sock_errors { static struct sock_errors {
int32 value; int value;
char *text; char *text;
} sock_errors[] = { } sock_errors[] = {
{WSAEWOULDBLOCK, "Operation would block"}, {WSAEWOULDBLOCK, "Operation would block"},
@ -152,26 +147,33 @@ static struct sock_errors {
}; };
char *sim_get_err_sock (const char *emsg)
SOCKET sim_err_sock (SOCKET s, const char *emsg, int32 flg)
{ {
int32 err = WSAGetLastError (); int err = WSAGetLastError ();
int32 i; int i;
static char err_buf[512];
for (i=0; (sock_errors[i].text) && (sock_errors[i].value != err); i++) for (i=0; (sock_errors[i].text) && (sock_errors[i].value != err); i++)
; ;
if (sock_errors[i].value == err) 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 else
#if defined(_WIN32) #if defined(_WIN32)
sim_printf ("Sockets: %s error %d\n", emsg, err); sprintf (err_buf, "Sockets: %s error %d\n", emsg, err);
#else #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 #endif
if (s != INVALID_SOCKET) return err_buf;
sim_close_sock (s, flg); }
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; return INVALID_SOCKET;
} }
@ -525,14 +527,14 @@ int load_ws2(void) {
Outputs: Outputs:
host = pointer to buffer for IP address (may be NULL), 0 = none host = pointer to buffer for IP address (may be NULL), 0 = none
port = pointer to buffer for IP port (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 parsing can't happen due to bad syntax, a value is
out of range, a result can't fit into a result buffer, out of range, a result can't fit into a result buffer,
a service name doesn't exist, or a validation name a service name doesn't exist, or a validation name
doesn't match the parsed host) 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 gbuf[CBUFSIZE];
char *hostp, *portp; char *hostp, *portp;
@ -545,14 +547,14 @@ if ((port != NULL) && (port_len != 0))
memset (port, 0, port_len); memset (port, 0, port_len);
if ((cptr == NULL) || (*cptr == 0)) { if ((cptr == NULL) || (*cptr == 0)) {
if (((default_host == NULL) || (*default_host == 0)) || ((default_port == NULL) || (*default_port == 0))) if (((default_host == NULL) || (*default_host == 0)) || ((default_port == NULL) || (*default_port == 0)))
return SCPE_ARG; return -1;
if ((host == NULL) || (port == NULL)) 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)) 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 (host, default_host);
strcpy (port, default_port); strcpy (port, default_port);
return SCPE_OK; return 0;
} }
gbuf[sizeof(gbuf)-1] = '\0'; gbuf[sizeof(gbuf)-1] = '\0';
strncpy (gbuf, cptr, sizeof(gbuf)-1); strncpy (gbuf, cptr, sizeof(gbuf)-1);
@ -571,25 +573,25 @@ else { /* No colon in input */
if (portp != NULL) { if (portp != NULL) {
portval = strtoul(portp, &endc, 10); portval = strtoul(portp, &endc, 10);
if ((*endc == '\0') && ((portval == 0) || (portval > 65535))) if ((*endc == '\0') && ((portval == 0) || (portval > 65535)))
return SCPE_ARG; /* numeric value too big */ return -1; /* numeric value too big */
if (*endc != '\0') { if (*endc != '\0') {
struct servent *se = getservbyname(portp, "tcp"); struct servent *se = getservbyname(portp, "tcp");
if (se == NULL) if (se == NULL)
return SCPE_ARG; /* invalid service name */ return -1; /* invalid service name */
} }
} }
if (port) /* port wanted? */ if (port) /* port wanted? */
if (portp != NULL) { if (portp != NULL) {
if (strlen(portp) >= port_len) if (strlen(portp) >= port_len)
return SCPE_ARG; /* no room */ return -1; /* no room */
else else
strcpy (port, portp); strcpy (port, portp);
} }
if (hostp != NULL) { if (hostp != NULL) {
if (']' == hostp[strlen(hostp)-1]) { if (']' == hostp[strlen(hostp)-1]) {
if ('[' != hostp[0]) 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 */ /* 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 */ strncpy(gbuf, hostp+1, sizeof(gbuf)-1); /* remove brackets from domain literal host */
hostp = gbuf; hostp = gbuf;
@ -599,20 +601,20 @@ if (hostp != NULL) {
if (host) { /* host wanted? */ if (host) { /* host wanted? */
if (hostp != NULL) { if (hostp != NULL) {
if (strlen(hostp) >= host_len) if (strlen(hostp) >= host_len)
return SCPE_ARG; /* no room */ return -1; /* no room */
else else
if (('\0' != hostp[0]) || (default_host == NULL)) if (('\0' != hostp[0]) || (default_host == NULL))
strcpy (host, hostp); strcpy (host, hostp);
else else
if (strlen(default_host) >= host_len) if (strlen(default_host) >= host_len)
return SCPE_ARG; /* no room */ return -1; /* no room */
else else
strcpy (host, default_host); strcpy (host, default_host);
} }
else { else {
if (default_host) { if (default_host) {
if (strlen(default_host) >= host_len) if (strlen(default_host) >= host_len)
return SCPE_ARG; /* no room */ return -1; /* no room */
else else
strcpy (host, default_host); strcpy (host, default_host);
} }
@ -620,40 +622,40 @@ if (host) { /* host wanted? */
} }
if (validate_addr) { if (validate_addr) {
struct addrinfo *ai_host, *ai_validate, *ai, *aiv; struct addrinfo *ai_host, *ai_validate, *ai, *aiv;
t_stat status; int status;
if (hostp == NULL) if (hostp == NULL)
return SCPE_ARG; return -1;
if (p_getaddrinfo(hostp, NULL, NULL, &ai_host)) if (p_getaddrinfo(hostp, NULL, NULL, &ai_host))
return SCPE_ARG; return -1;
if (p_getaddrinfo(validate_addr, NULL, NULL, &ai_validate)) { if (p_getaddrinfo(validate_addr, NULL, NULL, &ai_validate)) {
p_freeaddrinfo (ai_host); 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 (ai = ai_host; ai != NULL; ai = ai->ai_next) {
for (aiv = ai_validate; aiv != NULL; aiv = aiv->ai_next) { for (aiv = ai_validate; aiv != NULL; aiv = aiv->ai_next) {
if ((ai->ai_addrlen == aiv->ai_addrlen) && if ((ai->ai_addrlen == aiv->ai_addrlen) &&
(ai->ai_family == aiv->ai_family) && (ai->ai_family == aiv->ai_family) &&
(0 == memcmp (ai->ai_addr, aiv->ai_addr, ai->ai_addrlen))) { (0 == memcmp (ai->ai_addr, aiv->ai_addr, ai->ai_addrlen))) {
status = SCPE_OK; status = 0;
break; break;
} }
} }
} }
if (status != SCPE_OK) { if (status != 0) {
/* be generous and allow successful validations against variations of localhost addresses */ /* be generous and allow successful validations against variations of localhost addresses */
if (((0 == strcmp("127.0.0.1", hostp)) && if (((0 == strcmp("127.0.0.1", hostp)) &&
(0 == strcmp("::1", validate_addr))) || (0 == strcmp("::1", validate_addr))) ||
((0 == strcmp("127.0.0.1", validate_addr)) && ((0 == strcmp("127.0.0.1", validate_addr)) &&
(0 == strcmp("::1", hostp)))) (0 == strcmp("::1", hostp))))
status = SCPE_OK; status = 0;
} }
p_freeaddrinfo (ai_host); p_freeaddrinfo (ai_host);
p_freeaddrinfo (ai_validate); p_freeaddrinfo (ai_validate);
return status; return status;
} }
return SCPE_OK; return 0;
} }
/* sim_parse_addr_ex localport:host:port /* sim_parse_addr_ex localport:host:port
@ -690,7 +692,7 @@ return SCPE_OK;
a service name doesn't exist, or a validation name a service name doesn't exist, or a validation name
doesn't match the parsed host) 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; char *hostp;
@ -749,7 +751,7 @@ WSACleanup ();
} }
#if defined (_WIN32) /* Windows */ #if defined (_WIN32) /* Windows */
static int32 sim_setnonblock (SOCKET sock) static int sim_setnonblock (SOCKET sock)
{ {
unsigned long non_block = 1; unsigned long non_block = 1;
@ -757,7 +759,7 @@ return ioctlsocket (sock, FIONBIO, &non_block); /* set nonblocking */
} }
#elif defined (VMS) /* VMS */ #elif defined (VMS) /* VMS */
static int32 sim_setnonblock (SOCKET sock) static int sim_setnonblock (SOCKET sock)
{ {
int non_block = 1; int non_block = 1;
@ -765,9 +767,9 @@ return ioctl (sock, FIONBIO, &non_block); /* set nonblocking */
} }
#else /* Mac, Unix, OS/2 */ #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 */ fl = fcntl (sock, F_GETFL,0); /* get flags */
if (fl == -1) if (fl == -1)
@ -786,7 +788,7 @@ return 0;
#endif /* endif !Win32 && !VMS */ #endif /* endif !Win32 && !VMS */
static int32 sim_setnodelay (SOCKET sock) static int sim_setnodelay (SOCKET sock)
{ {
int nodelay = 1; int nodelay = 1;
int sta; int sta;
@ -813,28 +815,23 @@ if (sta == -1)
return sta; 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; 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? */ if (newsock == INVALID_SOCKET) { /* socket error? */
err = WSAGetLastError (); err = WSAGetLastError ();
#if defined(WSAEAFNOSUPPORT) #if defined(WSAEAFNOSUPPORT)
if (err == WSAEAFNOSUPPORT) /* expected error, just return */ if (err == WSAEAFNOSUPPORT) /* expected error, just return */
return newsock; return newsock;
#endif #endif
return sim_err_sock (newsock, "socket", 0); /* report error and return */ return sim_err_sock (newsock, "socket"); /* report error and return */
} }
return newsock; 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 Some platforms and/or network stacks have varying support for listening on
an IPv6 socket and receiving connections from both IPv4 and IPv6 client 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. 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; SOCKET newsock = INVALID_SOCKET;
int32 sta; int sta;
char host[CBUFSIZE], port[CBUFSIZE]; char host[CBUFSIZE], port[CBUFSIZE];
t_stat r; int r;
struct addrinfo hints; struct addrinfo hints;
struct addrinfo *result = NULL, *preferred; struct addrinfo *result = NULL, *preferred;
r = sim_parse_addr (hostport, host, sizeof(host), NULL, port, sizeof(port), NULL, NULL); r = sim_parse_addr (hostport, host, sizeof(host), NULL, port, sizeof(port), NULL, NULL);
if (parse_status) if (parse_status)
*parse_status = r; *parse_status = r;
if (r != SCPE_OK) if (r)
return newsock; return newsock;
memset(&hints, 0, sizeof(hints)); memset(&hints, 0, sizeof(hints));
@ -864,7 +861,7 @@ hints.ai_protocol = IPPROTO_TCP;
hints.ai_socktype = SOCK_STREAM; hints.ai_socktype = SOCK_STREAM;
if (p_getaddrinfo(host[0] ? host : NULL, port[0] ? port : NULL, &hints, &result)) { if (p_getaddrinfo(host[0] ? host : NULL, port[0] ? port : NULL, &hints, &result)) {
if (parse_status) if (parse_status)
*parse_status = SCPE_ARG; *parse_status = -1;
return newsock; return newsock;
} }
preferred = result; preferred = result;
@ -881,7 +878,7 @@ if (preferred == NULL)
preferred = result; preferred = result;
#endif #endif
retry: 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? */ if (newsock == INVALID_SOCKET) { /* socket error? */
#ifndef IPV6_V6ONLY #ifndef IPV6_V6ONLY
if (preferred->ai_next) { if (preferred->ai_next) {
@ -900,18 +897,18 @@ if (newsock == INVALID_SOCKET) { /* socket error? */
} }
#ifdef IPV6_V6ONLY #ifdef IPV6_V6ONLY
if (preferred->ai_family == AF_INET6) { if (preferred->ai_family == AF_INET6) {
int off = FALSE; int off = 0;
sta = setsockopt (newsock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&off, sizeof(off)); sta = setsockopt (newsock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&off, sizeof(off));
} }
#endif #endif
if (sim_switches & SWMASK ('U')) { if (opt_flags & SIM_SOCK_OPT_REUSEADDR) {
int on = TRUE; int on = 1;
sta = setsockopt (newsock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)); sta = setsockopt (newsock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on));
} }
#if defined (SO_EXCLUSIVEADDRUSE) #if defined (SO_EXCLUSIVEADDRUSE)
else { else {
int on = TRUE; int on = 1;
sta = setsockopt (newsock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (char *)&on, sizeof(on)); 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); sta = bind (newsock, preferred->ai_addr, preferred->ai_addrlen);
p_freeaddrinfo(result); p_freeaddrinfo(result);
if (sta == SOCKET_ERROR) /* bind error? */ if (sta == SOCKET_ERROR) /* bind error? */
return sim_err_sock (newsock, "bind", 1); return sim_err_sock (newsock, "bind");
if (!(opt_flags & SIM_SOCK_OPT_BLOCKING)) {
sta = sim_setnonblock (newsock); /* set nonblocking */ sta = sim_setnonblock (newsock); /* set nonblocking */
if (sta == SOCKET_ERROR) /* fcntl error? */ if (sta == SOCKET_ERROR) /* fcntl error? */
return sim_err_sock (newsock, "fcntl", 1); return sim_err_sock (newsock, "fcntl");
}
sta = listen (newsock, 1); /* listen on socket */ sta = listen (newsock, 1); /* listen on socket */
if (sta == SOCKET_ERROR) /* listen error? */ if (sta == SOCKET_ERROR) /* listen error? */
return sim_err_sock (newsock, "listen", 1); return sim_err_sock (newsock, "listen");
return newsock; /* got it! */ return newsock; /* got it! */
} }
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, int opt_flags)
{
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 newsock = INVALID_SOCKET; SOCKET newsock = INVALID_SOCKET;
int32 sta; int sta;
char host[CBUFSIZE], port[CBUFSIZE]; char host[CBUFSIZE], port[CBUFSIZE];
t_stat r;
struct addrinfo hints; struct addrinfo hints;
struct addrinfo *result = NULL, *source = NULL; struct addrinfo *result = NULL, *source = NULL;
r = sim_parse_addr (hostport, host, sizeof(host), default_host, port, sizeof(port), default_port, NULL); if (sim_parse_addr (hostport, host, sizeof(host), default_host, port, sizeof(port), default_port, NULL))
if (r != SCPE_OK)
return INVALID_SOCKET; return INVALID_SOCKET;
memset(&hints, 0, sizeof(hints)); memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC; hints.ai_family = AF_UNSPEC;
hints.ai_protocol = (datagram ? IPPROTO_UDP : IPPROTO_TCP); hints.ai_protocol = ((opt_flags & SIM_SOCK_OPT_DATAGRAM) ? IPPROTO_UDP : IPPROTO_TCP);
hints.ai_socktype = (datagram ? SOCK_DGRAM : SOCK_STREAM); 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)) if (p_getaddrinfo(host[0] ? host : NULL, port[0] ? port : NULL, &hints, &result))
return INVALID_SOCKET; return INVALID_SOCKET;
if (sourcehostport) { if (sourcehostport) {
/* Validate the local/source side address which we'll bind to */ /* 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 (sim_parse_addr (sourcehostport, host, sizeof(host), NULL, port, sizeof(port), NULL, NULL)) {
if (r != SCPE_OK) {
p_freeaddrinfo (result); p_freeaddrinfo (result);
return INVALID_SOCKET; return INVALID_SOCKET;
} }
@ -966,14 +957,14 @@ if (sourcehostport) {
memset(&hints, 0, sizeof(hints)); memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_PASSIVE; hints.ai_flags = AI_PASSIVE;
hints.ai_family = result->ai_family; /* Same family as connect destination */ hints.ai_family = result->ai_family; /* Same family as connect destination */
hints.ai_protocol = (datagram ? IPPROTO_UDP : IPPROTO_TCP); hints.ai_protocol = ((opt_flags & SIM_SOCK_OPT_DATAGRAM) ? IPPROTO_UDP : IPPROTO_TCP);
hints.ai_socktype = (datagram ? SOCK_DGRAM : SOCK_STREAM); 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)) { if (p_getaddrinfo(host[0] ? host : NULL, port[0] ? port : NULL, &hints, &source)) {
p_freeaddrinfo (result); p_freeaddrinfo (result);
return INVALID_SOCKET; 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? */ if (newsock == INVALID_SOCKET) { /* socket error? */
p_freeaddrinfo (result); p_freeaddrinfo (result);
p_freeaddrinfo (source); p_freeaddrinfo (source);
@ -985,55 +976,66 @@ if (sourcehostport) {
source = NULL; source = NULL;
if (sta == SOCKET_ERROR) { /* bind error? */ if (sta == SOCKET_ERROR) { /* bind error? */
p_freeaddrinfo (result); p_freeaddrinfo (result);
return sim_err_sock (newsock, "bind", 1); return sim_err_sock (newsock, "bind");
} }
} }
if (newsock == INVALID_SOCKET) { /* socket error? */ 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? */ if (newsock == INVALID_SOCKET) { /* socket error? */
p_freeaddrinfo (result); p_freeaddrinfo (result);
return newsock; return newsock;
} }
} }
if (!(opt_flags & SIM_SOCK_OPT_BLOCKING)) {
sta = sim_setnonblock (newsock); /* set nonblocking */ sta = sim_setnonblock (newsock); /* set nonblocking */
if (sta == SOCKET_ERROR) { /* fcntl error? */ if (sta == SOCKET_ERROR) { /* fcntl error? */
p_freeaddrinfo (result); p_freeaddrinfo (result);
return sim_err_sock (newsock, "fcntl", 1); 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 */ sta = sim_setnodelay (newsock); /* set nodelay */
if (sta == SOCKET_ERROR) { /* setsock error? */ if (sta == SOCKET_ERROR) { /* setsock error? */
p_freeaddrinfo (result); 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); if (!(opt_flags & SIM_SOCK_OPT_DATAGRAM)) {
p_freeaddrinfo (result);
if ((sta == SOCKET_ERROR) &&
(WSAGetLastError () != WSAEWOULDBLOCK) &&
(WSAGetLastError () != WSAEINPROGRESS))
return sim_err_sock (newsock, "connect", 1);
if (!datagram) {
int keepalive = 1; int keepalive = 1;
/* enable TCP Keep Alives */ /* enable TCP Keep Alives */
sta = setsockopt (newsock, SOL_SOCKET, SO_KEEPALIVE, (char *)&keepalive, sizeof(keepalive)); sta = setsockopt (newsock, SOL_SOCKET, SO_KEEPALIVE, (char *)&keepalive, sizeof(keepalive));
if (sta == -1) 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! */ 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); int sta = 0, err;
}
SOCKET sim_accept_conn_ex (SOCKET master, char **connectaddr, t_bool nodelay)
{
int32 sta, err;
int keepalive = 1; int keepalive = 1;
#if defined (macintosh) || defined (__linux) || defined (__linux__) || \ #if defined (macintosh) || defined (__linux) || defined (__linux__) || \
defined (__APPLE__) || defined (__OpenBSD__) || \ defined (__APPLE__) || defined (__OpenBSD__) || \
@ -1059,7 +1061,7 @@ newsock = accept (master, (struct sockaddr *) &clientname, &size);
if (newsock == INVALID_SOCKET) { /* error? */ if (newsock == INVALID_SOCKET) { /* error? */
err = WSAGetLastError (); err = WSAGetLastError ();
if (err != WSAEWOULDBLOCK) if (err != WSAEWOULDBLOCK)
sim_err_sock(newsock, "accept", 0); sim_err_sock(newsock, "accept");
return INVALID_SOCKET; return INVALID_SOCKET;
} }
if (connectaddr != NULL) { if (connectaddr != NULL) {
@ -1074,25 +1076,27 @@ if (connectaddr != NULL) {
#endif #endif
} }
if (!(opt_flags & SIM_SOCK_OPT_BLOCKING)) {
sta = sim_setnonblock (newsock); /* set nonblocking */ sta = sim_setnonblock (newsock); /* set nonblocking */
if (sta == SOCKET_ERROR) /* fcntl error? */ if (sta == SOCKET_ERROR) /* fcntl error? */
return sim_err_sock (newsock, "fcntl", 0); return sim_err_sock (newsock, "fcntl");
}
if (nodelay) { if ((opt_flags & SIM_SOCK_OPT_NODELAY)) {
sta = sim_setnodelay (newsock); /* set nonblocking */ sta = sim_setnodelay (newsock); /* set nonblocking */
if (sta == SOCKET_ERROR) /* setsockopt error? */ if (sta == SOCKET_ERROR) /* setsockopt error? */
return sim_err_sock (newsock, "setnodelay", 0); return sim_err_sock (newsock, "setnodelay");
} }
/* enable TCP Keep Alives */ /* enable TCP Keep Alives */
sta = setsockopt (newsock, SOL_SOCKET, SO_KEEPALIVE, (char *)&keepalive, sizeof(keepalive)); sta = setsockopt (newsock, SOL_SOCKET, SO_KEEPALIVE, (char *)&keepalive, sizeof(keepalive));
if (sta == -1) if (sta == -1)
return sim_err_sock (newsock, "setsockopt KEEPALIVE", 1); return sim_err_sock (newsock, "setsockopt KEEPALIVE");
return newsock; 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_set, er_set;
fd_set *rw_p = &rw_set; fd_set *rw_p = &rw_set;
@ -1132,7 +1136,7 @@ if (FD_ISSET (sock, rw_p)) {
return 0; 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__) || \ #if defined (macintosh) || defined (__linux) || defined (__linux__) || \
defined (__APPLE__) || defined (__OpenBSD__) || \ defined (__APPLE__) || defined (__OpenBSD__) || \
@ -1147,7 +1151,7 @@ int size = (int)addrsize;
#else #else
size_t size = addrsize; size_t size = addrsize;
#endif #endif
int32 ret = 0; int ret = 0;
#ifdef AF_INET6 #ifdef AF_INET6
*hostnamebuf = '\0'; *hostnamebuf = '\0';
@ -1165,7 +1169,7 @@ sprintf(portnamebuf, "%d", (int)ntohs(((struct sockaddr_in *)addr)->s_port)));
return ret; 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; struct sockaddr_storage sockname, peername;
#if defined (macintosh) || defined (__linux) || defined (__linux__) || \ #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); rbytes = recv (sock, buf, nbytes, 0);
if (rbytes == 0) /* disconnect */ if (rbytes == 0) /* disconnect */
@ -1225,15 +1229,15 @@ if (rbytes == SOCKET_ERROR) {
(err != WSAECONNREFUSED) && (err != WSAECONNREFUSED) &&
(err != WSAECONNABORTED) && (err != WSAECONNABORTED) &&
(err != WSAECONNRESET)) (err != WSAECONNRESET))
sim_err_sock (INVALID_SOCKET, "read", 0); sim_err_sock (INVALID_SOCKET, "read");
return -1; return -1;
} }
return rbytes; 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) { if (sbytes == SOCKET_ERROR) {
err = WSAGetLastError (); err = WSAGetLastError ();
@ -1247,7 +1251,7 @@ if (sbytes == SOCKET_ERROR) {
return sbytes; return sbytes;
} }
void sim_close_sock (SOCKET sock, t_bool master) void sim_close_sock (SOCKET sock)
{ {
shutdown(sock, SD_BOTH); shutdown(sock, SD_BOTH);
closesocket (sock); closesocket (sock);

View file

@ -51,8 +51,9 @@
#elif !defined (__OS2__) || defined (__EMX__) /* VMS, Mac, Unix, OS/2 EMX */ #elif !defined (__OS2__) || defined (__EMX__) /* VMS, Mac, Unix, OS/2 EMX */
#define WSAGetLastError() errno /* Windows macros */ #define WSAGetLastError() errno /* Windows macros */
#define WSASetLastError(err) errno = err
#define closesocket close #define closesocket close
#define SOCKET int32 #define SOCKET int
#if defined(__hpux) #if defined(__hpux)
#define WSAEWOULDBLOCK EAGAIN #define WSAEWOULDBLOCK EAGAIN
#else #else
@ -75,6 +76,8 @@
#define SOCKET_ERROR -1 #define SOCKET_ERROR -1
#include <sys/types.h> /* for fcntl, getpid */ #include <sys/types.h> /* for fcntl, getpid */
#include <sys/socket.h> /* for sockets */ #include <sys/socket.h> /* for sockets */
#include <string.h>
#include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <unistd.h> #include <unistd.h>
#include <netinet/in.h> /* for sockaddr_in */ #include <netinet/in.h> /* for sockaddr_in */
@ -102,19 +105,30 @@
#endif #endif
#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); #if !defined(CBUFSIZE)
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); #define CBUFSIZE 1024
SOCKET sim_master_sock (const char *hostport, t_stat *parse_status); #define sim_printf printf
SOCKET sim_connect_sock (const char *hostport, const char *default_host, const char *default_port); #endif
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); 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);
SOCKET sim_accept_conn_ex (SOCKET master, char **connectaddr, t_bool nodelay); 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);
int32 sim_check_conn (SOCKET sock, t_bool rd); #define SIM_SOCK_OPT_REUSEADDR 0x0001
int32 sim_read_sock (SOCKET sock, char *buf, int32 nbytes); #define SIM_SOCK_OPT_DATAGRAM 0x0002
int32 sim_write_sock (SOCKET sock, const char *msg, int32 nbytes); #define SIM_SOCK_OPT_NODELAY 0x0004
void sim_close_sock (SOCKET sock, t_bool master); #define SIM_SOCK_OPT_BLOCKING 0x0008
SOCKET sim_err_sock (SOCKET sock, const char *emsg, int32 flg); SOCKET sim_master_sock_ex (const char *hostport, int *parse_status, int opt_flags);
int32 sim_getnames_sock (SOCKET sock, char **socknamebuf, char **peernamebuf); #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_init_sock (void);
void sim_cleanup_sock (void); void sim_cleanup_sock (void);