Serial Multiplexer cleanup after review by Dave Bryan

- Added functionality to return the lines with attached serial ports by calling tmxr_poll_conn one time after a serial port is attached.
- Added the ability to close a serial port from the sim> prompt if a device implements a SET dev DISCONNECT=line command.  A serial port is closed if the -C switch is specified on the DISCONNECT command line.
- Cleaned up the multiplexer status display based on Dave's recommendations.
This commit is contained in:
Mark Pizzolato 2012-12-13 13:46:43 -08:00
parent b466bdc9c6
commit 59afee3128
2 changed files with 123 additions and 90 deletions

View file

@ -255,10 +255,18 @@
A device emulation may choose to implement a command interface to A device emulation may choose to implement a command interface to
disconnect specific individual lines. This would usually be done via disconnect specific individual lines. This would usually be done via
a Unit Modifier table entry (MTAB) which dispatches the command a Unit Modifier table entry (MTAB) which dispatches the command
"SET dev DISCONNECT[=line]" to tmxr_detach_line. "SET dev DISCONNECT[=line]" to tmxr_dscln. This will cause a telnet
connection to be closed, but a serial port will normally have DTR
dropped for 500ms and raised again (thus hanging up a modem on that
serial port).
sim> set MUX disconnect=2 sim> set MUX disconnect=2
A line which is connected to a serial port can be manually closed by
adding the -C switch to a disconnect command.
sim> set -C MUX disconnect=2
Full Modem Control serial port support. Full Modem Control serial port support.
This library supports devices which wish to emulate full modem This library supports devices which wish to emulate full modem
@ -717,49 +725,51 @@ mp->last_poll_time = poll_time;
/* Check for a pending Telnet connection */ /* Check for a pending Telnet connection */
newsock = sim_accept_conn (mp->master, &address); /* poll connect */ if (mp->master) {
newsock = sim_accept_conn (mp->master, &address); /* poll connect */
if (newsock != INVALID_SOCKET) { /* got a live one? */ if (newsock != INVALID_SOCKET) { /* got a live one? */
sprintf (msg, "tmxr_poll_conn() - Connection from %s", address); sprintf (msg, "tmxr_poll_conn() - Connection from %s", address);
tmxr_debug_trace (mp, msg); tmxr_debug_trace (mp, msg);
op = mp->lnorder; /* get line connection order list pointer */ op = mp->lnorder; /* get line connection order list pointer */
i = mp->lines; /* play it safe in case lines == 0 */ i = mp->lines; /* play it safe in case lines == 0 */
++mp->sessions; /* count the new session */ ++mp->sessions; /* count the new session */
for (j = 0; j < mp->lines; j++, i++) { /* find next avail line */ for (j = 0; j < mp->lines; j++, i++) { /* find next avail line */
if (op && (*op >= 0) && (*op < mp->lines)) /* order list present and valid? */ if (op && (*op >= 0) && (*op < mp->lines)) /* order list present and valid? */
i = *op++; /* get next line in list to try */ i = *op++; /* get next line in list to try */
else /* no list or not used or range error */ else /* no list or not used or range error */
i = j; /* get next sequential line */ i = j; /* get next sequential line */
lp = mp->ldsc + i; /* get pointer to line descriptor */ lp = mp->ldsc + i; /* get pointer to line descriptor */
if ((lp->conn == 0) && /* is the line available? */ if ((lp->conn == 0) && /* is the line available? */
(lp->destination == NULL) && (lp->destination == NULL) &&
(lp->master == 0)) (lp->master == 0))
break; /* yes, so stop search */ break; /* yes, so stop search */
}
if (i >= mp->lines) { /* all busy? */
tmxr_msg (newsock, "All connections busy\r\n");
tmxr_debug_trace (mp, "tmxr_poll_conn() - All connections busy");
sim_close_sock (newsock, 0);
free (address);
}
else {
lp = mp->ldsc + i; /* get line desc */
tmxr_init_line (lp); /* init line */
lp->conn = newsock; /* record connection */
lp->ipad = address; /* ip address */
lp->notelnet = mp->notelnet; /* apply mux default telnet setting */
if (!lp->notelnet) {
sim_write_sock (newsock, mantra, sizeof(mantra));
tmxr_debug (TMXR_DBG_XMT, lp, "Sending", mantra, sizeof(mantra));
} }
tmxr_report_connection (mp, lp);
lp->cnms = sim_os_msec (); /* time of conn */ if (i >= mp->lines) { /* all busy? */
return i; tmxr_msg (newsock, "All connections busy\r\n");
} tmxr_debug_trace (mp, "tmxr_poll_conn() - All connections busy");
} /* end if newsock */ sim_close_sock (newsock, 0);
free (address);
}
else {
lp = mp->ldsc + i; /* get line desc */
tmxr_init_line (lp); /* init line */
lp->conn = newsock; /* record connection */
lp->ipad = address; /* ip address */
lp->notelnet = mp->notelnet; /* apply mux default telnet setting */
if (!lp->notelnet) {
sim_write_sock (newsock, mantra, sizeof(mantra));
tmxr_debug (TMXR_DBG_XMT, lp, "Sending", mantra, sizeof(mantra));
}
tmxr_report_connection (mp, lp);
lp->cnms = sim_os_msec (); /* time of conn */
return i;
}
} /* end if newsock */
}
/* Look for per line listeners or outbound connecting sockets */ /* Look for per line listeners or outbound connecting sockets */
for (i = 0; i < mp->lines; i++) { /* check each line in sequence */ for (i = 0; i < mp->lines; i++) { /* check each line in sequence */
@ -781,47 +791,57 @@ for (i = 0; i < mp->lines; i++) { /* check each line in se
/* Check for a pending Telnet connection */ /* Check for a pending Telnet connection */
newsock = sim_accept_conn (lp->master, &address); /* poll connect */ if (lp->master) {
if (newsock != INVALID_SOCKET) { /* got a live one? */ newsock = sim_accept_conn (lp->master, &address);/* poll connect */
sprintf (msg, "tmxr_poll_conn() - Line Connection from %s", address);
tmxr_debug_trace_line (lp, msg);
++mp->sessions; /* count the new session */
if (lp->destination) { /* Virtual Null Modem Cable? */ if (newsock != INVALID_SOCKET) { /* got a live one? */
char host[CBUFSIZE]; sprintf (msg, "tmxr_poll_conn() - Line Connection from %s", address);
tmxr_debug_trace_line (lp, msg);
++mp->sessions; /* count the new session */
if (sim_parse_addr (lp->destination, host, sizeof(host), NULL, NULL, 0, NULL, address)) { if (lp->destination) { /* Virtual Null Modem Cable? */
tmxr_msg (newsock, "Rejecting connection from unexpected source\r\n"); char host[CBUFSIZE];
sprintf (msg, "tmxr_poll_conn() - Rejecting line connection from: %s, Expected: %s", address, host);
tmxr_debug_trace_line (lp, msg); if (sim_parse_addr (lp->destination, host, sizeof(host), NULL, NULL, 0, NULL, address)) {
tmxr_msg (newsock, "Rejecting connection from unexpected source\r\n");
sprintf (msg, "tmxr_poll_conn() - Rejecting line connection from: %s, Expected: %s", address, host);
tmxr_debug_trace_line (lp, msg);
sim_close_sock (newsock, 0);
free (address);
continue; /* Move on to next line */
}
if (lp->connecting) {
sim_close_sock (lp->connecting, 0); /* abort our as yet unconnnected socket */
lp->connecting = 0;
}
}
if (lp->conn == 0) { /* is the line available? */
tmxr_init_line (lp); /* init line */
lp->conn = newsock; /* record connection */
lp->ipad = address; /* ip address */
if (!lp->notelnet) {
sim_write_sock (newsock, mantra, sizeof(mantra));
tmxr_debug (TMXR_DBG_XMT, lp, "Sending", mantra, sizeof(mantra));
}
tmxr_report_connection (mp, lp);
lp->cnms = sim_os_msec (); /* time of conn */
return i;
}
else {
tmxr_msg (newsock, "Line connection busy\r\n");
tmxr_debug_trace_line (lp, "tmxr_poll_conn() - Line connection busy");
sim_close_sock (newsock, 0); sim_close_sock (newsock, 0);
free (address); free (address);
continue; /* Move on to next line */
}
if (lp->connecting) {
sim_close_sock (lp->connecting, 0); /* abort our as yet unconnnected socket */
lp->connecting = 0;
} }
} }
if (lp->conn == 0) { /* is the line available? */ }
tmxr_init_line (lp); /* init line */
lp->conn = newsock; /* record connection */ /* Check for pending serial port connection notification */
lp->ipad = address; /* ip address */
if (!lp->notelnet) { if (lp->ser_connect_pending) {
sim_write_sock (newsock, mantra, sizeof(mantra)); lp->ser_connect_pending = FALSE;
tmxr_debug (TMXR_DBG_XMT, lp, "Sending", mantra, sizeof(mantra)); return i;
}
tmxr_report_connection (mp, lp);
lp->cnms = sim_os_msec (); /* time of conn */
return i;
}
else {
tmxr_msg (newsock, "Line connection busy\r\n");
tmxr_debug_trace_line (lp, "tmxr_poll_conn() - Line connection busy");
sim_close_sock (newsock, 0);
free (address);
}
} }
} }
@ -832,8 +852,9 @@ return -1; /* no new connections ma
The telnet/tcp or serial session associated with multiplexer descriptor "mp" and The telnet/tcp or serial session associated with multiplexer descriptor "mp" and
line descriptor "lp" is disconnected. An associated tcp socket is line descriptor "lp" is disconnected. An associated tcp socket is
deallocated; a serial port is not, although for non modem control serial lines closed; a serial port is closed if the closeserial parameter is true, otherwise
DTR is dropped and raised again after 500ms to signal the attached serial device. for non modem control serial lines DTR is dropped and raised again after 500ms
to signal the attached serial device.
*/ */
static t_stat tmxr_reset_ln_ex (TMLN *lp, t_bool closeserial) static t_stat tmxr_reset_ln_ex (TMLN *lp, t_bool closeserial)
@ -847,6 +868,9 @@ if (lp->serport) {
if (closeserial) { if (closeserial) {
sim_close_serial (lp->serport); sim_close_serial (lp->serport);
lp->serport = 0; lp->serport = 0;
lp->ser_connect_pending = FALSE;
free (lp->destination);
lp->destination = NULL;
free (lp->serconfig); free (lp->serconfig);
lp->serconfig = NULL; lp->serconfig = NULL;
lp->cnms = 0; lp->cnms = 0;
@ -879,6 +903,11 @@ else {
tmxr_init_line (lp); /* initialize line state */ tmxr_init_line (lp); /* initialize line state */
lp->conn = 0; /* remove socket or connection flag */ lp->conn = 0; /* remove socket or connection flag */
} }
/* Revise the unit's connect string to reflect the current attachments */
lp->mp->uptr->filename = _mux_attach_string (lp->mp->uptr->filename, lp->mp);
/* No connections or listeners exist, then we're equivalent to being fully detached. We should reflect that */
if (lp->mp->uptr->filename == NULL)
tmxr_detach (lp->mp, lp->mp->uptr);
return SCPE_OK; return SCPE_OK;
} }
@ -1572,6 +1601,7 @@ while (*tptr) {
if (serport != INVALID_HANDLE) { if (serport != INVALID_HANDLE) {
lp->mp = mp; lp->mp = mp;
lp->serport = serport; lp->serport = serport;
lp->ser_connect_pending = TRUE;
lp->notelnet = TRUE; lp->notelnet = TRUE;
tmxr_init_line (lp); /* init the line state */ tmxr_init_line (lp); /* init the line state */
if (!lp->mp->modem_control) /* raise DTR and RTS for non modem control lines */ if (!lp->mp->modem_control) /* raise DTR and RTS for non modem control lines */
@ -1677,6 +1707,7 @@ while (*tptr) {
serport = sim_open_serial (lp->destination, lp, &r); serport = sim_open_serial (lp->destination, lp, &r);
if (serport != INVALID_HANDLE) { if (serport != INVALID_HANDLE) {
lp->serport = serport; lp->serport = serport;
lp->ser_connect_pending = TRUE;
lp->notelnet = TRUE; lp->notelnet = TRUE;
tmxr_init_line (lp); /* init the line state */ tmxr_init_line (lp); /* init the line state */
if (!lp->mp->modem_control) /* raise DTR and RTS for non modem control lines */ if (!lp->mp->modem_control) /* raise DTR and RTS for non modem control lines */
@ -2016,12 +2047,11 @@ return SCPE_OK;
} }
/* Detach unit from master socket. /* Detach unit from master socket and close all active network connections
and/or serial ports.
Note that we return SCPE_OK, regardless of whether a listening socket was Note that we return SCPE_OK, regardless of whether a listening socket was
attached. For single-line multiplexers that may be attached either to a attached.
listening socket or to a serial port, call "tmxr_detach_line" first. If that
routine returns SCPE_UNATT, then call "tmxr_detach".
*/ */
t_stat tmxr_detach (TMXR *mp, UNIT *uptr) t_stat tmxr_detach (TMXR *mp, UNIT *uptr)
@ -2119,17 +2149,19 @@ static const char *enab = "on";
static const char *dsab = "off"; static const char *dsab = "off";
if (ln >= 0) if (ln >= 0)
fprintf (st, "line %d:\b", ln); fprintf (st, "line %d:\n", ln);
if ((!lp->conn) && (!lp->connecting) && (!lp->serport)) if ((!lp->conn) && (!lp->connecting) && (!lp->serport))
fprintf (st, "line disconnected\n"); fprintf (st, "line disconnected\n");
if (lp->rxcnt) else {
fprintf (st, " input (%s) queued/total = %d/%d\n", if ((lp->rxcnt) || (!lp->rcve))
(lp->rcve? enab: dsab), fprintf (st, " input (%s) queued/total = %d/%d\n",
tmxr_rqln (lp), lp->rxcnt); (lp->rcve? enab: dsab),
if (lp->txcnt || lp->txbpi) tmxr_rqln (lp), lp->rxcnt);
fprintf (st, " output (%s) queued/total = %d/%d\n", if (lp->txcnt || lp->txbpi || (!lp->xmte))
(lp->xmte? enab: dsab), fprintf (st, " output (%s) queued/total = %d/%d\n",
tmxr_tqln (lp), lp->txcnt); (lp->xmte? enab: dsab),
tmxr_tqln (lp), lp->txcnt);
}
if (lp->txbfd) if (lp->txbfd)
fprintf (st, " output buffer size = %d\n", lp->txbsz); fprintf (st, " output buffer size = %d\n", lp->txbsz);
if (lp->txcnt || lp->txbpi) if (lp->txcnt || lp->txbpi)
@ -2185,7 +2217,7 @@ if (lp == NULL) /* bad line numb
if ((lp->conn) || (lp->serport)) { /* connection active? */ if ((lp->conn) || (lp->serport)) { /* connection active? */
if (!lp->notelnet) if (!lp->notelnet)
tmxr_linemsg (lp, "\r\nOperator disconnected line\r\n\n");/* report closure */ tmxr_linemsg (lp, "\r\nOperator disconnected line\r\n\n");/* report closure */
tmxr_reset_ln (lp); /* drop the line */ tmxr_reset_ln_ex (lp, (sim_switches & SWMASK ('C'))); /* drop the line */
} }
return SCPE_OK; return SCPE_OK;

View file

@ -116,6 +116,7 @@ struct tmln {
TMXR *mp; /* back pointer to mux */ TMXR *mp; /* back pointer to mux */
char *serconfig; /* line config */ char *serconfig; /* line config */
SERHANDLE serport; /* serial port handle */ SERHANDLE serport; /* serial port handle */
t_bool ser_connect_pending; /* serial connection notice pending */
SOCKET connecting; /* Outgoing socket while connecting */ SOCKET connecting; /* Outgoing socket while connecting */
char *destination; /* Outgoing destination address:port */ char *destination; /* Outgoing destination address:port */
UNIT *uptr; /* input polling unit (default to mp->uptr) */ UNIT *uptr; /* input polling unit (default to mp->uptr) */