1
0
mirror of https://github.com/UzixLS/picocom.git synced 2025-07-19 07:21:18 +03:00

Better RFC2217 socket shutdown / close

When an RFC2217 socket is closed, optionally, try to drain the
buffered data allowing the remote server to read and process
them. First the socket is shutdown only in the transmit (write)
direction. Then data are read from it (and discarded) until the server
closes the other direction (read(2) returns zero).

Also, don't bother trying to reset the port to its original settings
before exiting, since closing the connection to the remote server will
do this anyway (as per RFC2217).
This commit is contained in:
Nick Patavalis
2018-02-24 16:04:44 +02:00
parent 91916afc14
commit bcc753167a
3 changed files with 57 additions and 12 deletions

View File

@ -647,20 +647,23 @@ cleanup (int drain, int noreset, int hup)
/* Print msg if they fail? Can't do anything, anyway... */
if ( drain )
term_drain(tty_fd);
term_flush(tty_fd);
/* term_flush does not work with some drivers. If we try to
drain or even close the port while there are still data in
it's output buffers *and* flow-control is enabled we may
block forever. So we "fake" a flush, by temporarily setting
f/c to none, waiting for any data in the output buffer to
drain, and then reseting f/c to it's original setting. If
the real flush above does works, then the fake one should
amount to instantaneously switching f/c to none and then
back to its propper setting. */
if ( opts.flow != FC_NONE ) term_fake_flush(tty_fd);
else {
term_flush(tty_fd);
/* term_flush does not work with some drivers. If we try
to drain or even close the port while there are still
data in it's output buffers *and* flow-control is
enabled we may block forever. So we "fake" a flush, by
temporarily setting f/c to none, waiting for any data
in the output buffer to drain, and then reseting f/c to
it's original setting. If the real flush above does
work, then the fake one should amount to
instantaneously switching f/c to none and then back to
its propper setting. */
if ( opts.flow != FC_NONE ) term_fake_flush(tty_fd);
}
term_set_hupcl(tty_fd, !noreset || hup);
term_apply(tty_fd, 1);
if ( noreset ) {
if ( noreset || opts.telnet ) {
pinfo("Skipping tty reset...\r\n");
term_erase(tty_fd);
#ifdef USE_FLOCK
@ -668,7 +671,14 @@ cleanup (int drain, int noreset, int hup)
comments in term.c/term_exitfunc() for more. */
flock(tty_fd, LOCK_UN);
#endif
#ifdef USE_RFC2217
if ( opts.telnet )
tn2217_close(tty_fd, drain);
else
close(tty_fd);
#else
close(tty_fd);
#endif
tty_fd = -1;
}
}

View File

@ -435,6 +435,33 @@ out:
return fd;
}
/* Closes a TCP socket to a host. See "tn2217.h". */
int
tn2217_close(int fd, int drain)
{
char buff[1024];
long fl;
int n;
if ( ! drain )
return close(fd);
/* FIXME(npat): Maybe protect the "reading until server closes"
with a large-ish timeout? */
fl = fcntl(fd, F_GETFL);
fl &= ~O_NONBLOCK;
fcntl(fd, F_SETFL, fl);
shutdown(fd, SHUT_WR);
do {
n = read(fd, buff, sizeof(buff));
} while ( n > 0 );
if ( n < 0 )
return n;
return close(fd);
}
/* Sends {IAC SB COMPORT <cmd> <data> IAC SE} */
static void
tn2217_send_comport_cmd(struct term_s *t, unsigned char cmd,

View File

@ -32,6 +32,14 @@
* Returns -1 on failure, and prints an error message to stderr. */
int tn2217_open(const char *port);
/* Close a socket to a telnet service. If "drain" is zero, the socket
* is just close(2)ed and the return-value of close(2) is returned. If
* "drain" is non-zero, the write-direction of the socket is first
* shutdown, and then data are read (and discarded) from the socket,
* until the remote end closes it (read(2) returns zero). Returns zero
* on success, a negative on error. */
int tn2217_close(int fd, int drain);
struct term_ops;
extern const struct term_ops tn2217_ops;