gdb-server/request.c

152 lines
4.4 KiB
C
Raw Permalink Normal View History

2024-10-07 04:55:44 +00:00
#include <errno.h>
#include <hex.h>
#include <request.h>
#include <stdio.h>
2024-10-08 01:20:01 +00:00
#include <sys/socket.h>
2024-10-07 04:55:44 +00:00
#include <unistd.h>
2024-10-10 22:38:40 +00:00
void rdbRequestInit(RdbRequest *req, int connfd, char *buf, size_t buflen) {
2024-10-07 04:55:44 +00:00
req->connfd = connfd;
2024-10-08 02:00:01 +00:00
req->outbuf = buf;
2024-10-11 01:58:40 +00:00
req->outbuflen = buflen;
2024-10-08 01:20:01 +00:00
req->blocking = true;
2024-10-10 22:38:40 +00:00
rdbRequestReset(req);
2024-10-07 04:55:44 +00:00
}
2024-10-10 22:38:40 +00:00
void rdbRequestReset(RdbRequest *req) {
2024-10-07 04:55:44 +00:00
req->state = read_state_header;
req->inbuf.len = 0;
req->inbuf.index = 0;
req->chk = 0;
}
2024-10-10 22:38:40 +00:00
void rdbRequestSetBlocking(RdbRequest *req, bool blocking) {
2024-10-08 01:20:01 +00:00
req->blocking = blocking;
}
2024-10-10 22:38:40 +00:00
static rdb_read_result_t readChar(RdbRequest *req, char *in) {
2024-10-07 04:55:44 +00:00
if (req->inbuf.index >= req->inbuf.len) {
2024-10-08 01:20:01 +00:00
int flags = req->blocking ? 0 : MSG_DONTWAIT;
ssize_t inlen = recv(req->connfd, req->inbuf.buf, INBUF_LEN, flags);
2024-10-07 04:55:44 +00:00
if (inlen == 0) {
return read_result_disconnected;
}
if (inlen < 0) {
2024-10-08 01:20:01 +00:00
if (errno == EAGAIN || errno == EWOULDBLOCK) {
2024-10-07 04:55:44 +00:00
return read_result_pending;
} else {
perror("could not read incoming packet");
return read_result_error;
}
}
req->inbuf.index = 0;
req->inbuf.len = inlen;
}
*in = req->inbuf.buf[req->inbuf.index++];
return read_result_success;
}
2024-10-10 22:38:40 +00:00
rdb_read_result_t rdbRequestRead(RdbRequest *req, CommandBuf *cmd) {
2024-10-07 04:55:44 +00:00
rdb_read_result_t res;
2024-10-08 02:42:28 +00:00
char in, hi, lo;
2024-10-07 04:55:44 +00:00
switch (req->state) {
case read_state_header:
2024-10-08 02:00:01 +00:00
cmd->buf = req->outbuf;
cmd->len = 0;
2024-10-08 02:42:28 +00:00
/* read any acknowledgements and continue */
2024-10-07 04:55:44 +00:00
do {
2024-10-10 22:38:40 +00:00
res = readChar(req, &in);
2024-10-07 04:55:44 +00:00
if (res != read_result_success) return res;
} while (in == '+');
if (in == '-') {
fprintf(stderr, "negative ack not supported\n");
return read_result_error;
}
if (in == '\x03') {
2024-10-08 02:42:28 +00:00
/* interrupt from the server */
2024-10-08 02:00:01 +00:00
cmd->buf[0] = in;
cmd->len = 1;
2024-10-07 04:55:44 +00:00
return read_result_success;
}
2024-10-08 02:42:28 +00:00
/* now, we should be at the start of a packet */
2024-10-07 04:55:44 +00:00
if (in != '$') {
fprintf(stderr, "unexpected packet start \"%c\"\n", in);
return read_result_error;
}
req->state = read_state_body;
__attribute__ ((fallthrough));
case read_state_body:
case read_state_body_escape:
while (1) {
2024-10-10 22:38:40 +00:00
res = readChar(req, &in);
2024-10-07 04:55:44 +00:00
if (res != read_result_success) return res;
if (req->state == read_state_body && in == '#') {
2024-10-08 02:42:28 +00:00
/* end of packet body */
2024-10-07 04:55:44 +00:00
break;
}
req->chk += in;
if (req->state == read_state_body && in == '}') {
2024-10-08 02:42:28 +00:00
/* escape sequence */
2024-10-07 04:55:44 +00:00
req->state = read_state_body_escape;
continue;
}
2024-10-08 02:00:01 +00:00
if (cmd->len >= req->outbuflen) {
2024-10-08 02:42:28 +00:00
/* ran out of room in the buffer */
2024-10-07 04:55:44 +00:00
fprintf(stderr, "packet too big for buffer\n");
return read_result_error;
}
if (req->state == read_state_body_escape) {
2024-10-08 02:00:01 +00:00
cmd->buf[cmd->len++] = in ^ 0x20;
2024-10-07 04:55:44 +00:00
req->state = read_state_body;
} else {
2024-10-08 02:00:01 +00:00
cmd->buf[cmd->len++] = in;
2024-10-07 04:55:44 +00:00
}
}
req->state = read_state_checksum_1;
__attribute__ ((fallthrough));
case read_state_checksum_1:
2024-10-10 22:38:40 +00:00
res = readChar(req, &in);
2024-10-07 04:55:44 +00:00
if (res != read_result_success) return res;
2024-10-08 02:42:28 +00:00
/* check the high digit of the checksum */
2024-10-10 22:38:40 +00:00
if (!parseHexDigit(in, &hi)) {
2024-10-07 04:55:44 +00:00
fprintf(stderr, "invalid checksum1\n");
return read_result_error;
}
if (((req->chk >> 4) & 0x000f) != hi) {
fprintf(stderr, "invalid checksum2\n");
return read_result_error;
}
req->state = read_state_checksum_2;
__attribute__ ((fallthrough));
case read_state_checksum_2:
2024-10-10 22:38:40 +00:00
res = readChar(req, &in);
2024-10-07 04:55:44 +00:00
if (res != read_result_success) return res;
2024-10-08 02:42:28 +00:00
/* check the high digit of the checksum */
2024-10-10 22:38:40 +00:00
if (!parseHexDigit(in, &lo)) {
2024-10-07 04:55:44 +00:00
fprintf(stderr, "invalid checksum3 %c\n", in);
return read_result_error;
}
if ((req->chk & 0x000f) != lo) {
fprintf(stderr, "invalid checksum4\n");
return read_result_error;
}
return read_result_success;
default:
fprintf(stderr, "invalid state\n");
return read_result_error;
}
}