mirror of
https://github.com/tsl0922/ttyd.git
synced 2025-12-22 20:04:19 +01:00
protocol: use binary message
This commit is contained in:
@@ -17,7 +17,7 @@ html, body {
|
|||||||
background-color: #101010;
|
background-color: #101010;
|
||||||
color: #f0f0f0;
|
color: #f0f0f0;
|
||||||
font-size: 10pt;
|
font-size: 10pt;
|
||||||
font-family: Menlo,Consolas,"DejaVu Sans Mono","Liberation Mono",Courier,monospace;
|
font-family: "Menlo for Powerline", Menlo,Consolas,"DejaVu Sans Mono","Liberation Mono",Courier,monospace;
|
||||||
font-variant-ligatures: none;
|
font-variant-ligatures: none;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
<link inline href="css/app.css">
|
<link inline href="css/app.css">
|
||||||
<script inline src="node_modules/xterm/dist/xterm.js"></script>
|
<script inline src="node_modules/xterm/dist/xterm.js"></script>
|
||||||
<script inline src="node_modules/xterm/dist/addons/fit/fit.js"></script>
|
<script inline src="node_modules/xterm/dist/addons/fit/fit.js"></script>
|
||||||
<script inline src="js/utf8.js"></script>
|
|
||||||
<script inline src="js/overlay.js"></script>
|
<script inline src="js/overlay.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@@ -8,18 +8,30 @@
|
|||||||
term, pingTimer, wsError;
|
term, pingTimer, wsError;
|
||||||
|
|
||||||
var openWs = function() {
|
var openWs = function() {
|
||||||
var ws = new WebSocket(url, protocols);
|
var ws = new WebSocket(url, protocols),
|
||||||
|
textDecoder = new TextDecoder(),
|
||||||
|
textEncoder = new TextEncoder();
|
||||||
var unloadCallback = function(event) {
|
var unloadCallback = function(event) {
|
||||||
var message = 'Close terminal? this will also terminate the command.';
|
var message = 'Close terminal? this will also terminate the command.';
|
||||||
(event || window.event).returnValue = message;
|
(event || window.event).returnValue = message;
|
||||||
return message;
|
return message;
|
||||||
};
|
};
|
||||||
|
var sendMessage = function (msg) {
|
||||||
|
if (ws.readyState === WebSocket.OPEN) {
|
||||||
|
ws.send(textEncoder.encode(msg));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var sendPing = function() {
|
||||||
|
sendMessage("1");
|
||||||
|
};
|
||||||
|
|
||||||
ws.onopen = function(event) {
|
ws.binaryType = 'arraybuffer';
|
||||||
|
|
||||||
|
ws.onopen = function() {
|
||||||
console.log("Websocket connection opened");
|
console.log("Websocket connection opened");
|
||||||
wsError = false;
|
wsError = false;
|
||||||
ws.send(JSON.stringify({AuthToken: authToken}));
|
sendMessage(JSON.stringify({AuthToken: authToken}));
|
||||||
pingTimer = setInterval(sendPing, 30 * 1000, ws);
|
pingTimer = setInterval(sendPing, 30 * 1000);
|
||||||
|
|
||||||
if (typeof term !== 'undefined') {
|
if (typeof term !== 'undefined') {
|
||||||
term.destroy();
|
term.destroy();
|
||||||
@@ -28,18 +40,14 @@
|
|||||||
term = new Terminal();
|
term = new Terminal();
|
||||||
|
|
||||||
term.on('resize', function(size) {
|
term.on('resize', function(size) {
|
||||||
if (ws.readyState === WebSocket.OPEN) {
|
sendMessage("2" + JSON.stringify({columns: size.cols, rows: size.rows}));
|
||||||
ws.send("2" + JSON.stringify({columns: size.cols, rows: size.rows}));
|
|
||||||
}
|
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
term.showOverlay(size.cols + 'x' + size.rows);
|
term.showOverlay(size.cols + 'x' + size.rows);
|
||||||
}, 500);
|
}, 500);
|
||||||
});
|
});
|
||||||
|
|
||||||
term.on("data", function(data) {
|
term.on("data", function(data) {
|
||||||
if (ws.readyState === WebSocket.OPEN) {
|
sendMessage("0" + data);
|
||||||
ws.send("0" + data);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
term.on('open', function() {
|
term.on('open', function() {
|
||||||
@@ -62,10 +70,11 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
ws.onmessage = function(event) {
|
ws.onmessage = function(event) {
|
||||||
var data = event.data.slice(1);
|
var cmd = String.fromCharCode(new DataView(event.data).getUint8()),
|
||||||
switch(event.data[0]) {
|
data = textDecoder.decode(event.data.slice(1));
|
||||||
|
switch(cmd) {
|
||||||
case '0':
|
case '0':
|
||||||
term.writeUTF8(window.atob(data));
|
term.write(data);
|
||||||
break;
|
break;
|
||||||
case '1': // pong
|
case '1': // pong
|
||||||
break;
|
break;
|
||||||
@@ -104,9 +113,5 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
var sendPing = function(ws) {
|
|
||||||
ws.send("1");
|
|
||||||
};
|
|
||||||
|
|
||||||
openWs();
|
openWs();
|
||||||
})();
|
})();
|
||||||
118
html/js/utf8.js
118
html/js/utf8.js
@@ -1,118 +0,0 @@
|
|||||||
// ported from hterm.Terminal.IO.prototype.writeUTF8
|
|
||||||
// https://chromium.googlesource.com/apps/libapps/+/master/hterm/js/hterm_terminal_io.js
|
|
||||||
|
|
||||||
UTF8Decoder = function() {
|
|
||||||
this.bytesLeft = 0;
|
|
||||||
this.codePoint = 0;
|
|
||||||
this.lowerBound = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
UTF8Decoder.prototype.decode = function(str) {
|
|
||||||
var ret = '';
|
|
||||||
for (var i = 0; i < str.length; i++) {
|
|
||||||
var c = str.charCodeAt(i);
|
|
||||||
if (this.bytesLeft == 0) {
|
|
||||||
if (c <= 0x7F) {
|
|
||||||
ret += str.charAt(i);
|
|
||||||
} else if (0xC0 <= c && c <= 0xDF) {
|
|
||||||
this.codePoint = c - 0xC0;
|
|
||||||
this.bytesLeft = 1;
|
|
||||||
this.lowerBound = 0x80;
|
|
||||||
} else if (0xE0 <= c && c <= 0xEF) {
|
|
||||||
this.codePoint = c - 0xE0;
|
|
||||||
this.bytesLeft = 2;
|
|
||||||
this.lowerBound = 0x800;
|
|
||||||
} else if (0xF0 <= c && c <= 0xF7) {
|
|
||||||
this.codePoint = c - 0xF0;
|
|
||||||
this.bytesLeft = 3;
|
|
||||||
this.lowerBound = 0x10000;
|
|
||||||
} else if (0xF8 <= c && c <= 0xFB) {
|
|
||||||
this.codePoint = c - 0xF8;
|
|
||||||
this.bytesLeft = 4;
|
|
||||||
this.lowerBound = 0x200000;
|
|
||||||
} else if (0xFC <= c && c <= 0xFD) {
|
|
||||||
this.codePoint = c - 0xFC;
|
|
||||||
this.bytesLeft = 5;
|
|
||||||
this.lowerBound = 0x4000000;
|
|
||||||
} else {
|
|
||||||
ret += '\ufffd';
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (0x80 <= c && c <= 0xBF) {
|
|
||||||
this.bytesLeft--;
|
|
||||||
this.codePoint = (this.codePoint << 6) + (c - 0x80);
|
|
||||||
if (this.bytesLeft == 0) {
|
|
||||||
var codePoint = this.codePoint;
|
|
||||||
if (codePoint < this.lowerBound
|
|
||||||
|| (0xD800 <= codePoint && codePoint <= 0xDFFF)
|
|
||||||
|| codePoint > 0x10FFFF) {
|
|
||||||
ret += '\ufffd';
|
|
||||||
} else {
|
|
||||||
if (codePoint < 0x10000) {
|
|
||||||
ret += String.fromCharCode(codePoint);
|
|
||||||
} else {
|
|
||||||
codePoint -= 0x10000;
|
|
||||||
ret += String.fromCharCode(
|
|
||||||
0xD800 + ((codePoint >>> 10) & 0x3FF),
|
|
||||||
0xDC00 + (codePoint & 0x3FF));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ret += '\ufffd';
|
|
||||||
this.bytesLeft = 0;
|
|
||||||
i--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
};
|
|
||||||
|
|
||||||
Terminal.prototype.decodeUTF8 = function(str) {
|
|
||||||
return (new UTF8Decoder()).decode(str);
|
|
||||||
};
|
|
||||||
|
|
||||||
Terminal.prototype.encodeUTF8 = function(str) {
|
|
||||||
var ret = '';
|
|
||||||
for (var i = 0; i < str.length; i++) {
|
|
||||||
var c = str.charCodeAt(i);
|
|
||||||
if (0xDC00 <= c && c <= 0xDFFF) {
|
|
||||||
c = 0xFFFD;
|
|
||||||
} else if (0xD800 <= c && c <= 0xDBFF) {
|
|
||||||
if (i+1 < str.length) {
|
|
||||||
var d = str.charCodeAt(i+1);
|
|
||||||
if (0xDC00 <= d && d <= 0xDFFF) {
|
|
||||||
c = 0x10000 + ((c & 0x3FF) << 10) + (d & 0x3FF);
|
|
||||||
i++;
|
|
||||||
} else {
|
|
||||||
c = 0xFFFD;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
c = 0xFFFD;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var bytesLeft;
|
|
||||||
if (c <= 0x7F) {
|
|
||||||
ret += str.charAt(i);
|
|
||||||
continue;
|
|
||||||
} else if (c <= 0x7FF) {
|
|
||||||
ret += String.fromCharCode(0xC0 | (c >>> 6));
|
|
||||||
bytesLeft = 1;
|
|
||||||
} else if (c <= 0xFFFF) {
|
|
||||||
ret += String.fromCharCode(0xE0 | (c >>> 12));
|
|
||||||
bytesLeft = 2;
|
|
||||||
} else {
|
|
||||||
ret += String.fromCharCode(0xF0 | (c >>> 18));
|
|
||||||
bytesLeft = 3;
|
|
||||||
}
|
|
||||||
while (bytesLeft > 0) {
|
|
||||||
bytesLeft--;
|
|
||||||
ret += String.fromCharCode(0x80 | ((c >>> (6 * bytesLeft)) & 0x3F));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
};
|
|
||||||
|
|
||||||
Terminal.prototype.writeUTF8 = function (str) {
|
|
||||||
this.write(this.decodeUTF8(str));
|
|
||||||
};
|
|
||||||
5
src/index.html
vendored
5
src/index.html
vendored
File diff suppressed because one or more lines are too long
103
src/protocol.c
103
src/protocol.c
@@ -1,7 +1,5 @@
|
|||||||
#include "server.h"
|
#include "server.h"
|
||||||
|
|
||||||
#define BUF_SIZE 1024
|
|
||||||
|
|
||||||
int
|
int
|
||||||
send_initial_message(struct lws *wsi) {
|
send_initial_message(struct lws *wsi) {
|
||||||
unsigned char message[LWS_PRE + 256];
|
unsigned char message[LWS_PRE + 256];
|
||||||
@@ -13,17 +11,17 @@ send_initial_message(struct lws *wsi) {
|
|||||||
|
|
||||||
// window title
|
// window title
|
||||||
n = sprintf((char *) p, "%c%s (%s)", SET_WINDOW_TITLE, server->command, hostname);
|
n = sprintf((char *) p, "%c%s (%s)", SET_WINDOW_TITLE, server->command, hostname);
|
||||||
if (lws_write(wsi, p, (size_t) n, LWS_WRITE_TEXT) < n) {
|
if (lws_write(wsi, p, (size_t) n, LWS_WRITE_BINARY) < n) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
// reconnect time
|
// reconnect time
|
||||||
n = sprintf((char *) p, "%c%d", SET_RECONNECT, server->reconnect);
|
n = sprintf((char *) p, "%c%d", SET_RECONNECT, server->reconnect);
|
||||||
if (lws_write(wsi, p, (size_t) n, LWS_WRITE_TEXT) < n) {
|
if (lws_write(wsi, p, (size_t) n, LWS_WRITE_BINARY) < n) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
// client preferences
|
// client preferences
|
||||||
n = sprintf((char *) p, "%c%s", SET_PREFERENCES, server->prefs_json);
|
n = sprintf((char *) p, "%c%s", SET_PREFERENCES, server->prefs_json);
|
||||||
if (lws_write(wsi, p, (size_t) n, LWS_WRITE_TEXT) < n) {
|
if (lws_write(wsi, p, (size_t) n, LWS_WRITE_BINARY) < n) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -86,7 +84,7 @@ check_host_origin(struct lws *wsi) {
|
|||||||
|
|
||||||
void
|
void
|
||||||
tty_client_remove(struct tty_client *client) {
|
tty_client_remove(struct tty_client *client) {
|
||||||
pthread_mutex_lock(&server->lock);
|
pthread_mutex_lock(&server->mutex);
|
||||||
struct tty_client *iterator;
|
struct tty_client *iterator;
|
||||||
LIST_FOREACH(iterator, &server->clients, list) {
|
LIST_FOREACH(iterator, &server->clients, list) {
|
||||||
if (iterator == client) {
|
if (iterator == client) {
|
||||||
@@ -95,7 +93,7 @@ tty_client_remove(struct tty_client *client) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pthread_mutex_unlock(&server->lock);
|
pthread_mutex_unlock(&server->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -119,6 +117,8 @@ tty_client_destroy(struct tty_client *client) {
|
|||||||
if (client->buffer != NULL)
|
if (client->buffer != NULL)
|
||||||
free(client->buffer);
|
free(client->buffer);
|
||||||
|
|
||||||
|
pthread_mutex_destroy(&client->mutex);
|
||||||
|
|
||||||
// remove from client list
|
// remove from client list
|
||||||
tty_client_remove(client);
|
tty_client_remove(client);
|
||||||
}
|
}
|
||||||
@@ -127,8 +127,6 @@ void *
|
|||||||
thread_run_command(void *args) {
|
thread_run_command(void *args) {
|
||||||
struct tty_client *client;
|
struct tty_client *client;
|
||||||
int pty;
|
int pty;
|
||||||
int bytes;
|
|
||||||
char buf[BUF_SIZE];
|
|
||||||
fd_set des_set;
|
fd_set des_set;
|
||||||
|
|
||||||
client = (struct tty_client *) args;
|
client = (struct tty_client *) args;
|
||||||
@@ -141,11 +139,11 @@ thread_run_command(void *args) {
|
|||||||
case 0: /* child */
|
case 0: /* child */
|
||||||
if (setenv("TERM", "xterm-256color", true) < 0) {
|
if (setenv("TERM", "xterm-256color", true) < 0) {
|
||||||
perror("setenv");
|
perror("setenv");
|
||||||
exit(1);
|
pthread_exit((void *) 1);
|
||||||
}
|
}
|
||||||
if (execvp(server->argv[0], server->argv) < 0) {
|
if (execvp(server->argv[0], server->argv) < 0) {
|
||||||
perror("execvp");
|
perror("execvp");
|
||||||
exit(1);
|
pthread_exit((void *) 1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default: /* parent */
|
default: /* parent */
|
||||||
@@ -164,23 +162,25 @@ thread_run_command(void *args) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
if (FD_ISSET (pty, &des_set)) {
|
if (FD_ISSET (pty, &des_set)) {
|
||||||
memset(buf, 0, BUF_SIZE);
|
while (client->running) {
|
||||||
bytes = (int) read(pty, buf, BUF_SIZE);
|
pthread_mutex_lock(&client->mutex);
|
||||||
struct pty_data *frame = (struct pty_data *) xmalloc(sizeof(struct pty_data));
|
if (client->state == STATE_READY) {
|
||||||
frame->len = bytes;
|
pthread_mutex_unlock(&client->mutex);
|
||||||
if (bytes > 0) {
|
usleep(5);
|
||||||
frame->data = xmalloc((size_t) bytes);
|
continue;
|
||||||
memcpy(frame->data, buf, bytes);
|
}
|
||||||
|
memset(client->pty_buffer, 0, sizeof(client->pty_buffer));
|
||||||
|
client->pty_len = read(pty, client->pty_buffer, sizeof(client->pty_buffer));
|
||||||
|
client->state = STATE_READY;
|
||||||
|
pthread_mutex_unlock(&client->mutex);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
pthread_mutex_lock(&client->lock);
|
|
||||||
STAILQ_INSERT_TAIL(&client->queue, frame, list);
|
|
||||||
pthread_mutex_unlock(&client->lock);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
pthread_exit((void *) 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -216,15 +216,17 @@ callback_tty(struct lws *wsi, enum lws_callback_reasons reason,
|
|||||||
client->authenticated = false;
|
client->authenticated = false;
|
||||||
client->wsi = wsi;
|
client->wsi = wsi;
|
||||||
client->buffer = NULL;
|
client->buffer = NULL;
|
||||||
|
client->state = STATE_INIT;
|
||||||
|
client->pty_len = 0;
|
||||||
|
pthread_mutex_init(&client->mutex, NULL);
|
||||||
lws_get_peer_addresses(wsi, lws_get_socket_fd(wsi),
|
lws_get_peer_addresses(wsi, lws_get_socket_fd(wsi),
|
||||||
client->hostname, sizeof(client->hostname),
|
client->hostname, sizeof(client->hostname),
|
||||||
client->address, sizeof(client->address));
|
client->address, sizeof(client->address));
|
||||||
STAILQ_INIT(&client->queue);
|
|
||||||
|
|
||||||
pthread_mutex_lock(&server->lock);
|
pthread_mutex_lock(&server->mutex);
|
||||||
LIST_INSERT_HEAD(&server->clients, client, list);
|
LIST_INSERT_HEAD(&server->clients, client, list);
|
||||||
server->client_count++;
|
server->client_count++;
|
||||||
pthread_mutex_unlock(&server->lock);
|
pthread_mutex_unlock(&server->mutex);
|
||||||
lws_hdr_copy(wsi, buf, sizeof(buf), WSI_TOKEN_GET_URI);
|
lws_hdr_copy(wsi, buf, sizeof(buf), WSI_TOKEN_GET_URI);
|
||||||
|
|
||||||
lwsl_notice("WS %s - %s (%s), clients: %d\n", buf, client->address, client->hostname, server->client_count);
|
lwsl_notice("WS %s - %s (%s), clients: %d\n", buf, client->address, client->hostname, server->client_count);
|
||||||
@@ -240,44 +242,31 @@ callback_tty(struct lws *wsi, enum lws_callback_reasons reason,
|
|||||||
client->initialized = true;
|
client->initialized = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (client->state != STATE_READY)
|
||||||
|
break;
|
||||||
|
|
||||||
pthread_mutex_lock(&client->lock);
|
// read error or client exited, close connection
|
||||||
while (!STAILQ_EMPTY(&client->queue)) {
|
if (client->pty_len <= 0) {
|
||||||
struct pty_data *frame = STAILQ_FIRST(&client->queue);
|
tty_client_remove(client);
|
||||||
// read error or client exited, close connection
|
lws_close_reason(wsi,
|
||||||
if (frame->len <= 0) {
|
client->pty_len == 0 ? LWS_CLOSE_STATUS_NORMAL
|
||||||
STAILQ_REMOVE_HEAD(&client->queue, list);
|
: LWS_CLOSE_STATUS_UNEXPECTED_CONDITION,
|
||||||
free(frame);
|
NULL, 0);
|
||||||
tty_client_remove(client);
|
return -1;
|
||||||
lws_close_reason(wsi,
|
}
|
||||||
frame->len == 0 ? LWS_CLOSE_STATUS_NORMAL : LWS_CLOSE_STATUS_UNEXPECTED_CONDITION,
|
|
||||||
NULL, 0);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *b64_text = base64_encode((const unsigned char *) frame->data, (size_t) frame->len);
|
{
|
||||||
size_t msg_len = LWS_PRE + strlen(b64_text) + 1;
|
size_t n = (size_t) client->pty_len + 1;
|
||||||
unsigned char message[msg_len];
|
unsigned char message[LWS_PRE + n];
|
||||||
unsigned char *p = &message[LWS_PRE];
|
unsigned char *p = &message[LWS_PRE];
|
||||||
size_t n = sprintf((char *) p, "%c%s", OUTPUT, b64_text);
|
*p = OUTPUT;
|
||||||
|
memcpy(p + 1, client->pty_buffer, client->pty_len);
|
||||||
|
client->state = STATE_DONE;
|
||||||
|
|
||||||
free(b64_text);
|
if (lws_write(wsi, p, n, LWS_WRITE_BINARY) < n) {
|
||||||
|
|
||||||
if (lws_write(wsi, p, n, LWS_WRITE_TEXT) < n) {
|
|
||||||
lwsl_err("write data to WS\n");
|
lwsl_err("write data to WS\n");
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
STAILQ_REMOVE_HEAD(&client->queue, list);
|
|
||||||
free(frame->data);
|
|
||||||
free(frame);
|
|
||||||
|
|
||||||
if (lws_partial_buffered(wsi)) {
|
|
||||||
lws_callback_on_writable(wsi);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pthread_mutex_unlock(&client->lock);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LWS_CALLBACK_RECEIVE:
|
case LWS_CALLBACK_RECEIVE:
|
||||||
@@ -321,7 +310,7 @@ callback_tty(struct lws *wsi, enum lws_callback_reasons reason,
|
|||||||
case PING:
|
case PING:
|
||||||
{
|
{
|
||||||
unsigned char c = PONG;
|
unsigned char c = PONG;
|
||||||
if (lws_write(wsi, &c, 1, LWS_WRITE_TEXT) != 1) {
|
if (lws_write(wsi, &c, 1, LWS_WRITE_BINARY) != 1) {
|
||||||
lwsl_err("send PONG\n");
|
lwsl_err("send PONG\n");
|
||||||
tty_client_remove(client);
|
tty_client_remove(client);
|
||||||
lws_close_reason(wsi, LWS_CLOSE_STATUS_UNEXPECTED_CONDITION, NULL, 0);
|
lws_close_reason(wsi, LWS_CLOSE_STATUS_UNEXPECTED_CONDITION, NULL, 0);
|
||||||
|
|||||||
13
src/server.c
13
src/server.c
@@ -140,6 +140,7 @@ tty_server_free(struct tty_server *ts) {
|
|||||||
unlink(ts->socket_path);
|
unlink(ts->socket_path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pthread_mutex_destroy(&ts->mutex);
|
||||||
free(ts);
|
free(ts);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,6 +204,7 @@ main(int argc, char **argv) {
|
|||||||
|
|
||||||
int start = calc_command_start(argc, argv);
|
int start = calc_command_start(argc, argv);
|
||||||
server = tty_server_new(argc, argv, start);
|
server = tty_server_new(argc, argv, start);
|
||||||
|
pthread_mutex_init(&server->mutex, NULL);
|
||||||
|
|
||||||
struct lws_context_creation_info info;
|
struct lws_context_creation_info info;
|
||||||
memset(&info, 0, sizeof(info));
|
memset(&info, 0, sizeof(info));
|
||||||
@@ -442,16 +444,19 @@ main(int argc, char **argv) {
|
|||||||
|
|
||||||
// libwebsockets main loop
|
// libwebsockets main loop
|
||||||
while (!force_exit) {
|
while (!force_exit) {
|
||||||
pthread_mutex_lock(&server->lock);
|
pthread_mutex_lock(&server->mutex);
|
||||||
if (!LIST_EMPTY(&server->clients)) {
|
if (!LIST_EMPTY(&server->clients)) {
|
||||||
struct tty_client *client;
|
struct tty_client *client;
|
||||||
LIST_FOREACH(client, &server->clients, list) {
|
LIST_FOREACH(client, &server->clients, list) {
|
||||||
if (client->running && !STAILQ_EMPTY(&client->queue)) {
|
if (client->running) {
|
||||||
lws_callback_on_writable(client->wsi);
|
pthread_mutex_lock(&client->mutex);
|
||||||
|
if (client->state != STATE_DONE)
|
||||||
|
lws_callback_on_writable(client->wsi);
|
||||||
|
pthread_mutex_unlock(&client->mutex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pthread_mutex_unlock(&server->lock);
|
pthread_mutex_unlock(&server->mutex);
|
||||||
lws_service(context, 10);
|
lws_service(context, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
18
src/server.h
18
src/server.h
@@ -66,14 +66,14 @@
|
|||||||
// websocket url path
|
// websocket url path
|
||||||
#define WS_PATH "/ws"
|
#define WS_PATH "/ws"
|
||||||
|
|
||||||
|
#define BUF_SIZE 32768 // 32K
|
||||||
|
|
||||||
extern volatile bool force_exit;
|
extern volatile bool force_exit;
|
||||||
extern struct lws_context *context;
|
extern struct lws_context *context;
|
||||||
extern struct tty_server *server;
|
extern struct tty_server *server;
|
||||||
|
|
||||||
struct pty_data {
|
enum pty_state {
|
||||||
char *data;
|
STATE_INIT, STATE_READY, STATE_DONE
|
||||||
int len;
|
|
||||||
STAILQ_ENTRY(pty_data) list;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct tty_client {
|
struct tty_client {
|
||||||
@@ -87,12 +87,14 @@ struct tty_client {
|
|||||||
struct winsize size;
|
struct winsize size;
|
||||||
char *buffer;
|
char *buffer;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
int pid;
|
int pid;
|
||||||
int pty;
|
int pty;
|
||||||
|
enum pty_state state;
|
||||||
|
char pty_buffer[BUF_SIZE];
|
||||||
|
ssize_t pty_len;
|
||||||
pthread_t thread;
|
pthread_t thread;
|
||||||
|
pthread_mutex_t mutex;
|
||||||
STAILQ_HEAD(pty, pty_data) queue;
|
|
||||||
pthread_mutex_t lock;
|
|
||||||
|
|
||||||
LIST_ENTRY(tty_client) list;
|
LIST_ENTRY(tty_client) list;
|
||||||
};
|
};
|
||||||
@@ -113,7 +115,7 @@ struct tty_server {
|
|||||||
int max_clients; // maximum clients to support
|
int max_clients; // maximum clients to support
|
||||||
bool once; // whether accept only one client and exit on disconnection
|
bool once; // whether accept only one client and exit on disconnection
|
||||||
char socket_path[255]; // UNIX domain socket path
|
char socket_path[255]; // UNIX domain socket path
|
||||||
pthread_mutex_t lock;
|
pthread_mutex_t mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern int
|
extern int
|
||||||
|
|||||||
Reference in New Issue
Block a user