--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
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();
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]);
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);
+ };
};
void
tty_client_destroy(struct tty_client *client) {
- if (client->exit)
+ if (client->exit || client->pid <= 0)
return;
// stop event loop
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;
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:
{"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"
" --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"
case 'd':
debug_level = atoi(optarg);
break;
+ case 'o':
+ server->once = true;
+ break;
case 'p':
info.port = atoi(optarg);
if (info.port < 0) {
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) {
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;
};