mirror of https://github.com/martanne/abduco
Use the same packet structure for both ways of the client server communiction
This is slightly less efficient than before but allows the server to send different types of messages not only output data to the client.
This commit is contained in:
parent
c14b9c9173
commit
ed4f1ecdcd
35
abduco.c
35
abduco.c
|
|
@ -66,30 +66,23 @@ enum PacketType {
|
||||||
MSG_REDRAW = 4,
|
MSG_REDRAW = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* packet sent from client to server */
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
unsigned char type;
|
unsigned int type;
|
||||||
unsigned char len;
|
size_t len;
|
||||||
union {
|
union {
|
||||||
char msg[sizeof(struct winsize)];
|
char msg[BUFSIZ];
|
||||||
struct winsize ws;
|
struct winsize ws;
|
||||||
int i;
|
int i;
|
||||||
} u;
|
} u;
|
||||||
} ClientPacket;
|
} Packet;
|
||||||
|
|
||||||
/* packet sent from server to all clients */
|
|
||||||
typedef struct {
|
|
||||||
char buf[BUFSIZ];
|
|
||||||
size_t len;
|
|
||||||
} ServerPacket;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
ClientPacket pkt;
|
Packet pkt;
|
||||||
size_t off;
|
size_t off;
|
||||||
} ClientPacketState;
|
} ClientPacketState;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
ServerPacket *pkt;
|
Packet *pkt;
|
||||||
size_t off;
|
size_t off;
|
||||||
} ServerPacketState;
|
} ServerPacketState;
|
||||||
|
|
||||||
|
|
@ -113,9 +106,9 @@ typedef struct {
|
||||||
Client *clients;
|
Client *clients;
|
||||||
int client_count;
|
int client_count;
|
||||||
int socket;
|
int socket;
|
||||||
ServerPacket pty_output;
|
Packet pty_output;
|
||||||
ClientPacketState pty_input;
|
ClientPacketState pty_input;
|
||||||
ClientPacket queue[10];
|
Packet queue[10];
|
||||||
unsigned int queue_count;
|
unsigned int queue_count;
|
||||||
unsigned int queue_insert;
|
unsigned int queue_insert;
|
||||||
unsigned int queue_remove;
|
unsigned int queue_remove;
|
||||||
|
|
@ -139,12 +132,20 @@ 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, ...);
|
||||||
|
|
||||||
|
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) {
|
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) {
|
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) {
|
static bool is_server_packet_nonempty(ServerPacketState *pkt) {
|
||||||
|
|
|
||||||
41
client.c
41
client.c
|
|
@ -40,9 +40,10 @@ static ssize_t read_all(int fd, char *buf, size_t len) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool client_send_packet(ClientPacket *pkt) {
|
static bool client_send_packet(Packet *pkt) {
|
||||||
print_client_packet("client-send:", pkt);
|
print_packet("client-send:", pkt);
|
||||||
if (write_all(server.socket, (char *)pkt, sizeof(ClientPacket)) != sizeof(ClientPacket)) {
|
size_t size = packet_size(pkt);
|
||||||
|
if (write_all(server.socket, (char *)pkt, size) != size) {
|
||||||
debug("FAILED\n");
|
debug("FAILED\n");
|
||||||
server.running = false;
|
server.running = false;
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -50,16 +51,20 @@ static bool client_send_packet(ClientPacket *pkt) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool client_recv_packet(ServerPacket *pkt) {
|
static bool client_recv_packet(Packet *pkt) {
|
||||||
ssize_t len = pkt->len = read_all(server.socket, pkt->buf, sizeof(pkt->buf));
|
ssize_t len = read_all(server.socket, (char*)pkt, packet_header_size());
|
||||||
print_server_packet("client-recv:", pkt);
|
if (len <= 0 || len != packet_header_size() || pkt->len == 0)
|
||||||
if (len <= 0) {
|
goto error;
|
||||||
debug("FAILED\n");
|
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;
|
server.running = false;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void client_clear_screen() {
|
static void client_clear_screen() {
|
||||||
printf("\e[H\e[J");
|
printf("\e[H\e[J");
|
||||||
|
|
@ -88,7 +93,7 @@ static int client_mainloop() {
|
||||||
if (client.need_resize) {
|
if (client.need_resize) {
|
||||||
struct winsize ws;
|
struct winsize ws;
|
||||||
if (ioctl(0, TIOCGWINSZ, &ws) != -1) {
|
if (ioctl(0, TIOCGWINSZ, &ws) != -1) {
|
||||||
ClientPacket pkt = {
|
Packet pkt = {
|
||||||
.type = MSG_RESIZE,
|
.type = MSG_RESIZE,
|
||||||
.u = { .ws = ws },
|
.u = { .ws = ws },
|
||||||
.len = sizeof(ws),
|
.len = sizeof(ws),
|
||||||
|
|
@ -105,13 +110,18 @@ static int client_mainloop() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FD_ISSET(server.socket, &fds)) {
|
if (FD_ISSET(server.socket, &fds)) {
|
||||||
ServerPacket pkt;
|
Packet pkt;
|
||||||
if (client_recv_packet(&pkt))
|
if (client_recv_packet(&pkt)) {
|
||||||
write_all(STDOUT_FILENO, pkt.buf, pkt.len);
|
switch (pkt.type) {
|
||||||
|
case MSG_CONTENT:
|
||||||
|
write_all(STDOUT_FILENO, pkt.u.msg, pkt.len);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FD_ISSET(STDIN_FILENO, &fds)) {
|
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));
|
ssize_t len = read(STDIN_FILENO, pkt.u.msg, sizeof(pkt.u.msg));
|
||||||
if (len == -1 && errno != EAGAIN && errno != EINTR)
|
if (len == -1 && errno != EAGAIN && errno != EINTR)
|
||||||
die("client-stdin");
|
die("client-stdin");
|
||||||
|
|
@ -121,6 +131,7 @@ static int client_mainloop() {
|
||||||
client.need_resize = true;
|
client.need_resize = true;
|
||||||
} else if (pkt.u.msg[0] == KEY_DETACH) {
|
} else if (pkt.u.msg[0] == KEY_DETACH) {
|
||||||
pkt.type = MSG_DETACH;
|
pkt.type = MSG_DETACH;
|
||||||
|
pkt.len = 0;
|
||||||
client_send_packet(&pkt);
|
client_send_packet(&pkt);
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
19
debug.c
19
debug.c
|
|
@ -1,8 +1,7 @@
|
||||||
#ifdef NDEBUG
|
#ifdef NDEBUG
|
||||||
static void debug(const char *errstr, ...) { }
|
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_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) { }
|
static void print_server_packet_state(const char *prefix, ServerPacketState *pkt) { }
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
|
@ -13,7 +12,7 @@ static void debug(const char *errstr, ...) {
|
||||||
va_end(ap);
|
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";
|
char *s = "UNKNOWN";
|
||||||
switch (pkt->type) {
|
switch (pkt->type) {
|
||||||
case MSG_CONTENT:
|
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, "%c", pkt->u.msg[i]);
|
||||||
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
} else {
|
} 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) {
|
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))
|
if (is_client_packet_complete(pkt))
|
||||||
print_client_packet(prefix, &pkt->pkt);
|
print_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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_server_packet_state(const char *prefix, ServerPacketState *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))
|
if (is_server_packet_complete(pkt))
|
||||||
print_server_packet(prefix, pkt->pkt);
|
print_packet(prefix, pkt->pkt);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* NDEBUG */
|
#endif /* NDEBUG */
|
||||||
|
|
|
||||||
44
server.c
44
server.c
|
|
@ -42,18 +42,19 @@ static Client *server_accept_client(time_t now) {
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool server_read_pty(ServerPacket *pkt) {
|
static bool server_read_pty(Packet *pkt) {
|
||||||
ssize_t len = read(server.pty, pkt->buf, sizeof(pkt->buf));
|
pkt->type = MSG_CONTENT;
|
||||||
|
ssize_t len = read(server.pty, pkt->u.msg, sizeof(pkt->u.msg));
|
||||||
if (len != -1)
|
if (len != -1)
|
||||||
pkt->len = len;
|
pkt->len = len;
|
||||||
else if (errno != EAGAIN && errno != EINTR)
|
else if (errno != EAGAIN && errno != EINTR)
|
||||||
server.running = false;
|
server.running = false;
|
||||||
print_server_packet("server-read-pty:", pkt);
|
print_packet("server-read-pty:", pkt);
|
||||||
return len > 0;
|
return len > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool server_write_pty(ClientPacketState *pkt) {
|
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);
|
ssize_t len = write(server.pty, pkt->pkt.u.msg + pkt->off, count);
|
||||||
if (len == -1) {
|
if (len == -1) {
|
||||||
if (errno != EAGAIN && errno != EINTR)
|
if (errno != EAGAIN && errno != EINTR)
|
||||||
|
|
@ -65,16 +66,39 @@ static bool server_write_pty(ClientPacketState *pkt) {
|
||||||
return len == count;
|
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.pkt = pkt;
|
||||||
c->output.off = 0;
|
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) {
|
static bool server_recv_packet(Client *c) {
|
||||||
ClientPacketState *pkt = &c->input;
|
ClientPacketState *pkt = &c->input;
|
||||||
if (is_client_packet_complete(pkt))
|
if (is_client_packet_complete(pkt))
|
||||||
return true;
|
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);
|
ssize_t len = recv(c->socket, ((char *)&pkt->pkt) + pkt->off, count, 0);
|
||||||
switch (len) {
|
switch (len) {
|
||||||
case -1:
|
case -1:
|
||||||
|
|
@ -95,8 +119,8 @@ static bool server_send_packet(Client *c) {
|
||||||
ServerPacketState *pkt = &c->output;
|
ServerPacketState *pkt = &c->output;
|
||||||
if (is_server_packet_complete(pkt))
|
if (is_server_packet_complete(pkt))
|
||||||
return true;
|
return true;
|
||||||
size_t count = pkt->pkt->len - pkt->off;
|
size_t count = packet_size(pkt->pkt) - pkt->off;
|
||||||
ssize_t len = send(c->socket, pkt->pkt->buf + pkt->off, count, 0);
|
ssize_t len = send(c->socket, (char*)pkt->pkt + pkt->off, count, 0);
|
||||||
switch (len) {
|
switch (len) {
|
||||||
case -1:
|
case -1:
|
||||||
if (errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) {
|
if (errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) {
|
||||||
|
|
@ -138,7 +162,7 @@ static bool server_queue_empty() {
|
||||||
return server.queue_count == 0;
|
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))
|
if (server.queue_count >= countof(server.queue))
|
||||||
return false;
|
return false;
|
||||||
server.queue[server.queue_insert] = *pkt;
|
server.queue[server.queue_insert] = *pkt;
|
||||||
|
|
@ -148,7 +172,7 @@ static bool server_queue_packet(ClientPacket *pkt) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ClientPacket *server_peek_packet() {
|
static Packet *server_peek_packet() {
|
||||||
return &server.queue[server.queue_remove];
|
return &server.queue[server.queue_remove];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue