From 4911d0d39c210f8a7f433a80b8a47544404e71d9 Mon Sep 17 00:00:00 2001 From: KLuka Date: Mon, 28 Dec 2015 15:24:49 +0100 Subject: [PATCH] Issue #222: LOGIN service (can't reopen tty) * Workaround for random "Session closed" issues related to /bin/login closing and reopening our pty during initialization. This happens only on some systems like Fedora for example. Now we allow that our pty is closed by ignoring POLLHUP on first read. Delay is also needed so that login process has some time to reopen pty. * Note that the issue may occur anyway but with this workaround we reduce the chances. --- shellinabox/session.c | 2 ++ shellinabox/session.h | 2 ++ shellinabox/shellinaboxd.c | 30 ++++++++++++++++++++++++++++-- 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/shellinabox/session.c b/shellinabox/session.c index e699a5a..2f72dff 100644 --- a/shellinabox/session.c +++ b/shellinabox/session.c @@ -116,9 +116,11 @@ void initSession(struct Session *session, const char *sessionKey, session->http = NULL; session->done = 0; session->pty = -1; + session->ptyFirstRead = 1; session->width = 0; session->height = 0; session->buffered = NULL; + session->useLogin = 0; session->len = 0; session->pid = 0; session->cleanup = 0; diff --git a/shellinabox/session.h b/shellinabox/session.h index 73d0eb3..b6b3747 100644 --- a/shellinabox/session.h +++ b/shellinabox/session.h @@ -58,9 +58,11 @@ struct Session { HttpConnection *http; int done; int pty; + int ptyFirstRead; int width; int height; char *buffered; + int useLogin; int len; pid_t pid; int cleanup; diff --git a/shellinabox/shellinaboxd.c b/shellinabox/shellinaboxd.c index ad911cf..2362cf2 100644 --- a/shellinabox/shellinaboxd.c +++ b/shellinabox/shellinaboxd.c @@ -63,7 +63,7 @@ #include #include #include - +#include #include #ifdef HAVE_SYS_PRCTL_H @@ -291,6 +291,13 @@ static void sessionDone(void *arg) { completePendingRequest(session, "", 0, INT_MAX); } +static void delaySession(void) { + struct timespec ts; + ts.tv_sec = 0; + ts.tv_nsec = 200 * 1000; // Delay for 0.2 ms + nanosleep(&ts, NULL); +} + static int handleSession(struct ServerConnection *connection, void *arg, short *events, short revents) { struct Session *session = (struct Session *)arg; @@ -310,7 +317,7 @@ static int handleSession(struct ServerConnection *connection, void *arg, int timedOut = serverGetTimeout(connection) < 0; if (bytes || timedOut) { if (!session->http && timedOut) { - debug("[server] Timeout. Closing session!"); + debug("[server] Timeout. Closing session %s!", session->sessionKey); session->cleanup = 1; return 0; } @@ -324,8 +331,26 @@ static int handleSession(struct ServerConnection *connection, void *arg, *events = 0; } serverSetTimeout(connection, AJAX_TIMEOUT); + session->ptyFirstRead = 0; return 1; } else { + if (revents & POLLHUP) { + if (session->useLogin && session->ptyFirstRead) { + // Workaround for random "Session closed" issues related to /bin/login + // closing and reopening our pty during initialization. This happens only + // on some systems like Fedora for example. + // Here we allow that our pty is closed by ignoring POLLHUP on first read. + // Delay is also needed so that login process has some time to reopen pty. + // Note that the issue may occur anyway but with workaround we reduce the + // chances. + debug("[server] POLLHUP received on login PTY first read!"); + session->ptyFirstRead = 0; + delaySession(); + return 1; + } + debug("[server] POLLHUP received on PTY! Closing session %s!", + session->sessionKey); + } return 0; } } @@ -402,6 +427,7 @@ static int dataHandler(HttpConnection *http, struct Service *service, goto bad_new_session; } session->http = http; + session->useLogin = service->useLogin; if (launchChild(service->id, session, rootURL && *rootURL ? rootURL : urlGetURL(url)) < 0) { abandonSession(session);