From 3c9884a87b128fec70524f2b4d14876d874b0551 Mon Sep 17 00:00:00 2001 From: Shuanglei Tao Date: Mon, 10 Oct 2016 21:39:43 +0800 Subject: [PATCH] Add support for the --once option --- README.md | 1 + src/index.html | 36 +++++++++++++++++++++++++----------- src/protocol.c | 14 +++++++++++++- src/server.c | 9 ++++++++- src/server.h | 1 + 5 files changed, 48 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 8dd3759..117cf00 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,7 @@ OPTIONS: --gid, -g Group id to run with --signal, -s Signal to send to the command when exit it (default: SIGHUP) --reconnect, -r Time to reconnect for the client in seconds (default: 10) + --once, -o Accept only one client and exit on disconnection --ssl, -S Enable ssl --ssl-cert, -C Ssl certificate file path --ssl-key, -K Ssl key file path diff --git a/src/index.html b/src/index.html index 8a15414..25e5c63 100644 --- a/src/index.html +++ b/src/index.html @@ -600,20 +600,17 @@ var io = term.io.push(); io.onVTKeystroke = function(str) { - ws.send("0" + str); + if (ws.readyState === WebSocket.OPEN) { + ws.send("0" + str); + } }; io.sendString = io.onVTKeystroke; io.onTerminalResize = function(columns, rows) { - ws.send( - "2" + JSON.stringify( - { - columns: columns, - rows: rows, - } - ) - ) + if (ws.readyState === WebSocket.OPEN) { + ws.send("2" + JSON.stringify({columns: columns, rows: rows})); + } }; term.installKeyboard(); @@ -635,7 +632,7 @@ term.setWindowTitle(data); break; case '3': - preferences = JSON.parse(data); + var preferences = JSON.parse(data); Object.keys(preferences).forEach(function(key) { console.log("Setting " + key + ": " + preferences[key]); term.getPrefs().set(key, preferences[key]); @@ -651,13 +648,30 @@ ws.onclose = function(event) { if (term) { term.uninstallKeyboard(); - term.io.showOverlay("Connection Closed", null); + setTimeout(function(){ + term.io.showOverlay("Connection Closed", null); + }, 300); } clearInterval(pingTimer); if (autoReconnect > 0) { setTimeout(openWs, autoReconnect * 1000); } }; + + ws.onerror = function(event) { + var errorNode = document.createElement('div'); + errorNode.style.cssText = [ + "color: red", + "font-size: x-large", + "opacity: 0.75", + "text-align: center", + "margin: 1em", + "padding: 0.2em", + "border: 0.1em dotted #ccc" + ].join(";"); + errorNode.textContent = "Websocket handshake failed!"; + document.getElementById("terminal").appendChild(errorNode); + }; }; diff --git a/src/protocol.c b/src/protocol.c index 13077c9..7218c86 100644 --- a/src/protocol.c +++ b/src/protocol.c @@ -65,7 +65,7 @@ parse_window_size(const char *json) { void tty_client_destroy(struct tty_client *client) { - if (client->exit) + if (client->exit || client->pid <= 0) return; // stop event loop @@ -159,6 +159,12 @@ callback_tty(struct lws *wsi, enum lws_callback_reasons reason, struct winsize *size; switch (reason) { + case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION: + if (server->once && server->client_count > 0) { + lwsl_notice("refuse to serve new client due to the --once option.\n"); + return -1; + } + break; case LWS_CALLBACK_ESTABLISHED: client->exit = false; client->initialized = false; @@ -305,6 +311,12 @@ callback_tty(struct lws *wsi, enum lws_callback_reasons reason, case LWS_CALLBACK_CLOSED: tty_client_destroy(client); lwsl_notice("client disconnected from %s (%s), total: %d\n", client->hostname, client->address, server->client_count); + if (server->once && server->client_count == 0) { + lwsl_notice("exiting due to the --once option.\n"); + force_exit = true; + lws_cancel_service(context); + exit(0); + } break; default: diff --git a/src/server.c b/src/server.c index 7792cfa..2f5b412 100644 --- a/src/server.c +++ b/src/server.c @@ -33,12 +33,13 @@ static const struct option options[] = { {"ssl-cert", required_argument, NULL, 'C'}, {"ssl-key", required_argument, NULL, 'K'}, {"ssl-ca", required_argument, NULL, 'A'}, + {"once", no_argument, NULL, 'o'}, {"debug", required_argument, NULL, 'd'}, {"version", no_argument, NULL, 'v'}, {"help", no_argument, NULL, 'h'}, {NULL, 0, 0, 0} }; -static const char *opt_string = "p:i:c:u:g:s:r:aSC:K:A:d:vh"; +static const char *opt_string = "p:i:c:u:g:s:r:aSC:K:A:od:vh"; void print_help() { fprintf(stderr, "ttyd is a tool for sharing terminal over the web\n\n" @@ -54,6 +55,7 @@ void print_help() { " --gid, -g Group id to run with\n" " --signal, -s Signal to send to the command when exit it (default: SIGHUP)\n" " --reconnect, -r Time to reconnect for the client in seconds (default: 10)\n" + " --once, -o Accept only one client and exit on disconnection\n" " --ssl, -S Enable ssl\n" " --ssl-cert, -C Ssl certificate file path\n" " --ssl-key, -K Ssl key file path\n" @@ -200,6 +202,9 @@ main(int argc, char **argv) { case 'd': debug_level = atoi(optarg); break; + case 'o': + server->once = true; + break; case 'p': info.port = atoi(optarg); if (info.port < 0) { @@ -317,6 +322,8 @@ main(int argc, char **argv) { lwsl_notice(" start command: %s\n", server->command); lwsl_notice(" reconnect timeout: %ds\n", server->reconnect); lwsl_notice(" close signal: %s (%d)\n", server->sig_name, server->sig_code); + if (server->once) + lwsl_notice(" once: true\n"); // libwebsockets main loop while (!force_exit) { diff --git a/src/server.h b/src/server.h index 2e91451..8c197e8 100644 --- a/src/server.h +++ b/src/server.h @@ -71,6 +71,7 @@ struct tty_server { char **argv; // command with arguments int sig_code; // close signal char *sig_name; // human readable signal string + bool once; // whether accept only one client and exit on disconnection pthread_mutex_t lock; }; -- 2.43.4