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];
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;

View file

@ -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);

View file

@ -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;

View file

@ -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;
}

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;
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)

View file

@ -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

View file

@ -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 <signal.h>
#include <stdio.h>
#include <stdlib.h>
#if defined(AF_INET6) && defined(_WIN32)
#include <ws2tcpip.h>
@ -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);

View file

@ -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 <sys/types.h> /* for fcntl, getpid */
#include <sys/socket.h> /* for sockets */
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <netinet/in.h> /* 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);