简化协议,
/**
* Request
* Cmd: | OP(1) | argc(1) | repeat { arglen(4) | arg } |
*
* Response
* Rsp: | OP(1) | status(1) | datalen(4) | data |
*/
封装客户端进行批处理和单条命令测试。
This commit is contained in:
274
kvs_rw_tools.c
274
kvs_rw_tools.c
@@ -62,195 +62,125 @@ int kvs_write_u32(uint8_t **pp, const uint8_t *end, uint32_t v) {
|
||||
}
|
||||
|
||||
// return: -1 fail, 0 half, >0 consumed
|
||||
int kvs_parse_request(const uint8_t *msg, int length, kvs_request_t *req_out) {
|
||||
if (!msg || length <= 0 || !req_out) return -1;
|
||||
memset(req_out, 0, sizeof(*req_out));
|
||||
int kvs_parse_one_cmd(const uint8_t *request, int request_length, kvs_req_t *req_out){
|
||||
if (!request || request_length <= 0 || !req_out) return -1;
|
||||
|
||||
req_out->op = 0;
|
||||
req_out->argc = 0;
|
||||
req_out->args = NULL;
|
||||
|
||||
if(length < KVS_HDR_LEN) return 0;
|
||||
const uint8_t *p = request;
|
||||
const uint8_t *end = request + (size_t)request_length;
|
||||
|
||||
// header parser
|
||||
uint32_t magic_be;
|
||||
memcpy(&magic_be, msg, 4);
|
||||
uint32_t magic = ntohl(magic_be);
|
||||
if (magic != KVS_MAGIC) return -1;
|
||||
// OP + ARGC
|
||||
if (kvs_need(p, end, 2)) {
|
||||
return 0; // NEED_MORE
|
||||
}
|
||||
|
||||
//
|
||||
uint8_t type = *(msg+4);
|
||||
uint8_t op = 0, argc = 0;
|
||||
if (kvs_read_u8(&p, end, &op) < 0) return -1;
|
||||
if (kvs_read_u8(&p, end, &argc) < 0) return -1;
|
||||
|
||||
uint32_t payloadlen_be;
|
||||
memcpy(&payloadlen_be, msg+5, 4);
|
||||
uint32_t payloadlen = ntohl(payloadlen_be);
|
||||
if (argc > KVS_MAX_ARGC) return -1;
|
||||
|
||||
uint32_t reqId_be;
|
||||
memcpy(&reqId_be, msg + 9, 4);
|
||||
uint32_t reqId = ntohl(reqId_be);
|
||||
|
||||
uint8_t flag1 = *(msg + 13);
|
||||
|
||||
uint16_t flag2_be;
|
||||
memcpy(&flag2_be, msg + 14, 2);
|
||||
uint16_t flag2 = ntohs(flag2_be);
|
||||
|
||||
uint32_t totalLen = (uint32_t)KVS_HDR_LEN + payloadlen;
|
||||
if ((uint32_t)length < totalLen) return 0; // 半包
|
||||
|
||||
|
||||
// payload parser
|
||||
const uint8_t *ptr = msg + KVS_HDR_LEN;
|
||||
const uint8_t *end = ptr + payloadlen;
|
||||
|
||||
uint32_t opcount = 0;
|
||||
if(kvs_read_u32(&ptr, end, &opcount) < 0) return -1;
|
||||
if (opcount > KVS_MAX_OPCOUNT) return -1;
|
||||
|
||||
kvs_op_t *ops = (kvs_op_t *)kvs_malloc(sizeof(kvs_op_t) * opcount);
|
||||
if (!ops) return -1;
|
||||
memset(ops, 0, sizeof(kvs_op_t) * opcount);
|
||||
|
||||
// operator parser
|
||||
for (uint32_t i = 0; i < opcount; i++) {
|
||||
uint8_t op = 0;
|
||||
uint32_t argc = 0;
|
||||
|
||||
if (kvs_read_u8(&ptr, end, &op) < 0) goto FAIL;
|
||||
if (kvs_read_u32(&ptr, end, &argc) < 0) goto FAIL;
|
||||
if (argc > 16) goto FAIL;
|
||||
|
||||
char **argv = NULL;
|
||||
if (argc > 0) {
|
||||
argv = (char **)kvs_malloc(sizeof(char*) * argc);
|
||||
if (!argv) goto FAIL;
|
||||
memset(argv, 0, sizeof(char*) * argc);
|
||||
}
|
||||
|
||||
// operator args parser
|
||||
for (uint32_t a = 0; a < argc; a++) {
|
||||
uint32_t arglen = 0;
|
||||
if (kvs_read_u32(&ptr, end, &arglen) < 0) goto FAIL;
|
||||
if (kvs_need(ptr, end, arglen) < 0) goto FAIL;
|
||||
|
||||
char *s = (char *)kvs_malloc((size_t)arglen + 1);
|
||||
if (!s) goto FAIL;
|
||||
|
||||
memcpy(s, ptr, arglen);
|
||||
s[arglen] = '\0';
|
||||
argv[a] = s;
|
||||
ptr += arglen;
|
||||
}
|
||||
|
||||
ops[i].op = op;
|
||||
ops[i].argc = argc;
|
||||
ops[i].argv = argv;
|
||||
}
|
||||
|
||||
req_out->magic = magic;
|
||||
req_out->type = type;
|
||||
req_out->payloadLen = payloadlen;
|
||||
req_out->reqId = reqId;
|
||||
req_out->flag1 = flag1;
|
||||
req_out->flag2 = flag2;
|
||||
req_out->opcount = opcount;
|
||||
req_out->ops = ops;
|
||||
req_out->consumed = totalLen;
|
||||
|
||||
return (int)totalLen;
|
||||
|
||||
FAIL:
|
||||
if (ops) {
|
||||
for (uint32_t i = 0; i < opcount; i++) {
|
||||
if (ops[i].argv) {
|
||||
for (uint32_t a = 0; a < ops[i].argc; a++) {
|
||||
if (ops[i].argv[a]) kvs_free(ops[i].argv[a]);
|
||||
}
|
||||
kvs_free(ops[i].argv);
|
||||
// 先扫描一遍确认整条命令数据都在 buffer 里
|
||||
const uint8_t *scan = p;
|
||||
uint32_t lens[KVS_MAX_ARGC];
|
||||
if (argc > 0) {
|
||||
for (uint8_t i = 0; i < argc; i++) {
|
||||
if (kvs_need(scan, end, 4)) {
|
||||
return 0; // NEED_MORE
|
||||
}
|
||||
}
|
||||
kvs_free(ops);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
uint32_t alen = 0;
|
||||
if (kvs_read_u32(&scan, end, &alen) < 0) return -1;
|
||||
|
||||
void kvs_free_request(kvs_request_t *req) {
|
||||
if (!req) return;
|
||||
if (req->ops) {
|
||||
for (uint32_t i = 0; i < req->opcount; i++) {
|
||||
if (req->ops[i].argv) {
|
||||
for (uint32_t a = 0; a < req->ops[i].argc; a++) {
|
||||
if (req->ops[i].argv[a]) kvs_free(req->ops[i].argv[a]);
|
||||
}
|
||||
kvs_free(req->ops[i].argv);
|
||||
// 防御:单个参数长度限制
|
||||
if (alen > KVS_MAX_ARGLEN) return -1;
|
||||
|
||||
// 防御:scan + alen 越界 / 半包
|
||||
if (kvs_need(scan, end, (size_t)alen)) {
|
||||
return 0; // NEED_MORE
|
||||
}
|
||||
}
|
||||
kvs_free(req->ops);
|
||||
lens[i] = alen;
|
||||
scan += alen;
|
||||
}
|
||||
}
|
||||
memset(req, 0, sizeof(*req));
|
||||
|
||||
size_t total_len = (size_t)(scan - request);
|
||||
if (total_len > KVS_MAX_CMD_BYTES) return -1;
|
||||
|
||||
req_out->op = op;
|
||||
req_out->argc = argc;
|
||||
|
||||
if (argc == 0) {
|
||||
return (int)total_len;
|
||||
}
|
||||
|
||||
kvs_arg_t *args = (kvs_arg_t *)kvs_malloc((size_t)argc * sizeof(kvs_arg_t));
|
||||
if (!args) {
|
||||
kvs_free_request(req_out);
|
||||
return -1;
|
||||
}
|
||||
memset(args, 0, (size_t)argc * sizeof(kvs_arg_t));
|
||||
|
||||
for (uint8_t i = 0; i < argc; i++) {
|
||||
uint32_t alen = 0;
|
||||
if (kvs_read_u32(&p, end, &alen) < 0) {
|
||||
kvs_free(args);
|
||||
kvs_free_request(req_out);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// alen 与 lens[i] 应当一致(扫描时读过),不一致说明解析器/输入异常
|
||||
if (alen != lens[i]) {
|
||||
kvs_free(args);
|
||||
kvs_free_request(req_out);
|
||||
return -1;
|
||||
}
|
||||
|
||||
args[i].len = alen;
|
||||
args[i].data = p; // 直接指向输入 buffer(零拷贝)
|
||||
p += alen;
|
||||
}
|
||||
|
||||
|
||||
req_out->args = args;
|
||||
|
||||
return (int)(p - request);
|
||||
}
|
||||
|
||||
int kvs_execute_request(const kvs_request_t *req, kvs_response_t *results /* size opcount */) {
|
||||
if (!req || !results) return -1;
|
||||
|
||||
for (uint32_t i = 0; i < req->opcount; i++) {
|
||||
uint8_t status = KVS_STATUS_ERROR;
|
||||
const char *data = NULL;
|
||||
uint32_t dlen = 0;
|
||||
|
||||
kvs_exec_one_op(req->ops[i].op, req->ops[i].argc, req->ops[i].argv,
|
||||
&status, &data, &dlen);
|
||||
|
||||
results[i].status = status;
|
||||
results[i].datalen = dlen;
|
||||
results[i].data_ptr = data;
|
||||
}
|
||||
return 0;
|
||||
void kvs_free_request(kvs_req_t *req) {
|
||||
if (!req) return;
|
||||
if (req->args) {
|
||||
kvs_free(req->args);
|
||||
req->args = NULL;
|
||||
}
|
||||
req->op = 0;
|
||||
req->argc = 0;
|
||||
}
|
||||
|
||||
int kvs_build_one_rsp(const kvs_rsp_t *results, uint8_t *response, size_t response_cap){
|
||||
if (!results || !response) return -1;
|
||||
|
||||
int kvs_build_response(const kvs_request_t *req,
|
||||
const kvs_response_t *results,
|
||||
uint8_t *response, int response_cap) {
|
||||
if (!req || !results || !response || response_cap < KVS_HDR_LEN) return -1;
|
||||
const uint8_t *end = response + response_cap;
|
||||
uint8_t *p = response;
|
||||
|
||||
uint8_t *out = response;
|
||||
uint8_t *w = out + KVS_HDR_LEN;
|
||||
const uint8_t *w_end = out + response_cap;
|
||||
// 计算所需长度:1 + 1 + 4 + dlen
|
||||
// 注意防止 size_t 溢出
|
||||
size_t need = 1u + 1u + 4u + (size_t)results->dlen;
|
||||
if (need > response_cap) return -1;
|
||||
|
||||
// payload: opcount
|
||||
if (kvs_write_u32(&w, w_end, req->opcount) < 0) return -1;
|
||||
if (kvs_write_u8(&p, end, results->op) < 0) return -1;
|
||||
if (kvs_write_u8(&p, end, results->status) < 0) return -1;
|
||||
if (kvs_write_u32(&p, end, results->dlen) < 0) return -1;
|
||||
|
||||
for (uint32_t i = 0; i < req->opcount; i++) {
|
||||
if (kvs_write_u8(&w, w_end, results[i].status) < 0) return -1;
|
||||
if (kvs_write_u32(&w, w_end, results[i].datalen) < 0) return -1;
|
||||
if (results->dlen > 0) {
|
||||
if (!results->data) return -1; // 有长度却没指针,视为错误
|
||||
if (kvs_need(p, end, (size_t)results->dlen) < 0) return -1;
|
||||
memcpy(p, results->data, results->dlen);
|
||||
p += results->dlen;
|
||||
}
|
||||
|
||||
if (results[i].datalen > 0) {
|
||||
if (kvs_need(w, w_end, results[i].datalen) < 0) return -1;
|
||||
memcpy(w, results[i].data_ptr, results[i].datalen);
|
||||
w += results[i].datalen;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t respPayloadLen = (uint32_t)(w - (out + KVS_HDR_LEN));
|
||||
uint32_t total = KVS_HDR_LEN + respPayloadLen;
|
||||
|
||||
// header
|
||||
{
|
||||
uint32_t be = htonl(KVS_MAGIC);
|
||||
memcpy(out + 0, &be, 4);
|
||||
}
|
||||
out[4] = (uint8_t)KVS_TYPE_RESP;
|
||||
{
|
||||
uint32_t be = htonl(respPayloadLen);
|
||||
memcpy(out + 5, &be, 4);
|
||||
}
|
||||
{
|
||||
uint32_t be = htonl(req->reqId);
|
||||
memcpy(out + 9, &be, 4);
|
||||
}
|
||||
out[13] = req->flag1;
|
||||
{
|
||||
uint16_t be = htons(req->flag2);
|
||||
memcpy(out + 14, &be, 2);
|
||||
}
|
||||
|
||||
return (int)total;
|
||||
return (int)(p - response);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user