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:
parent
5b4e9d5891
commit
1fb209c275
8 changed files with 192 additions and 180 deletions
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
256
sim_sock.c
256
sim_sock.c
|
@ -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);
|
||||||
|
|
42
sim_sock.h
42
sim_sock.h
|
@ -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);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue