This commit is contained in:
Alexey Gladkov 2021-12-02 10:47:33 +00:00 committed by GitHub
commit 16536d2ae8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 129 additions and 5 deletions

View File

@ -37,6 +37,7 @@
#include <sys/wait.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/queue.h>
#if defined(__linux__) || defined(__CYGWIN__)
# include <pty.h>
#elif defined(__FreeBSD__) || defined(__DragonFly__)
@ -102,14 +103,24 @@ struct Client {
Client *next;
};
struct entry {
char *data;
int len;
bool complete;
TAILQ_ENTRY(entry) entries;
};
TAILQ_HEAD(screenhead, entry);
typedef struct {
Client *clients;
int socket;
Packet pty_output;
int pty;
int exit_status;
struct termios term;
struct winsize winsize;
struct screenhead screen;
int screen_rows;
pid_t pid;
volatile sig_atomic_t running;
const char *name;
@ -118,10 +129,11 @@ typedef struct {
bool read_pty;
} Server;
static Server server = { .running = true, .exit_status = -1, .host = "@localhost" };
static Server server = { .running = true, .exit_status = -1, .host = "@localhost", .screen_rows = 0 };
static Client client;
static struct termios orig_term, cur_term;
static bool has_term, alternate_buffer, quiet, passthrough;
static int screen_max_rows = 120;
static struct sockaddr_un sockaddr = {
.sun_family = AF_UNIX,
@ -223,7 +235,7 @@ static void die(const char *s) {
}
static void usage(void) {
fprintf(stderr, "usage: abduco [-a|-A|-c|-n] [-p] [-r] [-q] [-l] [-f] [-e detachkey] name command\n");
fprintf(stderr, "usage: abduco [-a|-A|-c|-n] [-p] [-r] [-q] [-l] [-f] [-e detachkey] [-L num] name command\n");
exit(EXIT_FAILURE);
}
@ -606,7 +618,7 @@ int main(int argc, char *argv[]) {
server.name = basename(argv[0]);
gethostname(server.host+1, sizeof(server.host) - 1);
while ((opt = getopt(argc, argv, "aAclne:fpqrv")) != -1) {
while ((opt = getopt(argc, argv, "aAclne:fpqrvL:")) != -1) {
switch (opt) {
case 'a':
case 'A':
@ -636,6 +648,15 @@ int main(int argc, char *argv[]) {
case 'l':
client.flags |= CLIENT_LOWPRIORITY;
break;
case 'L':
if (!optarg)
usage();
screen_max_rows = atoi(optarg);
if (screen_max_rows < 0) {
fputs("ERROR: a negative value for the number of rows is meaningless.\n", stderr);
usage();
}
break;
case 'v':
puts("abduco-"VERSION" © 2013-2018 Marc André Tanner");
exit(EXIT_SUCCESS);

105
server.c
View File

@ -178,6 +178,93 @@ static void server_atexit_handler(void) {
unlink(sockaddr.sun_path);
}
static void server_send_screen_buffer(Client *c) {
struct entry *np;
TAILQ_FOREACH_REVERSE(np, &server.screen, screenhead, entries) {
Packet pkt = {
.type = MSG_CONTENT,
.len = np->len,
};
strncpy(pkt.u.msg, np->data, np->len);
server_send_packet(c, &pkt);
}
}
static void server_preserve_screen_data(Packet *pkt) {
char *str, *end;
uint32_t len;
struct entry *scrline = NULL;
if (screen_max_rows == 0 || pkt->len <= 0 || pkt->type != MSG_CONTENT)
return;
str = pkt->u.msg;
len = pkt->len;
end = str + len;
while (str != end) {
char *data;
uint32_t i, dlen;
bool newline = false;
char *token = end;
for (i = 0; i < len; i++) {
if (str[i] == '\n') {
token = str + i + 1;
newline = true;
break;
}
}
if ((dlen = token - str) <= 0)
break;
scrline = TAILQ_FIRST(&server.screen);
if (scrline && !scrline->complete) {
data = realloc(scrline->data, scrline->len + dlen);
if (!data)
die("unable to extend string in the screen buffer");
memcpy(data + scrline->len, str, dlen);
scrline->complete = newline;
scrline->data = data;
scrline->len += dlen;
} else {
data = malloc(dlen);
if (!data)
die("unable to allocate memory for new line in the screen buffer");
memcpy(data, str, dlen);
scrline = malloc(sizeof(*scrline));
if (!scrline)
die("unable to allocate memory for screen buffer element");
scrline->complete = newline;
scrline->data = data;
scrline->len = dlen;
TAILQ_INSERT_HEAD(&server.screen, scrline, entries);
server.screen_rows++;
if (server.screen_rows > screen_max_rows) {
scrline = TAILQ_LAST(&server.screen, screenhead);
TAILQ_REMOVE(&server.screen, scrline, entries);
free(scrline->data);
free(scrline);
server.screen_rows--;
}
}
str = token;
len -= dlen;
}
}
static void server_mainloop(void) {
atexit(server_atexit_handler);
fd_set new_readfds, new_writefds;
@ -187,6 +274,8 @@ static void server_mainloop(void) {
int new_fdmax = server.socket;
bool exit_packet_delivered = false;
TAILQ_INIT(&server.screen);
if (server.read_pty)
FD_SET_MAX(server.pty, &new_readfds, new_fdmax);
@ -213,8 +302,11 @@ static void server_mainloop(void) {
if (FD_ISSET(server.socket, &readfds))
server_accept_client();
if (FD_ISSET(server.pty, &readfds))
if (FD_ISSET(server.pty, &readfds)) {
pty_data = server_read_pty(&server_packet);
if (pty_data)
server_preserve_screen_data(&server_packet);
}
for (Client **prev_next = &server.clients, *c = server.clients; c;) {
if (FD_ISSET(c->socket, &readfds) && server_recv_packet(c, &client_packet)) {
@ -226,6 +318,7 @@ static void server_mainloop(void) {
c->flags = client_packet.u.i;
if (c->flags & CLIENT_LOWPRIORITY)
server_sink_client();
server_send_screen_buffer(c);
break;
case MSG_RESIZE:
c->state = STATE_ATTACHED;
@ -291,5 +384,15 @@ static void server_mainloop(void) {
FD_SET_MAX(server.pty, &new_readfds, new_fdmax);
}
struct entry *n1, *n2;
n1 = TAILQ_FIRST(&server.screen);
while (n1 != NULL) {
n2 = TAILQ_NEXT(n1, entries);
free(n1->data);
free(n1);
n1 = n2;
}
exit(EXIT_SUCCESS);
}