225 lines
4.9 KiB
C
225 lines
4.9 KiB
C
|
|
#include "test_client.h"
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
#include <unistd.h>
|
|
|
|
int kvs_need(const uint8_t *p, const uint8_t *end, size_t n) {
|
|
return (p + n <= end) ? 0 : -1;
|
|
}
|
|
|
|
// 注意u8类型不需要ntoh或者hton
|
|
int kvs_read_u8(const uint8_t **pp, const uint8_t *end, uint8_t *out) {
|
|
const uint8_t *p = *pp;
|
|
if (kvs_need(p, end, 1) < 0) return -1;
|
|
*out = *p;
|
|
*pp = p + 1;
|
|
return 0;
|
|
}
|
|
|
|
int kvs_read_u16(const uint8_t **pp, const uint8_t *end, uint16_t *out) {
|
|
const uint8_t *p = *pp;
|
|
if (kvs_need(p, end, 2) < 0) return -1;
|
|
uint16_t v;
|
|
memcpy(&v, p, 2);
|
|
*out = ntohs(v);
|
|
*pp = p + 2;
|
|
return 0;
|
|
}
|
|
|
|
int kvs_read_u32(const uint8_t **pp, const uint8_t *end, uint32_t *out) {
|
|
const uint8_t *p = *pp;
|
|
if (kvs_need(p, end, 4) < 0) return -1;
|
|
uint32_t v;
|
|
memcpy(&v, p, 4);
|
|
*out = ntohl(v);
|
|
*pp = p + 4;
|
|
return 0;
|
|
}
|
|
|
|
int kvs_write_u8(uint8_t **pp, const uint8_t *end, uint8_t v) {
|
|
uint8_t *p = *pp;
|
|
if (kvs_need(p, end, 1) < 0) return -1;
|
|
*p = v;
|
|
*pp = p + 1;
|
|
return 0;
|
|
}
|
|
|
|
int kvs_write_u16(uint8_t **pp, const uint8_t *end, uint16_t v) {
|
|
uint8_t *p = *pp;
|
|
if (kvs_need(p, end, 2) < 0) return -1;
|
|
uint16_t be = htons(v);
|
|
memcpy(p, &be, 2);
|
|
*pp = p + 2;
|
|
return 0;
|
|
}
|
|
|
|
int kvs_write_u32(uint8_t **pp, const uint8_t *end, uint32_t v) {
|
|
uint8_t *p = *pp;
|
|
if (kvs_need(p, end, 4) < 0) return -1;
|
|
uint32_t be = htonl(v);
|
|
memcpy(p, &be, 4);
|
|
*pp = p + 4;
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int getcmd(uint8_t op, const char *key, const char *value, uint8_t *buf){
|
|
if(!buf) return -1;
|
|
uint8_t *end = buf + CMD_SIZE;
|
|
uint8_t *p = buf;
|
|
uint8_t argc = (key == NULL)?0:1;
|
|
argc += (value == NULL)?0:1;
|
|
|
|
|
|
if (kvs_write_u8(&p, end, op) < 0) return -1;
|
|
if (kvs_write_u8(&p, end, argc) < 0) return -1;
|
|
|
|
|
|
// 写入 key
|
|
if(key){
|
|
int keylen = strlen(key);
|
|
if (kvs_write_u32(&p, end, keylen) < 0) return -1;
|
|
if (kvs_need(p, end, keylen) < 0) return -1;
|
|
if (keylen > 0) {
|
|
memcpy(p, key, keylen);
|
|
p += keylen;
|
|
}
|
|
}
|
|
|
|
if(value){
|
|
int vallen = strlen(value);
|
|
if (kvs_write_u32(&p, end, vallen) < 0) return -1;
|
|
if (kvs_need(p, end, vallen) < 0) return -1;
|
|
if (vallen > 0) {
|
|
memcpy(p, value, vallen);
|
|
p += vallen;
|
|
}
|
|
}
|
|
|
|
return (p - buf);
|
|
}
|
|
|
|
int parse_response(const uint8_t *buf, int buflen, kvs_response_t *rsp) {
|
|
const uint8_t *p = buf;
|
|
const uint8_t *end = buf + buflen;
|
|
|
|
// 读取 OP
|
|
if (kvs_read_u8(&p, end, &rsp->op) < 0) {
|
|
fprintf(stderr, "Failed to read op\n");
|
|
return -1;
|
|
}
|
|
|
|
// 读取 status
|
|
if (kvs_read_u8(&p, end, &rsp->status) < 0) {
|
|
fprintf(stderr, "Failed to read status\n");
|
|
return -1;
|
|
}
|
|
|
|
// 读取 datalen
|
|
if (kvs_read_u32(&p, end, &rsp->datalen) < 0) {
|
|
fprintf(stderr, "Failed to read datalen\n");
|
|
return -1;
|
|
}
|
|
|
|
// 检查数据长度
|
|
if (kvs_need(p, end, rsp->datalen) < 0) {
|
|
fprintf(stderr, "Data length mismatch: expected %u bytes, but only %ld available\n",
|
|
rsp->datalen, end - p);
|
|
return -1;
|
|
}
|
|
|
|
// 指向数据部分
|
|
rsp->data = (uint8_t *)p;
|
|
|
|
return (p - buf) + rsp->datalen;
|
|
}
|
|
|
|
|
|
void print_response(const char *cmd_name, const kvs_response_t *rsp) {
|
|
printf("\n=== %s Response ===\n", cmd_name);
|
|
printf("OP: %u\n", rsp->op);
|
|
printf("Status: %u ", rsp->status);
|
|
|
|
switch (rsp->status) {
|
|
case KVS_STATUS_OK:
|
|
printf("(OK)\n");
|
|
break;
|
|
case KVS_STATUS_ERROR:
|
|
printf("(ERROR)\n");
|
|
break;
|
|
case KVS_STATUS_NO_EXIST:
|
|
printf("(NO_EXIST)\n");
|
|
break;
|
|
case KVS_STATUS_EXIST:
|
|
printf("(EXISTS)\n");
|
|
break;
|
|
default:
|
|
printf("(UNKNOWN)\n");
|
|
break;
|
|
}
|
|
|
|
printf("Data Length: %u\n", rsp->datalen);
|
|
|
|
if (rsp->datalen > 0 && rsp->data != NULL) {
|
|
printf("Data: ");
|
|
// 尝试以字符串形式打印(如果是可打印字符)
|
|
int is_printable = 1;
|
|
for (uint32_t i = 0; i < rsp->datalen; i++) {
|
|
if (rsp->data[i] < 32 || rsp->data[i] > 126) {
|
|
is_printable = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (is_printable) {
|
|
printf("\"");
|
|
for (uint32_t i = 0; i < rsp->datalen; i++) {
|
|
printf("%c", rsp->data[i]);
|
|
}
|
|
printf("\"\n");
|
|
} else {
|
|
// 以十六进制打印
|
|
printf("0x");
|
|
for (uint32_t i = 0; i < rsp->datalen; i++) {
|
|
printf("%02x", rsp->data[i]);
|
|
}
|
|
printf("\n");
|
|
}
|
|
} else {
|
|
printf("Data: (empty)\n");
|
|
}
|
|
printf("==================\n");
|
|
}
|
|
|
|
int verify_response(const kvs_response_t *rsp, uint8_t expected_op,
|
|
uint8_t expected_status, const char *expected_data) {
|
|
if (rsp->op != expected_op) {
|
|
printf("❌ OP mismatch: expected %u, got %u\n", expected_op, rsp->op);
|
|
return 0;
|
|
}
|
|
|
|
if (rsp->status != expected_status) {
|
|
printf("❌ Status mismatch: expected %u, got %u\n", expected_status, rsp->status);
|
|
return 0;
|
|
}
|
|
|
|
if (expected_data != NULL) {
|
|
uint32_t expected_len = strlen(expected_data);
|
|
if (rsp->datalen != expected_len) {
|
|
printf("❌ Data length mismatch: expected %u, got %u\n", expected_len, rsp->datalen);
|
|
return 0;
|
|
}
|
|
|
|
if (memcmp(rsp->data, expected_data, expected_len) != 0) {
|
|
printf("❌ Data content mismatch\n");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|