From e05de3e50cd7038360e98a24a1dd050455c2cd1b Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Fri, 8 Apr 2016 03:09:51 -0700 Subject: [PATCH] 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" --- sim_tmxr.c | 131 ++++++++++++++++++++++++++++++++++++++++++++++------- sim_tmxr.h | 4 ++ 2 files changed, 119 insertions(+), 16 deletions(-) diff --git a/sim_tmxr.c b/sim_tmxr.c index 2d835cc7..492e3c85 100644 --- a/sim_tmxr.c +++ b/sim_tmxr.c @@ -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,7 +1000,14 @@ mp->last_poll_time = poll_time; /* Check for a pending Telnet/tcp connection */ if (mp->master) { - newsock = sim_accept_conn_ex (mp->master, &address, (mp->packet ? SIM_SOCK_OPT_NODELAY : 0));/* poll connect */ + 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? */ sprintf (msg, "tmxr_poll_conn() - Connection from %s", address); @@ -1024,17 +1032,62 @@ if (mp->master) { } if (i >= mp->lines) { /* all busy? */ - tmxr_msg (newsock, "All connections busy\r\n"); - tmxr_debug_connect (mp, "tmxr_poll_conn() - All connections busy"); - sim_close_sock (newsock); - free (address); + 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 +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; + } + } + } 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; } diff --git a/sim_tmxr.h b/sim_tmxr.h index 146973ed..4ecef785 100644 --- a/sim_tmxr.h +++ b/sim_tmxr.h @@ -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 */