TMXR: Provide Modem RING signal to notify MUX line of potential connection

When a new connection arrives it will be bound to the first line found
which has DTR enabled (considering the line order rules).  If none is
available, then all currently unconnected lines will have the RING signal
enabled.  If no such lines exist, the incoming connection is rejected with
"All connections busy".   If a currently disconnected line (with RING
enabled) raises DTR within 3 seconds, then that line gets the pending
connection and all other lines with RING enabled have RING disabled.
If 3 seconds pass without DTR coming up on any line with RING enabled
coming on, all lines with RING enabled will have RING disabled and the
incoming connection will be rejected with "No answer on any connection"
This commit is contained in:
Mark Pizzolato 2016-04-08 03:09:51 -07:00
parent 7b3e63aa75
commit e05de3e50c
2 changed files with 119 additions and 16 deletions

View file

@ -431,6 +431,14 @@ static BITFIELD tmxr_modem_bits[] = {
ENDBITS
};
static u_char mantra[] = { /* Telnet Option Negotiation Mantra */
TN_IAC, TN_WILL, TN_LINE,
TN_IAC, TN_WILL, TN_SGA,
TN_IAC, TN_WILL, TN_ECHO,
TN_IAC, TN_WILL, TN_BIN,
TN_IAC, TN_DO, TN_BIN
};
/* Local routines */
static void tmxr_add_to_open_list (TMXR* mux);
@ -957,13 +965,6 @@ int32 i, j;
char *address;
char msg[512];
uint32 poll_time = sim_os_msec ();
static u_char mantra[] = {
TN_IAC, TN_WILL, TN_LINE,
TN_IAC, TN_WILL, TN_SGA,
TN_IAC, TN_WILL, TN_ECHO,
TN_IAC, TN_WILL, TN_BIN,
TN_IAC, TN_DO, TN_BIN
};
if (mp->last_poll_time == 0) { /* first poll initializations */
UNIT *uptr = mp->uptr;
@ -999,6 +1000,13 @@ mp->last_poll_time = poll_time;
/* Check for a pending Telnet/tcp connection */
if (mp->master) {
if (mp->ring_sock != INVALID_SOCKET) { /* Use currently 'ringing' socket if one is active */
newsock = mp->ring_sock;
mp->ring_sock = INVALID_SOCKET;
address = mp->ring_ipad;
mp->ring_ipad = NULL;
}
else
newsock = sim_accept_conn_ex (mp->master, &address, (mp->packet ? SIM_SOCK_OPT_NODELAY : 0));/* poll connect */
if (newsock != INVALID_SOCKET) { /* got a live one? */
@ -1024,17 +1032,62 @@ if (mp->master) {
}
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->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;
tmxr_set_get_modem_bits (lp, TMXR_MDM_RNG, 0, NULL);
tmxr_debug_connect_line (lp, "tmxr_poll_conn() - Ringing line");
}
}
if (ringable_count > 0) {
if (mp->ring_start_time == 0) {
mp->ring_start_time = poll_time;
mp->ring_sock = newsock;
mp->ring_ipad = address;
}
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);
}
}
}
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 {
lp = mp->ldsc + i; /* get line desc */
tmxr_init_line (lp); /* init line */
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 */
if (!lp->notelnet) {
sim_write_sock (newsock, (char *)mantra, sizeof(mantra));
@ -1137,10 +1190,10 @@ for (i = 0; i < mp->lines; i++) { /* check each line in se
}
if (lp->conn == FALSE) { /* is the line available? */
if ((!lp->modem_control) || (lp->modembits & TMXR_MDM_DTR)) {
tmxr_init_line (lp); /* init line */
lp->conn = TRUE; /* record connection */
lp->sock = newsock; /* save socket */
lp->ipad = address; /* ip address */
tmxr_init_line (lp); /* init line */
if (!lp->notelnet) {
sim_write_sock (newsock, (char *)mantra, sizeof(mantra));
tmxr_debug (TMXR_DBG_XMT, lp, "Sending", (char *)mantra, sizeof(mantra));
@ -1383,14 +1436,50 @@ if ((lp->sock) || (lp->serport) || (lp->loopback)) {
incoming_state |= TMXR_MDM_DCD;
}
else
incoming_state = TMXR_MDM_DCD | TMXR_MDM_DSR;
incoming_state = TMXR_MDM_DCD | TMXR_MDM_DSR | ((lp->modembits & TMXR_MDM_DTR) ? 0 : TMXR_MDM_RNG);
}
else {
if (((before_modem_bits & TMXR_MDM_DTR) == 0) && /* Upward transition of DTR? */
((lp->modembits & TMXR_MDM_DTR) != 0) &&
(lp->conn == FALSE) && /* Not connected */
(lp->modembits & TMXR_MDM_RNG)) { /* and Ring Signal Present */
if ((lp->destination == NULL) &&
(lp->master == 0) &&
(lp->mp && (lp->mp->ring_sock))) {
int ln;
lp->conn = TRUE; /* record connection */
lp->sock = lp->mp->ring_sock; /* save socket */
lp->mp->ring_sock = INVALID_SOCKET;
lp->ipad = lp->mp->ring_ipad; /* ip address */
lp->mp->ring_ipad = NULL;
lp->mp->ring_start_time = 0;
tmxr_init_line (lp); /* init line */
lp->notelnet = lp->mp->notelnet; /* apply mux default telnet setting */
if (!lp->notelnet) {
sim_write_sock (lp->sock, (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 (lp->mp, lp);
lp->cnms = sim_os_msec (); /* time of connection */
lp->modembits &= ~TMXR_MDM_RNG; /* turn off ring on this line*/
/* turn off other 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 ((lp->master) || (lp->mp && lp->mp->master) ||
(lp->port && lp->destination))
incoming_state = TMXR_MDM_DSR;
else
incoming_state = 0;
}
lp->modembits |= incoming_state;
dptr = (lp->dptr ? lp->dptr : (lp->mp ? lp->mp->dptr : NULL));
if ((lp->modembits != before_modem_bits) && (sim_deb && lp->mp && dptr)) {
@ -3614,6 +3703,9 @@ else {
}
}
fprintf(st, "\n");
if (mp->ring_start_time) {
fprintf (st, " incoming Connection from: %s ringing for %d milliseconds\n", mp->ring_ipad, sim_os_msec () - mp->ring_start_time);
}
for (j = 0; j < mp->lines; j++) {
lp = mp->ldsc + j;
if (mp->lines > 1) {
@ -3708,6 +3800,13 @@ if (mp->master)
mp->master = 0;
free (mp->port);
mp->port = NULL;
if (mp->ring_sock != INVALID_SOCKET) {
sim_close_sock (mp->ring_sock);
mp->ring_sock = INVALID_SOCKET;
free (mp->ring_ipad);
mp->ring_ipad = NULL;
mp->ring_start_time = 0;
}
_tmxr_remove_from_open_list (mp);
return SCPE_OK;
}

View file

@ -64,6 +64,7 @@ typedef int SERHANDLE;
#define TMXR_GUARD 12 /* buffer guard */
#define TMXR_DTR_DROP_TIME 500 /* milliseconds to drop DTR for 'pseudo' modem control */
#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 0x0010000 /* Debug Transmit Data */
@ -211,6 +212,9 @@ struct tmxr {
int32 sessions; /* count of tcp connections received */
uint32 poll_interval; /* frequency of connection polls (seconds) */
uint32 last_poll_time; /* time of last connection poll */
uint32 ring_start_time; /* time ring signal was raised */
char *ring_ipad; /* incoming connection address awaiting DTR */
SOCKET ring_sock; /* incoming connection socket awaiting DTR */
t_bool notelnet; /* default telnet capability for incoming connections */
t_bool modem_control; /* multiplexer supports modem control behaviors */
t_bool packet; /* Lines are packet oriented */