diff --git a/AltairZ80/altairz80_net.c b/AltairZ80/altairz80_net.c index fa5e5103..1a815486 100644 --- a/AltairZ80/altairz80_net.c +++ b/AltairZ80/altairz80_net.c @@ -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 (possibly twice) when ready" NLP); diff --git a/HP2100/hp2100_ipl.c b/HP2100/hp2100_ipl.c index 32e77f17..d20d0678 100644 --- a/HP2100/hp2100_ipl.c +++ b/HP2100/hp2100_ipl.c @@ -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? */ diff --git a/Ibm1130/ibm1130_sca.c b/Ibm1130/ibm1130_sca.c index b0e8e293..60e850a6 100644 --- a/Ibm1130/ibm1130_sca.c +++ b/Ibm1130/ibm1130_sca.c @@ -85,9 +85,6 @@ #include "ibm1130_defs.h" #include "sim_sock.h" /* include path must include main simh directory */ #include -#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,99 +451,75 @@ 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); - sca_unit.filename = mstring(name); - printf("%s\n", name); + sprintf(name, "(Listening on port %s)", sca_port); + sca_unit.filename = mstring(name); + printf("%s\n", sca_unit.filename); } else { - while (*cptr && *cptr <= ' ') + while (*cptr && *cptr <= ' ') cptr++; if (! *cptr) return SCPE_2FARG; - if ((colon = strchr(cptr, ':')) != NULL) { - *colon++ = '\0'; /* clip hostname at colon */ + 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); + } - port = atoi(colon); /* extract port number that follows it */ - if (port <= 0 || port > 65535) - return SCPE_ARG; - else - sca_port = port; - } + sprintf(sca_port, "%s%s%s:%s", strchr(host, ':') ? "[" : "", host, strchr(host, ':') ? "]" : "", 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 */ - - 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 */ diff --git a/scp.c b/scp.c index 3dcad038..52379d3d 100644 --- a/scp.c +++ b/scp.c @@ -216,6 +216,7 @@ #include "sim_defs.h" #include "sim_rev.h" #include "sim_ether.h" +#include "sim_sock.h" #include #include #include @@ -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: diff --git a/scp.h b/scp.h index 3ee43b97..6b8b2fa6 100644 --- a/scp.h +++ b/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); 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); diff --git a/sim_console.c b/sim_console.c index 956c8cbd..9592214f 100644 --- a/sim_console.c +++ b/sim_console.c @@ -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 */ + 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 - 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 { + 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 */ } - else return SCPE_NOPARAM; + 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); } diff --git a/sim_ether.c b/sim_ether.c index e49d0a5c..44f2433c 100644 --- a/sim_ether.c +++ b/sim_ether.c @@ -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 diff --git a/sim_sock.c b/sim_sock.c index 027f7f1d..980070b6 100644 --- a/sim_sock.c +++ b/sim_sock.c @@ -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 +extern FILE *sim_log; + +#if defined(AF_INET6) && defined(_WIN32) +#include +#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) +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; -int32 err; +struct addrinfo *a, *an; -#if defined (_WIN32) -WORD wVersionRequested; -WSADATA wsaData; -wVersionRequested = MAKEWORD (1, 1); +for (a=ai; a != NULL; a=an) { + an = a->ai_next; + free (a->ai_canonname); + free (a->ai_addr); + free (a); + } +} -if (sim_sock_cnt == 0) { - err = WSAStartup (wVersionRequested, &wsaData); /* start Winsock */ - if (err != 0) { - printf ("Winsock: startup error %d\n", err); - return INVALID_SOCKET; +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; } } -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 */ #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 */ diff --git a/sim_sock.h b/sim_sock.h index d8531cbe..250ac3c8 100644 --- a/sim_sock.h +++ b/sim_sock.h @@ -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 /* for fcntl, getpid */ #include /* for sockets */ #include #include #include /* for sockaddr_in */ +#include /* for inet_addr and inet_ntoa */ #include #include /* 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 diff --git a/sim_tmxr.c b/sim_tmxr.c index 4cb866de..82655d6b 100644 --- a/sim_tmxr.c +++ b/sim_tmxr.c @@ -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; } - 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 */ -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); } diff --git a/sim_tmxr.h b/sim_tmxr.h index 72826a04..f07b752f 100644 --- a/sim_tmxr.h +++ b/sim_tmxr.h @@ -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 */