mirror of
https://github.com/rcornwell/sims.git
synced 2026-01-11 23:52:48 +00:00
SCP: Updated to current.
This commit is contained in:
parent
265a4ae4a2
commit
bb699f3d94
@ -29,7 +29,7 @@ rem
|
||||
rem Everything implicitly requires BUILD to also be set to have
|
||||
rem any meaning, it always gets set.
|
||||
set _X_BUILD=BUILD
|
||||
set _X_REQUIRED_WINDOWS_BUILD=20191221
|
||||
set _X_REQUIRED_WINDOWS_BUILD=20220119
|
||||
call :FindVCVersion _VC_VER
|
||||
|
||||
set _PDB=%~dpn1.pdb
|
||||
|
||||
78
scp.c
78
scp.c
@ -6629,6 +6629,8 @@ if (flag) {
|
||||
char osversion[PATH_MAX+1] = "";
|
||||
char tarversion[PATH_MAX+1] = "";
|
||||
char curlversion[PATH_MAX+1] = "";
|
||||
char wmicpath[PATH_MAX+1] = "";
|
||||
char proc_name[CBUFSIZE] = "";
|
||||
FILE *f;
|
||||
|
||||
if ((f = _popen ("ver", "r"))) {
|
||||
@ -6643,6 +6645,23 @@ if (flag) {
|
||||
fprintf (st, "\n OS: %s", osversion);
|
||||
fprintf (st, "\n Architecture: %s%s%s, Processors: %s", arch, proc_arch3264 ? " on " : "", proc_arch3264 ? proc_arch3264 : "", procs);
|
||||
fprintf (st, "\n Processor Id: %s, Level: %s, Revision: %s", proc_id ? proc_id : "", proc_level ? proc_level : "", proc_rev ? proc_rev : "");
|
||||
strlcpy (wmicpath, sim_get_tool_path ("wmic"), sizeof (wmicpath));
|
||||
if (wmicpath[0]) {
|
||||
strlcat (wmicpath, " cpu get name", sizeof (wmicpath));
|
||||
if ((f = _popen (wmicpath, "r"))) {
|
||||
memset (proc_name, 0, sizeof(proc_name));
|
||||
do {
|
||||
if (NULL == fgets (proc_name, sizeof(proc_name)-1, f))
|
||||
break;
|
||||
sim_trim_endspc (proc_name);
|
||||
if (0 == strcmp (proc_name, "Name")) /* skip header line */
|
||||
memset (proc_name, 0, sizeof (proc_name));
|
||||
} while (proc_name[0] == '\0');
|
||||
_pclose (f);
|
||||
}
|
||||
if (proc_name[0] != '\0')
|
||||
fprintf (st, "\n Processor Name: %s", proc_name);
|
||||
}
|
||||
strlcpy (os_type, "Windows", sizeof (os_type));
|
||||
strlcpy (tarversion, _get_tool_version ("tar"), sizeof (tarversion));
|
||||
if (tarversion[0])
|
||||
@ -6677,6 +6696,41 @@ if (flag) {
|
||||
} while (os_type[0] == '\0');
|
||||
pclose (f);
|
||||
}
|
||||
#if (defined(__linux) || defined(__linux__))
|
||||
if ((f = popen ("lscpu 2>/dev/null | grep 'Model name:'", "r"))) {
|
||||
char proc_name[PATH_MAX+1] = "";
|
||||
|
||||
memset (proc_name, 0, sizeof (proc_name));
|
||||
do {
|
||||
if (NULL == fgets (proc_name, sizeof (proc_name)-1, f))
|
||||
break;
|
||||
sim_trim_endspc (proc_name);
|
||||
if (0 == memcmp ("Model name:", proc_name, 11)) {
|
||||
size_t offset = 11 + strspn (proc_name + 11, " ");
|
||||
memmove (proc_name, &proc_name[offset], 1 + strlen (&proc_name[offset]));
|
||||
}
|
||||
} while (proc_name[0] == '\0');
|
||||
pclose (f);
|
||||
if (proc_name[0] != '\0') {
|
||||
|
||||
fprintf (st, "\n Processor Name: %s", proc_name);
|
||||
}
|
||||
}
|
||||
#elif defined (__APPLE__)
|
||||
if ((f = popen ("sysctl -n machdep.cpu.brand_string 2>/dev/null", "r"))) {
|
||||
char proc_name[PATH_MAX+1] = "";
|
||||
|
||||
memset (proc_name, 0, sizeof (proc_name));
|
||||
do {
|
||||
if (NULL == fgets (proc_name, sizeof (proc_name)-1, f))
|
||||
break;
|
||||
sim_trim_endspc (proc_name);
|
||||
} while (proc_name[0] == '\0');
|
||||
pclose (f);
|
||||
if (proc_name[0] != '\0')
|
||||
fprintf (st, "\n Processor Name: %s", proc_name);
|
||||
}
|
||||
#endif
|
||||
strlcpy (tarversion, _get_tool_version ("tar"), sizeof (tarversion));
|
||||
if (tarversion[0])
|
||||
fprintf (st, "\n tar tool: %s", tarversion);
|
||||
@ -13553,7 +13607,7 @@ static const char *debtab_nomatch = "DEBTAB_NOMATCH";
|
||||
const char *some_match = NULL;
|
||||
int32 offset = 0;
|
||||
|
||||
if (dptr->debflags == 0)
|
||||
if (dptr->debflags == NULL)
|
||||
return debtab_none;
|
||||
|
||||
dbits &= (dptr->dctrl | (uptr ? uptr->dctrl : 0));/* Look for just the bits that matched */
|
||||
@ -13622,6 +13676,8 @@ uint32 value, beforevalue, mask;
|
||||
for (fields=offset=0; bitdefs[fields].name; ++fields) {
|
||||
if (bitdefs[fields].offset == 0xffffffff) /* fixup uninitialized offsets */
|
||||
bitdefs[fields].offset = offset;
|
||||
else
|
||||
offset = bitdefs[fields].offset;
|
||||
offset += bitdefs[fields].width;
|
||||
}
|
||||
for (i = fields-1; i >= 0; i--) { /* print xlation, transition */
|
||||
@ -13677,6 +13733,7 @@ if (sim_deb && dptr && (dptr->dctrl & dbits)) {
|
||||
sim_oline = saved_oline; /* restore original socket */
|
||||
}
|
||||
}
|
||||
|
||||
void sim_debug_bits(uint32 dbits, DEVICE* dptr, BITFIELD* bitdefs,
|
||||
uint32 before, uint32 after, int terminate)
|
||||
{
|
||||
@ -13758,15 +13815,20 @@ char *buf = stackbuf;
|
||||
int32 len;
|
||||
va_list arglist;
|
||||
t_bool inhibit_message = (!sim_show_message || (stat & SCPE_NOMESSAGE));
|
||||
char msg_prefix[32] = "";
|
||||
size_t prefix_len;
|
||||
|
||||
if ((stat == SCPE_OK) && (sim_quiet || (sim_switches & SWMASK ('Q'))))
|
||||
return stat;
|
||||
sprintf (msg_prefix, "%%SIM-%s: ", (stat == SCPE_OK) ? "INFO" : "ERROR");
|
||||
prefix_len = strlen (msg_prefix);
|
||||
while (1) { /* format passed string, args */
|
||||
va_start (arglist, fmt);
|
||||
strlcpy (buf, msg_prefix, bufsize);
|
||||
#if defined(NO_vsnprintf)
|
||||
len = vsprintf (buf, fmt, arglist);
|
||||
len = prefix_len + vsprintf (buf + prefix_len, fmt, arglist);
|
||||
#else /* !defined(NO_vsnprintf) */
|
||||
len = vsnprintf (buf, bufsize-1, fmt, arglist);
|
||||
len = prefix_len + vsnprintf (buf + prefix_len, bufsize - (1 + prefix_len), fmt, arglist);
|
||||
#endif /* NO_vsnprintf */
|
||||
va_end (arglist);
|
||||
|
||||
@ -16294,20 +16356,20 @@ for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {
|
||||
switch (DEV_TYPE(dptr)) {
|
||||
#if defined(USE_SIM_CARD)
|
||||
case DEV_CARD:
|
||||
tstat = sim_card_test (dptr);
|
||||
tstat = sim_card_test (dptr, cptr);
|
||||
break;
|
||||
#endif
|
||||
case DEV_DISK:
|
||||
tstat = sim_disk_test (dptr);
|
||||
tstat = sim_disk_test (dptr, cptr);
|
||||
break;
|
||||
case DEV_ETHER:
|
||||
tstat = sim_ether_test (dptr);
|
||||
tstat = sim_ether_test (dptr, cptr);
|
||||
break;
|
||||
case DEV_TAPE:
|
||||
tstat = sim_tape_test (dptr);
|
||||
tstat = sim_tape_test (dptr, cptr);
|
||||
break;
|
||||
case DEV_MUX:
|
||||
tstat = tmxr_sock_test (dptr);
|
||||
tstat = tmxr_sock_test (dptr, cptr);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
@ -1470,7 +1470,7 @@ return SCPE_OK;
|
||||
|
||||
#include <setjmp.h>
|
||||
|
||||
t_stat sim_card_test (DEVICE *dptr)
|
||||
t_stat sim_card_test (DEVICE *dptr, const char *cptr)
|
||||
{
|
||||
t_stat stat = SCPE_OK;
|
||||
#if defined(USE_SIM_CARD) && defined(SIM_CARD_API) && (SIM_MAJOR > 3)
|
||||
@ -1536,7 +1536,7 @@ t_stat sim_card_attach_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, cons
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat sim_card_test (DEVICE *dptr)
|
||||
t_stat sim_card_test (DEVICE *dptr, const char *cptr)
|
||||
{
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
@ -145,7 +145,7 @@ extern const char sim_ascii_to_six[128]; /* Map 7 bit ASCII to BCD */
|
||||
extern const uint8 sim_parity_table[64]; /* 64 entry odd parity table */
|
||||
|
||||
/* Unit test routine */
|
||||
extern t_stat sim_card_test (DEVICE *dptr);
|
||||
extern t_stat sim_card_test (DEVICE *dptr, const char *cptr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -1898,8 +1898,16 @@ static t_stat sim_set_rem_telnet (int32 flag, CONST char *cptr)
|
||||
t_stat r;
|
||||
|
||||
if (flag) {
|
||||
r = sim_parse_addr (cptr, NULL, 0, NULL, NULL, 0, NULL, NULL);
|
||||
char gbuf[CBUFSIZE];
|
||||
char *cp;
|
||||
|
||||
strlcpy (gbuf, cptr, sizeof (gbuf));
|
||||
if ((cp = strchr (gbuf, ';')))
|
||||
*cp = '\0';
|
||||
r = sim_parse_addr (gbuf, NULL, 0, NULL, NULL, 0, NULL, NULL);
|
||||
if (r == SCPE_OK) {
|
||||
if (cp != NULL)
|
||||
*cp = ';';
|
||||
if (sim_rem_con_tmxr.master) /* already open? */
|
||||
sim_set_rem_telnet (0, NULL); /* close first */
|
||||
if (sim_rem_con_tmxr.lines == 0) /* if no connection limit set */
|
||||
@ -2473,6 +2481,8 @@ while (*cptr != 0) { /* do all mods */
|
||||
return r;
|
||||
}
|
||||
else {
|
||||
if (cvptr) /* if we removed a = sign */
|
||||
*(--cvptr) = '='; /* restore it */
|
||||
if (sim_con_tmxr.master) /* already open? */
|
||||
sim_set_notelnet (0, NULL); /* close first */
|
||||
r = tmxr_attach (&sim_con_tmxr, &sim_con_unit, gbuf);/* open master socket */
|
||||
|
||||
@ -986,6 +986,7 @@ struct MEMFILE {
|
||||
/* Hidden Blob of Data - Only used for SAVE/RESTORE */
|
||||
#define SAVEDATA(nm,loc) \
|
||||
_REGDATANF(#nm,&(loc),0,8,0,1,NULL,NULL,0,sizeof(loc),sizeof(loc),SAVEDATA),(REG_HRO)
|
||||
#define STARTBIT {"", 0x00000000, 0, NULL, NULL} /* Start at beginning bit */
|
||||
#define BIT(nm) {#nm, 0xffffffff, 1, NULL, NULL} /* Single Bit definition */
|
||||
#define BITNC {"", 0xffffffff, 1, NULL, NULL} /* Don't care Bit definition */
|
||||
#define BITF(nm,sz) {#nm, 0xffffffff, sz, NULL, NULL} /* Bit Field definition */
|
||||
@ -1073,6 +1074,7 @@ struct MEMFILE {
|
||||
/* Hidden Blob of Data - Only used for SAVE/RESTORE */
|
||||
#define SAVEDATA(nm,loc) \
|
||||
_REGDATANF("nm",&(loc),0,8,0,1,NULL,NULL,0,sizeof(loc),sizeof(loc)),SAVEDATA),(REG_HRO)
|
||||
#define STARTBIT {"", 0x00000000, 0, NULL, NULL} /* Start at beginning bit */
|
||||
#define BIT(nm) {"nm", 0xffffffff, 1, NULL, NULL} /* Single Bit definition */
|
||||
#define BITNC {"", 0xffffffff, 1, NULL, NULL} /* Don't care Bit definition */
|
||||
#define BITF(nm,sz) {"nm", 0xffffffff, sz, NULL, NULL} /* Bit Field definition */
|
||||
|
||||
881
sim_disk.c
881
sim_disk.c
File diff suppressed because it is too large
Load Diff
14
sim_disk.h
14
sim_disk.h
@ -88,6 +88,18 @@ t_stat sim_disk_attach_ex (UNIT *uptr,
|
||||
int completion_delay, /* Minimum Delay for asynch I/O completion */
|
||||
const char **drivetypes); /* list of drive types (from smallest to largest) */
|
||||
/* to try and fit the container/file system into */
|
||||
t_stat sim_disk_attach_ex2 (UNIT *uptr,
|
||||
const char *cptr,
|
||||
size_t memory_sector_size, /* memory footprint of sector data */
|
||||
size_t xfer_element_size,
|
||||
t_bool dontchangecapac, /* if false just change uptr->capac as needed */
|
||||
uint32 dbit, /* debug bit */
|
||||
const char *dtype, /* drive type */
|
||||
uint32 pdp11tracksize, /* BAD144 track */
|
||||
int completion_delay, /* Minimum Delay for asynch I/O completion */
|
||||
const char **drivetypes, /* list of drive types (from smallest to largest) */
|
||||
/* to try and fit the container/file system into */
|
||||
size_t reserved_sectors); /* Unused sectors beyond the file system */
|
||||
t_stat sim_disk_detach (UNIT *uptr);
|
||||
t_stat sim_disk_attach_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
|
||||
t_stat sim_disk_rdsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectsread, t_seccnt sects);
|
||||
@ -114,7 +126,7 @@ t_bool sim_disk_vhd_support (void);
|
||||
t_bool sim_disk_raw_support (void);
|
||||
void sim_disk_data_trace (UNIT *uptr, const uint8 *data, size_t lba, size_t len, const char* txt, int detail, uint32 reason);
|
||||
t_stat sim_disk_info_cmd (int32 flag, CONST char *ptr);
|
||||
t_stat sim_disk_test (DEVICE *dptr);
|
||||
t_stat sim_disk_test (DEVICE *dptr, const char *cptr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -978,7 +978,7 @@ t_stat eth_show (FILE* st, UNIT* uptr, int32 val, CONST void* desc)
|
||||
}
|
||||
static int _eth_get_system_id (char *buf, size_t buf_size)
|
||||
{memset (buf, 0, buf_size); return 0;}
|
||||
t_stat sim_ether_test (DEVICE *dptr)
|
||||
t_stat sim_ether_test (DEVICE *dptr, const char *cptr)
|
||||
{return SCPE_OK;}
|
||||
#else /* endif unimplemented */
|
||||
|
||||
@ -4472,7 +4472,7 @@ return (errors == 0) ? SCPE_OK : SCPE_IERR;
|
||||
|
||||
#include <setjmp.h>
|
||||
|
||||
t_stat sim_ether_test (DEVICE *dptr)
|
||||
t_stat sim_ether_test (DEVICE *dptr, const char *cptr)
|
||||
{
|
||||
t_stat stat = SCPE_OK;
|
||||
SIM_TEST_INIT;
|
||||
|
||||
@ -387,7 +387,7 @@ void ethq_insert_data(ETH_QUE* que, int32 type, /* insert item into FIFO
|
||||
size_t crc_len, const uint8 *crc_data, int32 status);
|
||||
t_stat ethq_destroy(ETH_QUE* que); /* release FIFO queue */
|
||||
const char *eth_capabilities(void);
|
||||
t_stat sim_ether_test (DEVICE *dptr); /* unit test routine */
|
||||
t_stat sim_ether_test (DEVICE *dptr, const char *cptr); /* unit test routine */
|
||||
|
||||
#if !defined(SIM_TEST_INIT) /* Need stubs for test APIs */
|
||||
#define SIM_TEST_INIT
|
||||
|
||||
62
sim_fio.c
62
sim_fio.c
@ -54,7 +54,16 @@
|
||||
sim_byte_swap_data - swap data elements inplace in buffer
|
||||
sim_shmem_open create or attach to a shared memory region
|
||||
sim_shmem_close close a shared memory region
|
||||
|
||||
sim_chdir change working directory
|
||||
sim_mkdir create a directory
|
||||
sim_rmdir remove a directory
|
||||
sim_getcwd get the current working directory
|
||||
sim_copyfile copy a file
|
||||
sim_filepath_parts expand and extract filename/path parts
|
||||
sim_dirscan scan for a filename pattern
|
||||
sim_get_filelist get a list of files matching a pattern
|
||||
sim_free_filelist free a filelist
|
||||
sim_print_filelist print the elements of a filelist
|
||||
|
||||
sim_fopen and sim_fseek are OS-dependent. The other routines are not.
|
||||
sim_fsize is always a 32b routine (it is used only with small capacity random
|
||||
@ -347,6 +356,55 @@ if (NULL == _sim_expand_homedir (path, pathbuf, sizeof (pathbuf)))
|
||||
return rmdir (pathbuf);
|
||||
}
|
||||
|
||||
static void _sim_filelist_entry (const char *directory,
|
||||
const char *filename,
|
||||
t_offset FileSize,
|
||||
const struct stat *filestat,
|
||||
void *context)
|
||||
{
|
||||
char **filelist = *(char ***)context;
|
||||
char FullPath[PATH_MAX + 1];
|
||||
int listcount = 0;
|
||||
|
||||
snprintf (FullPath, sizeof (FullPath), "%s%s", directory, filename);
|
||||
if (filelist != NULL) {
|
||||
while (filelist[listcount++] != NULL);
|
||||
--listcount;
|
||||
}
|
||||
filelist = (char **)realloc (filelist, (listcount + 2) * sizeof (*filelist));
|
||||
filelist[listcount] = strdup (FullPath);
|
||||
filelist[listcount + 1] = NULL;
|
||||
*(char ***)context = filelist;
|
||||
}
|
||||
|
||||
char **sim_get_filelist (const char *filename)
|
||||
{
|
||||
char **filelist = NULL;
|
||||
|
||||
sim_dir_scan (filename, _sim_filelist_entry, &filelist);
|
||||
return filelist;
|
||||
}
|
||||
|
||||
void sim_free_filelist (char ***pfilelist)
|
||||
{
|
||||
char **listp = *pfilelist;
|
||||
|
||||
if (listp == NULL)
|
||||
return;
|
||||
while (*listp != NULL)
|
||||
free (*listp++);
|
||||
free (*pfilelist);
|
||||
*pfilelist = NULL;
|
||||
}
|
||||
|
||||
void sim_print_filelist (char **filelist)
|
||||
{
|
||||
if (filelist == NULL)
|
||||
return;
|
||||
while (*filelist != NULL)
|
||||
sim_printf ("%s\n", *filelist++);
|
||||
}
|
||||
|
||||
|
||||
/* OS-dependent routines */
|
||||
|
||||
@ -913,7 +971,7 @@ return getcwd (buf, buf_size);
|
||||
*
|
||||
* In the above example above %I% can be replaced by other
|
||||
* environment variables or numeric parameters to a DO command
|
||||
* invokation.
|
||||
* invocation.
|
||||
*/
|
||||
|
||||
char *sim_filepath_parts (const char *filepath, const char *parts)
|
||||
|
||||
@ -87,6 +87,9 @@ typedef void (*DIR_ENTRY_CALLBACK)(const char *directory,
|
||||
const struct stat *filestat,
|
||||
void *context);
|
||||
t_stat sim_dir_scan (const char *cptr, DIR_ENTRY_CALLBACK entry, void *context);
|
||||
char **sim_get_filelist (const char *filename);
|
||||
void sim_free_filelist (char ***pfilelist);
|
||||
void sim_print_filelist (char **filelist);
|
||||
|
||||
void sim_buf_swap_data (void *bptr, size_t size, size_t count);
|
||||
void sim_byte_swap_data (void *bptr, size_t size, size_t count);
|
||||
|
||||
@ -1709,7 +1709,7 @@ switch (dev->devtype) {
|
||||
return sim_disk_attach_ex (uptr, cptr, dev->block_size, sizeof (uint16), (uptr->flags & SCSI_NOAUTO), SCSI_DBG_DSK, dev->name, 0, 0, drivetypes);
|
||||
case SCSI_CDROM:
|
||||
sim_switches |= SWMASK ('R'); /* Force Read Only Attach for CDROM */
|
||||
return sim_disk_attach_ex (uptr, cptr, dev->block_size, sizeof (uint16), (uptr->flags & SCSI_NOAUTO), SCSI_DBG_DSK, dev->name, 0, 0, drivetypes);
|
||||
return sim_disk_attach_ex (uptr, cptr, dev->block_size, sizeof (uint16), FALSE, SCSI_DBG_DSK, dev->name, 0, 0, drivetypes);
|
||||
case SCSI_TAPE:
|
||||
return sim_tape_attach_ex (uptr, cptr, SCSI_DBG_TAP, 0);
|
||||
default:
|
||||
|
||||
192
sim_sock.c
192
sim_sock.c
@ -501,27 +501,38 @@ int load_ws2(void) {
|
||||
|
||||
/* OS independent routines
|
||||
|
||||
sim_parse_addr parse a hostname/ipaddress from port and apply defaults and
|
||||
optionally validate an address match
|
||||
sim_parse_addr parse a hostname/ipaddress from port and apply defaults
|
||||
and optionally validate an address match
|
||||
sim_addr_acl_check parse a hostname/ipaddress (possibly in CIDR form) and
|
||||
test against an acl
|
||||
*/
|
||||
|
||||
/* 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)
|
||||
Presumption is that the cptr 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 = optional pointer to host buffer
|
||||
host_len = length of host buffer
|
||||
default_port
|
||||
= optional pointer to default port if none specified
|
||||
default_host = optional pointer to default host if none specified
|
||||
in cptr
|
||||
port = optional pointer to port buffer
|
||||
port_len = length of port buffer
|
||||
default_port = optional pointer to default port if none specified
|
||||
in cptr
|
||||
validate_addr = optional name/addr which is checked to be equivalent
|
||||
to the host result of parsing the other input. This
|
||||
address would usually be returned by sim_accept_conn.
|
||||
The validate_addr can also be a CIDR address specifier
|
||||
which will match against the provided host.
|
||||
If the validate_addr is provided with cptr as NULL,
|
||||
the validate_addr is parsed for reasonableness and
|
||||
the result returned with 0 indicating a reasonable
|
||||
value and -1 indicating a parsing error.
|
||||
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
|
||||
@ -532,7 +543,9 @@ int load_ws2(void) {
|
||||
doesn't match the parsed host)
|
||||
*/
|
||||
|
||||
int sim_parse_addr (const char *cptr, char *host, size_t host_len, const char *default_host, char *port, size_t port_len, const char *default_port, const char *validate_addr)
|
||||
int sim_parse_addr (const char *cptr, char *host, size_t host_len, const char *default_host,
|
||||
char *port, size_t port_len, const char *default_port,
|
||||
const char *validate_addr)
|
||||
{
|
||||
char gbuf[CBUFSIZE], default_pbuf[CBUFSIZE];
|
||||
const char *hostp;
|
||||
@ -545,7 +558,8 @@ if ((host != NULL) && (host_len != 0))
|
||||
if ((port != NULL) && (port_len != 0))
|
||||
memset (port, 0, port_len);
|
||||
if ((cptr == NULL) || (*cptr == 0)) {
|
||||
if (((default_host == NULL) || (*default_host == 0)) || ((default_port == NULL) || (*default_port == 0)))
|
||||
if (((default_host == NULL) || (*default_host == 0)) ||
|
||||
((default_port == NULL) || (*default_port == 0)))
|
||||
return -1;
|
||||
if ((host == NULL) || (port == NULL))
|
||||
return -1; /* no place */
|
||||
@ -572,7 +586,7 @@ else { /* No colon in input */
|
||||
portp = gbuf; /* Input is the port specifier */
|
||||
hostp = (const char *)default_host; /* host is defaulted if provided */
|
||||
}
|
||||
if (portp != NULL) {
|
||||
if ((portp != NULL) && (*portp != '\0')) {
|
||||
portval = strtoul(portp, &endc, 10);
|
||||
if ((*endc == '\0') && ((portval == 0) || (portval > 65535)))
|
||||
return -1; /* numeric value too big */
|
||||
@ -590,7 +604,7 @@ if (port) /* port wanted? */
|
||||
else
|
||||
strcpy (port, portp);
|
||||
}
|
||||
if (hostp != NULL) {
|
||||
if ((hostp != NULL) && (*hostp != '\0')) {
|
||||
if (']' == hostp[strlen(hostp)-1]) {
|
||||
if ('[' != hostp[0])
|
||||
return -1; /* invalid domain literal */
|
||||
@ -626,16 +640,15 @@ if (validate_addr) {
|
||||
struct addrinfo *ai_host, *ai_validate, *ai, *aiv;
|
||||
int status;
|
||||
|
||||
if (hostp == NULL)
|
||||
return -1;
|
||||
if (p_getaddrinfo(hostp, NULL, NULL, &ai_host))
|
||||
if ((hostp == NULL) ||
|
||||
(0 != p_getaddrinfo(hostp, NULL, NULL, &ai_host)))
|
||||
return -1;
|
||||
if (p_getaddrinfo(validate_addr, NULL, NULL, &ai_validate)) {
|
||||
p_freeaddrinfo (ai_host);
|
||||
return -1;
|
||||
}
|
||||
status = -1;
|
||||
for (ai = ai_host; ai != NULL; ai = ai->ai_next) {
|
||||
for (ai = ai_host; (ai != NULL) && (status == -1); ai = ai->ai_next) {
|
||||
for (aiv = ai_validate; aiv != NULL; aiv = aiv->ai_next) {
|
||||
if ((ai->ai_addrlen == aiv->ai_addrlen) &&
|
||||
(ai->ai_family == aiv->ai_family) &&
|
||||
@ -660,6 +673,151 @@ if (validate_addr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* sim_addr_acl_check host:port,acl
|
||||
|
||||
parse a hostname/ipaddress (possibly in CIDR form) and
|
||||
test against an acl
|
||||
|
||||
Inputs:
|
||||
validate_addr = This address would usually be returned by
|
||||
sim_accept_conn. The validate_addr can also be a
|
||||
CIDR address specifier and in that mode, acl should
|
||||
be NULL so that we're just validating the syntax
|
||||
of what will likely become an entry in an acl list.
|
||||
If the validate_addr is provided with cptr as NULL,
|
||||
the validate_addr is parsed for reasonableness and
|
||||
the result returned with 0 indicating a reasonable
|
||||
value and -1 indicating a parsing error.
|
||||
acl = pointer to acl string which is comprised of comma
|
||||
separated entries each which may have a + or -
|
||||
prefix that indicated a permit or deny status when
|
||||
the entry matches. Each entry may specify a CIDR
|
||||
form match criteria.
|
||||
Outputs:
|
||||
result = status (0 on complete success or -1 if
|
||||
parsing can't happen due to bad syntax, a value is
|
||||
out of range or the validate_addr matches a reject
|
||||
entry in the acl or it is not mentioned at all in
|
||||
the acl.
|
||||
*/
|
||||
|
||||
int sim_addr_acl_check (const char *validate_addr, const char *acl)
|
||||
{
|
||||
int status = -1;
|
||||
int done = 0;
|
||||
struct addrinfo *ai_validate;
|
||||
unsigned long bits = 0;
|
||||
const char *c;
|
||||
char *c1, v_cpy[256];
|
||||
|
||||
if (validate_addr == NULL)
|
||||
return status;
|
||||
|
||||
c = strchr (validate_addr, '/');
|
||||
if (c != NULL) {
|
||||
bits = strtoul (c + 1, &c1, 10);
|
||||
if ((bits == 0) || (bits > 128) || (*c1 != '\0'))
|
||||
return status;
|
||||
if ((c - validate_addr) > sizeof (v_cpy) - 1)
|
||||
return status;
|
||||
memcpy (v_cpy, validate_addr, c - validate_addr); /* Copy everything before the / */
|
||||
v_cpy[1 + c - validate_addr] = '\0'; /* NUL terminate the result */
|
||||
validate_addr = v_cpy; /* Use the original string minus the prefix specifier */
|
||||
}
|
||||
if (p_getaddrinfo(validate_addr, NULL, NULL, &ai_validate))
|
||||
return status;
|
||||
if (acl == NULL) { /* Just checking validate_addr syntax? */
|
||||
status = 0;
|
||||
if ((ai_validate->ai_family == AF_INET) && (bits > 32))
|
||||
status = -1;
|
||||
p_freeaddrinfo (ai_validate);
|
||||
return status;
|
||||
}
|
||||
status = -1;
|
||||
while ((*acl != '\0') && !done) {
|
||||
struct addrinfo *ai_rule, *ai, *aiv;
|
||||
int permit;
|
||||
unsigned long bits = 0;
|
||||
const char *cc;
|
||||
char *c,*c1, rule[260];
|
||||
|
||||
permit = (*acl == '+');
|
||||
cc = strchr (acl, ',');
|
||||
if (cc != NULL) {
|
||||
if ((cc - acl) > sizeof (rule))
|
||||
break; /* Too big - error */
|
||||
memcpy (rule, acl + 1, cc - (acl + 1));
|
||||
rule[cc - (acl + 1)] = '\0';
|
||||
}
|
||||
else {
|
||||
if (strlen (acl) > sizeof (rule))
|
||||
break; /* Too big - error */
|
||||
strcpy (rule, acl + 1);
|
||||
}
|
||||
acl += strlen (rule) + 1 + (cc != NULL);
|
||||
c = strchr (rule, '/');
|
||||
if (c != NULL) {
|
||||
bits = strtoul (c + 1, &c1, 10);
|
||||
if ((bits == 0) || (bits > 128) || (*c1 != '\0'))
|
||||
break;
|
||||
*c = '\0';
|
||||
}
|
||||
|
||||
if (p_getaddrinfo(rule, NULL, NULL, &ai_rule))
|
||||
break;
|
||||
|
||||
for (ai = ai_rule; (ai != NULL) && (done == 0); ai = ai->ai_next) {
|
||||
for (aiv = ai_validate; aiv != NULL; aiv = aiv->ai_next) {
|
||||
if ((ai->ai_addrlen == aiv->ai_addrlen) &&
|
||||
(ai->ai_family == aiv->ai_family)) {
|
||||
unsigned int bit, addr_bits;
|
||||
unsigned char *da, *dav;
|
||||
|
||||
if (ai->ai_family == AF_INET) {
|
||||
da = (unsigned char *)&((struct sockaddr_in *)ai->ai_addr)->sin_addr;
|
||||
dav = (unsigned char *)&((struct sockaddr_in *)aiv->ai_addr)->sin_addr;
|
||||
addr_bits = 32;
|
||||
}
|
||||
#if !defined(AF_INET6)
|
||||
else {
|
||||
done = 1;
|
||||
break;
|
||||
}
|
||||
#else
|
||||
else {
|
||||
if (ai->ai_family == AF_INET6) {
|
||||
da = (unsigned char *)&((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr;
|
||||
dav = (unsigned char *)&((struct sockaddr_in6 *)aiv->ai_addr)->sin6_addr;
|
||||
addr_bits = 128;
|
||||
}
|
||||
else {
|
||||
done = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (bits == 0) /* Bits not specified? */
|
||||
bits = addr_bits; /* Use them all */
|
||||
for (bit=0; (bit < bits) && (bit < addr_bits); bit++) {
|
||||
unsigned int bitmask = 1 << (7 - (bit & 7));
|
||||
|
||||
if ((da[bit>>3] & bitmask) != (dav[bit>>3] & bitmask))
|
||||
break;
|
||||
}
|
||||
if (bit == bits) { /* All desired bits matched? */
|
||||
done = 1;
|
||||
status = permit ? 0 : -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
p_freeaddrinfo (ai_rule);
|
||||
}
|
||||
p_freeaddrinfo (ai_validate);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* sim_parse_addr_ex localport:host:port
|
||||
|
||||
Presumption is that the input, if it doesn't contain a ':' character is a port specifier.
|
||||
|
||||
@ -111,8 +111,12 @@ extern "C" {
|
||||
#define sim_printf printf
|
||||
#endif
|
||||
|
||||
int sim_parse_addr (const char *cptr, char *host, size_t hostlen, const char *default_host, char *port, size_t port_len, const char *default_port, const char *validate_addr);
|
||||
int sim_parse_addr_ex (const char *cptr, char *host, size_t hostlen, const char *default_host, char *port, size_t port_len, char *localport, size_t local_port_len, const char *default_port);
|
||||
int sim_parse_addr (const char *cptr, char *host, size_t hostlen, const char *default_host,
|
||||
char *port, size_t port_len, const char *default_port,
|
||||
const char *validate_addr);
|
||||
int sim_parse_addr_ex (const char *cptr, char *host, size_t hostlen, const char *default_host,
|
||||
char *port, size_t port_len, char *localport, size_t local_port_len, const char *default_port);
|
||||
int sim_addr_acl_check (const char *validate_addr, const char *acl);
|
||||
#define SIM_SOCK_OPT_REUSEADDR 0x0001
|
||||
#define SIM_SOCK_OPT_DATAGRAM 0x0002
|
||||
#define SIM_SOCK_OPT_NODELAY 0x0004
|
||||
|
||||
@ -4292,7 +4292,7 @@ return SCPE_OK;
|
||||
|
||||
#include <setjmp.h>
|
||||
|
||||
t_stat sim_tape_test (DEVICE *dptr)
|
||||
t_stat sim_tape_test (DEVICE *dptr, const char *cptr)
|
||||
{
|
||||
int32 saved_switches = sim_switches;
|
||||
SIM_TEST_INIT;
|
||||
|
||||
@ -233,7 +233,7 @@ t_stat sim_tape_show_dens (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
|
||||
t_stat sim_tape_density_supported (char *string, size_t string_size, int32 valid_bits);
|
||||
t_stat sim_tape_set_asynch (UNIT *uptr, int latency);
|
||||
t_stat sim_tape_clr_asynch (UNIT *uptr);
|
||||
t_stat sim_tape_test (DEVICE *dptr);
|
||||
t_stat sim_tape_test (DEVICE *dptr, const char *cptr);
|
||||
t_stat sim_tape_add_debug (DEVICE *dptr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
317
sim_tmxr.c
317
sim_tmxr.c
@ -916,11 +916,21 @@ tptr = (char *) calloc (1, 1);
|
||||
if (tptr == NULL) /* no more mem? */
|
||||
return tptr;
|
||||
|
||||
if (mp->port) /* copy port */
|
||||
if (mp->port) { /* copy port */
|
||||
sprintf (growstring(&tptr, 33 + strlen (mp->port)), "%s%s", mp->port,
|
||||
mp->notelnet ? ";notelnet" :
|
||||
(mp->nomessage ? ";nomessage" :
|
||||
""));
|
||||
if (mp->acl) { /* copy acl in pieces */
|
||||
char gbuf[CBUFSIZE];
|
||||
const char *c = mp->acl;
|
||||
|
||||
while (*c != '\0') {
|
||||
c = get_glyph_nc (c, gbuf, ',');
|
||||
sprintf (growstring(&tptr, 9 + strlen (gbuf)), ";%s=%s", (gbuf[0] == '+') ? "Accept" : "Reject", gbuf + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mp->logfiletmpl[0]) /* logfile info */
|
||||
sprintf (growstring(&tptr, 7 + strlen (mp->logfiletmpl)), ",Log=%s", mp->logfiletmpl);
|
||||
if (mp->buffered)
|
||||
@ -989,10 +999,20 @@ if (lp->destination || lp->port || lp->txlogname || (lp->conn == TMXR_LINE_DISAB
|
||||
sprintf (growstring(&tptr, 8), ",%s", lp->datagram ? "UDP" : "TCP");
|
||||
if (lp->mp->packet != lp->packet)
|
||||
sprintf (growstring(&tptr, 8), ",Packet");
|
||||
if (lp->port)
|
||||
if (lp->port) {
|
||||
sprintf (growstring(&tptr, 32 + strlen (lp->port)), ",%s%s%s", lp->port,
|
||||
((lp->mp->notelnet != lp->notelnet) && (!lp->datagram)) ? (lp->notelnet ? ";notelnet" : ";telnet") : "",
|
||||
((lp->mp->nomessage != lp->nomessage) && (!lp->datagram)) ? (lp->nomessage ? ";nomessage" : ";message") : "");
|
||||
if (lp->acl) { /* copy acl in pieces */
|
||||
char gbuf[CBUFSIZE];
|
||||
const char *c = lp->acl;
|
||||
|
||||
while (*c != '\0') {
|
||||
c = get_glyph_nc (c, gbuf, ',');
|
||||
sprintf (growstring(&tptr, 9 + strlen (gbuf)), ";%s=%s", (gbuf[0] == '+') ? "Accept" : "Reject", gbuf + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (lp->destination) {
|
||||
if (lp->serport) {
|
||||
char portname[CBUFSIZE];
|
||||
@ -1120,94 +1140,106 @@ if (mp->master) {
|
||||
i = mp->lines; /* play it safe in case lines == 0 */
|
||||
++mp->sessions; /* count the new session */
|
||||
|
||||
for (j = 0; j < mp->lines; j++, i++) { /* find next avail line */
|
||||
if (op && (*op >= 0) && (*op < mp->lines)) /* order list present and valid? */
|
||||
i = *op++; /* get next line in list to try */
|
||||
else /* no list or not used or range error */
|
||||
i = j; /* get next sequential line */
|
||||
|
||||
lp = mp->ldsc + i; /* get pointer to line descriptor */
|
||||
if ((lp->conn == FALSE) && /* is the line available? */
|
||||
(lp->destination == NULL) &&
|
||||
(lp->master == 0) &&
|
||||
(lp->ser_connect_pending == FALSE) &&
|
||||
(lp->modem_control ? ((lp->modembits & TMXR_MDM_DTR) != 0) : TRUE))
|
||||
break; /* yes, so stop search */
|
||||
if (mp->acl) {
|
||||
if (sim_addr_acl_check (address, mp->acl) != 0) {
|
||||
tmxr_debug_connect (mp, "tmxr_poll_conn() - Connection Specifically rejected by ACL");
|
||||
sim_close_sock (newsock);
|
||||
free (address);
|
||||
++mp->acl_rejected_sessions;
|
||||
}
|
||||
else
|
||||
++mp->acl_accepted_sessions;
|
||||
}
|
||||
else {
|
||||
for (j = 0; j < mp->lines; j++, i++) { /* find next avail line */
|
||||
if (op && (*op >= 0) && (*op < mp->lines)) /* order list present and valid? */
|
||||
i = *op++; /* get next line in list to try */
|
||||
else /* no list or not used or range error */
|
||||
i = j; /* get next sequential line */
|
||||
|
||||
if (i >= mp->lines) { /* all busy? */
|
||||
int32 ringable_count = 0;
|
||||
|
||||
for (j = 0; j < mp->lines; j++, i++) { /* find next avail line */
|
||||
lp = mp->ldsc + j; /* get pointer to line descriptor */
|
||||
if (lp->framer)
|
||||
continue;
|
||||
|
||||
if ((lp->conn == FALSE) && /* is the line available? */
|
||||
lp = mp->ldsc + i; /* get pointer to line descriptor */
|
||||
if ((lp->conn == FALSE) && /* is the line available? */
|
||||
(lp->destination == NULL) &&
|
||||
(lp->master == 0) &&
|
||||
(lp->ser_connect_pending == FALSE) &&
|
||||
((lp->modembits & TMXR_MDM_DTR) == 0)) {
|
||||
++ringable_count;
|
||||
lp->modembits |= TMXR_MDM_RNG;
|
||||
tmxr_debug_connect_line (lp, "tmxr_poll_conn() - Ringing line");
|
||||
}
|
||||
(lp->modem_control ? ((lp->modembits & TMXR_MDM_DTR) != 0) : TRUE))
|
||||
break; /* yes, so stop search */
|
||||
}
|
||||
if (ringable_count > 0) {
|
||||
ringing = -2;
|
||||
if (mp->ring_start_time == 0) {
|
||||
mp->ring_start_time = poll_time;
|
||||
mp->ring_sock = newsock;
|
||||
mp->ring_ipad = address;
|
||||
|
||||
if (i >= mp->lines) { /* all busy? */
|
||||
int32 ringable_count = 0;
|
||||
|
||||
for (j = 0; j < mp->lines; j++, i++) { /* find next avail line */
|
||||
lp = mp->ldsc + j; /* get pointer to line descriptor */
|
||||
if (lp->framer)
|
||||
continue;
|
||||
|
||||
if ((lp->conn == FALSE) && /* is the line available? */
|
||||
(lp->destination == NULL) &&
|
||||
(lp->master == 0) &&
|
||||
(lp->ser_connect_pending == FALSE) &&
|
||||
((lp->modembits & TMXR_MDM_DTR) == 0)) {
|
||||
++ringable_count;
|
||||
lp->modembits |= TMXR_MDM_RNG;
|
||||
tmxr_debug_connect_line (lp, "tmxr_poll_conn() - Ringing line");
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ((poll_time - mp->ring_start_time) < TMXR_MODEM_RING_TIME*1000) {
|
||||
if (ringable_count > 0) {
|
||||
ringing = -2;
|
||||
if (mp->ring_start_time == 0) {
|
||||
mp->ring_start_time = poll_time;
|
||||
mp->ring_sock = newsock;
|
||||
mp->ring_ipad = address;
|
||||
}
|
||||
else { /* Timeout waiting for DTR */
|
||||
int ln;
|
||||
|
||||
/* turn off pending ring signals */
|
||||
for (ln = 0; ln < lp->mp->lines; ln++) {
|
||||
TMLN *tlp = lp->mp->ldsc + ln;
|
||||
if (((tlp->destination == NULL) && (tlp->master == 0)) &&
|
||||
(tlp->modembits & TMXR_MDM_RNG) && (tlp->conn == FALSE))
|
||||
tlp->modembits &= ~TMXR_MDM_RNG;
|
||||
else {
|
||||
if ((poll_time - mp->ring_start_time) < TMXR_MODEM_RING_TIME*1000) {
|
||||
mp->ring_sock = newsock;
|
||||
mp->ring_ipad = address;
|
||||
}
|
||||
else { /* Timeout waiting for DTR */
|
||||
int ln;
|
||||
|
||||
/* turn off pending ring signals */
|
||||
for (ln = 0; ln < lp->mp->lines; ln++) {
|
||||
TMLN *tlp = lp->mp->ldsc + ln;
|
||||
if (((tlp->destination == NULL) && (tlp->master == 0)) &&
|
||||
(tlp->modembits & TMXR_MDM_RNG) && (tlp->conn == FALSE))
|
||||
tlp->modembits &= ~TMXR_MDM_RNG;
|
||||
}
|
||||
mp->ring_start_time = 0;
|
||||
tmxr_msg (newsock, "No answer on any connection\r\n");
|
||||
tmxr_debug_connect (mp, "tmxr_poll_conn() - No Answer - All connections busy");
|
||||
sim_close_sock (newsock);
|
||||
free (address);
|
||||
}
|
||||
mp->ring_start_time = 0;
|
||||
tmxr_msg (newsock, "No answer on any connection\r\n");
|
||||
tmxr_debug_connect (mp, "tmxr_poll_conn() - No Answer - All connections busy");
|
||||
sim_close_sock (newsock);
|
||||
free (address);
|
||||
}
|
||||
}
|
||||
else {
|
||||
tmxr_msg (newsock, "All connections busy\r\n");
|
||||
tmxr_debug_connect (mp, "tmxr_poll_conn() - All connections busy");
|
||||
sim_close_sock (newsock);
|
||||
free (address);
|
||||
}
|
||||
}
|
||||
else {
|
||||
tmxr_msg (newsock, "All connections busy\r\n");
|
||||
tmxr_debug_connect (mp, "tmxr_poll_conn() - All connections busy");
|
||||
sim_close_sock (newsock);
|
||||
free (address);
|
||||
lp = mp->ldsc + i; /* get line desc */
|
||||
lp->conn = TRUE; /* record connection */
|
||||
lp->sock = newsock; /* save socket */
|
||||
lp->ipad = address; /* ip address */
|
||||
tmxr_init_line (lp); /* init line */
|
||||
lp->notelnet = mp->notelnet; /* apply mux default telnet setting */
|
||||
lp->nomessage = mp->nomessage; /* apply mux default telnet setting */
|
||||
if (!lp->notelnet) {
|
||||
sim_write_sock (newsock, (char *)mantra, sizeof(mantra));
|
||||
tmxr_debug (TMXR_DBG_XMT, lp, "Sending", (char *)mantra, sizeof(mantra));
|
||||
lp->telnet_sent_opts = (uint8 *)realloc (lp->telnet_sent_opts, 256);
|
||||
memset (lp->telnet_sent_opts, 0, 256);
|
||||
}
|
||||
tmxr_report_connection (mp, lp);
|
||||
lp->cnms = sim_os_msec (); /* time of connection */
|
||||
return i;
|
||||
}
|
||||
}
|
||||
else {
|
||||
lp = mp->ldsc + i; /* get line desc */
|
||||
lp->conn = TRUE; /* record connection */
|
||||
lp->sock = newsock; /* save socket */
|
||||
lp->ipad = address; /* ip address */
|
||||
tmxr_init_line (lp); /* init line */
|
||||
lp->notelnet = mp->notelnet; /* apply mux default telnet setting */
|
||||
lp->nomessage = mp->nomessage; /* apply mux default telnet setting */
|
||||
if (!lp->notelnet) {
|
||||
sim_write_sock (newsock, (char *)mantra, sizeof(mantra));
|
||||
tmxr_debug (TMXR_DBG_XMT, lp, "Sending", (char *)mantra, sizeof(mantra));
|
||||
lp->telnet_sent_opts = (uint8 *)realloc (lp->telnet_sent_opts, 256);
|
||||
memset (lp->telnet_sent_opts, 0, 256);
|
||||
}
|
||||
tmxr_report_connection (mp, lp);
|
||||
lp->cnms = sim_os_msec (); /* time of connection */
|
||||
return i;
|
||||
}
|
||||
} /* end if newsock */
|
||||
}
|
||||
|
||||
@ -1296,6 +1328,18 @@ for (i = 0; i < mp->lines; i++) { /* check each line in se
|
||||
free (peername);
|
||||
++mp->sessions; /* count the new session */
|
||||
|
||||
if (lp->acl) { /* Restrict connection with ACL rules? */
|
||||
if (sim_addr_acl_check (address, lp->acl) != 0) {
|
||||
snprintf (msg, sizeof (msg) -1, "tmxr_poll_conn() - ACL Rejecting line connection from: %s", address);
|
||||
tmxr_debug_connect_line (lp, msg);
|
||||
sim_close_sock (newsock);
|
||||
free (address);
|
||||
++lp->acl_rejected_sessions;
|
||||
continue; /* Go back for another connection */
|
||||
}
|
||||
else
|
||||
++lp->acl_accepted_sessions;
|
||||
}
|
||||
if (lp->destination) { /* Virtual Null Modem Cable? */
|
||||
char host[sizeof(msg) - 64];
|
||||
|
||||
@ -1654,6 +1698,7 @@ if (!mp->port_speed_control && mp->uptr && !(mp->uptr->flags & UNIT_ATT))
|
||||
mp->port_speed_control = TRUE;
|
||||
for (i=0; i<mp->lines; ++i)
|
||||
mp->ldsc[i].port_speed_control = mp->port_speed_control;
|
||||
sim_debug (TMXR_DBG_CFG, mp->dptr, "Speed Mode: Enabled\n");
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
@ -1672,6 +1717,7 @@ if (mp->port_speed_control && mp->uptr && !(mp->uptr->flags & UNIT_ATT))
|
||||
mp->port_speed_control = FALSE;
|
||||
for (i=0; i<mp->lines; ++i)
|
||||
mp->ldsc[i].port_speed_control = mp->port_speed_control;
|
||||
sim_debug (TMXR_DBG_CFG, mp->dptr, "Speed Mode: Disabled\n");
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
@ -1690,6 +1736,7 @@ if (mp->uptr && !(mp->uptr->flags & UNIT_ATT))
|
||||
if (line >= mp->lines)
|
||||
return sim_messagef (SCPE_ARG, "Invalid line for multiplexer: %d\n", line);
|
||||
mp->ldsc[line].port_speed_control = TRUE;
|
||||
sim_debug (TMXR_DBG_CFG, mp->dptr, "Speed Mode: Enabled for line %d\n", line);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
@ -1706,6 +1753,7 @@ if (mp->uptr && !(mp->uptr->flags & UNIT_ATT))
|
||||
if (line >= mp->lines)
|
||||
return sim_messagef (SCPE_ARG, "Invalid line for multiplexer: %d\n", line);
|
||||
mp->ldsc[line].port_speed_control = FALSE;
|
||||
sim_debug (TMXR_DBG_CFG, mp->dptr, "Speed Mode: Disabled for line %d\n", line);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
@ -1913,6 +1961,8 @@ return SCPE_INCOMP;
|
||||
*/
|
||||
t_stat tmxr_set_line_loopback (TMLN *lp, t_bool enable_loopback)
|
||||
{
|
||||
DEVICE *dptr = (lp->dptr ? lp->dptr : (lp->mp ? lp->mp->dptr : NULL));
|
||||
|
||||
if (lp->loopback == (enable_loopback != FALSE))
|
||||
return SCPE_OK; /* Nothing to do */
|
||||
lp->loopback = (enable_loopback != FALSE);
|
||||
@ -1928,6 +1978,7 @@ else {
|
||||
lp->lpb = NULL;
|
||||
lp->lpbsz = 0;
|
||||
}
|
||||
sim_debug (TMXR_DBG_CFG, dptr, "Loopback %s for line %d\n", enable_loopback ? "Enabled" : "Disabled", (int)(lp - lp->mp->ldsc));
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
@ -1952,9 +2003,12 @@ return (lp->loopback != FALSE);
|
||||
*/
|
||||
t_stat tmxr_set_line_halfduplex (TMLN *lp, t_bool enable_halfduplex)
|
||||
{
|
||||
DEVICE *dptr = (lp->dptr ? lp->dptr : (lp->mp ? lp->mp->dptr : NULL));
|
||||
|
||||
if (lp->halfduplex == (enable_halfduplex != FALSE))
|
||||
return SCPE_OK; /* Nothing to do */
|
||||
lp->halfduplex = (enable_halfduplex != FALSE);
|
||||
sim_debug (TMXR_DBG_CFG, dptr, "Half Duplex %s for line %d\n", enable_halfduplex ? "Enabled" : "Disabled", (int)(lp - lp->mp->ldsc));
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
@ -1966,6 +2020,8 @@ return (lp->halfduplex != FALSE);
|
||||
t_stat tmxr_set_config_line (TMLN *lp, CONST char *config)
|
||||
{
|
||||
t_stat r;
|
||||
DEVICE *dptr = (lp->dptr ? lp->dptr : (lp->mp ? lp->mp->dptr : NULL));
|
||||
char *prior = lp->serconfig ? strdup (lp->serconfig) : NULL;
|
||||
|
||||
tmxr_debug_trace_line (lp, "tmxr_set_config_line()");
|
||||
if (lp->serport) {
|
||||
@ -1982,6 +2038,8 @@ else {
|
||||
lp->serconfig = NULL;
|
||||
}
|
||||
}
|
||||
sim_debug (TMXR_DBG_CFG, dptr, "Line %d changed from %s to %s\n", (int)(lp - lp->mp->ldsc), prior ? prior : "", lp->serconfig);
|
||||
free (prior);
|
||||
if ((r == SCPE_OK) && (lp->mp) && (lp->mp->uptr)) /* Record port state for proper restore */
|
||||
lp->mp->uptr->filename = tmxr_mux_attach_string (lp->mp->uptr->filename, lp->mp);
|
||||
return r;
|
||||
@ -2844,7 +2902,8 @@ t_stat tmxr_open_master (TMXR *mp, CONST char *cptr)
|
||||
int32 i, line, nextline = -1;
|
||||
char tbuf[CBUFSIZE], listen[CBUFSIZE], destination[CBUFSIZE],
|
||||
logfiletmpl[CBUFSIZE], buffered[CBUFSIZE], hostport[CBUFSIZE],
|
||||
port[CBUFSIZE], option[CBUFSIZE], speed[CBUFSIZE], dev_name[CBUFSIZE];
|
||||
port[CBUFSIZE], option[CBUFSIZE], speed[CBUFSIZE], dev_name[CBUFSIZE],
|
||||
acl[CBUFSIZE];
|
||||
char framer[CBUFSIZE],fr_eth[CBUFSIZE];
|
||||
int num;
|
||||
int8 fr_mode;
|
||||
@ -2882,6 +2941,7 @@ while (*tptr) {
|
||||
memset(destination, '\0', sizeof(destination));
|
||||
memset(buffered, '\0', sizeof(buffered));
|
||||
memset(port, '\0', sizeof(port));
|
||||
memset(acl, '\0', sizeof(acl));
|
||||
memset(option, '\0', sizeof(option));
|
||||
memset(speed, '\0', sizeof(speed));
|
||||
memset(framer, '\0', sizeof(framer));
|
||||
@ -3012,6 +3072,7 @@ while (*tptr) {
|
||||
cptr = get_glyph (gbuf, port, ';');
|
||||
if (sim_parse_addr (port, NULL, 0, NULL, NULL, 0, NULL, NULL))
|
||||
return sim_messagef (SCPE_ARG, "Invalid Port Specifier: %s\n", port);
|
||||
memset (acl, '\0', sizeof (acl));
|
||||
while (cptr && *cptr) {
|
||||
char *tptr = gbuf + (cptr - gbuf);
|
||||
|
||||
@ -3027,10 +3088,28 @@ while (*tptr) {
|
||||
else
|
||||
if (0 == MATCH_CMD (tptr, "MESSAGE"))
|
||||
listennomessage = FALSE;
|
||||
else {
|
||||
if (*tptr)
|
||||
return sim_messagef (SCPE_ARG, "Invalid Specifier: %s\n", tptr);
|
||||
}
|
||||
else
|
||||
if (0 == memcmp (option, "ACCEPT=", 7)) {
|
||||
if (sim_addr_acl_check (option + 7, NULL))
|
||||
return sim_messagef (SCPE_ARG, "Invalid Accept Criteria: %s\n", option + 7);
|
||||
if (acl[0] != '\0')
|
||||
strlcat (acl, ",", sizeof (acl));
|
||||
strlcat (acl, "+", sizeof (acl)); /* Tag as Accept rule */
|
||||
strlcat (acl, option + 7, sizeof (acl));
|
||||
}
|
||||
else
|
||||
if (0 == memcmp (option, "REJECT=", 7)) {
|
||||
if (sim_addr_acl_check (option + 7, NULL))
|
||||
return sim_messagef (SCPE_ARG, "Invalid Reject Criteria: %s\n", option + 7);
|
||||
if (acl[0] != '\0')
|
||||
strlcat (acl, ",", sizeof (acl));
|
||||
strlcat (acl, "-", sizeof (acl)); /* Tag as Reject rule */
|
||||
strlcat (acl, option + 7, sizeof (acl));
|
||||
}
|
||||
else {
|
||||
if (*tptr)
|
||||
return sim_messagef (SCPE_ARG, "Invalid Specifier: %s\n", tptr);
|
||||
}
|
||||
}
|
||||
cptr = init_cptr;
|
||||
}
|
||||
@ -3043,6 +3122,7 @@ while (*tptr) {
|
||||
sim_close_sock (sock);
|
||||
sim_os_ms_sleep (2); /* let the close finish (required on some platforms) */
|
||||
strcpy (listen, port);
|
||||
memset (acl, '\0', sizeof (acl));
|
||||
cptr = get_glyph (cptr, option, ';');
|
||||
while (option[0]) {
|
||||
if (0 == MATCH_CMD (option, "NOTELNET"))
|
||||
@ -3057,7 +3137,25 @@ while (*tptr) {
|
||||
if (0 == MATCH_CMD (option, "MESSAGE"))
|
||||
listennomessage = FALSE;
|
||||
else
|
||||
return sim_messagef (SCPE_ARG, "Invalid Specifier: %s\n", option);
|
||||
if (0 == memcmp (option, "ACCEPT=", 7)) {
|
||||
if (sim_addr_acl_check (option + 7, NULL))
|
||||
return sim_messagef (SCPE_ARG, "Invalid Accept Criteria: %s\n", option + 7);
|
||||
if (acl[0] != '\0')
|
||||
strlcat (acl, ",", sizeof (acl));
|
||||
strlcat (acl, "+", sizeof (acl)); /* Tag as Accept rule */
|
||||
strlcat (acl, option + 7, sizeof (acl));
|
||||
}
|
||||
else
|
||||
if (0 == memcmp (option, "REJECT=", 7)) {
|
||||
if (sim_addr_acl_check (option + 7, NULL))
|
||||
return sim_messagef (SCPE_ARG, "Invalid Reject Criteria: %s\n", option + 7);
|
||||
if (acl[0] != '\0')
|
||||
strlcat (acl, ",", sizeof (acl));
|
||||
strlcat (acl, "-", sizeof (acl)); /* Tag as Reject rule */
|
||||
strlcat (acl, option + 7, sizeof (acl));
|
||||
}
|
||||
else
|
||||
return sim_messagef (SCPE_ARG, "Invalid Specifier: %s\n", option);
|
||||
cptr = get_glyph (cptr, option, ';');
|
||||
}
|
||||
}
|
||||
@ -3072,8 +3170,8 @@ while (*tptr) {
|
||||
serport = sim_open_serial (destination, NULL, &r);
|
||||
if (serport != INVALID_HANDLE) {
|
||||
sim_close_serial (serport);
|
||||
if (strchr (destination, ';') && mp->modem_control && !(sim_switches & SIM_SW_REST))
|
||||
return sim_messagef (SCPE_ARG, "Serial line parameters must be set within simulated OS: %s\n", 1 + strchr (destination, ';'));
|
||||
if (strchr (destination, ';') && (mp->modem_control || mp->port_speed_control) && !(sim_switches & SIM_SW_REST))
|
||||
return sim_messagef (SCPE_ARG, "%sSerial line parameters can only be set within simulated OS: %s\n", dev_name, 1 + strchr (destination, ';'));
|
||||
}
|
||||
else {
|
||||
char *eptr;
|
||||
@ -3235,6 +3333,8 @@ while (*tptr) {
|
||||
mp->ring_start_time = 0;
|
||||
mp->notelnet = listennotelnet; /* save desired telnet behavior flag */
|
||||
mp->nomessage = listennomessage; /* save desired telnet behavior flag */
|
||||
if (acl[0])
|
||||
mp->acl = strdup (acl); /* save specified access control list */
|
||||
for (i = 0; i < mp->lines; i++) { /* initialize lines */
|
||||
lp = mp->ldsc + i;
|
||||
lp->mp = mp; /* set the back pointer */
|
||||
@ -3449,6 +3549,8 @@ while (*tptr) {
|
||||
lp->nomessage = listennomessage;
|
||||
else
|
||||
lp->nomessage = mp->nomessage;
|
||||
if (acl[0])
|
||||
lp->acl = strdup (acl);
|
||||
}
|
||||
if (destination[0]) {
|
||||
serport = sim_open_serial (destination, lp, &r);
|
||||
@ -4441,6 +4543,10 @@ if (attach)
|
||||
free (attach);
|
||||
tmxr_show_summ(st, NULL, 0, mp);
|
||||
fprintf(st, ", sessions=%d", mp->sessions);
|
||||
if (mp->acl_accepted_sessions)
|
||||
fprintf(st, ", accepted=%d", mp->acl_accepted_sessions);
|
||||
if (mp->acl_rejected_sessions)
|
||||
fprintf(st, ", rejected=%d", mp->acl_rejected_sessions);
|
||||
if (mp->lines == 1) {
|
||||
if (mp->ldsc->rxbps) {
|
||||
fprintf(st, ", Speed=%d", mp->ldsc->rxbps);
|
||||
@ -4483,6 +4589,13 @@ for (j = 0; j < mp->lines; j++) {
|
||||
if (lp->bpsfactor != 1.0)
|
||||
fprintf(st, ", Speed=*%.0f bps", lp->bpsfactor);
|
||||
}
|
||||
if (lp->sessions) {
|
||||
fprintf(st, ", Sessions=%d", lp->sessions);
|
||||
if (lp->acl_accepted_sessions)
|
||||
fprintf(st, ", Accepted=%d", lp->acl_accepted_sessions);
|
||||
if (lp->acl_rejected_sessions)
|
||||
fprintf(st, ", Rejected=%d", lp->acl_rejected_sessions);
|
||||
}
|
||||
fprintf (st, "\n");
|
||||
}
|
||||
if ((!lp->sock) && (!lp->connecting) && (!lp->serport) && (!lp->master)) {
|
||||
@ -4570,6 +4683,8 @@ for (i = 0; i < mp->lines; i++) { /* loop thru conn */
|
||||
}
|
||||
free (lp->destination);
|
||||
lp->destination = NULL;
|
||||
free (lp->acl);
|
||||
lp->acl = NULL;
|
||||
if (lp->connecting) {
|
||||
lp->sock = lp->connecting;
|
||||
lp->connecting = 0;
|
||||
@ -4831,6 +4946,15 @@ if (single_line) { /* Single Line Multiplexer */
|
||||
}
|
||||
fprintf (st, "A Telnet listening port can be configured with:\n\n");
|
||||
fprintf (st, " sim> ATTACH %s {interface:}port\n\n", dptr->name);
|
||||
fprintf (st, "Connections to the specified port, by default, will be unrestricted.\n");
|
||||
fprintf (st, "Connections from particular IPv4 or IPv6 addresses can be restricted\n");
|
||||
fprintf (st, "or allowed based on rules you can add to the \"{interface:}port\"\n");
|
||||
fprintf (st, "specifier on the attach command. You can add as many rules as you need\n");
|
||||
fprintf (st, "to the attach command specified with \";ACCEPT=rule-detail\" or\n");
|
||||
fprintf (st, "\";REJECT=rule-detail\" where rule-detail can be an IP address, hostname\n");
|
||||
fprintf (st, "or network block in CIDR form. Rules are interpreted in order and if,\n");
|
||||
fprintf (st, "while processing the list, the end is reached the connection will be\n");
|
||||
fprintf (st, "rejected.\n\n");
|
||||
fprintf (st, "The -U switch can be specified on the attach command that specifies\n");
|
||||
fprintf (st, "a listening port. This will allow a listening port to be reused if\n");
|
||||
fprintf (st, "some prior connections haven't completely shutdown.\n\n");
|
||||
@ -4998,6 +5122,15 @@ else {
|
||||
fprintf (st, "Line specific tcp listening ports are supported. These are configured\n");
|
||||
fprintf (st, "using commands of the form:\n\n");
|
||||
fprintf (st, " sim> ATTACH %s Line=n,{interface:}port{;notelnet}|{;nomessage}\n\n", dptr->name);
|
||||
fprintf (st, "Connections to the specified port, by default, will be unrestricted.\n");
|
||||
fprintf (st, "Connections from particular IPv4 or IPv6 addresses can be restricted\n");
|
||||
fprintf (st, "or allowed based on rules you can add to the \"{interface:}port\"\n");
|
||||
fprintf (st, "specifier on the attach command. You can add as many rules as you need\n");
|
||||
fprintf (st, "to the attach command specified with \";ACCEPT=rule-detail\" or\n");
|
||||
fprintf (st, "\";REJECT=rule-detail\" where rule-detail can be an IP address, hostname\n");
|
||||
fprintf (st, "or network block in CIDR form. Rules are interpreted in order and if,\n");
|
||||
fprintf (st, "while processing the list, the end is reached the connection will be\n");
|
||||
fprintf (st, "rejected.\n\n");
|
||||
}
|
||||
fprintf (st, "Direct computer to computer connections (Virutal Null Modem cables) may\n");
|
||||
fprintf (st, "be established using the telnet protocol or via raw tcp sockets.\n\n");
|
||||
@ -5180,8 +5313,11 @@ if (lp->sock) {
|
||||
free (peername);
|
||||
}
|
||||
|
||||
if ((lp->port) && (!lp->datagram))
|
||||
if ((lp->port) && (!lp->datagram)) {
|
||||
fprintf (st, "Listening on port %s\n", lp->port); /* print port name */
|
||||
if (lp->acl)
|
||||
fprintf (st, "Connections will be accepted/rejected based on: %s\n", lp->acl);
|
||||
}
|
||||
|
||||
if (lp->serport) /* serial connection? */
|
||||
fprintf (st, "Connected to serial port %s\n", lp->destination); /* print port name */
|
||||
@ -6005,7 +6141,7 @@ return SCPE_OK;
|
||||
|
||||
#include <setjmp.h>
|
||||
|
||||
t_stat tmxr_sock_test (DEVICE *dptr)
|
||||
t_stat tmxr_sock_test (DEVICE *dptr, const char *cptr)
|
||||
{
|
||||
char cmd[CBUFSIZE], host[CBUFSIZE], port[CBUFSIZE];
|
||||
int line;
|
||||
@ -6022,6 +6158,13 @@ SIM_TEST(sim_parse_addr ("", NULL, 0, "localhost", NULL, 0, "1234", NULL) != -1)
|
||||
SIM_TEST(sim_parse_addr ("", host, 0, "localhost", NULL, 0, "1234", NULL) != -1);
|
||||
SIM_TEST(sim_parse_addr ("", host, sizeof(host), "localhost", port, 0, "1234", NULL) != -1);
|
||||
SIM_TEST((sim_parse_addr ("", host, sizeof(host), "localhost", port, sizeof(port), "1234", NULL) == -1) || (strcmp(host, "localhost")) || (strcmp(port,"1234")));
|
||||
SIM_TEST(sim_addr_acl_check ("127.0.0.1", NULL) == -1);
|
||||
SIM_TEST(sim_addr_acl_check ("127.0.0.1/0", NULL) != -1);
|
||||
SIM_TEST(sim_addr_acl_check ("127.0.0.1/32", NULL) == -1);
|
||||
SIM_TEST(sim_addr_acl_check ("127.0.0.1/64", NULL) != -1);
|
||||
SIM_TEST(sim_addr_acl_check ("127.0.0.6", "+127.0.0.1/32,-127.0.0.2") != -1);
|
||||
SIM_TEST(sim_addr_acl_check ("127.0.0.2", "+127.0.0.1,-127.0.0.2/32,+127.0.0.3") != -1);
|
||||
SIM_TEST(sim_parse_addr ("", host, sizeof(host), "localhost", port, sizeof(port), "1234", "127.0.0.1") == -1);
|
||||
SIM_TEST((sim_parse_addr ("localhost:6666", host, sizeof(host), "localhost", port, sizeof(port), "1234", NULL) == -1) || (strcmp(host, "localhost")) || (strcmp(port,"6666")));
|
||||
SIM_TEST(sim_parse_addr ("localhost:66666", host, sizeof(host), "localhost", port, sizeof(port), "1234", NULL) != -1);
|
||||
SIM_TEST((sim_parse_addr ("localhost:telnet", host, sizeof(host), "localhost", port, sizeof(port), "1234", NULL) == -1) || (strcmp(host, "localhost")) || (strcmp(port,"telnet")));
|
||||
@ -6064,12 +6207,12 @@ return stat;
|
||||
|
||||
static int framer_await_status (TMLN *line, int cnt)
|
||||
{
|
||||
int i, stat, xtry, flen;
|
||||
int i, stat, attempt, flen;
|
||||
ETH_PACK framer_rpkt;
|
||||
|
||||
i = line->framer->status_cnt;
|
||||
xtry = 0;
|
||||
while (xtry < 5) {
|
||||
attempt = 0;
|
||||
while (attempt < 5) {
|
||||
stat = eth_read (line->framer->eth, &framer_rpkt, NULL);
|
||||
if (stat) {
|
||||
flen = framer_rpkt.msg[14] + (framer_rpkt.msg[15] << 8);
|
||||
@ -6084,7 +6227,7 @@ while (xtry < 5) {
|
||||
}
|
||||
if (i != line->framer->status_cnt)
|
||||
return 1;
|
||||
xtry++;
|
||||
attempt++;
|
||||
sim_os_ms_sleep (50);
|
||||
}
|
||||
tmxr_debug_trace_line (line, "no status received\n");
|
||||
|
||||
17
sim_tmxr.h
17
sim_tmxr.h
@ -66,10 +66,11 @@ typedef struct SERPORT *SERHANDLE;
|
||||
#define TMXR_MODEM_RING_TIME 3 /* seconds to wait for DTR for incoming connections */
|
||||
#define TMXR_DEFAULT_CONNECT_POLL_INTERVAL 1 /* seconds between connection polls */
|
||||
|
||||
#define TMXR_DBG_XMT 0x00200000 /* Debug Transmit Data */
|
||||
#define TMXR_DBG_RCV 0x00400000 /* Debug Received Data */
|
||||
#define TMXR_DBG_RET 0x00800000 /* Debug Returned Received Data */
|
||||
#define TMXR_DBG_MDM 0x01000000 /* Debug Modem Signals */
|
||||
#define TMXR_DBG_XMT 0x00100000 /* Debug Transmit Data */
|
||||
#define TMXR_DBG_RCV 0x00200000 /* Debug Received Data */
|
||||
#define TMXR_DBG_RET 0x00400000 /* Debug Returned Received Data */
|
||||
#define TMXR_DBG_MDM 0x00800000 /* Debug Modem Signals */
|
||||
#define TMXR_DBG_CFG 0x01000000 /* Debug Line Configuration Activities */
|
||||
#define TMXR_DBG_CON 0x02000000 /* Debug Connection Activities */
|
||||
#define TMXR_DBG_ASY 0x04000000 /* Debug Asynchronous Activities */
|
||||
#define TMXR_DBG_TRC 0x08000000 /* Debug trace routine calls */
|
||||
@ -140,6 +141,9 @@ struct tmln {
|
||||
char *ipad; /* IP address */
|
||||
SOCKET master; /* line specific master socket */
|
||||
char *port; /* line specific listening port */
|
||||
char *acl; /* Access control list (CIDR) to accept or reject connects from */
|
||||
int32 acl_accepted_sessions; /* count of ACL accepted tcp connections */
|
||||
int32 acl_rejected_sessions; /* count of ACL rejected tcp connections */
|
||||
int32 sessions; /* count of tcp connections received */
|
||||
uint32 cnms; /* conn time */
|
||||
int32 tsta; /* Telnet state */
|
||||
@ -217,6 +221,9 @@ struct tmxr {
|
||||
TMLN *ldsc; /* line descriptors */
|
||||
int32 *lnorder; /* line connection order */
|
||||
DEVICE *dptr; /* multiplexer device */
|
||||
char *acl; /* Access control list (CIDR) to accept or reject connects from */
|
||||
int32 acl_accepted_sessions; /* count of ACL accepted tcp connections */
|
||||
int32 acl_rejected_sessions; /* count of ACL rejected tcp connections */
|
||||
UNIT *uptr; /* polling unit (connection) */
|
||||
char logfiletmpl[FILENAME_MAX]; /* template logfile name */
|
||||
int32 txcount; /* count of transmit bytes */
|
||||
@ -318,7 +325,7 @@ const char *tmxr_send_line_name (const SEND *snd);
|
||||
const char *tmxr_expect_line_name (const EXPECT *exp);
|
||||
t_stat tmxr_startup (void);
|
||||
t_stat tmxr_shutdown (void);
|
||||
t_stat tmxr_sock_test (DEVICE *dptr);
|
||||
t_stat tmxr_sock_test (DEVICE *dptr, const char *cptr);
|
||||
t_stat tmxr_start_poll (void);
|
||||
t_stat tmxr_stop_poll (void);
|
||||
/* Framer support. These are a NOP if called on a non-framer line. */
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user