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:
parent
b466bdc9c6
commit
59afee3128
2 changed files with 123 additions and 90 deletions
212
sim_tmxr.c
212
sim_tmxr.c
|
@ -255,10 +255,18 @@
|
|||
A device emulation may choose to implement a command interface to
|
||||
disconnect specific individual lines. This would usually be done via
|
||||
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
|
||||
|
||||
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.
|
||||
|
||||
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 */
|
||||
|
||||
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? */
|
||||
sprintf (msg, "tmxr_poll_conn() - Connection from %s", address);
|
||||
tmxr_debug_trace (mp, msg);
|
||||
op = mp->lnorder; /* get line connection order list pointer */
|
||||
i = mp->lines; /* play it safe in case lines == 0 */
|
||||
++mp->sessions; /* count the new session */
|
||||
if (newsock != INVALID_SOCKET) { /* got a live one? */
|
||||
sprintf (msg, "tmxr_poll_conn() - Connection from %s", address);
|
||||
tmxr_debug_trace (mp, msg);
|
||||
op = mp->lnorder; /* get line connection order list pointer */
|
||||
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 */
|
||||
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 == 0) && /* is the line available? */
|
||||
(lp->destination == NULL) &&
|
||||
(lp->master == 0))
|
||||
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));
|
||||
lp = mp->ldsc + i; /* get pointer to line descriptor */
|
||||
if ((lp->conn == 0) && /* is the line available? */
|
||||
(lp->destination == NULL) &&
|
||||
(lp->master == 0))
|
||||
break; /* yes, so stop search */
|
||||
}
|
||||
tmxr_report_connection (mp, lp);
|
||||
lp->cnms = sim_os_msec (); /* time of conn */
|
||||
return i;
|
||||
}
|
||||
} /* end if newsock */
|
||||
|
||||
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 */
|
||||
return i;
|
||||
}
|
||||
} /* end if newsock */
|
||||
}
|
||||
|
||||
/* Look for per line listeners or outbound connecting sockets */
|
||||
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 */
|
||||
|
||||
newsock = sim_accept_conn (lp->master, &address); /* poll connect */
|
||||
if (lp->master) {
|
||||
|
||||
if (newsock != INVALID_SOCKET) { /* got a live one? */
|
||||
sprintf (msg, "tmxr_poll_conn() - Line Connection from %s", address);
|
||||
tmxr_debug_trace_line (lp, msg);
|
||||
++mp->sessions; /* count the new session */
|
||||
newsock = sim_accept_conn (lp->master, &address);/* poll connect */
|
||||
|
||||
if (lp->destination) { /* Virtual Null Modem Cable? */
|
||||
char host[CBUFSIZE];
|
||||
if (newsock != INVALID_SOCKET) { /* got a live one? */
|
||||
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)) {
|
||||
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);
|
||||
if (lp->destination) { /* Virtual Null Modem Cable? */
|
||||
char host[CBUFSIZE];
|
||||
|
||||
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);
|
||||
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);
|
||||
free (address);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for pending serial port connection notification */
|
||||
|
||||
if (lp->ser_connect_pending) {
|
||||
lp->ser_connect_pending = FALSE;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -832,8 +852,9 @@ return -1; /* no new connections ma
|
|||
|
||||
The telnet/tcp or serial session associated with multiplexer descriptor "mp" and
|
||||
line descriptor "lp" is disconnected. An associated tcp socket is
|
||||
deallocated; a serial port is not, although for non modem control serial lines
|
||||
DTR is dropped and raised again after 500ms to signal the attached serial device.
|
||||
closed; a serial port is closed if the closeserial parameter is true, otherwise
|
||||
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)
|
||||
|
@ -847,6 +868,9 @@ if (lp->serport) {
|
|||
if (closeserial) {
|
||||
sim_close_serial (lp->serport);
|
||||
lp->serport = 0;
|
||||
lp->ser_connect_pending = FALSE;
|
||||
free (lp->destination);
|
||||
lp->destination = NULL;
|
||||
free (lp->serconfig);
|
||||
lp->serconfig = NULL;
|
||||
lp->cnms = 0;
|
||||
|
@ -879,6 +903,11 @@ else {
|
|||
tmxr_init_line (lp); /* initialize line state */
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1572,6 +1601,7 @@ while (*tptr) {
|
|||
if (serport != INVALID_HANDLE) {
|
||||
lp->mp = mp;
|
||||
lp->serport = serport;
|
||||
lp->ser_connect_pending = TRUE;
|
||||
lp->notelnet = TRUE;
|
||||
tmxr_init_line (lp); /* init the line state */
|
||||
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);
|
||||
if (serport != INVALID_HANDLE) {
|
||||
lp->serport = serport;
|
||||
lp->ser_connect_pending = TRUE;
|
||||
lp->notelnet = TRUE;
|
||||
tmxr_init_line (lp); /* init the line state */
|
||||
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
|
||||
attached. For single-line multiplexers that may be attached either to a
|
||||
listening socket or to a serial port, call "tmxr_detach_line" first. If that
|
||||
routine returns SCPE_UNATT, then call "tmxr_detach".
|
||||
attached.
|
||||
*/
|
||||
|
||||
t_stat tmxr_detach (TMXR *mp, UNIT *uptr)
|
||||
|
@ -2119,17 +2149,19 @@ static const char *enab = "on";
|
|||
static const char *dsab = "off";
|
||||
|
||||
if (ln >= 0)
|
||||
fprintf (st, "line %d:\b", ln);
|
||||
fprintf (st, "line %d:\n", ln);
|
||||
if ((!lp->conn) && (!lp->connecting) && (!lp->serport))
|
||||
fprintf (st, "line disconnected\n");
|
||||
if (lp->rxcnt)
|
||||
fprintf (st, " input (%s) queued/total = %d/%d\n",
|
||||
(lp->rcve? enab: dsab),
|
||||
tmxr_rqln (lp), lp->rxcnt);
|
||||
if (lp->txcnt || lp->txbpi)
|
||||
fprintf (st, " output (%s) queued/total = %d/%d\n",
|
||||
(lp->xmte? enab: dsab),
|
||||
tmxr_tqln (lp), lp->txcnt);
|
||||
else {
|
||||
if ((lp->rxcnt) || (!lp->rcve))
|
||||
fprintf (st, " input (%s) queued/total = %d/%d\n",
|
||||
(lp->rcve? enab: dsab),
|
||||
tmxr_rqln (lp), lp->rxcnt);
|
||||
if (lp->txcnt || lp->txbpi || (!lp->xmte))
|
||||
fprintf (st, " output (%s) queued/total = %d/%d\n",
|
||||
(lp->xmte? enab: dsab),
|
||||
tmxr_tqln (lp), lp->txcnt);
|
||||
}
|
||||
if (lp->txbfd)
|
||||
fprintf (st, " output buffer size = %d\n", lp->txbsz);
|
||||
if (lp->txcnt || lp->txbpi)
|
||||
|
@ -2185,7 +2217,7 @@ if (lp == NULL) /* bad line numb
|
|||
if ((lp->conn) || (lp->serport)) { /* connection active? */
|
||||
if (!lp->notelnet)
|
||||
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;
|
||||
|
|
|
@ -116,6 +116,7 @@ struct tmln {
|
|||
TMXR *mp; /* back pointer to mux */
|
||||
char *serconfig; /* line config */
|
||||
SERHANDLE serport; /* serial port handle */
|
||||
t_bool ser_connect_pending; /* serial connection notice pending */
|
||||
SOCKET connecting; /* Outgoing socket while connecting */
|
||||
char *destination; /* Outgoing destination address:port */
|
||||
UNIT *uptr; /* input polling unit (default to mp->uptr) */
|
||||
|
|
Loading…
Add table
Reference in a new issue