Revised the socket library sim_sock(.c & .h) to support both IPv4 and IPv6 leveraging the RFC3493 APIs.
All dependent code has been updated to use the revised interfaces.
This commit is contained in:
parent
6692832785
commit
30ce7fdbaa
11 changed files with 686 additions and 311 deletions
|
@ -150,36 +150,33 @@ static t_stat net_reset(DEVICE *dptr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static t_stat net_attach(UNIT *uptr, char *cptr) {
|
static t_stat net_attach(UNIT *uptr, char *cptr) {
|
||||||
uint32 i, ipa, ipp;
|
uint32 i;
|
||||||
t_stat r = get_ipaddr(cptr, &ipa, &ipp);
|
char host[CBUFSIZE], port[CBUFSIZE];
|
||||||
|
t_stat r;
|
||||||
|
|
||||||
|
r = sim_parse_addr (cptr, host, sizeof(host), "localhost", port, sizeof(port), "3000");
|
||||||
if (r != SCPE_OK)
|
if (r != SCPE_OK)
|
||||||
return SCPE_ARG;
|
return SCPE_ARG;
|
||||||
if (ipa == 0)
|
|
||||||
ipa = 0x7F000001; /* localhost = 127.0.0.1 */
|
|
||||||
if (ipp == 0)
|
|
||||||
ipp = 3000;
|
|
||||||
net_unit.u3 = ipp;
|
|
||||||
net_unit.u4 = ipa;
|
|
||||||
net_reset(&net_dev);
|
net_reset(&net_dev);
|
||||||
for (i = 0; i <= MAX_CONNECTIONS; i++)
|
for (i = 0; i <= MAX_CONNECTIONS; i++)
|
||||||
serviceDescriptor[i].ioSocket = 0;
|
serviceDescriptor[i].ioSocket = 0;
|
||||||
if (net_unit.flags & UNIT_SERVER) {
|
if (net_unit.flags & UNIT_SERVER) {
|
||||||
net_unit.wait = NET_INIT_POLL_SERVER;
|
net_unit.wait = NET_INIT_POLL_SERVER;
|
||||||
serviceDescriptor[1].masterSocket = sim_master_sock(ipp);
|
serviceDescriptor[1].masterSocket = sim_master_sock(cptr, NULL);
|
||||||
if (serviceDescriptor[1].masterSocket == INVALID_SOCKET)
|
if (serviceDescriptor[1].masterSocket == INVALID_SOCKET)
|
||||||
return SCPE_IOERR;
|
return SCPE_IOERR;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
net_unit.wait = NET_INIT_POLL_CLIENT;
|
net_unit.wait = NET_INIT_POLL_CLIENT;
|
||||||
serviceDescriptor[0].ioSocket = sim_connect_sock(ipa, ipp);
|
serviceDescriptor[0].ioSocket = sim_connect_sock(cptr, "localhost", "3000");
|
||||||
if (serviceDescriptor[0].ioSocket == INVALID_SOCKET)
|
if (serviceDescriptor[0].ioSocket == INVALID_SOCKET)
|
||||||
return SCPE_IOERR;
|
return SCPE_IOERR;
|
||||||
}
|
}
|
||||||
net_unit.flags |= UNIT_ATT;
|
net_unit.flags |= UNIT_ATT;
|
||||||
net_unit.filename = (char *) calloc(CBUFSIZE, sizeof (char)); /* alloc name buf */
|
net_unit.filename = (char *) calloc(1, strlen(cptr)+1); /* alloc name buf */
|
||||||
if (net_unit.filename == NULL)
|
if (net_unit.filename == NULL)
|
||||||
return SCPE_MEM;
|
return SCPE_MEM;
|
||||||
strncpy(net_unit.filename, cptr, CBUFSIZE); /* save name */
|
strcpy(net_unit.filename, cptr); /* save name */
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,7 +213,7 @@ static t_stat net_svc(UNIT *uptr) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (serviceDescriptor[0].ioSocket == 0) {
|
else if (serviceDescriptor[0].ioSocket == 0) {
|
||||||
serviceDescriptor[0].ioSocket = sim_connect_sock(net_unit.u4, net_unit.u3);
|
serviceDescriptor[0].ioSocket = sim_connect_sock(net_unit.filename, "localhost", "3000");
|
||||||
if (serviceDescriptor[0].ioSocket == INVALID_SOCKET)
|
if (serviceDescriptor[0].ioSocket == INVALID_SOCKET)
|
||||||
return SCPE_IOERR;
|
return SCPE_IOERR;
|
||||||
printf("\rWaiting for server ... Type g<return> (possibly twice) when ready" NLP);
|
printf("\rWaiting for server ... Type g<return> (possibly twice) when ready" NLP);
|
||||||
|
|
|
@ -570,56 +570,56 @@ return SCPE_OK;
|
||||||
t_stat ipl_attach (UNIT *uptr, char *cptr)
|
t_stat ipl_attach (UNIT *uptr, char *cptr)
|
||||||
{
|
{
|
||||||
SOCKET newsock;
|
SOCKET newsock;
|
||||||
uint32 i, t, ipa, ipp, oldf;
|
uint32 i, t, oldf;
|
||||||
char *tptr;
|
char host[CBUFSIZE], port[CBUFSIZE], hostport[2*CBUFSIZE+3];
|
||||||
|
char *tptr = NULL;
|
||||||
t_stat r;
|
t_stat r;
|
||||||
|
|
||||||
r = get_ipaddr (cptr, &ipa, &ipp);
|
|
||||||
if ((r != SCPE_OK) || (ipp == 0))
|
|
||||||
return SCPE_ARG;
|
|
||||||
oldf = uptr->flags;
|
oldf = uptr->flags;
|
||||||
if (oldf & UNIT_ATT)
|
if (oldf & UNIT_ATT)
|
||||||
ipl_detach (uptr);
|
ipl_detach (uptr);
|
||||||
if ((sim_switches & SWMASK ('C')) ||
|
if ((sim_switches & SWMASK ('C')) ||
|
||||||
((sim_switches & SIM_SW_REST) && (oldf & UNIT_ACTV))) {
|
((sim_switches & SIM_SW_REST) && (oldf & UNIT_ACTV))) {
|
||||||
if (ipa == 0)
|
r = sim_parse_addr (cptr, host, sizeof(host), "localhost", port, sizeof(port), NULL);
|
||||||
ipa = 0x7F000001;
|
if ((r != SCPE_OK) || (port[0] == '\0'))
|
||||||
newsock = sim_connect_sock (ipa, ipp);
|
return SCPE_ARG;
|
||||||
|
sprintf(hostport, "%s%s%s%s%s", strchr(host, ':') ? "[" : "", host, strchr(host, ':') ? "]" : "", host[0] ? ":" : "", port);
|
||||||
|
newsock = sim_connect_sock (hostport, NULL, NULL);
|
||||||
if (newsock == INVALID_SOCKET)
|
if (newsock == INVALID_SOCKET)
|
||||||
return SCPE_IOERR;
|
return SCPE_IOERR;
|
||||||
printf ("Connecting to IP address %d.%d.%d.%d, port %d\n",
|
printf ("Connecting to %s\n", hostport);
|
||||||
(ipa >> 24) & 0xff, (ipa >> 16) & 0xff,
|
|
||||||
(ipa >> 8) & 0xff, ipa & 0xff, ipp);
|
|
||||||
if (sim_log)
|
if (sim_log)
|
||||||
fprintf (sim_log,
|
fprintf (sim_log,
|
||||||
"Connecting to IP address %d.%d.%d.%d, port %d\n",
|
"Connecting to %s\n", hostport);
|
||||||
(ipa >> 24) & 0xff, (ipa >> 16) & 0xff,
|
|
||||||
(ipa >> 8) & 0xff, ipa & 0xff, ipp);
|
|
||||||
uptr->flags = uptr->flags | UNIT_ACTV;
|
uptr->flags = uptr->flags | UNIT_ACTV;
|
||||||
uptr->LSOCKET = 0;
|
uptr->LSOCKET = 0;
|
||||||
uptr->DSOCKET = newsock;
|
uptr->DSOCKET = newsock;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (ipa != 0)
|
r = sim_parse_addr (cptr, host, sizeof(host), NULL, port, sizeof(port), NULL);
|
||||||
|
if (r != SCPE_OK)
|
||||||
return SCPE_ARG;
|
return SCPE_ARG;
|
||||||
newsock = sim_master_sock (ipp);
|
sprintf(hostport, "%s%s%s%s%s", strchr(host, ':') ? "[" : "", host, strchr(host, ':') ? "]" : "", host[0] ? ":" : "", port);
|
||||||
|
newsock = sim_master_sock (hostport, &r);
|
||||||
|
if (r != SCPE_OK)
|
||||||
|
return r;
|
||||||
if (newsock == INVALID_SOCKET)
|
if (newsock == INVALID_SOCKET)
|
||||||
return SCPE_IOERR;
|
return SCPE_IOERR;
|
||||||
printf ("Listening on port %d\n", ipp);
|
printf ("Listening on port %s\n", hostport);
|
||||||
if (sim_log)
|
if (sim_log)
|
||||||
fprintf (sim_log, "Listening on port %d\n", ipp);
|
fprintf (sim_log, "Listening on port %s\n", hostport);
|
||||||
uptr->flags = uptr->flags & ~UNIT_ACTV;
|
uptr->flags = uptr->flags & ~UNIT_ACTV;
|
||||||
uptr->LSOCKET = newsock;
|
uptr->LSOCKET = newsock;
|
||||||
uptr->DSOCKET = 0;
|
uptr->DSOCKET = 0;
|
||||||
}
|
}
|
||||||
uptr->IBUF = uptr->OBUF = 0;
|
uptr->IBUF = uptr->OBUF = 0;
|
||||||
uptr->flags = (uptr->flags | UNIT_ATT) & ~(UNIT_ESTB | UNIT_HOLD);
|
uptr->flags = (uptr->flags | UNIT_ATT) & ~(UNIT_ESTB | UNIT_HOLD);
|
||||||
tptr = (char *) malloc (strlen (cptr) + 1); /* get string buf */
|
tptr = (char *) malloc (strlen (hostport) + 1); /* get string buf */
|
||||||
if (tptr == NULL) { /* no memory? */
|
if (tptr == NULL) { /* no memory? */
|
||||||
ipl_detach (uptr); /* close sockets */
|
ipl_detach (uptr); /* close sockets */
|
||||||
return SCPE_MEM;
|
return SCPE_MEM;
|
||||||
}
|
}
|
||||||
strcpy (tptr, cptr); /* copy ipaddr:port */
|
strcpy (tptr, hostport); /* copy ipaddr:port */
|
||||||
uptr->filename = tptr; /* save */
|
uptr->filename = tptr; /* save */
|
||||||
sim_activate (uptr, POLL_FIRST); /* activate first poll "immediately" */
|
sim_activate (uptr, POLL_FIRST); /* activate first poll "immediately" */
|
||||||
if (sim_switches & SWMASK ('W')) { /* wait? */
|
if (sim_switches & SWMASK ('W')) { /* wait? */
|
||||||
|
|
|
@ -85,9 +85,6 @@
|
||||||
#include "ibm1130_defs.h"
|
#include "ibm1130_defs.h"
|
||||||
#include "sim_sock.h" /* include path must include main simh directory */
|
#include "sim_sock.h" /* include path must include main simh directory */
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#ifndef INADDR_NONE
|
|
||||||
#define INADDR_NONE ((unsigned long)-1)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define DEBUG_SCA_FLUSH 0x0001 /* debugging options */
|
#define DEBUG_SCA_FLUSH 0x0001 /* debugging options */
|
||||||
#define DEBUG_SCA_TRANSMIT 0x0002
|
#define DEBUG_SCA_TRANSMIT 0x0002
|
||||||
|
@ -106,7 +103,7 @@
|
||||||
/* #define DEBUG_SCA (DEBUG_SCA_TIMERS|DEBUG_SCA_FLUSH|DEBUG_SCA_TRANSMIT|DEBUG_SCA_CHECK_INDATA|DEBUG_SCA_RECEIVE_SYNC|DEBUG_SCA_RECEIVE_DATA|DEBUG_SCA_XIO_INITR|DEBUG_SCA_XIO_INITW) */
|
/* #define DEBUG_SCA (DEBUG_SCA_TIMERS|DEBUG_SCA_FLUSH|DEBUG_SCA_TRANSMIT|DEBUG_SCA_CHECK_INDATA|DEBUG_SCA_RECEIVE_SYNC|DEBUG_SCA_RECEIVE_DATA|DEBUG_SCA_XIO_INITR|DEBUG_SCA_XIO_INITW) */
|
||||||
#define DEBUG_SCA (DEBUG_SCA_TIMERS|DEBUG_SCA_FLUSH|DEBUG_SCA_CHECK_INDATA|DEBUG_SCA_XIO_INITR|DEBUG_SCA_XIO_INITW)
|
#define DEBUG_SCA (DEBUG_SCA_TIMERS|DEBUG_SCA_FLUSH|DEBUG_SCA_CHECK_INDATA|DEBUG_SCA_XIO_INITR|DEBUG_SCA_XIO_INITW)
|
||||||
|
|
||||||
#define SCA_DEFAULT_PORT 2703 /* default socket, This is the number of the IBM 360's BSC device */
|
#define SCA_DEFAULT_PORT "2703" /* default socket, This is the number of the IBM 360's BSC device */
|
||||||
|
|
||||||
#define MAX_SYNS 100 /* number of consecutive syn's after which we stop buffering them */
|
#define MAX_SYNS 100 /* number of consecutive syn's after which we stop buffering them */
|
||||||
|
|
||||||
|
@ -164,7 +161,7 @@ static uint32 sca_state = SCA_STATE_IDLE;
|
||||||
static uint8 sichar = 0; /* sync/idle character */
|
static uint8 sichar = 0; /* sync/idle character */
|
||||||
static uint8 rcvd_char = 0; /* most recently received character */
|
static uint8 rcvd_char = 0; /* most recently received character */
|
||||||
static uint8 sca_frame = 8;
|
static uint8 sca_frame = 8;
|
||||||
static uint16 sca_port = SCA_DEFAULT_PORT; /* listening port number */
|
static char sca_port[CBUFSIZE]; /* listening port */
|
||||||
static int32 sca_keepalive = 0; /* keepalive SYN packet period in msec, default = 0 (disabled) */
|
static int32 sca_keepalive = 0; /* keepalive SYN packet period in msec, default = 0 (disabled) */
|
||||||
static SCA_TIMER_STATE sca_timer_state[3]; /* current timer state */
|
static SCA_TIMER_STATE sca_timer_state[3]; /* current timer state */
|
||||||
static int sca_timer_endtime[3]; /* clocktime when timeout is to occur if state is RUNNING */
|
static int sca_timer_endtime[3]; /* clocktime when timeout is to occur if state is RUNNING */
|
||||||
|
@ -221,7 +218,7 @@ REG sca_reg[] = { /* DEVICE STATE/SETTABLE PARAMETERS: */
|
||||||
{ DRDATA (SCASTATE, sca_state, 32), PV_LEFT }, /* current state */
|
{ DRDATA (SCASTATE, sca_state, 32), PV_LEFT }, /* current state */
|
||||||
{ DRDATA (CTIME, sca_cwait, 32), PV_LEFT }, /* inter-character wait */
|
{ DRDATA (CTIME, sca_cwait, 32), PV_LEFT }, /* inter-character wait */
|
||||||
{ DRDATA (ITIME, sca_iwait, 32), PV_LEFT }, /* idle wait (polling interval for socket connects) */
|
{ DRDATA (ITIME, sca_iwait, 32), PV_LEFT }, /* idle wait (polling interval for socket connects) */
|
||||||
{ DRDATA (SCASOCKET, sca_port, 16), PV_LEFT }, /* listening port number */
|
{ BRDATA (SCASOCKET, sca_port, 8, 8, sizeof(sca_port)) }, /* listening port number */
|
||||||
{ DRDATA (KEEPALIVE, sca_keepalive, 32), PV_LEFT }, /* keepalive packet period in msec */
|
{ DRDATA (KEEPALIVE, sca_keepalive, 32), PV_LEFT }, /* keepalive packet period in msec */
|
||||||
{ NULL } };
|
{ NULL } };
|
||||||
|
|
||||||
|
@ -317,7 +314,7 @@ static void sca_socket_error (void)
|
||||||
free(sca_unit.filename);
|
free(sca_unit.filename);
|
||||||
|
|
||||||
if (sca_unit.flags & UNIT_LISTEN) {
|
if (sca_unit.flags & UNIT_LISTEN) {
|
||||||
sprintf(name, "(Listening on port %d)", sca_port);
|
sprintf(name, "(Listening on port %s)", sca_port);
|
||||||
sca_unit.filename = mstring(name);
|
sca_unit.filename = mstring(name);
|
||||||
printf("%s\n", name);
|
printf("%s\n", name);
|
||||||
}
|
}
|
||||||
|
@ -454,99 +451,75 @@ static t_stat sca_reset (DEVICE *dptr)
|
||||||
|
|
||||||
static t_stat sca_attach (UNIT *uptr, char *cptr)
|
static t_stat sca_attach (UNIT *uptr, char *cptr)
|
||||||
{
|
{
|
||||||
|
char host[CBUFSIZE], port[CBUFSIZE];
|
||||||
t_bool do_listen;
|
t_bool do_listen;
|
||||||
char *colon;
|
char name[CBUFSIZE];
|
||||||
uint32 ipaddr;
|
t_stat r;
|
||||||
int32 port;
|
|
||||||
struct hostent *he;
|
|
||||||
char name[256];
|
|
||||||
static SOCKET sdummy = INVALID_SOCKET;
|
|
||||||
fd_set wr_set, err_set;
|
|
||||||
|
|
||||||
do_listen = sim_switches & SWMASK('L'); /* -l means listen mode */
|
do_listen = sim_switches & SWMASK('L'); /* -l means listen mode */
|
||||||
|
|
||||||
if (sca_unit.flags & UNIT_ATT) /* if already attached, detach */
|
if (sca_unit.flags & UNIT_ATT) /* if already attached, detach */
|
||||||
detach_unit(&sca_unit);
|
detach_unit(&sca_unit);
|
||||||
|
|
||||||
if (do_listen) { /* if listen mode, string specifies socket 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) */
|
||||||
if (isdigit(*cptr)) { /* if digits specified, extract port number */
|
r = sim_parse_addr (cptr, host, sizeof(host), NULL, port, sizeof(port), SCA_DEFAULT_PORT);
|
||||||
port = atoi(cptr);
|
if (r != SCPE_OK)
|
||||||
if (port <= 0 || port > 65535)
|
return r;
|
||||||
return SCPE_ARG;
|
if ((0 == strcmp(port, cptr)) && (0 == strcmp(port, "dummy")))
|
||||||
else
|
strcpy(port, SCA_DEFAULT_PORT);
|
||||||
sca_port = port;
|
|
||||||
}
|
sprintf(sca_port, "%s%s%s:%s", strchr(host, ':') ? "[" : "", host, strchr(host, ':') ? "]" : "", port);
|
||||||
|
|
||||||
/* else if nondigits specified, ignore... but the command has to have something there otherwise the core scp */
|
/* else if nondigits specified, ignore... but the command has to have something there otherwise the core scp */
|
||||||
/* attach_cmd() routine complains "too few arguments". */
|
/* attach_cmd() routine complains "too few arguments". */
|
||||||
|
|
||||||
if ((sca_lsock = sim_master_sock(sca_port)) == INVALID_SOCKET)
|
sca_lsock = sim_master_sock(sca_port, &r);
|
||||||
|
if (r != SCPE_OK)
|
||||||
|
return r;
|
||||||
|
if (sca_lsock == INVALID_SOCKET)
|
||||||
return SCPE_OPENERR;
|
return SCPE_OPENERR;
|
||||||
|
|
||||||
SETBIT(sca_unit.flags, UNIT_LISTEN); /* note that we are listening, not yet connected */
|
SETBIT(sca_unit.flags, UNIT_LISTEN); /* note that we are listening, not yet connected */
|
||||||
|
|
||||||
sprintf(name, "(Listening on port %d)", sca_port);
|
sprintf(name, "(Listening on port %s)", sca_port);
|
||||||
sca_unit.filename = mstring(name);
|
sca_unit.filename = mstring(name);
|
||||||
printf("%s\n", name);
|
printf("%s\n", sca_unit.filename);
|
||||||
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
while (*cptr && *cptr <= ' ')
|
while (*cptr && *cptr <= ' ')
|
||||||
cptr++;
|
cptr++;
|
||||||
|
|
||||||
if (! *cptr)
|
if (! *cptr)
|
||||||
return SCPE_2FARG;
|
return SCPE_2FARG;
|
||||||
|
|
||||||
if ((colon = strchr(cptr, ':')) != NULL) {
|
r = sim_parse_addr (cptr, host, sizeof(host), NULL, port, sizeof(port), SCA_DEFAULT_PORT);
|
||||||
*colon++ = '\0'; /* clip hostname at colon */
|
if (r != SCPE_OK)
|
||||||
|
return r;
|
||||||
|
if ((0 == strcmp(cptr, port)) && (0 == strcmp(host, ""))) {
|
||||||
|
strcpy(host, port);
|
||||||
|
strcpy(port, SCA_DEFAULT_PORT);
|
||||||
|
}
|
||||||
|
|
||||||
port = atoi(colon); /* extract port number that follows it */
|
sprintf(sca_port, "%s%s%s:%s", strchr(host, ':') ? "[" : "", host, strchr(host, ':') ? "]" : "", port);
|
||||||
if (port <= 0 || port > 65535)
|
|
||||||
return SCPE_ARG;
|
|
||||||
else
|
|
||||||
sca_port = port;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sdummy == INVALID_SOCKET)
|
if ((sca_sock = sim_connect_sock(sca_port, NULL, NULL)) == INVALID_SOCKET)
|
||||||
if ((sdummy = sim_create_sock()) == INVALID_SOCKET) /* create and keep a socket, to force initialization */
|
|
||||||
return SCPE_IERR; /* of socket library (e.g on Win32 call WSAStartup), else gethostbyname fails */
|
|
||||||
|
|
||||||
if (get_ipaddr(cptr, &ipaddr, NULL) != SCPE_OK) { /* try to parse hostname as dotted decimal nnn.nnn.nnn.nnn */
|
|
||||||
if ((he = gethostbyname(cptr)) == NULL) /* if not decimal, look up name through DNS */
|
|
||||||
return SCPE_OPENERR;
|
|
||||||
|
|
||||||
if ((ipaddr = * (unsigned long *) he->h_addr_list[0]) == INADDR_NONE)
|
|
||||||
return SCPE_OPENERR;
|
|
||||||
|
|
||||||
ipaddr = ntohl(ipaddr); /* convert to host byte order; gethostbyname() gives us network order */
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((sca_sock = sim_connect_sock(ipaddr, sca_port)) == INVALID_SOCKET)
|
|
||||||
return SCPE_OPENERR;
|
return SCPE_OPENERR;
|
||||||
|
|
||||||
/* sim_connect_sock() sets socket to nonblocking before initiating the connect, so
|
/* sim_connect_sock() sets socket to nonblocking before initiating the connect, so
|
||||||
* the connect is pending when it returns. For outgoing connections, the attach command should wait
|
* the connect is pending when it returns. For outgoing connections, the attach command should wait
|
||||||
* until the connection succeeds or fails. We use "accept" to wait and find out which way it goes...
|
* until the connection succeeds or fails. We use "sim_check_conn" to wait and find out which way it goes...
|
||||||
*/
|
*/
|
||||||
|
|
||||||
FD_ZERO(&wr_set); /* we are only interested in info for sca_sock */
|
while (0 == sim_check_conn(sca_sock, 0))/* wait for connection to complete or fail */
|
||||||
FD_ZERO(&err_set);
|
sim_os_ms_sleep(1000);
|
||||||
FD_SET(sca_sock, &wr_set);
|
|
||||||
FD_SET(sca_sock, &err_set);
|
|
||||||
|
|
||||||
select(3, NULL, &wr_set, &err_set, NULL); /* wait for connection to complete or fail */
|
if (1 == sim_check_conn(sca_sock, 0)) { /* sca_sock appears in "writable" set -- connect completed */
|
||||||
|
sprintf(name, "%s%s%s:%s", strchr(host, ':') ? "[" : "", host, strchr(host, ':') ? "]" : "", port);
|
||||||
if (FD_ISSET(sca_sock, &wr_set)) { /* sca_sock appears in "writable" set -- connect completed */
|
|
||||||
sprintf(name, "%s:%d", cptr, sca_port);
|
|
||||||
sca_unit.filename = mstring(name);
|
sca_unit.filename = mstring(name);
|
||||||
SETBIT(sca_dsw, SCA_DSW_READY);
|
SETBIT(sca_dsw, SCA_DSW_READY);
|
||||||
}
|
}
|
||||||
else if (FD_ISSET(sca_sock, &err_set)) { /* sca_sock appears in "error" set -- connect failed */
|
else { /* sca_sock appears in "error" set -- connect failed */
|
||||||
sim_close_sock(sca_sock, TRUE);
|
|
||||||
sca_sock = INVALID_SOCKET;
|
|
||||||
return SCPE_OPENERR;
|
|
||||||
}
|
|
||||||
else { /* if we get here my assumption about how select works is wrong */
|
|
||||||
printf("SCA_SOCK NOT FOUND IN WR_SET -OR- ERR_SET, CODING IN IBM1130_SCA IS WRONG\n");
|
|
||||||
sim_close_sock(sca_sock, TRUE);
|
sim_close_sock(sca_sock, TRUE);
|
||||||
sca_sock = INVALID_SOCKET;
|
sca_sock = INVALID_SOCKET;
|
||||||
return SCPE_OPENERR;
|
return SCPE_OPENERR;
|
||||||
|
@ -610,22 +583,17 @@ static t_stat sca_detach (UNIT *uptr)
|
||||||
|
|
||||||
static void sca_check_connect (void)
|
static void sca_check_connect (void)
|
||||||
{
|
{
|
||||||
uint32 ipaddr;
|
char *connectaddress;
|
||||||
char name[100];
|
|
||||||
|
|
||||||
if ((sca_sock = sim_accept_conn(sca_lsock, &ipaddr)) == INVALID_SOCKET)
|
if ((sca_sock = sim_accept_conn(sca_lsock, &connectaddress)) == INVALID_SOCKET)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ipaddr = htonl(ipaddr); /* convert to network order so we can print it */
|
printf("(SCA connection from %s)\n", connectaddress);
|
||||||
|
|
||||||
sprintf(name, "%d.%d.%d.%d", ipaddr & 0xFF, (ipaddr >> 8) & 0xFF, (ipaddr >> 16) & 0xFF, (ipaddr >> 24) & 0xFF);
|
|
||||||
|
|
||||||
printf("(SCA connection from %s)\n", name);
|
|
||||||
|
|
||||||
if (sca_unit.filename != NULL)
|
if (sca_unit.filename != NULL)
|
||||||
free(sca_unit.filename);
|
free(sca_unit.filename);
|
||||||
|
|
||||||
sca_unit.filename = mstring(name);
|
sca_unit.filename = connectaddress;
|
||||||
|
|
||||||
SETBIT(sca_dsw, SCA_DSW_READY); /* indicate active connection */
|
SETBIT(sca_dsw, SCA_DSW_READY); /* indicate active connection */
|
||||||
|
|
||||||
|
|
66
scp.c
66
scp.c
|
@ -216,6 +216,7 @@
|
||||||
#include "sim_defs.h"
|
#include "sim_defs.h"
|
||||||
#include "sim_rev.h"
|
#include "sim_rev.h"
|
||||||
#include "sim_ether.h"
|
#include "sim_ether.h"
|
||||||
|
#include "sim_sock.h"
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
@ -786,6 +787,7 @@ for (i = 1; i < argc; i++) { /* loop thru args */
|
||||||
sim_quiet = sim_switches & SWMASK ('Q'); /* -q means quiet */
|
sim_quiet = sim_switches & SWMASK ('Q'); /* -q means quiet */
|
||||||
sim_on_inherit = sim_switches & SWMASK ('O'); /* -o means inherit on state */
|
sim_on_inherit = sim_switches & SWMASK ('O'); /* -o means inherit on state */
|
||||||
|
|
||||||
|
sim_init_sock (); /* init socket capabilities */
|
||||||
AIO_INIT; /* init Asynch I/O */
|
AIO_INIT; /* init Asynch I/O */
|
||||||
if (sim_vm_init != NULL) /* call once only */
|
if (sim_vm_init != NULL) /* call once only */
|
||||||
(*sim_vm_init)();
|
(*sim_vm_init)();
|
||||||
|
@ -899,6 +901,7 @@ sim_set_logoff (0, NULL); /* close log */
|
||||||
sim_set_notelnet (0, NULL); /* close Telnet */
|
sim_set_notelnet (0, NULL); /* close Telnet */
|
||||||
sim_ttclose (); /* close console */
|
sim_ttclose (); /* close console */
|
||||||
AIO_CLEANUP; /* Asynch I/O */
|
AIO_CLEANUP; /* Asynch I/O */
|
||||||
|
sim_cleanup_sock (); /* cleanup sockets */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4574,69 +4577,6 @@ if (term && (*tptr++ != term))
|
||||||
return tptr;
|
return tptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get_ipaddr IP address:port
|
|
||||||
|
|
||||||
Inputs:
|
|
||||||
cptr = pointer to input string
|
|
||||||
Outputs:
|
|
||||||
ipa = pointer to IP address (may be NULL), 0 = none
|
|
||||||
ipp = pointer to IP port (may be NULL), 0 = none
|
|
||||||
result = status
|
|
||||||
*/
|
|
||||||
|
|
||||||
t_stat get_ipaddr (char *cptr, uint32 *ipa, uint32 *ipp)
|
|
||||||
{
|
|
||||||
char gbuf[CBUFSIZE];
|
|
||||||
char *addrp, *portp, *octetp;
|
|
||||||
uint32 i, addr, port, octet;
|
|
||||||
t_stat r;
|
|
||||||
|
|
||||||
if ((cptr == NULL) || (*cptr == 0))
|
|
||||||
return SCPE_ARG;
|
|
||||||
strncpy (gbuf, cptr, CBUFSIZE);
|
|
||||||
addrp = gbuf; /* default addr */
|
|
||||||
if ((portp = strchr (gbuf, ':'))) /* x:y? split */
|
|
||||||
*portp++ = 0;
|
|
||||||
else if (strchr (gbuf, '.')) /* x.y...? */
|
|
||||||
portp = NULL;
|
|
||||||
else {
|
|
||||||
portp = gbuf; /* port only */
|
|
||||||
addrp = NULL; /* no addr */
|
|
||||||
}
|
|
||||||
if (portp) { /* port string? */
|
|
||||||
if (ipp == NULL) /* not wanted? */
|
|
||||||
return SCPE_ARG;
|
|
||||||
port = (int32) get_uint (portp, 10, 65535, &r);
|
|
||||||
if ((r != SCPE_OK) || (port == 0))
|
|
||||||
return SCPE_ARG;
|
|
||||||
}
|
|
||||||
else port = 0;
|
|
||||||
if (addrp) { /* addr string? */
|
|
||||||
if (ipa == NULL) /* not wanted? */
|
|
||||||
return SCPE_ARG;
|
|
||||||
for (i = addr = 0; i < 4; i++) { /* four octets */
|
|
||||||
octetp = strchr (addrp, '.'); /* find octet end */
|
|
||||||
if (octetp != NULL) /* split string */
|
|
||||||
*octetp++ = 0;
|
|
||||||
else if (i < 3) /* except last */
|
|
||||||
return SCPE_ARG;
|
|
||||||
octet = (int32) get_uint (addrp, 10, 255, &r);
|
|
||||||
if (r != SCPE_OK)
|
|
||||||
return SCPE_ARG;
|
|
||||||
addr = (addr << 8) | octet;
|
|
||||||
addrp = octetp;
|
|
||||||
}
|
|
||||||
if (((addr & 0377) == 0) || ((addr & 0377) == 255))
|
|
||||||
return SCPE_ARG;
|
|
||||||
}
|
|
||||||
else addr = 0;
|
|
||||||
if (ipp) /* return req values */
|
|
||||||
*ipp = port;
|
|
||||||
if (ipa)
|
|
||||||
*ipa = addr;
|
|
||||||
return SCPE_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find_device find device matching input string
|
/* Find_device find device matching input string
|
||||||
|
|
||||||
Inputs:
|
Inputs:
|
||||||
|
|
1
scp.h
1
scp.h
|
@ -106,7 +106,6 @@ char *get_glyph_nc (char *iptr, char *optr, char mchar);
|
||||||
t_value get_uint (char *cptr, uint32 radix, t_value max, t_stat *status);
|
t_value get_uint (char *cptr, uint32 radix, t_value max, t_stat *status);
|
||||||
char *get_range (DEVICE *dptr, char *cptr, t_addr *lo, t_addr *hi,
|
char *get_range (DEVICE *dptr, char *cptr, t_addr *lo, t_addr *hi,
|
||||||
uint32 rdx, t_addr max, char term);
|
uint32 rdx, t_addr max, char term);
|
||||||
t_stat get_ipaddr (char *cptr, uint32 *ipa, uint32 *ipp);
|
|
||||||
t_value strtotv (char *cptr, char **endptr, uint32 radix);
|
t_value strtotv (char *cptr, char **endptr, uint32 radix);
|
||||||
t_stat fprint_val (FILE *stream, t_value val, uint32 rdx, uint32 wid, uint32 fmt);
|
t_stat fprint_val (FILE *stream, t_value val, uint32 rdx, uint32 wid, uint32 fmt);
|
||||||
CTAB *find_cmd (char *gbuf);
|
CTAB *find_cmd (char *gbuf);
|
||||||
|
|
|
@ -428,18 +428,20 @@ while (*cptr != 0) { /* do all mods */
|
||||||
if ((cvptr = strchr (gbuf, '='))) /* = value? */
|
if ((cvptr = strchr (gbuf, '='))) /* = value? */
|
||||||
*cvptr++ = 0;
|
*cvptr++ = 0;
|
||||||
get_glyph (gbuf, gbuf, 0); /* modifier to UC */
|
get_glyph (gbuf, gbuf, 0); /* modifier to UC */
|
||||||
if (isdigit (*gbuf)) {
|
if ((ctptr = find_ctab (set_con_telnet_tab, gbuf))) { /* match? */
|
||||||
if (sim_con_tmxr.master) /* already open? */
|
r = ctptr->action (ctptr->arg, cvptr); /* do the rest */
|
||||||
sim_set_notelnet (0, NULL); /* close first */
|
if (r != SCPE_OK)
|
||||||
return tmxr_open_master (&sim_con_tmxr, gbuf); /* open master socket */
|
return r;
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
if ((ctptr = find_ctab (set_con_telnet_tab, gbuf))) { /* match? */
|
r = sim_parse_addr (gbuf, NULL, 0, NULL, NULL, 0, NULL);
|
||||||
r = ctptr->action (ctptr->arg, cvptr); /* do the rest */
|
if (r == SCPE_OK) {
|
||||||
if (r != SCPE_OK)
|
if (sim_con_tmxr.master) /* already open? */
|
||||||
return r;
|
sim_set_notelnet (0, NULL); /* close first */
|
||||||
|
return tmxr_open_master (&sim_con_tmxr, gbuf); /* open master socket */
|
||||||
}
|
}
|
||||||
else return SCPE_NOPARAM;
|
return SCPE_NOPARAM;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
@ -465,9 +467,9 @@ if (sim_con_tmxr.master == 0)
|
||||||
fprintf (st, "Connected to console window\n");
|
fprintf (st, "Connected to console window\n");
|
||||||
else {
|
else {
|
||||||
if (sim_con_ldsc.conn == 0)
|
if (sim_con_ldsc.conn == 0)
|
||||||
fprintf (st, "Listening on port %d\n", sim_con_tmxr.port);
|
fprintf (st, "Listening on port %s\n", sim_con_tmxr.port);
|
||||||
else {
|
else {
|
||||||
fprintf (st, "Listening on port %d, connected to socket %d\n",
|
fprintf (st, "Listening on port %s, connected to socket %d\n",
|
||||||
sim_con_tmxr.port, sim_con_ldsc.conn);
|
sim_con_tmxr.port, sim_con_ldsc.conn);
|
||||||
tmxr_fconns (st, &sim_con_ldsc, -1);
|
tmxr_fconns (st, &sim_con_ldsc, -1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -942,7 +942,7 @@ static char* (*p_pcap_lib_version) (void);
|
||||||
/* load function pointer from DLL */
|
/* load function pointer from DLL */
|
||||||
typedef int (*_func)();
|
typedef int (*_func)();
|
||||||
|
|
||||||
void load_function(char* function, _func* func_ptr) {
|
static void load_function(char* function, _func* func_ptr) {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
*func_ptr = (_func)GetProcAddress(hLib, function);
|
*func_ptr = (_func)GetProcAddress(hLib, function);
|
||||||
#else
|
#else
|
||||||
|
|
659
sim_sock.c
659
sim_sock.c
|
@ -23,6 +23,7 @@
|
||||||
used in advertising or otherwise to promote the sale, use or other dealings
|
used in advertising or otherwise to promote the sale, use or other dealings
|
||||||
in this Software without prior written authorization from Robert M Supnik.
|
in this Software without prior written authorization from Robert M Supnik.
|
||||||
|
|
||||||
|
25-Sep-12 MP Reworked for RFC3493 interfaces supporting IPv6 and IPv4
|
||||||
22-Jun-10 RMS Fixed types in sim_accept_conn (from Mark Pizzolato)
|
22-Jun-10 RMS Fixed types in sim_accept_conn (from Mark Pizzolato)
|
||||||
19-Nov-05 RMS Added conditional for OpenBSD (from Federico G. Schwindt)
|
19-Nov-05 RMS Added conditional for OpenBSD (from Federico G. Schwindt)
|
||||||
16-Aug-05 RMS Fixed spurious SIGPIPE signal error in Unix
|
16-Aug-05 RMS Fixed spurious SIGPIPE signal error in Unix
|
||||||
|
@ -43,6 +44,24 @@
|
||||||
#include "sim_sock.h"
|
#include "sim_sock.h"
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
|
extern FILE *sim_log;
|
||||||
|
|
||||||
|
#if defined(AF_INET6) && defined(_WIN32)
|
||||||
|
#include <ws2tcpip.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef WSAAPI
|
||||||
|
#define WSAAPI
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(SHUT_RDWR) && !defined(SD_BOTH)
|
||||||
|
#define SD_BOTH SHUT_RDWR
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef NI_MAXHOST
|
||||||
|
#define NI_MAXHOST 1025
|
||||||
|
#endif
|
||||||
|
|
||||||
/* OS dependent routines
|
/* OS dependent routines
|
||||||
|
|
||||||
sim_master_sock create master socket
|
sim_master_sock create master socket
|
||||||
|
@ -54,23 +73,118 @@
|
||||||
sim_msg_sock send message to socket
|
sim_msg_sock send message to socket
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int32 sim_sock_cnt = 0;
|
/* OS independent routines
|
||||||
|
|
||||||
|
sim_parse_addr parse a hostname/ipaddress from port and apply defaults
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* sim_parse_addr host:port
|
||||||
|
|
||||||
|
Presumption is that the input, if it doesn't contain a ':' character is a port specifier.
|
||||||
|
If the host field contains one or more colon characters (i.e. it is an IPv6 address),
|
||||||
|
the IPv6 address MUST be enclosed in square bracket characters (i.e. Domain Literal format)
|
||||||
|
|
||||||
|
Inputs:
|
||||||
|
cptr = pointer to input string
|
||||||
|
default_host
|
||||||
|
= optional pointer to default host if none specified
|
||||||
|
host_len = length of host buffer
|
||||||
|
default_port
|
||||||
|
= optional pointer to default host if none specified
|
||||||
|
port_len = length of port buffer
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
char gbuf[CBUFSIZE];
|
||||||
|
char *hostp, *portp;
|
||||||
|
char *endc;
|
||||||
|
unsigned long portval;
|
||||||
|
|
||||||
|
if ((cptr == NULL) || (*cptr == 0))
|
||||||
|
return SCPE_ARG;
|
||||||
|
if ((host != NULL) && (host_len != 0))
|
||||||
|
memset (host, 0, host_len);
|
||||||
|
if ((port != NULL) && (port_len != 0))
|
||||||
|
memset (port, 0, port_len);
|
||||||
|
strncpy (gbuf, cptr, CBUFSIZE);
|
||||||
|
hostp = gbuf; /* default addr */
|
||||||
|
portp = NULL;
|
||||||
|
if ((portp = strrchr (gbuf, ':')) && /* x:y? split */
|
||||||
|
(NULL == strchr (portp, ']'))) {
|
||||||
|
*portp++ = 0;
|
||||||
|
if (*portp == '\0')
|
||||||
|
portp = (char *)default_port;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (default_port)
|
||||||
|
portp = (char *)default_port;
|
||||||
|
else {
|
||||||
|
portp = gbuf;
|
||||||
|
hostp = NULL;
|
||||||
|
}
|
||||||
|
if (portp != NULL) {
|
||||||
|
portval = strtoul(portp, &endc, 10);
|
||||||
|
if ((*endc == '\0') && ((portval == 0) || (portval > 65535)))
|
||||||
|
return SCPE_ARG; /* value too big */
|
||||||
|
if (*endc != '\0') {
|
||||||
|
struct servent *se = getservbyname(portp, "tcp");
|
||||||
|
|
||||||
|
if (se == NULL)
|
||||||
|
return SCPE_ARG; /* invalid service name */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (port) /* port wanted? */
|
||||||
|
if (portp != NULL) {
|
||||||
|
if (strlen(portp) >= port_len)
|
||||||
|
return SCPE_ARG; /* no room */
|
||||||
|
else
|
||||||
|
strcpy (port, portp);
|
||||||
|
}
|
||||||
|
if (hostp != NULL) {
|
||||||
|
if (']' == hostp[strlen(hostp)-1]) {
|
||||||
|
if ('[' != hostp[0])
|
||||||
|
return SCPE_ARG; /* invalid domain literal */
|
||||||
|
strcpy(hostp, hostp+1); /* remove brackets from domain literal host */
|
||||||
|
hostp[strlen(hostp)-1] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (host) /* host wanted? */
|
||||||
|
if (hostp != NULL)
|
||||||
|
if (strlen(hostp) >= host_len)
|
||||||
|
return SCPE_ARG; /* no room */
|
||||||
|
else
|
||||||
|
strcpy (host, hostp);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
/* First, all the non-implemented versions */
|
/* First, all the non-implemented versions */
|
||||||
|
|
||||||
#if defined (__OS2__) && !defined (__EMX__)
|
#if defined (__OS2__) && !defined (__EMX__)
|
||||||
|
|
||||||
SOCKET sim_master_sock (int32 port)
|
void sim_init_sock (void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void sim_cleanup_sock (void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SOCKET sim_master_sock (const char *hostport, t_stat *parse_status)
|
||||||
{
|
{
|
||||||
return INVALID_SOCKET;
|
return INVALID_SOCKET;
|
||||||
}
|
}
|
||||||
|
|
||||||
SOCKET sim_connect_sock (int32 ip, int32 port)
|
SOCKET sim_connect_sock (const char *hostport, const char *default_host, const char *default_port)
|
||||||
{
|
{
|
||||||
return INVALID_SOCKET;
|
return INVALID_SOCKET;
|
||||||
}
|
}
|
||||||
|
|
||||||
SOCKET sim_accept_conn (SOCKET master, uint32 *ipaddr)
|
SOCKET sim_accept_conn (SOCKET master, char **connectaddr);
|
||||||
{
|
{
|
||||||
return INVALID_SOCKET;
|
return INVALID_SOCKET;
|
||||||
}
|
}
|
||||||
|
@ -90,11 +204,6 @@ void sim_close_sock (SOCKET sock, t_bool master)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 sim_setnonblock (SOCKET sock)
|
|
||||||
{
|
|
||||||
return SOCKET_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else /* endif unimpl */
|
#else /* endif unimpl */
|
||||||
|
|
||||||
/* UNIX, Win32, Macintosh, VMS, OS2 (Berkeley socket) routines */
|
/* UNIX, Win32, Macintosh, VMS, OS2 (Berkeley socket) routines */
|
||||||
|
@ -108,30 +217,383 @@ sim_close_sock (s, flg);
|
||||||
return INVALID_SOCKET;
|
return INVALID_SOCKET;
|
||||||
}
|
}
|
||||||
|
|
||||||
SOCKET sim_create_sock (void)
|
static void (WSAAPI *p_freeaddrinfo) (struct addrinfo *ai);
|
||||||
|
|
||||||
|
static int (WSAAPI *p_getaddrinfo) (const char *hostname,
|
||||||
|
const char *service,
|
||||||
|
const struct addrinfo *hints,
|
||||||
|
struct addrinfo **res);
|
||||||
|
|
||||||
|
static int (WSAAPI *p_getnameinfo) (const struct sockaddr *sa, socklen_t salen,
|
||||||
|
char *host, size_t hostlen,
|
||||||
|
char *serv, size_t servlen,
|
||||||
|
int flags);
|
||||||
|
|
||||||
|
|
||||||
|
static void WSAAPI s_freeaddrinfo (struct addrinfo *ai)
|
||||||
{
|
{
|
||||||
SOCKET newsock;
|
struct addrinfo *a, *an;
|
||||||
int32 err;
|
|
||||||
|
|
||||||
#if defined (_WIN32)
|
for (a=ai; a != NULL; a=an) {
|
||||||
WORD wVersionRequested;
|
an = a->ai_next;
|
||||||
WSADATA wsaData;
|
free (a->ai_canonname);
|
||||||
wVersionRequested = MAKEWORD (1, 1);
|
free (a->ai_addr);
|
||||||
|
free (a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (sim_sock_cnt == 0) {
|
static int WSAAPI s_getaddrinfo (const char *hostname,
|
||||||
err = WSAStartup (wVersionRequested, &wsaData); /* start Winsock */
|
const char *service,
|
||||||
if (err != 0) {
|
const struct addrinfo *hints,
|
||||||
printf ("Winsock: startup error %d\n", err);
|
struct addrinfo **res)
|
||||||
return INVALID_SOCKET;
|
{
|
||||||
|
struct hostent *he;
|
||||||
|
struct servent *se;
|
||||||
|
struct sockaddr_in *sin;
|
||||||
|
struct addrinfo *result = NULL;
|
||||||
|
struct addrinfo *ai, *lai;
|
||||||
|
struct addrinfo dhints;
|
||||||
|
struct in_addr ipaddr;
|
||||||
|
struct in_addr *fixed[2];
|
||||||
|
struct in_addr **ips;
|
||||||
|
struct in_addr **ip;
|
||||||
|
const char *cname = NULL;
|
||||||
|
int port = 0;
|
||||||
|
|
||||||
|
// Validate parameters
|
||||||
|
if ((hostname == NULL) && (service == NULL))
|
||||||
|
return EAI_NONAME;
|
||||||
|
|
||||||
|
if (hints) {
|
||||||
|
if ((hints->ai_family != PF_INET) && (hints->ai_family != PF_UNSPEC))
|
||||||
|
return EAI_FAMILY;
|
||||||
|
switch (hints->ai_socktype)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
return EAI_SOCKTYPE;
|
||||||
|
case SOCK_DGRAM:
|
||||||
|
case SOCK_STREAM:
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sim_sock_cnt = sim_sock_cnt + 1;
|
else {
|
||||||
|
hints = &dhints;
|
||||||
|
memset(&dhints, 0, sizeof(dhints));
|
||||||
|
dhints.ai_family = PF_UNSPEC;
|
||||||
|
}
|
||||||
|
if (service) {
|
||||||
|
char *c;
|
||||||
|
|
||||||
|
port = strtoul(service, &c, 10);
|
||||||
|
if ((port == 0) && (*c != '\0') && (hints->ai_flags & AI_NUMERICSERV))
|
||||||
|
return EAI_NONAME;
|
||||||
|
if ((port == 0) || (*c != '\0')) {
|
||||||
|
switch (hints->ai_socktype)
|
||||||
|
{
|
||||||
|
case SOCK_DGRAM:
|
||||||
|
se = getservbyname(service, "udp");
|
||||||
|
break;
|
||||||
|
case SOCK_STREAM:
|
||||||
|
case 0:
|
||||||
|
se = getservbyname(service, "tcp");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (NULL == se)
|
||||||
|
return EAI_SERVICE;
|
||||||
|
port = se->s_port;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hostname) {
|
||||||
|
if ((0xffffffff != (ipaddr.s_addr = inet_addr(hostname))) ||
|
||||||
|
(0 == strcmp("255.255.255.255", hostname))) {
|
||||||
|
fixed[0] = &ipaddr;
|
||||||
|
fixed[1] = NULL;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if ((0xffffffff != (ipaddr.s_addr = inet_addr(hostname))) ||
|
||||||
|
(0 == strcmp("255.255.255.255", hostname))) {
|
||||||
|
fixed[0] = &ipaddr;
|
||||||
|
fixed[1] = NULL;
|
||||||
|
if ((hints->ai_flags & AI_CANONNAME) && !(hints->ai_flags & AI_NUMERICHOST)) {
|
||||||
|
he = gethostbyaddr((char *)&ipaddr, 4, AF_INET);
|
||||||
|
if (NULL != he)
|
||||||
|
cname = he->h_name;
|
||||||
|
else
|
||||||
|
cname = hostname;
|
||||||
|
}
|
||||||
|
ips = fixed;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (hints->ai_flags & AI_NUMERICHOST)
|
||||||
|
return EAI_NONAME;
|
||||||
|
he = gethostbyname(hostname);
|
||||||
|
if (he) {
|
||||||
|
ips = (struct in_addr **)he->h_addr_list;
|
||||||
|
if (hints->ai_flags & AI_CANONNAME)
|
||||||
|
cname = he->h_name;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
switch (h_errno)
|
||||||
|
{
|
||||||
|
case HOST_NOT_FOUND:
|
||||||
|
case NO_DATA:
|
||||||
|
return EAI_NONAME;
|
||||||
|
case TRY_AGAIN:
|
||||||
|
return EAI_AGAIN;
|
||||||
|
default:
|
||||||
|
return EAI_FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (hints->ai_flags & AI_PASSIVE)
|
||||||
|
ipaddr.s_addr = htonl(INADDR_ANY);
|
||||||
|
else
|
||||||
|
ipaddr.s_addr = htonl(INADDR_LOOPBACK);
|
||||||
|
fixed[0] = &ipaddr;
|
||||||
|
fixed[1] = NULL;
|
||||||
|
ips = fixed;
|
||||||
|
}
|
||||||
|
for (ip=ips; *ip != NULL; ++ip) {
|
||||||
|
ai = calloc(1, sizeof(*ai));
|
||||||
|
if (NULL == ai) {
|
||||||
|
s_freeaddrinfo(result);
|
||||||
|
return EAI_MEMORY;
|
||||||
|
}
|
||||||
|
ai->ai_family = PF_INET;
|
||||||
|
ai->ai_socktype = hints->ai_socktype;
|
||||||
|
ai->ai_protocol = hints->ai_protocol;
|
||||||
|
ai->ai_addr = NULL;
|
||||||
|
ai->ai_addrlen = sizeof(struct sockaddr_in);
|
||||||
|
ai->ai_canonname = NULL;
|
||||||
|
ai->ai_next = NULL;
|
||||||
|
ai->ai_addr = calloc(1, sizeof(struct sockaddr_in));
|
||||||
|
if (NULL == ai->ai_addr) {
|
||||||
|
free(ai);
|
||||||
|
s_freeaddrinfo(result);
|
||||||
|
return EAI_MEMORY;
|
||||||
|
}
|
||||||
|
sin = (struct sockaddr_in *)ai->ai_addr;
|
||||||
|
sin->sin_family = PF_INET;
|
||||||
|
sin->sin_port = port;
|
||||||
|
memcpy(&sin->sin_addr, *ip, sizeof(sin->sin_addr));
|
||||||
|
if (NULL == result)
|
||||||
|
result = ai;
|
||||||
|
else
|
||||||
|
lai->ai_next = ai;
|
||||||
|
lai = ai;
|
||||||
|
}
|
||||||
|
if (cname) {
|
||||||
|
result->ai_canonname = calloc(1, strlen(cname)+1);
|
||||||
|
if (NULL == result->ai_canonname) {
|
||||||
|
s_freeaddrinfo(result);
|
||||||
|
return EAI_MEMORY;
|
||||||
|
}
|
||||||
|
strcpy(result->ai_canonname, cname);
|
||||||
|
}
|
||||||
|
*res = result;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef EAI_OVERFLOW
|
||||||
|
#define EAI_OVERFLOW WSAENAMETOOLONG
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int WSAAPI s_getnameinfo (const struct sockaddr *sa, socklen_t salen,
|
||||||
|
char *host, size_t hostlen,
|
||||||
|
char *serv, size_t servlen,
|
||||||
|
int flags)
|
||||||
|
{
|
||||||
|
struct hostent *he;
|
||||||
|
struct servent *se = NULL;
|
||||||
|
struct sockaddr_in *sin = (struct sockaddr_in *)sa;
|
||||||
|
|
||||||
|
if (sin->sin_family != PF_INET)
|
||||||
|
return EAI_FAMILY;
|
||||||
|
if ((NULL == host) && (NULL == serv))
|
||||||
|
return EAI_NONAME;
|
||||||
|
if ((serv) && (servlen > 0)) {
|
||||||
|
if (flags & NI_NUMERICSERV)
|
||||||
|
se = NULL;
|
||||||
|
else
|
||||||
|
if (flags & NI_DGRAM)
|
||||||
|
se = getservbyport(sin->sin_port, "udp");
|
||||||
|
else
|
||||||
|
se = getservbyport(sin->sin_port, "tcp");
|
||||||
|
if (se) {
|
||||||
|
if (servlen <= strlen(se->s_name))
|
||||||
|
return EAI_OVERFLOW;
|
||||||
|
strcpy(serv, se->s_name);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
char buf[16];
|
||||||
|
|
||||||
|
sprintf(buf, "%d", ntohs(sin->sin_port));
|
||||||
|
if (servlen <= strlen(buf))
|
||||||
|
return EAI_OVERFLOW;
|
||||||
|
strcpy(serv, buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((host) && (hostlen > 0)) {
|
||||||
|
if (flags & NI_NUMERICHOST)
|
||||||
|
he = NULL;
|
||||||
|
else
|
||||||
|
he = gethostbyaddr((char *)&sin->sin_addr, 4, AF_INET);
|
||||||
|
if (he) {
|
||||||
|
if (hostlen < strlen(he->h_name)+1)
|
||||||
|
return EAI_OVERFLOW;
|
||||||
|
strcpy(host, he->h_name);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (flags & NI_NAMEREQD)
|
||||||
|
return EAI_NONAME;
|
||||||
|
if (hostlen < strlen(inet_ntoa(sin->sin_addr))+1)
|
||||||
|
return EAI_OVERFLOW;
|
||||||
|
strcpy(host, inet_ntoa(sin->sin_addr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||||
|
|
||||||
|
/* Dynamic DLL load variables */
|
||||||
|
static HINSTANCE hLib = 0; /* handle to DLL */
|
||||||
|
static int lib_loaded = 0; /* 0=not loaded, 1=loaded, 2=library load failed, 3=Func load failed */
|
||||||
|
static char* lib_name = "Ws2_32.dll";
|
||||||
|
|
||||||
|
/* load function pointer from DLL */
|
||||||
|
typedef int (*_func)();
|
||||||
|
|
||||||
|
static void load_function(char* function, _func* func_ptr) {
|
||||||
|
*func_ptr = (_func)GetProcAddress(hLib, function);
|
||||||
|
if (*func_ptr == 0) {
|
||||||
|
char* msg = "Sockets: Failed to find function '%s' in %s\r\n";
|
||||||
|
|
||||||
|
printf (msg, function, lib_name);
|
||||||
|
if (sim_log) fprintf (sim_log, msg, function, lib_name);
|
||||||
|
lib_loaded = 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* load Ws2_32.dll as required */
|
||||||
|
int load_ws2(void) {
|
||||||
|
switch(lib_loaded) {
|
||||||
|
case 0: /* not loaded */
|
||||||
|
/* attempt to load DLL */
|
||||||
|
#ifdef _WIN32
|
||||||
|
hLib = LoadLibraryA(lib_name);
|
||||||
|
#else
|
||||||
|
hLib = dlopen(lib_name, RTLD_NOW);
|
||||||
|
#endif
|
||||||
|
if (hLib == 0) {
|
||||||
|
/* failed to load DLL */
|
||||||
|
char* msg = "Sockets: Failed to load %s\r\n";
|
||||||
|
|
||||||
|
printf (msg, lib_name);
|
||||||
|
if (sim_log)
|
||||||
|
fprintf (sim_log, msg, lib_name);
|
||||||
|
lib_loaded = 2;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
/* library loaded OK */
|
||||||
|
lib_loaded = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* load required functions; sets dll_load=3 on error */
|
||||||
|
load_function("getaddrinfo", (_func *) &p_getaddrinfo);
|
||||||
|
load_function("getnameinfo", (_func *) &p_getnameinfo);
|
||||||
|
load_function("freeaddrinfo", (_func *) &p_freeaddrinfo);
|
||||||
|
|
||||||
|
if (lib_loaded != 1) {
|
||||||
|
/* unsuccessful load, connect stubs */
|
||||||
|
p_getaddrinfo = s_getaddrinfo;
|
||||||
|
p_getnameinfo = s_getnameinfo;
|
||||||
|
p_freeaddrinfo = s_freeaddrinfo;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default: /* loaded or failed */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return (lib_loaded == 1) ? 1 : 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void sim_init_sock (void)
|
||||||
|
{
|
||||||
|
#if defined (_WIN32)
|
||||||
|
int err;
|
||||||
|
WORD wVersionRequested;
|
||||||
|
WSADATA wsaData;
|
||||||
|
wVersionRequested = MAKEWORD (2, 2);
|
||||||
|
|
||||||
|
|
||||||
|
err = WSAStartup (wVersionRequested, &wsaData); /* start Winsock */
|
||||||
|
if (err != 0)
|
||||||
|
printf ("Winsock: startup error %d\n", err);
|
||||||
|
#if defined(AF_INET6)
|
||||||
|
load_ws2 ();
|
||||||
|
#endif /* endif AF_INET6 */
|
||||||
#endif /* endif Win32 */
|
#endif /* endif Win32 */
|
||||||
#if defined (SIGPIPE)
|
#if defined (SIGPIPE)
|
||||||
signal (SIGPIPE, SIG_IGN); /* no pipe signals */
|
signal (SIGPIPE, SIG_IGN); /* no pipe signals */
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
newsock = socket (AF_INET, SOCK_STREAM, 0); /* create socket */
|
void sim_cleanup_sock (void)
|
||||||
|
{
|
||||||
|
#if defined (_WIN32)
|
||||||
|
WSACleanup ();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined (_WIN32) /* Windows */
|
||||||
|
static int32 sim_setnonblock (SOCKET sock)
|
||||||
|
{
|
||||||
|
unsigned long non_block = 1;
|
||||||
|
|
||||||
|
return ioctlsocket (sock, FIONBIO, &non_block); /* set nonblocking */
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined (VMS) /* VMS */
|
||||||
|
static int32 sim_setnonblock (SOCKET sock)
|
||||||
|
{
|
||||||
|
int non_block = 1;
|
||||||
|
|
||||||
|
return ioctl (sock, FIONBIO, &non_block); /* set nonblocking */
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* Mac, Unix, OS/2 */
|
||||||
|
static int32 sim_setnonblock (SOCKET sock)
|
||||||
|
{
|
||||||
|
int32 fl, sta;
|
||||||
|
|
||||||
|
fl = fcntl (sock, F_GETFL,0); /* get flags */
|
||||||
|
if (fl == -1)
|
||||||
|
return SOCKET_ERROR;
|
||||||
|
sta = fcntl (sock, F_SETFL, fl | O_NONBLOCK); /* set nonblock */
|
||||||
|
if (sta == -1)
|
||||||
|
return SOCKET_ERROR;
|
||||||
|
#if !defined (macintosh) && !defined (__EMX__) /* Unix only */
|
||||||
|
sta = fcntl (sock, F_SETOWN, getpid()); /* set ownership */
|
||||||
|
if (sta == -1)
|
||||||
|
return SOCKET_ERROR;
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* endif !Win32 && !VMS */
|
||||||
|
|
||||||
|
static SOCKET sim_create_sock (int af)
|
||||||
|
{
|
||||||
|
SOCKET newsock;
|
||||||
|
int32 err;
|
||||||
|
|
||||||
|
newsock = socket (af, SOCK_STREAM, 0); /* create socket */
|
||||||
if (newsock == INVALID_SOCKET) { /* socket error? */
|
if (newsock == INVALID_SOCKET) { /* socket error? */
|
||||||
err = WSAGetLastError ();
|
err = WSAGetLastError ();
|
||||||
printf ("Sockets: socket error %d\n", err);
|
printf ("Sockets: socket error %d\n", err);
|
||||||
|
@ -140,21 +602,49 @@ if (newsock == INVALID_SOCKET) { /* socket error? */
|
||||||
return newsock;
|
return newsock;
|
||||||
}
|
}
|
||||||
|
|
||||||
SOCKET sim_master_sock (int32 port)
|
/*
|
||||||
{
|
Some platforms and/or network stacks have varying support for listening on
|
||||||
SOCKET newsock;
|
an IPv6 socket and receiving connections from both IPv4 and IPv6 client
|
||||||
struct sockaddr_in name;
|
connections. This is known as IPv4-Mapped. Some platforms claim such
|
||||||
int32 sta;
|
support (i.e. some Windows versions), but it doesn't work in all cases.
|
||||||
|
*/
|
||||||
|
|
||||||
newsock = sim_create_sock (); /* create socket */
|
SOCKET sim_master_sock (const char *hostport, t_stat *parse_status)
|
||||||
if (newsock == INVALID_SOCKET) /* socket error? */
|
{
|
||||||
|
SOCKET newsock = INVALID_SOCKET;
|
||||||
|
int32 sta;
|
||||||
|
char host[CBUFSIZE], port[CBUFSIZE];
|
||||||
|
t_stat r;
|
||||||
|
struct addrinfo hints;
|
||||||
|
struct addrinfo *result = NULL;
|
||||||
|
|
||||||
|
r = sim_parse_addr (hostport, host, sizeof(host), NULL, port, sizeof(port), NULL);
|
||||||
|
if (parse_status)
|
||||||
|
*parse_status = r;
|
||||||
|
if (r != SCPE_OK)
|
||||||
return newsock;
|
return newsock;
|
||||||
|
|
||||||
name.sin_family = AF_INET; /* name socket */
|
memset(&hints, 0, sizeof(hints));
|
||||||
name.sin_port = htons ((unsigned short) port); /* insert port */
|
hints.ai_flags = AI_PASSIVE;
|
||||||
name.sin_addr.s_addr = htonl (INADDR_ANY); /* insert addr */
|
hints.ai_family = AF_UNSPEC;
|
||||||
|
hints.ai_protocol = IPPROTO_TCP;
|
||||||
sta = bind (newsock, (struct sockaddr *) &name, sizeof (name));
|
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;
|
||||||
|
return newsock;
|
||||||
|
}
|
||||||
|
newsock = sim_create_sock (result->ai_family); /* create socket */
|
||||||
|
if (newsock == INVALID_SOCKET) { /* socket error? */
|
||||||
|
p_freeaddrinfo(result);
|
||||||
|
return newsock;
|
||||||
|
}
|
||||||
|
if (result->ai_family == AF_INET6) {
|
||||||
|
int off = FALSE;
|
||||||
|
sta = setsockopt (newsock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&off, sizeof(off));
|
||||||
|
}
|
||||||
|
sta = bind (newsock, result->ai_addr, result->ai_addrlen);
|
||||||
|
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", 1);
|
||||||
sta = sim_setnonblock (newsock); /* set nonblocking */
|
sta = sim_setnonblock (newsock); /* set nonblocking */
|
||||||
|
@ -166,24 +656,38 @@ if (sta == SOCKET_ERROR) /* listen error? */
|
||||||
return newsock; /* got it! */
|
return newsock; /* got it! */
|
||||||
}
|
}
|
||||||
|
|
||||||
SOCKET sim_connect_sock (int32 ip, int32 port)
|
SOCKET sim_connect_sock (const char *hostport, const char *default_host, const char *default_port)
|
||||||
{
|
{
|
||||||
SOCKET newsock;
|
SOCKET newsock = INVALID_SOCKET;
|
||||||
struct sockaddr_in name;
|
|
||||||
int32 sta;
|
int32 sta;
|
||||||
|
char host[CBUFSIZE], port[CBUFSIZE];
|
||||||
|
t_stat r;
|
||||||
|
struct addrinfo hints;
|
||||||
|
struct addrinfo *result = NULL;
|
||||||
|
|
||||||
newsock = sim_create_sock (); /* create socket */
|
r = sim_parse_addr (hostport, host, sizeof(host), default_host, port, sizeof(port), default_port);
|
||||||
if (newsock == INVALID_SOCKET) /* socket error? */
|
if (r != SCPE_OK)
|
||||||
return newsock;
|
return newsock;
|
||||||
|
|
||||||
name.sin_family = AF_INET; /* name socket */
|
memset(&hints, 0, sizeof(hints));
|
||||||
name.sin_port = htons ((unsigned short) port); /* insert port */
|
hints.ai_family = AF_UNSPEC;
|
||||||
name.sin_addr.s_addr = htonl (ip); /* insert addr */
|
hints.ai_protocol = IPPROTO_TCP;
|
||||||
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
if (p_getaddrinfo(host[0] ? host : NULL, port[0] ? port : NULL, &hints, &result))
|
||||||
|
return newsock;
|
||||||
|
newsock = sim_create_sock (result->ai_family); /* create socket */
|
||||||
|
if (newsock == INVALID_SOCKET) { /* socket error? */
|
||||||
|
p_freeaddrinfo (result);
|
||||||
|
return newsock;
|
||||||
|
}
|
||||||
|
|
||||||
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);
|
||||||
return sim_err_sock (newsock, "fcntl", 1);
|
return sim_err_sock (newsock, "fcntl", 1);
|
||||||
sta = connect (newsock, (struct sockaddr *) &name, sizeof (name));
|
}
|
||||||
|
sta = connect (newsock, result->ai_addr, result->ai_addrlen);
|
||||||
|
p_freeaddrinfo (result);
|
||||||
if ((sta == SOCKET_ERROR) &&
|
if ((sta == SOCKET_ERROR) &&
|
||||||
(WSAGetLastError () != WSAEWOULDBLOCK) &&
|
(WSAGetLastError () != WSAEWOULDBLOCK) &&
|
||||||
(WSAGetLastError () != WSAEINPROGRESS))
|
(WSAGetLastError () != WSAEINPROGRESS))
|
||||||
|
@ -192,7 +696,7 @@ if ((sta == SOCKET_ERROR) &&
|
||||||
return newsock; /* got it! */
|
return newsock; /* got it! */
|
||||||
}
|
}
|
||||||
|
|
||||||
SOCKET sim_accept_conn (SOCKET master, uint32 *ipaddr)
|
SOCKET sim_accept_conn (SOCKET master, char **connectaddr)
|
||||||
{
|
{
|
||||||
int32 sta, err;
|
int32 sta, err;
|
||||||
#if defined (macintosh) || defined (__linux) || \
|
#if defined (macintosh) || defined (__linux) || \
|
||||||
|
@ -206,11 +710,12 @@ int size;
|
||||||
size_t size;
|
size_t size;
|
||||||
#endif
|
#endif
|
||||||
SOCKET newsock;
|
SOCKET newsock;
|
||||||
struct sockaddr_in clientname;
|
struct sockaddr_storage clientname;
|
||||||
|
|
||||||
if (master == 0) /* not attached? */
|
if (master == 0) /* not attached? */
|
||||||
return INVALID_SOCKET;
|
return INVALID_SOCKET;
|
||||||
size = sizeof (clientname);
|
size = sizeof (clientname);
|
||||||
|
memset (&clientname, 0, sizeof(clientname));
|
||||||
newsock = accept (master, (struct sockaddr *) &clientname, &size);
|
newsock = accept (master, (struct sockaddr *) &clientname, &size);
|
||||||
if (newsock == INVALID_SOCKET) { /* error? */
|
if (newsock == INVALID_SOCKET) { /* error? */
|
||||||
err = WSAGetLastError ();
|
err = WSAGetLastError ();
|
||||||
|
@ -218,8 +723,14 @@ if (newsock == INVALID_SOCKET) { /* error? */
|
||||||
printf ("Sockets: accept error %d\n", err);
|
printf ("Sockets: accept error %d\n", err);
|
||||||
return INVALID_SOCKET;
|
return INVALID_SOCKET;
|
||||||
}
|
}
|
||||||
if (ipaddr != NULL)
|
if (connectaddr != NULL) {
|
||||||
*ipaddr = ntohl (clientname.sin_addr.s_addr);
|
*connectaddr = calloc(1, NI_MAXHOST+1);
|
||||||
|
#ifdef AF_INET6
|
||||||
|
p_getnameinfo((struct sockaddr *)&clientname, size, *connectaddr, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
|
||||||
|
#else
|
||||||
|
strcpy(*connectaddr, inet_ntoa(((struct sockaddr_in *)&connectaddr)->s_addr));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
sta = sim_setnonblock (newsock); /* set nonblocking */
|
sta = sim_setnonblock (newsock); /* set nonblocking */
|
||||||
if (sta == SOCKET_ERROR) /* fcntl error? */
|
if (sta == SOCKET_ERROR) /* fcntl error? */
|
||||||
|
@ -273,56 +784,8 @@ return send (sock, msg, nbytes, 0);
|
||||||
|
|
||||||
void sim_close_sock (SOCKET sock, t_bool master)
|
void sim_close_sock (SOCKET sock, t_bool master)
|
||||||
{
|
{
|
||||||
#if defined (_WIN32)
|
shutdown(sock, SD_BOTH);
|
||||||
closesocket (sock);
|
closesocket (sock);
|
||||||
if (master) {
|
|
||||||
sim_sock_cnt = sim_sock_cnt - 1;
|
|
||||||
if (sim_sock_cnt <= 0) {
|
|
||||||
WSACleanup ();
|
|
||||||
sim_sock_cnt = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
close (sock);
|
|
||||||
#endif
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined (_WIN32) /* Windows */
|
|
||||||
int32 sim_setnonblock (SOCKET sock)
|
|
||||||
{
|
|
||||||
unsigned long non_block = 1;
|
|
||||||
|
|
||||||
return ioctlsocket (sock, FIONBIO, &non_block); /* set nonblocking */
|
|
||||||
}
|
|
||||||
|
|
||||||
#elif defined (VMS) /* VMS */
|
|
||||||
int32 sim_setnonblock (SOCKET sock)
|
|
||||||
{
|
|
||||||
int non_block = 1;
|
|
||||||
|
|
||||||
return ioctl (sock, FIONBIO, &non_block); /* set nonblocking */
|
|
||||||
}
|
|
||||||
|
|
||||||
#else /* Mac, Unix, OS/2 */
|
|
||||||
int32 sim_setnonblock (SOCKET sock)
|
|
||||||
{
|
|
||||||
int32 fl, sta;
|
|
||||||
|
|
||||||
fl = fcntl (sock, F_GETFL,0); /* get flags */
|
|
||||||
if (fl == -1)
|
|
||||||
return SOCKET_ERROR;
|
|
||||||
sta = fcntl (sock, F_SETFL, fl | O_NONBLOCK); /* set nonblock */
|
|
||||||
if (sta == -1)
|
|
||||||
return SOCKET_ERROR;
|
|
||||||
#if !defined (macintosh) && !defined (__EMX__) /* Unix only */
|
|
||||||
sta = fcntl (sock, F_SETOWN, getpid()); /* set ownership */
|
|
||||||
if (sta == -1)
|
|
||||||
return SOCKET_ERROR;
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* endif !Win32 && !VMS */
|
|
||||||
|
|
||||||
#endif /* end else !implemented */
|
#endif /* end else !implemented */
|
||||||
|
|
16
sim_sock.h
16
sim_sock.h
|
@ -23,6 +23,7 @@
|
||||||
used in advertising or otherwise to promote the sale, use or other dealings
|
used in advertising or otherwise to promote the sale, use or other dealings
|
||||||
in this Software without prior written authorization from Robert M Supnik.
|
in this Software without prior written authorization from Robert M Supnik.
|
||||||
|
|
||||||
|
25-Sep-12 MP Reworked for RFC3493 interfaces supporting IPv6 and IPv4
|
||||||
04-Jun-08 RMS Addes sim_create_sock, for IBM 1130
|
04-Jun-08 RMS Addes sim_create_sock, for IBM 1130
|
||||||
14-Apr-05 RMS Added WSAEINPROGRESS (from Tim Riker)
|
14-Apr-05 RMS Added WSAEINPROGRESS (from Tim Riker)
|
||||||
20-Aug-04 HV Added missing definition for OS/2 (from Holger Veit)
|
20-Aug-04 HV Added missing definition for OS/2 (from Holger Veit)
|
||||||
|
@ -49,16 +50,18 @@
|
||||||
|
|
||||||
#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 closesocket close
|
||||||
#define SOCKET int32
|
#define SOCKET int32
|
||||||
#define WSAEWOULDBLOCK EWOULDBLOCK
|
#define WSAEWOULDBLOCK EWOULDBLOCK
|
||||||
#define WSAEINPROGRESS EINPROGRESS
|
#define WSAEINPROGRESS EINPROGRESS
|
||||||
#define INVALID_SOCKET -1
|
#define INVALID_SOCKET ((SOCKET)-1)
|
||||||
#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 <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 */
|
||||||
|
#include <arpa/inet.h> /* for inet_addr and inet_ntoa */
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
#include <sys/time.h> /* for EMX */
|
#include <sys/time.h> /* for EMX */
|
||||||
#endif
|
#endif
|
||||||
|
@ -75,14 +78,15 @@
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
SOCKET sim_master_sock (int32 port);
|
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);
|
||||||
SOCKET sim_connect_sock (int32 ip, int32 port);
|
SOCKET sim_master_sock (const char *hostport, t_stat *parse_status);
|
||||||
SOCKET sim_create_sock (void);
|
SOCKET sim_connect_sock (const char *hostport, const char *default_host, const char *default_port);
|
||||||
SOCKET sim_accept_conn (SOCKET master, uint32 *ipaddr);
|
SOCKET sim_accept_conn (SOCKET master, char **connectaddr);
|
||||||
int32 sim_check_conn (SOCKET sock, t_bool rd);
|
int32 sim_check_conn (SOCKET sock, t_bool rd);
|
||||||
int32 sim_read_sock (SOCKET sock, char *buf, int32 nbytes);
|
int32 sim_read_sock (SOCKET sock, char *buf, int32 nbytes);
|
||||||
int32 sim_write_sock (SOCKET sock, char *msg, int32 nbytes);
|
int32 sim_write_sock (SOCKET sock, char *msg, int32 nbytes);
|
||||||
void sim_close_sock (SOCKET sock, t_bool master);
|
void sim_close_sock (SOCKET sock, t_bool master);
|
||||||
int32 sim_setnonblock (SOCKET sock);
|
void sim_init_sock (void);
|
||||||
|
void sim_cleanup_sock (void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
42
sim_tmxr.c
42
sim_tmxr.c
|
@ -158,7 +158,7 @@ SOCKET newsock;
|
||||||
TMLN *lp;
|
TMLN *lp;
|
||||||
int32 *op;
|
int32 *op;
|
||||||
int32 i, j, psave;
|
int32 i, j, psave;
|
||||||
uint32 ipaddr;
|
char *address;
|
||||||
char cmsg[80];
|
char cmsg[80];
|
||||||
char dmsg[80] = "";
|
char dmsg[80] = "";
|
||||||
char lmsg[80] = "";
|
char lmsg[80] = "";
|
||||||
|
@ -171,7 +171,7 @@ static char mantra[] = {
|
||||||
TN_IAC, TN_DO, TN_BIN
|
TN_IAC, TN_DO, TN_BIN
|
||||||
};
|
};
|
||||||
|
|
||||||
newsock = sim_accept_conn (mp->master, &ipaddr); /* poll connect */
|
newsock = sim_accept_conn (mp->master, &address); /* poll connect */
|
||||||
if (newsock != INVALID_SOCKET) { /* got a live one? */
|
if (newsock != INVALID_SOCKET) { /* got a live one? */
|
||||||
op = mp->lnorder; /* get line connection order list pointer */
|
op = mp->lnorder; /* get line connection order list pointer */
|
||||||
i = mp->lines; /* play it safe in case lines == 0 */
|
i = mp->lines; /* play it safe in case lines == 0 */
|
||||||
|
@ -194,7 +194,7 @@ if (newsock != INVALID_SOCKET) { /* got a live one? */
|
||||||
else {
|
else {
|
||||||
lp = mp->ldsc + i; /* get line desc */
|
lp = mp->ldsc + i; /* get line desc */
|
||||||
lp->conn = newsock; /* record connection */
|
lp->conn = newsock; /* record connection */
|
||||||
lp->ipad = ipaddr; /* ip address */
|
lp->ipad = address; /* ip address */
|
||||||
lp->mp = mp; /* save mux */
|
lp->mp = mp; /* save mux */
|
||||||
sim_write_sock (newsock, mantra, sizeof(mantra));
|
sim_write_sock (newsock, mantra, sizeof(mantra));
|
||||||
tmxr_debug (TMXR_DBG_XMT, lp, "Sending", mantra, sizeof(mantra));
|
tmxr_debug (TMXR_DBG_XMT, lp, "Sending", mantra, sizeof(mantra));
|
||||||
|
@ -243,6 +243,8 @@ if (lp->txlog) /* dump log */
|
||||||
fflush (lp->txlog);
|
fflush (lp->txlog);
|
||||||
tmxr_send_buffered_data (lp); /* send buffered data */
|
tmxr_send_buffered_data (lp); /* send buffered data */
|
||||||
sim_close_sock (lp->conn, 0); /* reset conn */
|
sim_close_sock (lp->conn, 0); /* reset conn */
|
||||||
|
free (lp->ipad);
|
||||||
|
lp->ipad = NULL;
|
||||||
lp->conn = lp->tsta = 0; /* reset state */
|
lp->conn = lp->tsta = 0; /* reset state */
|
||||||
lp->rxbpr = lp->rxbpi = 0;
|
lp->rxbpr = lp->rxbpi = 0;
|
||||||
if (!lp->txbfd)
|
if (!lp->txbfd)
|
||||||
|
@ -560,13 +562,15 @@ return (lp->txbpi - lp->txbpr + ((lp->txbpi < lp->txbpr)? lp->txbsz: 0));
|
||||||
|
|
||||||
t_stat tmxr_open_master (TMXR *mp, char *cptr)
|
t_stat tmxr_open_master (TMXR *mp, char *cptr)
|
||||||
{
|
{
|
||||||
int32 i, port;
|
int32 i;
|
||||||
SOCKET sock;
|
SOCKET sock;
|
||||||
TMLN *lp;
|
TMLN *lp;
|
||||||
t_stat r;
|
t_stat r;
|
||||||
|
|
||||||
if (!isdigit(*cptr)) {
|
if (!isdigit(*cptr)) {
|
||||||
char gbuf[CBUFSIZE];
|
char gbuf[CBUFSIZE];
|
||||||
|
char *init_cptr = cptr;
|
||||||
|
|
||||||
cptr = get_glyph (cptr, gbuf, '=');
|
cptr = get_glyph (cptr, gbuf, '=');
|
||||||
if (0 == MATCH_CMD (gbuf, "LOG")) {
|
if (0 == MATCH_CMD (gbuf, "LOG")) {
|
||||||
if ((NULL == cptr) || ('\0' == *cptr))
|
if ((NULL == cptr) || ('\0' == *cptr))
|
||||||
|
@ -638,18 +642,20 @@ if (!isdigit(*cptr)) {
|
||||||
}
|
}
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
return SCPE_ARG;
|
if (SCPE_OK != sim_parse_addr (gbuf, NULL, 0, NULL, NULL, 0, NULL))
|
||||||
|
return SCPE_ARG;
|
||||||
|
cptr = init_cptr;
|
||||||
}
|
}
|
||||||
port = (int32) get_uint (cptr, 10, 65535, &r); /* get port */
|
sock = sim_master_sock (cptr, &r); /* make master socket */
|
||||||
if ((r != SCPE_OK) || (port == 0))
|
if (r != SCPE_OK)
|
||||||
return SCPE_ARG;
|
return r;
|
||||||
sock = sim_master_sock (port); /* make master socket */
|
|
||||||
if (sock == INVALID_SOCKET) /* open error */
|
if (sock == INVALID_SOCKET) /* open error */
|
||||||
return SCPE_OPENERR;
|
return SCPE_OPENERR;
|
||||||
printf ("Listening on port %d (socket %d)\n", port, sock);
|
printf ("Listening on port %s (socket %d)\n", cptr, sock);
|
||||||
if (sim_log)
|
if (sim_log)
|
||||||
fprintf (sim_log, "Listening on port %d (socket %d)\n", port, sock);
|
fprintf (sim_log, "Listening on port %s (socket %d)\n", cptr, sock);
|
||||||
mp->port = port; /* save port */
|
mp->port = calloc(1, 1+strlen(cptr)); /* save port */
|
||||||
|
strcpy(mp->port, cptr);
|
||||||
mp->master = sock; /* save master socket */
|
mp->master = sock; /* save master socket */
|
||||||
for (i = 0; i < mp->lines; i++) { /* initialize lines */
|
for (i = 0; i < mp->lines; i++) { /* initialize lines */
|
||||||
lp = mp->ldsc + i;
|
lp = mp->ldsc + i;
|
||||||
|
@ -674,7 +680,7 @@ t_stat tmxr_attach (TMXR *mp, UNIT *uptr, char *cptr)
|
||||||
{
|
{
|
||||||
char* tptr;
|
char* tptr;
|
||||||
t_stat r;
|
t_stat r;
|
||||||
char pmsg[20], bmsg[32] = "", lmsg[64+PATH_MAX] = "";
|
char pmsg[256], bmsg[32] = "", lmsg[64+PATH_MAX] = "";
|
||||||
|
|
||||||
tptr = (char *) malloc (strlen (cptr) + /* get string buf */
|
tptr = (char *) malloc (strlen (cptr) + /* get string buf */
|
||||||
sizeof(pmsg) +
|
sizeof(pmsg) +
|
||||||
|
@ -686,7 +692,7 @@ if (r != SCPE_OK) { /* error? */
|
||||||
free (tptr); /* release buf */
|
free (tptr); /* release buf */
|
||||||
return SCPE_OPENERR;
|
return SCPE_OPENERR;
|
||||||
}
|
}
|
||||||
sprintf (pmsg, "%d", mp->port); /* copy port */
|
sprintf (pmsg, "%s", mp->port); /* copy port */
|
||||||
if (mp->buffered)
|
if (mp->buffered)
|
||||||
sprintf (bmsg, ", buffered=%d", mp->buffered); /* buffer info */
|
sprintf (bmsg, ", buffered=%d", mp->buffered); /* buffer info */
|
||||||
if (mp->logfiletmpl[0])
|
if (mp->logfiletmpl[0])
|
||||||
|
@ -772,18 +778,14 @@ void tmxr_fconns (FILE *st, TMLN *lp, int32 ln)
|
||||||
if (ln >= 0)
|
if (ln >= 0)
|
||||||
fprintf (st, "line %d: ", ln);
|
fprintf (st, "line %d: ", ln);
|
||||||
if (lp->conn) {
|
if (lp->conn) {
|
||||||
int32 o1, o2, o3, o4, hr, mn, sc;
|
int32 hr, mn, sc;
|
||||||
uint32 ctime;
|
uint32 ctime;
|
||||||
|
|
||||||
o1 = (lp->ipad >> 24) & 0xFF;
|
|
||||||
o2 = (lp->ipad >> 16) & 0xFF;
|
|
||||||
o3 = (lp->ipad >> 8) & 0xFF;
|
|
||||||
o4 = (lp->ipad) & 0xFF;
|
|
||||||
ctime = (sim_os_msec () - lp->cnms) / 1000;
|
ctime = (sim_os_msec () - lp->cnms) / 1000;
|
||||||
hr = ctime / 3600;
|
hr = ctime / 3600;
|
||||||
mn = (ctime / 60) % 60;
|
mn = (ctime / 60) % 60;
|
||||||
sc = ctime % 60;
|
sc = ctime % 60;
|
||||||
fprintf (st, "IP address %d.%d.%d.%d", o1, o2, o3, o4);
|
fprintf (st, "IP address %s", lp->ipad);
|
||||||
if (ctime)
|
if (ctime)
|
||||||
fprintf (st, ", connected %02d:%02d:%02d\n", hr, mn, sc);
|
fprintf (st, ", connected %02d:%02d:%02d\n", hr, mn, sc);
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,7 +57,7 @@ typedef struct tmxr TMXR;
|
||||||
|
|
||||||
struct tmln {
|
struct tmln {
|
||||||
SOCKET conn; /* line conn */
|
SOCKET conn; /* line conn */
|
||||||
uint32 ipad; /* IP address */
|
char *ipad; /* IP address */
|
||||||
uint32 cnms; /* conn time */
|
uint32 cnms; /* conn time */
|
||||||
int32 tsta; /* Telnet state */
|
int32 tsta; /* Telnet state */
|
||||||
int32 rcve; /* rcv enable */
|
int32 rcve; /* rcv enable */
|
||||||
|
@ -83,7 +83,7 @@ struct tmln {
|
||||||
|
|
||||||
struct tmxr {
|
struct tmxr {
|
||||||
int32 lines; /* # lines */
|
int32 lines; /* # lines */
|
||||||
int32 port; /* listening port */
|
char *port; /* listening port */
|
||||||
SOCKET master; /* master socket */
|
SOCKET master; /* master socket */
|
||||||
TMLN *ldsc; /* line descriptors */
|
TMLN *ldsc; /* line descriptors */
|
||||||
int32 *lnorder; /* line connection order */
|
int32 *lnorder; /* line connection order */
|
||||||
|
|
Loading…
Add table
Reference in a new issue