115 lines
2.9 KiB
C
115 lines
2.9 KiB
C
|
#include <response.h>
|
||
|
#include <stdio.h>
|
||
|
#include <stdint.h>
|
||
|
#include <string.h>
|
||
|
#include <unistd.h>
|
||
|
|
||
|
static bool write_char(RdbResponse *res, char out) {
|
||
|
if (res->len >= res->buflen) {
|
||
|
return false;
|
||
|
}
|
||
|
if (out == '#' || out == '$' || out == '}' || out == '*') {
|
||
|
res->buf[res->len++] = '}';
|
||
|
res->chk += '}';
|
||
|
if (res->len >= res->buflen) {
|
||
|
return false;
|
||
|
}
|
||
|
out ^= 0x20;
|
||
|
}
|
||
|
res->buf[res->len++] = out;
|
||
|
res->chk += out;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool char_to_hex_digit(char in, char *out) {
|
||
|
if (in & 0xf0) {
|
||
|
return false;
|
||
|
}
|
||
|
in &= 0x0f;
|
||
|
if (in > 9) {
|
||
|
*out = 'a' + in - 10;
|
||
|
} else {
|
||
|
*out = '0' + in;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool char_to_hex_digits(char in, char *hi, char *lo) {
|
||
|
return char_to_hex_digit((in & 0xf0) >> 4, hi)
|
||
|
&& char_to_hex_digit(in & 0x0f, lo);
|
||
|
}
|
||
|
|
||
|
void rdb_response_init(RdbResponse *res, int connfd, char *buf, size_t buflen) {
|
||
|
res->connfd = connfd;
|
||
|
res->buf = buf;
|
||
|
res->buflen = buflen;
|
||
|
res->len = 0;
|
||
|
res->chk = 0;
|
||
|
res->should_ack = true;
|
||
|
}
|
||
|
|
||
|
void rdb_response_begin_packet(RdbResponse *res) {
|
||
|
res->len = 0;
|
||
|
res->chk = 0;
|
||
|
if (res->should_ack) {
|
||
|
res->buf[res->len++] = '+';
|
||
|
}
|
||
|
res->buf[res->len++] = '$';
|
||
|
}
|
||
|
|
||
|
bool rdb_response_write_str(RdbResponse *res, const char *str) {
|
||
|
size_t len = strlen(str);
|
||
|
for (size_t i = 0; i < len; ++i) {
|
||
|
if (!write_char(res, str[i])) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool rdb_response_write_str_hex(RdbResponse *res, const char *str) {
|
||
|
size_t len = strlen(str);
|
||
|
for (size_t i = 0; i < len; ++i) {
|
||
|
char hi, lo;
|
||
|
if (!char_to_hex_digits(str[i], &hi, &lo)
|
||
|
|| !write_char(res, hi)
|
||
|
|| !write_char(res, lo)) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool rdb_response_write_i8_hex(RdbResponse *res, uint8_t value) {
|
||
|
char hi, lo;
|
||
|
return char_to_hex_digits(value, &hi, &lo)
|
||
|
&& write_char(res, hi)
|
||
|
&& write_char(res, lo);
|
||
|
}
|
||
|
|
||
|
bool rdb_response_write_i32_hex(RdbResponse *res, uint32_t value) {
|
||
|
return rdb_response_write_i8_hex(res, (uint8_t) value)
|
||
|
&& rdb_response_write_i8_hex(res, (uint8_t) (value >> 8))
|
||
|
&& rdb_response_write_i8_hex(res, (uint8_t) (value >> 16))
|
||
|
&& rdb_response_write_i8_hex(res, (uint8_t) (value >> 24));
|
||
|
}
|
||
|
|
||
|
int rdb_response_send_packet(RdbResponse *res) {
|
||
|
if (res->len + 3 > res->buflen) {
|
||
|
return -1;
|
||
|
}
|
||
|
res->buf[res->len++] = '#';
|
||
|
char hi, lo;
|
||
|
if (!char_to_hex_digits(res->chk, &hi, &lo)) {
|
||
|
return -1;
|
||
|
}
|
||
|
res->buf[res->len++] = hi;
|
||
|
res->buf[res->len++] = lo;
|
||
|
printf("sending command \"%.*s\" %d\n", (int) res->len, res->buf, (int)res->len);
|
||
|
|
||
|
ssize_t rwrite = write(res->connfd, res->buf, res->len);
|
||
|
if (rwrite == -1) {
|
||
|
return -1;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|