diff --git a/abduco.c b/abduco.c index 2880714..90b95e1 100644 --- a/abduco.c +++ b/abduco.c @@ -66,30 +66,23 @@ enum PacketType { MSG_REDRAW = 4, }; -/* packet sent from client to server */ typedef struct { - unsigned char type; - unsigned char len; + unsigned int type; + size_t len; union { - char msg[sizeof(struct winsize)]; + char msg[BUFSIZ]; struct winsize ws; int i; } u; -} ClientPacket; - -/* packet sent from server to all clients */ -typedef struct { - char buf[BUFSIZ]; - size_t len; -} ServerPacket; +} Packet; typedef struct { - ClientPacket pkt; + Packet pkt; size_t off; } ClientPacketState; typedef struct { - ServerPacket *pkt; + Packet *pkt; size_t off; } ServerPacketState; @@ -113,9 +106,9 @@ typedef struct { Client *clients; int client_count; int socket; - ServerPacket pty_output; + Packet pty_output; ClientPacketState pty_input; - ClientPacket queue[10]; + Packet queue[10]; unsigned int queue_count; unsigned int queue_insert; unsigned int queue_remove; @@ -139,16 +132,24 @@ static int create_socket(const char *name); static void die(const char *s); static void info(const char *str, ...); +static inline size_t packet_header_size() { + return offsetof(Packet, u); +} + +static size_t packet_size(Packet *pkt) { + return packet_header_size() + pkt->len; +} + static bool is_client_packet_complete(ClientPacketState *pkt) { - return pkt->off == sizeof pkt->pkt; + return pkt->off >= packet_header_size() && pkt->off == packet_size(&pkt->pkt); } static bool is_server_packet_complete(ServerPacketState *pkt) { - return pkt->pkt && pkt->off == pkt->pkt->len; + return pkt->pkt && pkt->off == packet_size(pkt->pkt); } static bool is_server_packet_nonempty(ServerPacketState *pkt) { - return pkt->pkt && pkt->pkt->len > 0; + return pkt->pkt && pkt->pkt->len > 0; } #include "debug.c" diff --git a/client.c b/client.c index f5832f2..240605c 100644 --- a/client.c +++ b/client.c @@ -40,9 +40,10 @@ static ssize_t read_all(int fd, char *buf, size_t len) { return ret; } -static bool client_send_packet(ClientPacket *pkt) { - print_client_packet("client-send:", pkt); - if (write_all(server.socket, (char *)pkt, sizeof(ClientPacket)) != sizeof(ClientPacket)) { +static bool client_send_packet(Packet *pkt) { + print_packet("client-send:", pkt); + size_t size = packet_size(pkt); + if (write_all(server.socket, (char *)pkt, size) != size) { debug("FAILED\n"); server.running = false; return false; @@ -50,15 +51,19 @@ static bool client_send_packet(ClientPacket *pkt) { return true; } -static bool client_recv_packet(ServerPacket *pkt) { - ssize_t len = pkt->len = read_all(server.socket, pkt->buf, sizeof(pkt->buf)); - print_server_packet("client-recv:", pkt); - if (len <= 0) { - debug("FAILED\n"); - server.running = false; - return false; - } +static bool client_recv_packet(Packet *pkt) { + ssize_t len = read_all(server.socket, (char*)pkt, packet_header_size()); + if (len <= 0 || len != packet_header_size() || pkt->len == 0) + goto error; + len = read_all(server.socket, pkt->u.msg, pkt->len); + print_packet("client-recv:", pkt); + if (len <= 0 || len != pkt->len) + goto error; return true; +error: + debug("FAILED here\n"); + server.running = false; + return false; } static void client_clear_screen() { @@ -88,7 +93,7 @@ static int client_mainloop() { if (client.need_resize) { struct winsize ws; if (ioctl(0, TIOCGWINSZ, &ws) != -1) { - ClientPacket pkt = { + Packet pkt = { .type = MSG_RESIZE, .u = { .ws = ws }, .len = sizeof(ws), @@ -105,13 +110,18 @@ static int client_mainloop() { } if (FD_ISSET(server.socket, &fds)) { - ServerPacket pkt; - if (client_recv_packet(&pkt)) - write_all(STDOUT_FILENO, pkt.buf, pkt.len); + Packet pkt; + if (client_recv_packet(&pkt)) { + switch (pkt.type) { + case MSG_CONTENT: + write_all(STDOUT_FILENO, pkt.u.msg, pkt.len); + break; + } + } } if (FD_ISSET(STDIN_FILENO, &fds)) { - ClientPacket pkt = { .type = MSG_CONTENT }; + Packet pkt = { .type = MSG_CONTENT }; ssize_t len = read(STDIN_FILENO, pkt.u.msg, sizeof(pkt.u.msg)); if (len == -1 && errno != EAGAIN && errno != EINTR) die("client-stdin"); @@ -121,6 +131,7 @@ static int client_mainloop() { client.need_resize = true; } else if (pkt.u.msg[0] == KEY_DETACH) { pkt.type = MSG_DETACH; + pkt.len = 0; client_send_packet(&pkt); return -1; } else { diff --git a/debug.c b/debug.c index 0157d71..94be37e 100644 --- a/debug.c +++ b/debug.c @@ -1,8 +1,7 @@ #ifdef NDEBUG static void debug(const char *errstr, ...) { } -static void print_client_packet(const char *prefix, ClientPacket *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(const char *prefix, ServerPacket *pkt) { } static void print_server_packet_state(const char *prefix, ServerPacketState *pkt) { } #else @@ -13,7 +12,7 @@ static void debug(const char *errstr, ...) { va_end(ap); } -static void print_client_packet(const char *prefix, ClientPacket *pkt) { +static void print_packet(const char *prefix, Packet *pkt) { char *s = "UNKNOWN"; switch (pkt->type) { case MSG_CONTENT: @@ -39,24 +38,20 @@ static void print_client_packet(const char *prefix, ClientPacket *pkt) { fprintf(stderr, "%c", pkt->u.msg[i]); fprintf(stderr, "\n"); } else { - fprintf(stderr, "%s %s\n", prefix, s); + 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, sizeof(ClientPacket)); + fprintf(stderr, "%s %d/%d\n", prefix, pkt->off, packet_size(&pkt->pkt)); if (is_client_packet_complete(pkt)) - print_client_packet(prefix, &pkt->pkt); -} - -static void print_server_packet(const char *prefix, ServerPacket *pkt) { - fprintf(stderr, "%s len: %d buf: \n\t%s\n", prefix, pkt->len, pkt->buf); + 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, pkt->pkt->len); + fprintf(stderr, "%s %d/%d\n", prefix, pkt->off, packet_size(pkt->pkt)); if (is_server_packet_complete(pkt)) - print_server_packet(prefix, pkt->pkt); + print_packet(prefix, pkt->pkt); } #endif /* NDEBUG */ diff --git a/server.c b/server.c index d0b30d7..895d666 100644 --- a/server.c +++ b/server.c @@ -42,18 +42,19 @@ static Client *server_accept_client(time_t now) { return c; } -static bool server_read_pty(ServerPacket *pkt) { - ssize_t len = read(server.pty, pkt->buf, sizeof(pkt->buf)); +static bool server_read_pty(Packet *pkt) { + pkt->type = MSG_CONTENT; + ssize_t len = read(server.pty, pkt->u.msg, sizeof(pkt->u.msg)); if (len != -1) pkt->len = len; else if (errno != EAGAIN && errno != EINTR) server.running = false; - print_server_packet("server-read-pty:", pkt); + print_packet("server-read-pty:", pkt); return len > 0; } static bool server_write_pty(ClientPacketState *pkt) { - int count = pkt->pkt.len - pkt->off; + size_t count = pkt->pkt.len - pkt->off; ssize_t len = write(server.pty, pkt->pkt.u.msg + pkt->off, count); if (len == -1) { if (errno != EAGAIN && errno != EINTR) @@ -65,16 +66,39 @@ static bool server_write_pty(ClientPacketState *pkt) { return len == count; } -static void server_place_packet(Client *c, ServerPacket *pkt) { +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; + size_t count = packet_header_size() - 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); + return len == count; +} + static bool server_recv_packet(Client *c) { ClientPacketState *pkt = &c->input; if (is_client_packet_complete(pkt)) return true; - size_t count = sizeof(ClientPacket) - pkt->off; + 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: @@ -95,8 +119,8 @@ static bool server_send_packet(Client *c) { ServerPacketState *pkt = &c->output; if (is_server_packet_complete(pkt)) return true; - size_t count = pkt->pkt->len - pkt->off; - ssize_t len = send(c->socket, pkt->pkt->buf + pkt->off, count, 0); + size_t count = packet_size(pkt->pkt) - pkt->off; + ssize_t len = send(c->socket, (char*)pkt->pkt + pkt->off, count, 0); switch (len) { case -1: if (errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) { @@ -138,7 +162,7 @@ static bool server_queue_empty() { return server.queue_count == 0; } -static bool server_queue_packet(ClientPacket *pkt) { +static bool server_queue_packet(Packet *pkt) { if (server.queue_count >= countof(server.queue)) return false; server.queue[server.queue_insert] = *pkt; @@ -148,7 +172,7 @@ static bool server_queue_packet(ClientPacket *pkt) { return true; } -static ClientPacket *server_peek_packet() { +static Packet *server_peek_packet() { return &server.queue[server.queue_remove]; }