ETHER,VAX,PDP11: Added UDP as a link type for Ethernet packet connectivity.
This will allow a single simulator to directly connect to HECnet systems without needing an external bridge program.
This commit is contained in:
parent
c1aa85d944
commit
834e986eaf
5 changed files with 210 additions and 44 deletions
|
@ -51,6 +51,8 @@ A remote console session will close when an EOF character is entered (i.e. ^D or
|
||||||
when connected to serial ports).
|
when connected to serial ports).
|
||||||
DHU11 (device VH) on Unibus systems now has 16 ports per multiplexer.
|
DHU11 (device VH) on Unibus systems now has 16 ports per multiplexer.
|
||||||
XQ devices (DEQNA, DELQA and DELQA-T) are bootable on Qbus PDP11 simulators
|
XQ devices (DEQNA, DELQA and DELQA-T) are bootable on Qbus PDP11 simulators
|
||||||
|
XQ and XU devices (DEQNA, DELQA, DELQA-T, DEUNA and DELQA) devices can now
|
||||||
|
directly communicate to a remote device via UDP (i.e. a built-in HECnet bridge).
|
||||||
MicroVAX 3900 and MicroVAX II have SET CPU AUTOBOOT option
|
MicroVAX 3900 and MicroVAX II have SET CPU AUTOBOOT option
|
||||||
MicroVAX 3900 has a SET CPU MODEL=(MicroVAX|VAXServer) command to change between system types
|
MicroVAX 3900 has a SET CPU MODEL=(MicroVAX|VAXServer) command to change between system types
|
||||||
MicroVAX I has a SET CPU MODEL=(MicroVAX|VAXSTATION) command to change between system types
|
MicroVAX I has a SET CPU MODEL=(MicroVAX|VAXSTATION) command to change between system types
|
||||||
|
|
167
sim_ether.c
167
sim_ether.c
|
@ -1410,6 +1410,8 @@ static void eth_get_nic_hw_addr(ETH_DEV* dev, char *devname)
|
||||||
{
|
{
|
||||||
memset(&dev->host_nic_phy_hw_addr, 0, sizeof(dev->host_nic_phy_hw_addr));
|
memset(&dev->host_nic_phy_hw_addr, 0, sizeof(dev->host_nic_phy_hw_addr));
|
||||||
dev->have_host_nic_phy_addr = 0;
|
dev->have_host_nic_phy_addr = 0;
|
||||||
|
if (dev->eth_api != ETH_API_PCAP)
|
||||||
|
return;
|
||||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||||
if (!pcap_mac_if_win32(devname, dev->host_nic_phy_hw_addr))
|
if (!pcap_mac_if_win32(devname, dev->host_nic_phy_hw_addr))
|
||||||
dev->have_host_nic_phy_addr = 1;
|
dev->have_host_nic_phy_addr = 1;
|
||||||
|
@ -1426,8 +1428,6 @@ static void eth_get_nic_hw_addr(ETH_DEV* dev, char *devname)
|
||||||
"egrep [0-9a-fA-F]?[0-9a-fA-F]:[0-9a-fA-F]?[0-9a-fA-F]:[0-9a-fA-F]?[0-9a-fA-F]:[0-9a-fA-F]?[0-9a-fA-F]:[0-9a-fA-F]?[0-9a-fA-F]:[0-9a-fA-F]?[0-9a-fA-F]",
|
"egrep [0-9a-fA-F]?[0-9a-fA-F]:[0-9a-fA-F]?[0-9a-fA-F]:[0-9a-fA-F]?[0-9a-fA-F]:[0-9a-fA-F]?[0-9a-fA-F]:[0-9a-fA-F]?[0-9a-fA-F]:[0-9a-fA-F]?[0-9a-fA-F]",
|
||||||
NULL};
|
NULL};
|
||||||
|
|
||||||
if (0 == strncmp("vde:", devname, 4))
|
|
||||||
return;
|
|
||||||
memset(command, 0, sizeof(command));
|
memset(command, 0, sizeof(command));
|
||||||
for (i=0; patterns[i] && (0 == dev->have_host_nic_phy_addr); ++i) {
|
for (i=0; patterns[i] && (0 == dev->have_host_nic_phy_addr); ++i) {
|
||||||
snprintf(command, sizeof(command)-1, "ifconfig %s | %s >NIC.hwaddr", devname, patterns[i]);
|
snprintf(command, sizeof(command)-1, "ifconfig %s | %s >NIC.hwaddr", devname, patterns[i]);
|
||||||
|
@ -1484,12 +1484,12 @@ ETH_DEV* volatile dev = (ETH_DEV*)arg;
|
||||||
int status = 0;
|
int status = 0;
|
||||||
int sched_policy;
|
int sched_policy;
|
||||||
struct sched_param sched_priority;
|
struct sched_param sched_priority;
|
||||||
#if defined (_WIN32)
|
|
||||||
HANDLE hWait = pcap_getevent ((pcap_t*)dev->handle);
|
|
||||||
#else
|
|
||||||
int sel_ret;
|
int sel_ret;
|
||||||
int do_select = 0;
|
int do_select = 0;
|
||||||
int select_fd = 0;
|
SOCKET select_fd = 0;
|
||||||
|
#if defined (_WIN32)
|
||||||
|
HANDLE hWait = (dev->eth_api == ETH_API_PCAP) ? pcap_getevent ((pcap_t*)dev->handle) : NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
switch (dev->eth_api) {
|
switch (dev->eth_api) {
|
||||||
case ETH_API_PCAP:
|
case ETH_API_PCAP:
|
||||||
|
@ -1500,11 +1500,11 @@ switch (dev->eth_api) {
|
||||||
break;
|
break;
|
||||||
case ETH_API_TAP:
|
case ETH_API_TAP:
|
||||||
case ETH_API_VDE:
|
case ETH_API_VDE:
|
||||||
|
case ETH_API_UDP:
|
||||||
do_select = 1;
|
do_select = 1;
|
||||||
select_fd = dev->fd_handle;
|
select_fd = dev->fd_handle;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
sim_debug(dev->dbit, dev->dptr, "Reader Thread Starting\n");
|
sim_debug(dev->dbit, dev->dptr, "Reader Thread Starting\n");
|
||||||
|
|
||||||
|
@ -1515,26 +1515,31 @@ pthread_getschedparam (pthread_self(), &sched_policy, &sched_priority);
|
||||||
++sched_priority.sched_priority;
|
++sched_priority.sched_priority;
|
||||||
pthread_setschedparam (pthread_self(), sched_policy, &sched_priority);
|
pthread_setschedparam (pthread_self(), sched_policy, &sched_priority);
|
||||||
|
|
||||||
while (dev->handle) {
|
while (dev->fd_handle) {
|
||||||
#if defined (_WIN32)
|
#if defined (_WIN32)
|
||||||
if (WAIT_OBJECT_0 == WaitForSingleObject (hWait, 250)) {
|
if (dev->eth_api == ETH_API_PCAP) {
|
||||||
#else
|
if (WAIT_OBJECT_0 == WaitForSingleObject (hWait, 250))
|
||||||
fd_set setl;
|
sel_ret = 1;
|
||||||
struct timeval timeout;
|
|
||||||
|
|
||||||
if (do_select) {
|
|
||||||
FD_ZERO(&setl);
|
|
||||||
FD_SET(select_fd, &setl);
|
|
||||||
timeout.tv_sec = 0;
|
|
||||||
timeout.tv_usec = 250*1000;
|
|
||||||
sel_ret = select(1+select_fd, &setl, NULL, NULL, &timeout);
|
|
||||||
}
|
}
|
||||||
else
|
if (dev->eth_api == ETH_API_UDP)
|
||||||
sel_ret = 1;
|
|
||||||
if (sel_ret < 0 && errno != EINTR) break;
|
|
||||||
if (sel_ret > 0) {
|
|
||||||
#endif /* _WIN32 */
|
#endif /* _WIN32 */
|
||||||
if (!dev->handle)
|
if (1) {
|
||||||
|
fd_set setl;
|
||||||
|
struct timeval timeout;
|
||||||
|
|
||||||
|
if (do_select) {
|
||||||
|
FD_ZERO(&setl);
|
||||||
|
FD_SET(select_fd, &setl);
|
||||||
|
timeout.tv_sec = 0;
|
||||||
|
timeout.tv_usec = 250*1000;
|
||||||
|
sel_ret = select(1+select_fd, &setl, NULL, NULL, &timeout);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
sel_ret = 1;
|
||||||
|
if (sel_ret < 0 && errno != EINTR) break;
|
||||||
|
}
|
||||||
|
if (sel_ret > 0) {
|
||||||
|
if (!dev->fd_handle)
|
||||||
break;
|
break;
|
||||||
/* dispatch read request queue available packets */
|
/* dispatch read request queue available packets */
|
||||||
switch (dev->eth_api) {
|
switch (dev->eth_api) {
|
||||||
|
@ -1579,6 +1584,23 @@ while (dev->handle) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#endif /* USE_VDE_NETWORK */
|
#endif /* USE_VDE_NETWORK */
|
||||||
|
case ETH_API_UDP:
|
||||||
|
if (1) {
|
||||||
|
struct pcap_pkthdr header;
|
||||||
|
int len;
|
||||||
|
u_char buf[ETH_MAX_JUMBO_FRAME];
|
||||||
|
|
||||||
|
memset(&header, 0, sizeof(header));
|
||||||
|
len = (int)sim_read_sock (select_fd, (char *)buf, (int32)sizeof(buf));
|
||||||
|
if (len > 0) {
|
||||||
|
status = 1;
|
||||||
|
header.caplen = header.len = len;
|
||||||
|
_eth_callback((u_char *)dev, &header, buf);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
status = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if ((status > 0) && (dev->asynch_io)) {
|
if ((status > 0) && (dev->asynch_io)) {
|
||||||
int wakeup_needed;
|
int wakeup_needed;
|
||||||
|
@ -1616,7 +1638,7 @@ pthread_setschedparam (pthread_self(), sched_policy, &sched_priority);
|
||||||
sim_debug(dev->dbit, dev->dptr, "Writer Thread Starting\n");
|
sim_debug(dev->dbit, dev->dptr, "Writer Thread Starting\n");
|
||||||
|
|
||||||
pthread_mutex_lock (&dev->writer_lock);
|
pthread_mutex_lock (&dev->writer_lock);
|
||||||
while (dev->handle) {
|
while (dev->fd_handle) {
|
||||||
pthread_cond_wait (&dev->writer_cond, &dev->writer_lock);
|
pthread_cond_wait (&dev->writer_cond, &dev->writer_lock);
|
||||||
while (NULL != (request = dev->write_requests)) {
|
while (NULL != (request = dev->write_requests)) {
|
||||||
/* Pull buffer off request list */
|
/* Pull buffer off request list */
|
||||||
|
@ -1819,17 +1841,48 @@ else
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
strncpy(errbuf, "No support for vde: network devices", sizeof(errbuf)-1);
|
strncpy(errbuf, "No support for vde: network devices", sizeof(errbuf)-1);
|
||||||
#endif /* !defined(__linux) && !defined(USE_BSDTUNTAP) */
|
#endif /* defined(USE_VDE_NETWORK) */
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
dev->handle = (void*) pcap_open_live(savname, bufsz, ETH_PROMISC, PCAP_READ_TIMEOUT, errbuf);
|
if (0 == strncmp("udp:", savname, 4)) {
|
||||||
if (!dev->handle) { /* can't open device */
|
char localport[CBUFSIZE], host[CBUFSIZE], port[CBUFSIZE];
|
||||||
msg = "Eth: pcap_open_live error - %s\r\n";
|
char hostport[2*CBUFSIZE];
|
||||||
printf (msg, errbuf);
|
|
||||||
if (sim_log) fprintf (sim_log, msg, errbuf);
|
if (!strcmp(savname, "udp:sourceport:remotehost:remoteport")) {
|
||||||
return SCPE_OPENERR;
|
msg = "Eth: Must specify actual udp host and ports(i.e. udp:1224:somehost.com:2234)\r\n";
|
||||||
|
printf (msg, errbuf);
|
||||||
|
if (sim_log) fprintf (sim_log, msg, errbuf);
|
||||||
|
return SCPE_OPENERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SCPE_OK != sim_parse_addr_ex (savname+4, host, sizeof(host), "localhost", port, sizeof(port), localport, sizeof(localport), NULL))
|
||||||
|
return SCPE_OPENERR;
|
||||||
|
|
||||||
|
if (localport[0] == '\0')
|
||||||
|
strcpy (localport, port);
|
||||||
|
sprintf (hostport, "%s:%s", host, port);
|
||||||
|
if ((SCPE_OK == sim_parse_addr (hostport, NULL, 0, NULL, NULL, 0, NULL, "localhost")) &&
|
||||||
|
(0 == strcmp (localport, port))) {
|
||||||
|
msg = "Eth: Must specify different udp localhost ports\r\n";
|
||||||
|
printf (msg, errbuf);
|
||||||
|
if (sim_log) fprintf (sim_log, msg, errbuf);
|
||||||
|
return SCPE_OPENERR;
|
||||||
|
}
|
||||||
|
dev->fd_handle = sim_connect_sock_ex (localport, hostport, NULL, NULL, TRUE);
|
||||||
|
if (INVALID_SOCKET == dev->fd_handle)
|
||||||
|
return SCPE_OPENERR;
|
||||||
|
dev->eth_api = ETH_API_UDP;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dev->handle = (void*) pcap_open_live(savname, bufsz, ETH_PROMISC, PCAP_READ_TIMEOUT, errbuf);
|
||||||
|
if (!dev->handle) { /* can't open device */
|
||||||
|
msg = "Eth: pcap_open_live error - %s\r\n";
|
||||||
|
printf (msg, errbuf);
|
||||||
|
if (sim_log) fprintf (sim_log, msg, errbuf);
|
||||||
|
return SCPE_OPENERR;
|
||||||
|
}
|
||||||
|
dev->eth_api = ETH_API_PCAP;
|
||||||
}
|
}
|
||||||
dev->eth_api = ETH_API_PCAP;
|
|
||||||
}
|
}
|
||||||
if (errbuf[0]) {
|
if (errbuf[0]) {
|
||||||
msg = "Eth: open error - %s\r\n";
|
msg = "Eth: open error - %s\r\n";
|
||||||
|
@ -1866,7 +1919,8 @@ if (1) {
|
||||||
pthread_attr_t attr;
|
pthread_attr_t attr;
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
pcap_setmintocopy (dev->handle, 0);
|
if (dev->eth_api == ETH_API_PCAP)
|
||||||
|
pcap_setmintocopy (dev->handle, 0);
|
||||||
#endif
|
#endif
|
||||||
ethq_init (&dev->read_queue, 200); /* initialize FIFO queue */
|
ethq_init (&dev->read_queue, 200); /* initialize FIFO queue */
|
||||||
pthread_mutex_init (&dev->lock, NULL);
|
pthread_mutex_init (&dev->lock, NULL);
|
||||||
|
@ -1918,7 +1972,7 @@ t_stat eth_close(ETH_DEV* dev)
|
||||||
{
|
{
|
||||||
char* msg = "Eth: closed %s\r\n";
|
char* msg = "Eth: closed %s\r\n";
|
||||||
pcap_t *pcap;
|
pcap_t *pcap;
|
||||||
int pcap_fd;
|
SOCKET pcap_fd;
|
||||||
|
|
||||||
/* make sure device exists */
|
/* make sure device exists */
|
||||||
if (!dev) return SCPE_UNATT;
|
if (!dev) return SCPE_UNATT;
|
||||||
|
@ -1965,6 +2019,14 @@ switch (dev->eth_api) {
|
||||||
case ETH_API_VDE:
|
case ETH_API_VDE:
|
||||||
vde_close((VDECONN*)pcap);
|
vde_close((VDECONN*)pcap);
|
||||||
break;
|
break;
|
||||||
|
#endif
|
||||||
|
case ETH_API_UDP:
|
||||||
|
sim_close_sock(pcap_fd, TRUE);
|
||||||
|
break;
|
||||||
|
#ifdef USE_SLIRP_NETWORK
|
||||||
|
case ETH_API_NAT:
|
||||||
|
vde_close((VDECONN*)pcap);
|
||||||
|
break;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
printf (msg, dev->name);
|
printf (msg, dev->name);
|
||||||
|
@ -2178,6 +2240,9 @@ if ((packet->len >= ETH_MIN_PACKET) && (packet->len <= ETH_MAX_PACKET)) {
|
||||||
status = 1;
|
status = 1;
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
case ETH_API_UDP:
|
||||||
|
status = (((int32)packet->len == sim_write_sock (dev->fd_handle, (char *)packet->msg, (int32)packet->len)) ? 0 : -1);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
++dev->packets_sent; /* basic bookkeeping */
|
++dev->packets_sent; /* basic bookkeeping */
|
||||||
/* On error, correct loopback bookkeeping */
|
/* On error, correct loopback bookkeeping */
|
||||||
|
@ -2721,6 +2786,7 @@ switch (dev->eth_api) {
|
||||||
#endif /* USE_BPF */
|
#endif /* USE_BPF */
|
||||||
case ETH_API_TAP:
|
case ETH_API_TAP:
|
||||||
case ETH_API_VDE:
|
case ETH_API_VDE:
|
||||||
|
case ETH_API_UDP:
|
||||||
bpf_used = 0;
|
bpf_used = 0;
|
||||||
to_me = 0;
|
to_me = 0;
|
||||||
eth_packet_trace (dev, data, header->len, "received");
|
eth_packet_trace (dev, data, header->len, "received");
|
||||||
|
@ -2902,6 +2968,23 @@ do {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#endif /* USE_VDE_NETWORK */
|
#endif /* USE_VDE_NETWORK */
|
||||||
|
case ETH_API_UDP:
|
||||||
|
if (1) {
|
||||||
|
struct pcap_pkthdr header;
|
||||||
|
int len;
|
||||||
|
u_char buf[ETH_MAX_JUMBO_FRAME];
|
||||||
|
|
||||||
|
memset(&header, 0, sizeof(header));
|
||||||
|
len = (int)sim_read_sock (dev->fd_handle, buf, (int32)sizeof(buf));
|
||||||
|
if (len > 0) {
|
||||||
|
status = 1;
|
||||||
|
header.caplen = header.len = len;
|
||||||
|
_eth_callback((u_char *)dev, &header, buf);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
status = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} while ((status) && (0 == packet->len));
|
} while ((status) && (0 == packet->len));
|
||||||
|
|
||||||
|
@ -3225,6 +3308,20 @@ if (used < max) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (used < max) {
|
||||||
|
sprintf(list[used].name, "%s", "udp:sourceport:remotehost:remoteport");
|
||||||
|
sprintf(list[used].desc, "%s", "Integrated UDP bridge support");
|
||||||
|
++used;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USE_SLIRP_NETWORK
|
||||||
|
if (used < max) {
|
||||||
|
sprintf(list[used].name, "%s", "nat:device");
|
||||||
|
sprintf(list[used].desc, "%s", "Integrated User Mode NAT support");
|
||||||
|
++used;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return used;
|
return used;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -67,6 +67,7 @@
|
||||||
#define SIM_ETHER_H
|
#define SIM_ETHER_H
|
||||||
|
|
||||||
#include "sim_defs.h"
|
#include "sim_defs.h"
|
||||||
|
#include "sim_sock.h"
|
||||||
|
|
||||||
/* make common BSD code a bit easier to read in this file */
|
/* make common BSD code a bit easier to read in this file */
|
||||||
/* OS/X seems to define and compile using one of these BSD types */
|
/* OS/X seems to define and compile using one of these BSD types */
|
||||||
|
@ -212,11 +213,13 @@ typedef struct eth_item ETH_ITEM;
|
||||||
struct eth_device {
|
struct eth_device {
|
||||||
char* name; /* name of ethernet device */
|
char* name; /* name of ethernet device */
|
||||||
void* handle; /* handle of implementation-specific device */
|
void* handle; /* handle of implementation-specific device */
|
||||||
int fd_handle; /* fd to kernel device (where needed) */
|
SOCKET fd_handle; /* fd to kernel device (where needed) */
|
||||||
int eth_api; /* Designator for which API is being used to move packets */
|
int eth_api; /* Designator for which API is being used to move packets */
|
||||||
#define ETH_API_PCAP 0 /* Pcap API in use */
|
#define ETH_API_PCAP 0 /* Pcap API in use */
|
||||||
#define ETH_API_TAP 1 /* tun/tap API in use */
|
#define ETH_API_TAP 1 /* tun/tap API in use */
|
||||||
#define ETH_API_VDE 2 /* VDE API in use */
|
#define ETH_API_VDE 2 /* VDE API in use */
|
||||||
|
#define ETH_API_UDP 3 /* UDP API in use */
|
||||||
|
#define ETH_API_NAT 4 /* NAT (SLiRP) API in use */
|
||||||
ETH_PCALLBACK read_callback; /* read callback function */
|
ETH_PCALLBACK read_callback; /* read callback function */
|
||||||
ETH_PCALLBACK write_callback; /* write callback function */
|
ETH_PCALLBACK write_callback; /* write callback function */
|
||||||
ETH_PACK* read_packet; /* read packet */
|
ETH_PACK* read_packet; /* read packet */
|
||||||
|
|
79
sim_sock.c
79
sim_sock.c
|
@ -551,12 +551,19 @@ char *hostp, *portp;
|
||||||
char *endc;
|
char *endc;
|
||||||
unsigned long portval;
|
unsigned long portval;
|
||||||
|
|
||||||
if ((cptr == NULL) || (*cptr == 0))
|
|
||||||
return SCPE_ARG;
|
|
||||||
if ((host != NULL) && (host_len != 0))
|
if ((host != NULL) && (host_len != 0))
|
||||||
memset (host, 0, host_len);
|
memset (host, 0, host_len);
|
||||||
if ((port != NULL) && (port_len != 0))
|
if ((port != NULL) && (port_len != 0))
|
||||||
memset (port, 0, port_len);
|
memset (port, 0, port_len);
|
||||||
|
if ((cptr == NULL) || (*cptr == 0)) {
|
||||||
|
if (((default_host == NULL) || (*default_host == 0)) && ((default_port == NULL) || (*default_port == 0)))
|
||||||
|
return SCPE_ARG;
|
||||||
|
if ((strlen(default_host) >= host_len) || (strlen(default_port) >= port_len))
|
||||||
|
return SCPE_ARG; /* no room */
|
||||||
|
strcpy (host, default_host);
|
||||||
|
strcpy (port, default_port);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
gbuf[sizeof(gbuf)-1] = '\0';
|
gbuf[sizeof(gbuf)-1] = '\0';
|
||||||
strncpy (gbuf, cptr, sizeof(gbuf)-1);
|
strncpy (gbuf, cptr, sizeof(gbuf)-1);
|
||||||
hostp = gbuf; /* default addr */
|
hostp = gbuf; /* default addr */
|
||||||
|
@ -622,7 +629,7 @@ if (host) { /* host wanted? */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (validate_addr) {
|
if (validate_addr) {
|
||||||
struct addrinfo *ai_host, *ai_validate, *ai;
|
struct addrinfo *ai_host, *ai_validate, *ai, *aiv;
|
||||||
t_stat status;
|
t_stat status;
|
||||||
|
|
||||||
if (hostp == NULL)
|
if (hostp == NULL)
|
||||||
|
@ -635,11 +642,13 @@ if (validate_addr) {
|
||||||
}
|
}
|
||||||
status = SCPE_ARG;
|
status = SCPE_ARG;
|
||||||
for (ai = ai_host; ai != NULL; ai = ai->ai_next) {
|
for (ai = ai_host; ai != NULL; ai = ai->ai_next) {
|
||||||
if ((ai->ai_addrlen == ai_validate->ai_addrlen) &&
|
for (aiv = ai_validate; aiv != NULL; aiv = aiv->ai_next) {
|
||||||
(ai->ai_family == ai_validate->ai_family) &&
|
if ((ai->ai_addrlen == aiv->ai_addrlen) &&
|
||||||
(0 == memcmp (ai->ai_addr, ai_validate->ai_addr, ai->ai_addrlen))) {
|
(ai->ai_family == aiv->ai_family) &&
|
||||||
status = SCPE_OK;
|
(0 == memcmp (ai->ai_addr, aiv->ai_addr, ai->ai_addrlen))) {
|
||||||
break;
|
status = SCPE_OK;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (status != SCPE_OK) {
|
if (status != SCPE_OK) {
|
||||||
|
@ -657,6 +666,60 @@ if (validate_addr) {
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* sim_parse_addr_ex localport: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)
|
||||||
|
|
||||||
|
llll:w.x.y.z:rrrr
|
||||||
|
llll:name.domain.com:rrrr
|
||||||
|
llll::rrrr
|
||||||
|
rrrr
|
||||||
|
w.x.y.z:rrrr
|
||||||
|
[w.x.y.z]:rrrr
|
||||||
|
name.domain.com:rrrr
|
||||||
|
|
||||||
|
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 port 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
|
||||||
|
localport
|
||||||
|
= pointer to buffer for local IP port (may be NULL), 0 = none
|
||||||
|
result = status (SCPE_OK on complete success or SCPE_ARG if
|
||||||
|
parsing can't happen due to bad syntax, a value is
|
||||||
|
out of range, a result can't fit into a result buffer,
|
||||||
|
a service name doesn't exist, or a validation name
|
||||||
|
doesn't match the parsed host)
|
||||||
|
*/
|
||||||
|
t_stat sim_parse_addr_ex (const char *cptr, char *host, size_t hostlen, const char *default_host, char *port, size_t port_len, char *localport, size_t localport_len, const char *default_port)
|
||||||
|
{
|
||||||
|
char *hostp;
|
||||||
|
|
||||||
|
if ((localport != NULL) && (localport_len != 0))
|
||||||
|
memset (localport, 0, localport_len);
|
||||||
|
hostp = strchr (cptr, ':');
|
||||||
|
if ((hostp != NULL) && ((hostp[1] == '[') || (NULL != strchr (hostp+1, ':')))) {
|
||||||
|
if ((localport != NULL) && (localport_len != 0)) {
|
||||||
|
localport_len -= 1;
|
||||||
|
if (localport_len > (size_t)(hostp-cptr))
|
||||||
|
localport_len = (size_t)(hostp-cptr);
|
||||||
|
memcpy (localport, cptr, localport_len);
|
||||||
|
}
|
||||||
|
return sim_parse_addr (hostp+1, host, hostlen, default_host, port, port_len, default_port, NULL);
|
||||||
|
}
|
||||||
|
return sim_parse_addr (cptr, host, hostlen, default_host, port, port_len, default_port, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void sim_init_sock (void)
|
void sim_init_sock (void)
|
||||||
{
|
{
|
||||||
#if defined (_WIN32)
|
#if defined (_WIN32)
|
||||||
|
|
|
@ -102,6 +102,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
t_stat sim_parse_addr (const char *cptr, char *host, size_t hostlen, const char *default_host, char *port, size_t port_len, const char *default_port, const char *validate_addr);
|
t_stat sim_parse_addr (const char *cptr, char *host, size_t hostlen, const char *default_host, char *port, size_t port_len, const char *default_port, const char *validate_addr);
|
||||||
|
t_stat sim_parse_addr_ex (const char *cptr, char *host, size_t hostlen, const char *default_host, char *port, size_t port_len, char *localport, size_t local_port_len, const char *default_port);
|
||||||
SOCKET sim_master_sock (const char *hostport, t_stat *parse_status);
|
SOCKET sim_master_sock (const char *hostport, t_stat *parse_status);
|
||||||
SOCKET sim_connect_sock (const char *hostport, const char *default_host, const char *default_port);
|
SOCKET sim_connect_sock (const char *hostport, const char *default_host, const char *default_port);
|
||||||
SOCKET sim_connect_sock_ex (const char *sourcehostport, const char *hostport, const char *default_host, const char *default_port, t_bool datagram);
|
SOCKET sim_connect_sock_ex (const char *sourcehostport, const char *hostport, const char *default_host, const char *default_port, t_bool datagram);
|
||||||
|
|
Loading…
Add table
Reference in a new issue