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:
Mark Pizzolato 2012-09-28 15:34:55 -07:00
parent 6692832785
commit 30ce7fdbaa
11 changed files with 686 additions and 311 deletions

View file

@ -150,36 +150,33 @@ static t_stat net_reset(DEVICE *dptr) {
}
static t_stat net_attach(UNIT *uptr, char *cptr) {
uint32 i, ipa, ipp;
t_stat r = get_ipaddr(cptr, &ipa, &ipp);
uint32 i;
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)
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);
for (i = 0; i <= MAX_CONNECTIONS; i++)
serviceDescriptor[i].ioSocket = 0;
if (net_unit.flags & UNIT_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)
return SCPE_IOERR;
}
else {
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)
return SCPE_IOERR;
}
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)
return SCPE_MEM;
strncpy(net_unit.filename, cptr, CBUFSIZE); /* save name */
strcpy(net_unit.filename, cptr); /* save name */
return SCPE_OK;
}
@ -216,7 +213,7 @@ static t_stat net_svc(UNIT *uptr) {
}
}
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)
return SCPE_IOERR;
printf("\rWaiting for server ... Type g<return> (possibly twice) when ready" NLP);

View file

@ -570,56 +570,56 @@ return SCPE_OK;
t_stat ipl_attach (UNIT *uptr, char *cptr)
{
SOCKET newsock;
uint32 i, t, ipa, ipp, oldf;
char *tptr;
uint32 i, t, oldf;
char host[CBUFSIZE], port[CBUFSIZE], hostport[2*CBUFSIZE+3];
char *tptr = NULL;
t_stat r;
r = get_ipaddr (cptr, &ipa, &ipp);
if ((r != SCPE_OK) || (ipp == 0))
return SCPE_ARG;
oldf = uptr->flags;
if (oldf & UNIT_ATT)
ipl_detach (uptr);
if ((sim_switches & SWMASK ('C')) ||
((sim_switches & SIM_SW_REST) && (oldf & UNIT_ACTV))) {
if (ipa == 0)
ipa = 0x7F000001;
newsock = sim_connect_sock (ipa, ipp);
r = sim_parse_addr (cptr, host, sizeof(host), "localhost", port, sizeof(port), NULL);
if ((r != SCPE_OK) || (port[0] == '\0'))
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)
return SCPE_IOERR;
printf ("Connecting to IP address %d.%d.%d.%d, port %d\n",
(ipa >> 24) & 0xff, (ipa >> 16) & 0xff,
(ipa >> 8) & 0xff, ipa & 0xff, ipp);
printf ("Connecting to %s\n", hostport);
if (sim_log)
fprintf (sim_log,
"Connecting to IP address %d.%d.%d.%d, port %d\n",
(ipa >> 24) & 0xff, (ipa >> 16) & 0xff,
(ipa >> 8) & 0xff, ipa & 0xff, ipp);
"Connecting to %s\n", hostport);
uptr->flags = uptr->flags | UNIT_ACTV;
uptr->LSOCKET = 0;
uptr->DSOCKET = newsock;
}
else {
if (ipa != 0)
r = sim_parse_addr (cptr, host, sizeof(host), NULL, port, sizeof(port), NULL);
if (r != SCPE_OK)
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)
return SCPE_IOERR;
printf ("Listening on port %d\n", ipp);
printf ("Listening on port %s\n", hostport);
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->LSOCKET = newsock;
uptr->DSOCKET = 0;
}
uptr->IBUF = uptr->OBUF = 0;
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? */
ipl_detach (uptr); /* close sockets */
return SCPE_MEM;
}
strcpy (tptr, cptr); /* copy ipaddr:port */
strcpy (tptr, hostport); /* copy ipaddr:port */
uptr->filename = tptr; /* save */
sim_activate (uptr, POLL_FIRST); /* activate first poll "immediately" */
if (sim_switches & SWMASK ('W')) { /* wait? */

View file

@ -85,9 +85,6 @@
#include "ibm1130_defs.h"
#include "sim_sock.h" /* include path must include main simh directory */
#include <ctype.h>
#ifndef INADDR_NONE
#define INADDR_NONE ((unsigned long)-1)
#endif
#define DEBUG_SCA_FLUSH 0x0001 /* debugging options */
#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_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 */
@ -164,7 +161,7 @@ static uint32 sca_state = SCA_STATE_IDLE;
static uint8 sichar = 0; /* sync/idle character */
static uint8 rcvd_char = 0; /* most recently received character */
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 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 */
@ -221,7 +218,7 @@ REG sca_reg[] = { /* DEVICE STATE/SETTABLE PARAMETERS: */
{ DRDATA (SCASTATE, sca_state, 32), PV_LEFT }, /* current state */
{ 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 (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 */
{ NULL } };
@ -317,7 +314,7 @@ static void sca_socket_error (void)
free(sca_unit.filename);
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);
printf("%s\n", name);
}
@ -454,39 +451,39 @@ static t_stat sca_reset (DEVICE *dptr)
static t_stat sca_attach (UNIT *uptr, char *cptr)
{
char host[CBUFSIZE], port[CBUFSIZE];
t_bool do_listen;
char *colon;
uint32 ipaddr;
int32 port;
struct hostent *he;
char name[256];
static SOCKET sdummy = INVALID_SOCKET;
fd_set wr_set, err_set;
char name[CBUFSIZE];
t_stat r;
do_listen = sim_switches & SWMASK('L'); /* -l means listen mode */
if (sca_unit.flags & UNIT_ATT) /* if already attached, detach */
detach_unit(&sca_unit);
if (do_listen) { /* if listen mode, string specifies socket number (only; otherwise it's a dummy argument) */
if (isdigit(*cptr)) { /* if digits specified, extract port number */
port = atoi(cptr);
if (port <= 0 || port > 65535)
return SCPE_ARG;
else
sca_port = port;
}
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);
if (r != SCPE_OK)
return r;
if ((0 == strcmp(port, cptr)) && (0 == strcmp(port, "dummy")))
strcpy(port, SCA_DEFAULT_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 */
/* 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;
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);
printf("%s\n", name);
printf("%s\n", sca_unit.filename);
}
else {
@ -496,57 +493,33 @@ static t_stat sca_attach (UNIT *uptr, char *cptr)
if (! *cptr)
return SCPE_2FARG;
if ((colon = strchr(cptr, ':')) != NULL) {
*colon++ = '\0'; /* clip hostname at colon */
port = atoi(colon); /* extract port number that follows it */
if (port <= 0 || port > 65535)
return SCPE_ARG;
else
sca_port = port;
r = sim_parse_addr (cptr, host, sizeof(host), NULL, port, sizeof(port), SCA_DEFAULT_PORT);
if (r != SCPE_OK)
return r;
if ((0 == strcmp(cptr, port)) && (0 == strcmp(host, ""))) {
strcpy(host, port);
strcpy(port, SCA_DEFAULT_PORT);
}
if (sdummy == 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 */
sprintf(sca_port, "%s%s%s:%s", strchr(host, ':') ? "[" : "", host, strchr(host, ':') ? "]" : "", port);
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)
if ((sca_sock = sim_connect_sock(sca_port, NULL, NULL)) == INVALID_SOCKET)
return SCPE_OPENERR;
/* 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
* 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 */
FD_ZERO(&err_set);
FD_SET(sca_sock, &wr_set);
FD_SET(sca_sock, &err_set);
while (0 == sim_check_conn(sca_sock, 0))/* wait for connection to complete or fail */
sim_os_ms_sleep(1000);
select(3, NULL, &wr_set, &err_set, NULL); /* wait for connection to complete or fail */
if (FD_ISSET(sca_sock, &wr_set)) { /* sca_sock appears in "writable" set -- connect completed */
sprintf(name, "%s:%d", cptr, sca_port);
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);
sca_unit.filename = mstring(name);
SETBIT(sca_dsw, SCA_DSW_READY);
}
else if (FD_ISSET(sca_sock, &err_set)) { /* 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");
else { /* sca_sock appears in "error" set -- connect failed */
sim_close_sock(sca_sock, TRUE);
sca_sock = INVALID_SOCKET;
return SCPE_OPENERR;
@ -610,22 +583,17 @@ static t_stat sca_detach (UNIT *uptr)
static void sca_check_connect (void)
{
uint32 ipaddr;
char name[100];
char *connectaddress;
if ((sca_sock = sim_accept_conn(sca_lsock, &ipaddr)) == INVALID_SOCKET)
if ((sca_sock = sim_accept_conn(sca_lsock, &connectaddress)) == INVALID_SOCKET)
return;
ipaddr = htonl(ipaddr); /* convert to network order so we can print it */
sprintf(name, "%d.%d.%d.%d", ipaddr & 0xFF, (ipaddr >> 8) & 0xFF, (ipaddr >> 16) & 0xFF, (ipaddr >> 24) & 0xFF);
printf("(SCA connection from %s)\n", name);
printf("(SCA connection from %s)\n", connectaddress);
if (sca_unit.filename != NULL)
free(sca_unit.filename);
sca_unit.filename = mstring(name);
sca_unit.filename = connectaddress;
SETBIT(sca_dsw, SCA_DSW_READY); /* indicate active connection */

66
scp.c
View file

@ -216,6 +216,7 @@
#include "sim_defs.h"
#include "sim_rev.h"
#include "sim_ether.h"
#include "sim_sock.h"
#include <signal.h>
#include <ctype.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_on_inherit = sim_switches & SWMASK ('O'); /* -o means inherit on state */
sim_init_sock (); /* init socket capabilities */
AIO_INIT; /* init Asynch I/O */
if (sim_vm_init != NULL) /* call once only */
(*sim_vm_init)();
@ -899,6 +901,7 @@ sim_set_logoff (0, NULL); /* close log */
sim_set_notelnet (0, NULL); /* close Telnet */
sim_ttclose (); /* close console */
AIO_CLEANUP; /* Asynch I/O */
sim_cleanup_sock (); /* cleanup sockets */
return 0;
}
@ -4574,69 +4577,6 @@ if (term && (*tptr++ != term))
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
Inputs:

1
scp.h
View file

@ -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);
char *get_range (DEVICE *dptr, char *cptr, t_addr *lo, t_addr *hi,
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_stat fprint_val (FILE *stream, t_value val, uint32 rdx, uint32 wid, uint32 fmt);
CTAB *find_cmd (char *gbuf);

View file

@ -428,18 +428,20 @@ while (*cptr != 0) { /* do all mods */
if ((cvptr = strchr (gbuf, '='))) /* = value? */
*cvptr++ = 0;
get_glyph (gbuf, gbuf, 0); /* modifier to UC */
if (isdigit (*gbuf)) {
if (sim_con_tmxr.master) /* already open? */
sim_set_notelnet (0, NULL); /* close first */
return tmxr_open_master (&sim_con_tmxr, gbuf); /* open master socket */
}
else
if ((ctptr = find_ctab (set_con_telnet_tab, gbuf))) { /* match? */
r = ctptr->action (ctptr->arg, cvptr); /* do the rest */
if (r != SCPE_OK)
return r;
}
else return SCPE_NOPARAM;
else {
r = sim_parse_addr (gbuf, NULL, 0, NULL, NULL, 0, NULL);
if (r == SCPE_OK) {
if (sim_con_tmxr.master) /* already open? */
sim_set_notelnet (0, NULL); /* close first */
return tmxr_open_master (&sim_con_tmxr, gbuf); /* open master socket */
}
return SCPE_NOPARAM;
}
}
return SCPE_OK;
}
@ -465,9 +467,9 @@ if (sim_con_tmxr.master == 0)
fprintf (st, "Connected to console window\n");
else {
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 {
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);
tmxr_fconns (st, &sim_con_ldsc, -1);
}

View file

@ -942,7 +942,7 @@ static char* (*p_pcap_lib_version) (void);
/* load function pointer from DLL */
typedef int (*_func)();
void load_function(char* function, _func* func_ptr) {
static void load_function(char* function, _func* func_ptr) {
#ifdef _WIN32
*func_ptr = (_func)GetProcAddress(hLib, function);
#else

View file

@ -23,6 +23,7 @@
used in advertising or otherwise to promote the sale, use or other dealings
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)
19-Nov-05 RMS Added conditional for OpenBSD (from Federico G. Schwindt)
16-Aug-05 RMS Fixed spurious SIGPIPE signal error in Unix
@ -43,6 +44,24 @@
#include "sim_sock.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
sim_master_sock create master socket
@ -54,23 +73,118 @@
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 */
#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;
}
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;
}
SOCKET sim_accept_conn (SOCKET master, uint32 *ipaddr)
SOCKET sim_accept_conn (SOCKET master, char **connectaddr);
{
return INVALID_SOCKET;
}
@ -90,11 +204,6 @@ void sim_close_sock (SOCKET sock, t_bool master)
return;
}
int32 sim_setnonblock (SOCKET sock)
{
return SOCKET_ERROR;
}
#else /* endif unimpl */
/* UNIX, Win32, Macintosh, VMS, OS2 (Berkeley socket) routines */
@ -108,30 +217,383 @@ sim_close_sock (s, flg);
return INVALID_SOCKET;
}
SOCKET sim_create_sock (void)
{
SOCKET newsock;
int32 err;
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)
{
struct addrinfo *a, *an;
for (a=ai; a != NULL; a=an) {
an = a->ai_next;
free (a->ai_canonname);
free (a->ai_addr);
free (a);
}
}
static int WSAAPI s_getaddrinfo (const char *hostname,
const char *service,
const struct addrinfo *hints,
struct addrinfo **res)
{
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;
}
}
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 (1, 1);
wVersionRequested = MAKEWORD (2, 2);
if (sim_sock_cnt == 0) {
err = WSAStartup (wVersionRequested, &wsaData); /* start Winsock */
if (err != 0) {
if (err != 0)
printf ("Winsock: startup error %d\n", err);
return INVALID_SOCKET;
}
}
sim_sock_cnt = sim_sock_cnt + 1;
#if defined(AF_INET6)
load_ws2 ();
#endif /* endif AF_INET6 */
#endif /* endif Win32 */
#if defined (SIGPIPE)
signal (SIGPIPE, SIG_IGN); /* no pipe signals */
#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? */
err = WSAGetLastError ();
printf ("Sockets: socket error %d\n", err);
@ -140,21 +602,49 @@ if (newsock == INVALID_SOCKET) { /* socket error? */
return newsock;
}
SOCKET sim_master_sock (int32 port)
{
SOCKET newsock;
struct sockaddr_in name;
int32 sta;
/*
Some platforms and/or network stacks have varying support for listening on
an IPv6 socket and receiving connections from both IPv4 and IPv6 client
connections. This is known as IPv4-Mapped. Some platforms claim such
support (i.e. some Windows versions), but it doesn't work in all cases.
*/
newsock = sim_create_sock (); /* create socket */
if (newsock == INVALID_SOCKET) /* socket error? */
SOCKET sim_master_sock (const char *hostport, t_stat *parse_status)
{
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;
name.sin_family = AF_INET; /* name socket */
name.sin_port = htons ((unsigned short) port); /* insert port */
name.sin_addr.s_addr = htonl (INADDR_ANY); /* insert addr */
sta = bind (newsock, (struct sockaddr *) &name, sizeof (name));
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_PASSIVE;
hints.ai_family = AF_UNSPEC;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_socktype = SOCK_STREAM;
if (p_getaddrinfo(host[0] ? host : NULL, port[0] ? port : NULL, &hints, &result)) {
if (parse_status)
*parse_status = SCPE_ARG;
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? */
return sim_err_sock (newsock, "bind", 1);
sta = sim_setnonblock (newsock); /* set nonblocking */
@ -166,24 +656,38 @@ if (sta == SOCKET_ERROR) /* listen error? */
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;
struct sockaddr_in name;
SOCKET newsock = INVALID_SOCKET;
int32 sta;
char host[CBUFSIZE], port[CBUFSIZE];
t_stat r;
struct addrinfo hints;
struct addrinfo *result = NULL;
newsock = sim_create_sock (); /* create socket */
if (newsock == INVALID_SOCKET) /* socket error? */
r = sim_parse_addr (hostport, host, sizeof(host), default_host, port, sizeof(port), default_port);
if (r != SCPE_OK)
return newsock;
name.sin_family = AF_INET; /* name socket */
name.sin_port = htons ((unsigned short) port); /* insert port */
name.sin_addr.s_addr = htonl (ip); /* insert addr */
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
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 */
if (sta == SOCKET_ERROR) /* fcntl error? */
if (sta == SOCKET_ERROR) { /* fcntl error? */
p_freeaddrinfo (result);
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) &&
(WSAGetLastError () != WSAEWOULDBLOCK) &&
(WSAGetLastError () != WSAEINPROGRESS))
@ -192,7 +696,7 @@ if ((sta == SOCKET_ERROR) &&
return newsock; /* got it! */
}
SOCKET sim_accept_conn (SOCKET master, uint32 *ipaddr)
SOCKET sim_accept_conn (SOCKET master, char **connectaddr)
{
int32 sta, err;
#if defined (macintosh) || defined (__linux) || \
@ -206,11 +710,12 @@ int size;
size_t size;
#endif
SOCKET newsock;
struct sockaddr_in clientname;
struct sockaddr_storage clientname;
if (master == 0) /* not attached? */
return INVALID_SOCKET;
size = sizeof (clientname);
memset (&clientname, 0, sizeof(clientname));
newsock = accept (master, (struct sockaddr *) &clientname, &size);
if (newsock == INVALID_SOCKET) { /* error? */
err = WSAGetLastError ();
@ -218,8 +723,14 @@ if (newsock == INVALID_SOCKET) { /* error? */
printf ("Sockets: accept error %d\n", err);
return INVALID_SOCKET;
}
if (ipaddr != NULL)
*ipaddr = ntohl (clientname.sin_addr.s_addr);
if (connectaddr != NULL) {
*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 */
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)
{
#if defined (_WIN32)
shutdown(sock, SD_BOTH);
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 */

View file

@ -23,6 +23,7 @@
used in advertising or otherwise to promote the sale, use or other dealings
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
14-Apr-05 RMS Added WSAEINPROGRESS (from Tim Riker)
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 */
#define WSAGetLastError() errno /* Windows macros */
#define closesocket close
#define SOCKET int32
#define WSAEWOULDBLOCK EWOULDBLOCK
#define WSAEINPROGRESS EINPROGRESS
#define INVALID_SOCKET -1
#define INVALID_SOCKET ((SOCKET)-1)
#define SOCKET_ERROR -1
#include <sys/types.h> /* for fcntl, getpid */
#include <sys/socket.h> /* for sockets */
#include <fcntl.h>
#include <unistd.h>
#include <netinet/in.h> /* for sockaddr_in */
#include <arpa/inet.h> /* for inet_addr and inet_ntoa */
#include <netdb.h>
#include <sys/time.h> /* for EMX */
#endif
@ -75,14 +78,15 @@
#endif
#endif
SOCKET sim_master_sock (int32 port);
SOCKET sim_connect_sock (int32 ip, int32 port);
SOCKET sim_create_sock (void);
SOCKET sim_accept_conn (SOCKET master, uint32 *ipaddr);
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_master_sock (const char *hostport, t_stat *parse_status);
SOCKET sim_connect_sock (const char *hostport, const char *default_host, const char *default_port);
SOCKET sim_accept_conn (SOCKET master, char **connectaddr);
int32 sim_check_conn (SOCKET sock, t_bool rd);
int32 sim_read_sock (SOCKET sock, char *buf, int32 nbytes);
int32 sim_write_sock (SOCKET sock, char *msg, int32 nbytes);
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

View file

@ -158,7 +158,7 @@ SOCKET newsock;
TMLN *lp;
int32 *op;
int32 i, j, psave;
uint32 ipaddr;
char *address;
char cmsg[80];
char dmsg[80] = "";
char lmsg[80] = "";
@ -171,7 +171,7 @@ static char mantra[] = {
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? */
op = mp->lnorder; /* get line connection order list pointer */
i = mp->lines; /* play it safe in case lines == 0 */
@ -194,7 +194,7 @@ if (newsock != INVALID_SOCKET) { /* got a live one? */
else {
lp = mp->ldsc + i; /* get line desc */
lp->conn = newsock; /* record connection */
lp->ipad = ipaddr; /* ip address */
lp->ipad = address; /* ip address */
lp->mp = mp; /* save mux */
sim_write_sock (newsock, 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);
tmxr_send_buffered_data (lp); /* send buffered data */
sim_close_sock (lp->conn, 0); /* reset conn */
free (lp->ipad);
lp->ipad = NULL;
lp->conn = lp->tsta = 0; /* reset state */
lp->rxbpr = lp->rxbpi = 0;
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)
{
int32 i, port;
int32 i;
SOCKET sock;
TMLN *lp;
t_stat r;
if (!isdigit(*cptr)) {
char gbuf[CBUFSIZE];
char *init_cptr = cptr;
cptr = get_glyph (cptr, gbuf, '=');
if (0 == MATCH_CMD (gbuf, "LOG")) {
if ((NULL == cptr) || ('\0' == *cptr))
@ -638,18 +642,20 @@ if (!isdigit(*cptr)) {
}
return SCPE_OK;
}
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 */
if ((r != SCPE_OK) || (port == 0))
return SCPE_ARG;
sock = sim_master_sock (port); /* make master socket */
sock = sim_master_sock (cptr, &r); /* make master socket */
if (r != SCPE_OK)
return r;
if (sock == INVALID_SOCKET) /* open error */
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)
fprintf (sim_log, "Listening on port %d (socket %d)\n", port, sock);
mp->port = port; /* save port */
fprintf (sim_log, "Listening on port %s (socket %d)\n", cptr, sock);
mp->port = calloc(1, 1+strlen(cptr)); /* save port */
strcpy(mp->port, cptr);
mp->master = sock; /* save master socket */
for (i = 0; i < mp->lines; i++) { /* initialize lines */
lp = mp->ldsc + i;
@ -674,7 +680,7 @@ t_stat tmxr_attach (TMXR *mp, UNIT *uptr, char *cptr)
{
char* tptr;
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 */
sizeof(pmsg) +
@ -686,7 +692,7 @@ if (r != SCPE_OK) { /* error? */
free (tptr); /* release buf */
return SCPE_OPENERR;
}
sprintf (pmsg, "%d", mp->port); /* copy port */
sprintf (pmsg, "%s", mp->port); /* copy port */
if (mp->buffered)
sprintf (bmsg, ", buffered=%d", mp->buffered); /* buffer info */
if (mp->logfiletmpl[0])
@ -772,18 +778,14 @@ void tmxr_fconns (FILE *st, TMLN *lp, int32 ln)
if (ln >= 0)
fprintf (st, "line %d: ", ln);
if (lp->conn) {
int32 o1, o2, o3, o4, hr, mn, sc;
int32 hr, mn, sc;
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;
hr = ctime / 3600;
mn = (ctime / 60) % 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)
fprintf (st, ", connected %02d:%02d:%02d\n", hr, mn, sc);
}

View file

@ -57,7 +57,7 @@ typedef struct tmxr TMXR;
struct tmln {
SOCKET conn; /* line conn */
uint32 ipad; /* IP address */
char *ipad; /* IP address */
uint32 cnms; /* conn time */
int32 tsta; /* Telnet state */
int32 rcve; /* rcv enable */
@ -83,7 +83,7 @@ struct tmln {
struct tmxr {
int32 lines; /* # lines */
int32 port; /* listening port */
char *port; /* listening port */
SOCKET master; /* master socket */
TMLN *ldsc; /* line descriptors */
int32 *lnorder; /* line connection order */