mirror of https://github.com/martanne/abduco
Simplify I/O handling
This commit is contained in:
parent
6bd887dc96
commit
a99e46fd23
76
abduco.c
76
abduco.c
|
|
@ -77,20 +77,8 @@ typedef struct {
|
||||||
} u;
|
} u;
|
||||||
} Packet;
|
} Packet;
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
Packet pkt;
|
|
||||||
size_t off;
|
|
||||||
} ClientPacketState;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
Packet *pkt;
|
|
||||||
size_t off;
|
|
||||||
} ServerPacketState;
|
|
||||||
|
|
||||||
typedef struct Client Client;
|
typedef struct Client Client;
|
||||||
struct Client {
|
struct Client {
|
||||||
ServerPacketState output; /* display output as received from server */
|
|
||||||
ClientPacketState input; /* input as sent to the server */
|
|
||||||
int socket;
|
int socket;
|
||||||
enum {
|
enum {
|
||||||
STATE_CONNECTED,
|
STATE_CONNECTED,
|
||||||
|
|
@ -98,7 +86,6 @@ struct Client {
|
||||||
STATE_DETACHED,
|
STATE_DETACHED,
|
||||||
STATE_DISCONNECTED,
|
STATE_DISCONNECTED,
|
||||||
} state;
|
} state;
|
||||||
time_t last_activity;
|
|
||||||
bool need_resize;
|
bool need_resize;
|
||||||
Client *next;
|
Client *next;
|
||||||
};
|
};
|
||||||
|
|
@ -108,11 +95,6 @@ typedef struct {
|
||||||
int client_count;
|
int client_count;
|
||||||
int socket;
|
int socket;
|
||||||
Packet pty_output;
|
Packet pty_output;
|
||||||
ClientPacketState pty_input;
|
|
||||||
Packet queue[10];
|
|
||||||
unsigned int queue_count;
|
|
||||||
unsigned int queue_insert;
|
|
||||||
unsigned int queue_remove;
|
|
||||||
int pty;
|
int pty;
|
||||||
int exit_status;
|
int exit_status;
|
||||||
struct termios term;
|
struct termios term;
|
||||||
|
|
@ -134,6 +116,8 @@ static int create_socket(const char *name);
|
||||||
static void die(const char *s);
|
static void die(const char *s);
|
||||||
static void info(const char *str, ...);
|
static void info(const char *str, ...);
|
||||||
|
|
||||||
|
#include "debug.c"
|
||||||
|
|
||||||
static inline size_t packet_header_size() {
|
static inline size_t packet_header_size() {
|
||||||
return offsetof(Packet, u);
|
return offsetof(Packet, u);
|
||||||
}
|
}
|
||||||
|
|
@ -142,19 +126,61 @@ static size_t packet_size(Packet *pkt) {
|
||||||
return packet_header_size() + pkt->len;
|
return packet_header_size() + pkt->len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool is_client_packet_complete(ClientPacketState *pkt) {
|
static ssize_t write_all(int fd, const char *buf, size_t len) {
|
||||||
return pkt->off >= packet_header_size() && pkt->off == packet_size(&pkt->pkt);
|
debug("write_all(%d)\n", len);
|
||||||
|
ssize_t ret = len;
|
||||||
|
while (len > 0) {
|
||||||
|
ssize_t res = write(fd, buf, len);
|
||||||
|
if (res < 0) {
|
||||||
|
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
|
||||||
|
continue;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (res == 0)
|
||||||
|
return ret - len;
|
||||||
|
buf += res;
|
||||||
|
len -= res;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool is_server_packet_complete(ServerPacketState *pkt) {
|
static ssize_t read_all(int fd, char *buf, size_t len) {
|
||||||
return pkt->pkt && pkt->off == packet_size(pkt->pkt);
|
debug("read_all(%d)\n", len);
|
||||||
|
ssize_t ret = len;
|
||||||
|
while (len > 0) {
|
||||||
|
ssize_t res = read(fd, buf, len);
|
||||||
|
if (res < 0) {
|
||||||
|
if (errno == EWOULDBLOCK)
|
||||||
|
return ret - len;
|
||||||
|
if (errno == EAGAIN || errno == EINTR)
|
||||||
|
continue;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (res == 0)
|
||||||
|
return ret - len;
|
||||||
|
buf += res;
|
||||||
|
len -= res;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool is_server_packet_nonempty(ServerPacketState *pkt) {
|
static bool send_packet(int socket, Packet *pkt) {
|
||||||
return pkt->pkt && pkt->pkt->len > 0;
|
size_t size = packet_size(pkt);
|
||||||
|
return write_all(socket, (char *)pkt, size) == size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool recv_packet(int socket, Packet *pkt) {
|
||||||
|
ssize_t len = read_all(socket, (char*)pkt, packet_header_size());
|
||||||
|
if (len <= 0 || len != packet_header_size())
|
||||||
|
return false;
|
||||||
|
if (pkt->len > 0) {
|
||||||
|
len = read_all(socket, pkt->u.msg, pkt->len);
|
||||||
|
if (len <= 0 || len != pkt->len)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "debug.c"
|
|
||||||
#include "client.c"
|
#include "client.c"
|
||||||
#include "server.c"
|
#include "server.c"
|
||||||
|
|
||||||
|
|
|
||||||
65
client.c
65
client.c
|
|
@ -4,64 +4,21 @@ static void client_sigwinch_handler(int sig) {
|
||||||
client.need_resize = true;
|
client.need_resize = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t write_all(int fd, const char *buf, size_t len) {
|
|
||||||
ssize_t ret = len;
|
|
||||||
while (len > 0) {
|
|
||||||
ssize_t res = write(fd, buf, len);
|
|
||||||
if (res < 0) {
|
|
||||||
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
|
|
||||||
continue;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (res == 0)
|
|
||||||
return ret - len;
|
|
||||||
buf += res;
|
|
||||||
len -= res;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t read_all(int fd, char *buf, size_t len) {
|
|
||||||
ssize_t ret = len;
|
|
||||||
while (len > 0) {
|
|
||||||
ssize_t res = read(fd, buf, len);
|
|
||||||
if (res < 0) {
|
|
||||||
if (errno == EWOULDBLOCK)
|
|
||||||
return ret - len;
|
|
||||||
if (errno == EAGAIN || errno == EINTR)
|
|
||||||
continue;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (res == 0)
|
|
||||||
return ret - len;
|
|
||||||
buf += res;
|
|
||||||
len -= res;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool client_send_packet(Packet *pkt) {
|
static bool client_send_packet(Packet *pkt) {
|
||||||
print_packet("client-send:", pkt);
|
print_packet("client-send:", pkt);
|
||||||
size_t size = packet_size(pkt);
|
if (send_packet(server.socket, pkt))
|
||||||
if (write_all(server.socket, (char *)pkt, size) != size) {
|
return true;
|
||||||
debug("FAILED\n");
|
debug("FAILED\n");
|
||||||
server.running = false;
|
server.running = false;
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool client_recv_packet(Packet *pkt) {
|
static bool client_recv_packet(Packet *pkt) {
|
||||||
ssize_t len = read_all(server.socket, (char*)pkt, packet_header_size());
|
if (recv_packet(server.socket, pkt)) {
|
||||||
if (len <= 0 || len != packet_header_size() || pkt->len == 0)
|
print_packet("client-recv:", pkt);
|
||||||
goto error;
|
return true;
|
||||||
len = read_all(server.socket, pkt->u.msg, pkt->len);
|
}
|
||||||
print_packet("client-recv:", pkt);
|
debug("client-recv: FAILED\n");
|
||||||
if (len <= 0 || len != pkt->len)
|
|
||||||
goto error;
|
|
||||||
return true;
|
|
||||||
error:
|
|
||||||
debug("FAILED here\n");
|
|
||||||
server.running = false;
|
server.running = false;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -123,7 +80,7 @@ static int client_mainloop() {
|
||||||
if (len == -1 && errno != EAGAIN && errno != EINTR)
|
if (len == -1 && errno != EAGAIN && errno != EINTR)
|
||||||
die("client-stdin");
|
die("client-stdin");
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
debug("client-stdin: %c", pkt.u.msg[0]);
|
debug("client-stdin: %c\n", pkt.u.msg[0]);
|
||||||
pkt.len = len;
|
pkt.len = len;
|
||||||
if (pkt.u.msg[0] == KEY_REDRAW) {
|
if (pkt.u.msg[0] == KEY_REDRAW) {
|
||||||
client.need_resize = true;
|
client.need_resize = true;
|
||||||
|
|
|
||||||
17
debug.c
17
debug.c
|
|
@ -1,8 +1,6 @@
|
||||||
#ifdef NDEBUG
|
#ifdef NDEBUG
|
||||||
static void debug(const char *errstr, ...) { }
|
static void debug(const char *errstr, ...) { }
|
||||||
static void print_packet(const char *prefix, Packet *pkt) { }
|
static void print_packet(const char *prefix, Packet *pkt) { }
|
||||||
static void print_client_packet_state(const char *prefix, ClientPacketState *pkt) { }
|
|
||||||
static void print_server_packet_state(const char *prefix, ServerPacketState *pkt) { }
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
static void debug(const char *errstr, ...) {
|
static void debug(const char *errstr, ...) {
|
||||||
|
|
@ -13,6 +11,7 @@ static void debug(const char *errstr, ...) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_packet(const char *prefix, Packet *pkt) {
|
static void print_packet(const char *prefix, Packet *pkt) {
|
||||||
|
// XXX: look up table
|
||||||
char *s = "UNKNOWN";
|
char *s = "UNKNOWN";
|
||||||
switch (pkt->type) {
|
switch (pkt->type) {
|
||||||
case MSG_CONTENT:
|
case MSG_CONTENT:
|
||||||
|
|
@ -40,21 +39,11 @@ static void print_packet(const char *prefix, Packet *pkt) {
|
||||||
for (size_t i = 0; i < pkt->len && i < sizeof(pkt->u.msg); i++)
|
for (size_t i = 0; i < pkt->len && i < sizeof(pkt->u.msg); i++)
|
||||||
fprintf(stderr, "%c", pkt->u.msg[i]);
|
fprintf(stderr, "%c", pkt->u.msg[i]);
|
||||||
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
|
} else if (pkt->type == MSG_RESIZE) {
|
||||||
|
fprintf(stderr, "%s %s %d x %d\n", prefix, s, pkt->u.ws.ws_col, pkt->u.ws.ws_row);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "%s %s len: %d\n", prefix, s, pkt->len);
|
fprintf(stderr, "%s %s len: %d\n", prefix, s, pkt->len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_client_packet_state(const char *prefix, ClientPacketState *pkt) {
|
|
||||||
fprintf(stderr, "%s %d/%d\n", prefix, pkt->off, packet_size(&pkt->pkt));
|
|
||||||
if (is_client_packet_complete(pkt))
|
|
||||||
print_packet(prefix, &pkt->pkt);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void print_server_packet_state(const char *prefix, ServerPacketState *pkt) {
|
|
||||||
fprintf(stderr, "%s %d/%d\n", prefix, pkt->off, packet_size(pkt->pkt));
|
|
||||||
if (is_server_packet_complete(pkt))
|
|
||||||
print_packet(prefix, pkt->pkt);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* NDEBUG */
|
#endif /* NDEBUG */
|
||||||
|
|
|
||||||
218
server.c
218
server.c
|
|
@ -43,7 +43,6 @@ static int server_create_socket(const char *name) {
|
||||||
goto error;
|
goto error;
|
||||||
if (listen(socket, 5) == -1)
|
if (listen(socket, 5) == -1)
|
||||||
goto error;
|
goto error;
|
||||||
debug("old: %d new: %d\n", server.socket, socket);
|
|
||||||
return socket;
|
return socket;
|
||||||
error:
|
error:
|
||||||
unlink(sockaddr.sun_path);
|
unlink(sockaddr.sun_path);
|
||||||
|
|
@ -57,7 +56,7 @@ static int server_set_socket_non_blocking(int sock) {
|
||||||
return fcntl(sock, F_SETFL, flags | O_NONBLOCK);
|
return fcntl(sock, F_SETFL, flags | O_NONBLOCK);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Client *server_accept_client(time_t now) {
|
static Client *server_accept_client() {
|
||||||
int newfd = accept(server.socket, NULL, NULL);
|
int newfd = accept(server.socket, NULL, NULL);
|
||||||
if (newfd == -1)
|
if (newfd == -1)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -69,7 +68,6 @@ static Client *server_accept_client(time_t now) {
|
||||||
server_set_socket_non_blocking(newfd);
|
server_set_socket_non_blocking(newfd);
|
||||||
c->socket = newfd;
|
c->socket = newfd;
|
||||||
c->state = STATE_CONNECTED;
|
c->state = STATE_CONNECTED;
|
||||||
c->last_activity = now;
|
|
||||||
c->next = server.clients;
|
c->next = server.clients;
|
||||||
server.clients = c;
|
server.clients = c;
|
||||||
server.client_count++;
|
server.client_count++;
|
||||||
|
|
@ -87,87 +85,33 @@ static bool server_read_pty(Packet *pkt) {
|
||||||
return len > 0;
|
return len > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool server_write_pty(ClientPacketState *pkt) {
|
static bool server_write_pty(Packet *pkt) {
|
||||||
size_t count = pkt->pkt.len - pkt->off;
|
print_packet("server-write-pty:", pkt);
|
||||||
ssize_t len = write(server.pty, pkt->pkt.u.msg + pkt->off, count);
|
size_t size = pkt->len;
|
||||||
if (len == -1) {
|
if (write_all(server.pty, pkt->u.msg, size) == size)
|
||||||
if (errno != EAGAIN && errno != EINTR)
|
|
||||||
server.running = false;
|
|
||||||
} else {
|
|
||||||
pkt->off += len;
|
|
||||||
}
|
|
||||||
print_client_packet_state("server-write-pty:", pkt);
|
|
||||||
return len == count;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void server_place_packet(Client *c, Packet *pkt) {
|
|
||||||
c->output.pkt = pkt;
|
|
||||||
c->output.off = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool server_recv_packet_header(Client *c) {
|
|
||||||
ClientPacketState *pkt = &c->input;
|
|
||||||
if (pkt->off >= packet_header_size())
|
|
||||||
return true;
|
return true;
|
||||||
size_t count = packet_header_size() - pkt->off;
|
debug("FAILED\n");
|
||||||
ssize_t len = recv(c->socket, ((char *)&pkt->pkt) + pkt->off, count, 0);
|
server.running = false;
|
||||||
switch (len) {
|
return false;
|
||||||
case -1:
|
|
||||||
if (errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) {
|
|
||||||
case 0:
|
|
||||||
c->state = STATE_DISCONNECTED;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
pkt->off += len;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
print_client_packet_state("server-recv:", pkt);
|
|
||||||
return len == count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool server_recv_packet(Client *c) {
|
static bool server_recv_packet(Client *c, Packet *pkt) {
|
||||||
ClientPacketState *pkt = &c->input;
|
if (recv_packet(c->socket, pkt)) {
|
||||||
if (is_client_packet_complete(pkt))
|
print_packet("server-recv:", pkt);
|
||||||
return true;
|
return true;
|
||||||
if (!server_recv_packet_header(c))
|
|
||||||
return false;
|
|
||||||
size_t count = packet_size(&pkt->pkt) - pkt->off;
|
|
||||||
ssize_t len = recv(c->socket, ((char *)&pkt->pkt) + pkt->off, count, 0);
|
|
||||||
switch (len) {
|
|
||||||
case -1:
|
|
||||||
if (errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) {
|
|
||||||
case 0:
|
|
||||||
c->state = STATE_DISCONNECTED;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
pkt->off += len;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
print_client_packet_state("server-recv:", pkt);
|
debug("server-recv: FAILED\n");
|
||||||
return len == count;
|
c->state = STATE_DISCONNECTED;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool server_send_packet(Client *c) {
|
static bool server_send_packet(Client *c, Packet *pkt) {
|
||||||
ServerPacketState *pkt = &c->output;
|
print_packet("server-send:", pkt);
|
||||||
if (is_server_packet_complete(pkt))
|
if (send_packet(c->socket, pkt))
|
||||||
return true;
|
return true;
|
||||||
size_t count = packet_size(pkt->pkt) - pkt->off;
|
debug("FAILED\n");
|
||||||
ssize_t len = send(c->socket, (char*)pkt->pkt + pkt->off, count, 0);
|
c->state = STATE_DISCONNECTED;
|
||||||
switch (len) {
|
return false;
|
||||||
case -1:
|
|
||||||
if (errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) {
|
|
||||||
case 0:
|
|
||||||
c->state = STATE_DISCONNECTED;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
pkt->off += len;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
print_server_packet_state("server-send:", pkt);
|
|
||||||
return len == count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void server_pty_died_handler(int sig) {
|
static void server_pty_died_handler(int sig) {
|
||||||
|
|
@ -201,30 +145,6 @@ static void server_atexit_handler() {
|
||||||
unlink(sockaddr.sun_path);
|
unlink(sockaddr.sun_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool server_queue_empty() {
|
|
||||||
return server.queue_count == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool server_queue_packet(Packet *pkt) {
|
|
||||||
if (server.queue_count >= countof(server.queue))
|
|
||||||
return false;
|
|
||||||
server.queue[server.queue_insert] = *pkt;
|
|
||||||
server.queue_insert++;
|
|
||||||
server.queue_insert %= countof(server.queue);
|
|
||||||
server.queue_count++;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Packet *server_peek_packet() {
|
|
||||||
return &server.queue[server.queue_remove];
|
|
||||||
}
|
|
||||||
|
|
||||||
static void server_dequeue_packet() {
|
|
||||||
server.queue_remove++;
|
|
||||||
server.queue_remove %= countof(server.queue);
|
|
||||||
server.queue_count--;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void server_mainloop() {
|
static void server_mainloop() {
|
||||||
atexit(server_atexit_handler);
|
atexit(server_atexit_handler);
|
||||||
fd_set new_readfds, new_writefds;
|
fd_set new_readfds, new_writefds;
|
||||||
|
|
@ -232,25 +152,14 @@ static void server_mainloop() {
|
||||||
FD_ZERO(&new_writefds);
|
FD_ZERO(&new_writefds);
|
||||||
FD_SET(server.socket, &new_readfds);
|
FD_SET(server.socket, &new_readfds);
|
||||||
int new_fdmax = server.socket;
|
int new_fdmax = server.socket;
|
||||||
|
Packet *exit_pkt = NULL;
|
||||||
|
|
||||||
for (;;) {
|
while (!exit_pkt) {
|
||||||
int fdmax = new_fdmax;
|
int fdmax = new_fdmax;
|
||||||
fd_set readfds = new_readfds;
|
fd_set readfds = new_readfds;
|
||||||
fd_set writefds = new_writefds;
|
fd_set writefds = new_writefds;
|
||||||
FD_SET_MAX(server.socket, &readfds, fdmax);
|
FD_SET_MAX(server.socket, &readfds, fdmax);
|
||||||
|
|
||||||
if (!server.running && server.exit_status != -1 && server.clients) { /* application terminated */
|
|
||||||
Packet pkt = { .type = MSG_EXIT, .len = sizeof(int), .u.i = server.exit_status };
|
|
||||||
server.pty_output = pkt;
|
|
||||||
time_t now = time(NULL);
|
|
||||||
for (Client *c = server.clients; c; c = c->next) {
|
|
||||||
server_place_packet(c, &server.pty_output);
|
|
||||||
c->last_activity = now;
|
|
||||||
FD_SET_MAX(c->socket, &writefds, fdmax);
|
|
||||||
}
|
|
||||||
server.exit_status = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (select(fdmax+1, &readfds, &writefds, NULL, NULL) == -1) {
|
if (select(fdmax+1, &readfds, &writefds, NULL, NULL) == -1) {
|
||||||
if (errno == EINTR)
|
if (errno == EINTR)
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -261,15 +170,21 @@ static void server_mainloop() {
|
||||||
FD_ZERO(&new_writefds);
|
FD_ZERO(&new_writefds);
|
||||||
new_fdmax = server.socket;
|
new_fdmax = server.socket;
|
||||||
|
|
||||||
time_t now = time(NULL);
|
bool pty_data = false;
|
||||||
time_t timeout = now - CLIENT_TIMEOUT;
|
|
||||||
bool pty_data = false, clients_ready = true, exit_sent = false;
|
Packet server_packet, client_packet;
|
||||||
|
|
||||||
if (FD_ISSET(server.socket, &readfds))
|
if (FD_ISSET(server.socket, &readfds))
|
||||||
server_accept_client(now);
|
server_accept_client();
|
||||||
|
|
||||||
if (FD_ISSET(server.pty, &readfds))
|
if (FD_ISSET(server.pty, &readfds))
|
||||||
pty_data = server_read_pty(&server.pty_output);
|
pty_data = server_read_pty(&server_packet);
|
||||||
|
|
||||||
|
if (!server.running && server.exit_status != -1 && server.clients) { /* application terminated */
|
||||||
|
Packet pkt = { .type = MSG_EXIT, .len = sizeof(int), .u.i = server.exit_status };
|
||||||
|
exit_pkt = &pkt;
|
||||||
|
server.exit_status = -1;
|
||||||
|
}
|
||||||
|
|
||||||
for (Client **prev_next = &server.clients, *c = server.clients; c;) {
|
for (Client **prev_next = &server.clients, *c = server.clients; c;) {
|
||||||
if (c->state == STATE_DISCONNECTED) {
|
if (c->state == STATE_DISCONNECTED) {
|
||||||
|
|
@ -281,20 +196,19 @@ static void server_mainloop() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FD_ISSET(c->socket, &readfds))
|
if (FD_ISSET(c->socket, &readfds) && server_recv_packet(c, &client_packet)) {
|
||||||
server_recv_packet(c);
|
switch (client_packet.type) {
|
||||||
if (is_client_packet_complete(&c->input)) {
|
|
||||||
bool packet_handled = true;
|
|
||||||
switch (c->input.pkt.type) {
|
|
||||||
case MSG_CONTENT:
|
case MSG_CONTENT:
|
||||||
packet_handled = server_queue_packet(&c->input.pkt);
|
server_write_pty(&client_packet);
|
||||||
break;
|
break;
|
||||||
case MSG_ATTACH:
|
case MSG_ATTACH:
|
||||||
case MSG_RESIZE:
|
case MSG_RESIZE:
|
||||||
c->state = STATE_ATTACHED;
|
c->state = STATE_ATTACHED;
|
||||||
case MSG_REDRAW:
|
case MSG_REDRAW:
|
||||||
if (c->input.pkt.type == MSG_REDRAW || c == server.clients)
|
if (client_packet.type == MSG_REDRAW || c == server.clients) {
|
||||||
ioctl(server.pty, TIOCSWINSZ, &c->input.pkt.u.ws);
|
debug("server-ioct: TIOCSWINSZ\n");
|
||||||
|
ioctl(server.pty, TIOCSWINSZ, &client_packet.u.ws);
|
||||||
|
}
|
||||||
kill(-server.pid, SIGWINCH);
|
kill(-server.pid, SIGWINCH);
|
||||||
break;
|
break;
|
||||||
case MSG_DETACH:
|
case MSG_DETACH:
|
||||||
|
|
@ -303,61 +217,21 @@ static void server_mainloop() {
|
||||||
default: /* ignore package */
|
default: /* ignore package */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (packet_handled) {
|
|
||||||
c->input.off = 0;
|
|
||||||
FD_SET_MAX(c->socket, &new_readfds, new_fdmax);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
FD_SET_MAX(c->socket, &new_readfds, new_fdmax);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pty_data) {
|
FD_SET_MAX(c->socket, &new_readfds, new_fdmax);
|
||||||
server_place_packet(c, &server.pty_output);
|
|
||||||
c->last_activity = now;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FD_ISSET(c->socket, &writefds)) {
|
if (pty_data)
|
||||||
server_send_packet(c);
|
server_send_packet(c, &server_packet);
|
||||||
c->last_activity = now;
|
if (exit_pkt)
|
||||||
}
|
server_send_packet(c, exit_pkt);
|
||||||
|
|
||||||
if (!is_server_packet_complete(&c->output)) {
|
|
||||||
if (c->last_activity < timeout) {
|
|
||||||
c->state = STATE_DISCONNECTED;
|
|
||||||
} else if (is_server_packet_nonempty(&c->output)) {
|
|
||||||
clients_ready = false;
|
|
||||||
FD_SET_MAX(c->socket, &new_writefds, new_fdmax);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
exit_sent = (c->output.pkt && c->output.pkt->type == MSG_EXIT);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c->state != STATE_ATTACHED)
|
|
||||||
clients_ready = false;
|
|
||||||
prev_next = &c->next;
|
prev_next = &c->next;
|
||||||
c = c->next;
|
c = c->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (server.running && clients_ready)
|
if (server.running)
|
||||||
FD_SET_MAX(server.pty, &new_readfds, new_fdmax);
|
FD_SET_MAX(server.pty, &new_readfds, new_fdmax);
|
||||||
|
|
||||||
if (FD_ISSET(server.pty, &writefds)) {
|
|
||||||
while (!server_queue_empty()) {
|
|
||||||
if (!server.pty_input.off)
|
|
||||||
server.pty_input.pkt = *server_peek_packet();
|
|
||||||
if (!server_write_pty(&server.pty_input))
|
|
||||||
break;
|
|
||||||
server_dequeue_packet();
|
|
||||||
server.pty_input.off = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!server_queue_empty())
|
|
||||||
FD_SET_MAX(server.pty, &new_writefds, new_fdmax);
|
|
||||||
|
|
||||||
if (exit_sent)
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue