Created
July 17, 2013 10:59
-
-
Save charsyam/6019587 to your computer and use it in GitHub Desktop.
redis protocol parsing code and test.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <stdint.h> | |
#include <ctype.h> | |
#include <string.h> | |
#define CR '\r' | |
#define LF '\n' | |
class message { | |
public: | |
int state; | |
char *pos; | |
int narg; | |
int ret; | |
int rlen; | |
int rexpectedlen; | |
int needsplit; | |
}; | |
void parse(char *buffer, int buf_size, message *msg) { | |
enum { | |
START, | |
NARG, | |
NARG_LF, | |
ARGN_LEN_MARK, | |
ARGN_LEN, | |
ARGN_LEN_LF, | |
ARGN, | |
ARGN_LF, | |
}; | |
int state = msg->state; | |
char *pos = msg->pos; | |
char *end = buffer + buf_size; | |
char ch; | |
int len; | |
for ( ;pos < end; pos++) { | |
ch = *pos; | |
switch(state) { | |
case START: | |
if (ch != '*') { | |
goto error; | |
} | |
state = NARG; | |
msg->narg = 0; | |
msg->rlen = 0; | |
msg->rexpectedlen = 0; | |
break; | |
case NARG: | |
if (isdigit(ch)) { | |
msg->narg = msg->narg * 10 + (uint32_t)(ch - '0'); | |
} else if (ch == CR) { | |
if (msg->narg == 0) { | |
printf("ERROR: %d(%s)\n", __LINE__, pos); | |
goto error; | |
} | |
state = NARG_LF; | |
} else { | |
printf("ERROR: %d(%s)\n", __LINE__, pos); | |
goto error; | |
} | |
break; | |
case NARG_LF: | |
if (ch != LF) { | |
printf("ERROR: %d(%s)\n", __LINE__, pos); | |
goto error; | |
} | |
state = ARGN_LEN_MARK; | |
break; | |
case ARGN_LEN_MARK: | |
if (ch == '$') { | |
state = ARGN_LEN; | |
msg->rlen = 0; | |
} else { | |
printf("ERROR: %d(%s)\n", __LINE__, pos); | |
goto error; | |
} | |
break; | |
case ARGN_LEN: | |
if (isdigit(ch)) { | |
msg->rlen = msg->rlen * 10 + (uint32_t)(ch - '0'); | |
} else if (ch == CR) { | |
state = ARGN_LEN_LF; | |
} else { | |
printf("ERROR: %d(%s)\n", __LINE__, pos); | |
goto error; | |
} | |
break; | |
case ARGN_LEN_LF: | |
if (ch != LF) { | |
printf("ERROR: %d(%s)\n", __LINE__, pos); | |
goto error; | |
} | |
state = ARGN; | |
break; | |
case ARGN: | |
len = msg->rexpectedlen ? msg->rexpectedlen : msg->rlen; | |
if (pos + len > end) { | |
msg->rexpectedlen = (uint32_t)(pos + len - end); | |
pos = end - 1; | |
} else { | |
if (*(pos + len) != CR) { | |
printf("ERROR: %d(%d:%s)\n", __LINE__, len, pos); | |
goto error; | |
} | |
pos += len; | |
msg->rexpectedlen = 0; | |
msg->rlen = 0; | |
state = ARGN_LF; | |
msg->narg--; | |
} | |
break; | |
case ARGN_LF: | |
if (ch != LF) { | |
printf("ERROR: %d(%s)\n", __LINE__, pos); | |
goto error; | |
} | |
if (msg->narg == 0) { | |
goto done; | |
} | |
state = ARGN_LEN_MARK; | |
break; | |
} | |
} | |
msg->state = state; | |
msg->pos = pos; | |
//need next packet | |
msg->ret = 3; | |
return; | |
error: | |
msg->ret = -1; | |
return; | |
done: | |
msg->state = START; | |
msg->pos = pos + 1; | |
msg->ret = 0; | |
if (msg->pos != end) { | |
msg->needsplit = 1; | |
} | |
return; | |
} | |
int main(int argc, char *argv[]) { | |
message msg; | |
memset(&msg, 0, sizeof(message)); | |
char *ptr = (char *)"*3\r\n$3\r\nset\r\n$3\r\nkey\r\n$5\r\nvalue\r\n"; | |
msg.pos = ptr; | |
parse(ptr, strlen(ptr), &msg); | |
printf("ret: %d(%d)\n", msg.ret, msg.needsplit); | |
memset(&msg, 0, sizeof(message)); | |
ptr = (char *)"*3\r\n$3\r\nset\r\n$3"; | |
msg.pos = ptr; | |
parse(ptr, strlen(ptr), &msg); | |
printf("ret: %d(%d)\n", msg.ret, msg.needsplit); | |
ptr = (char *)"\r\nkey\r\n$5\r\nvalue\r\n"; | |
msg.pos = ptr; | |
parse(ptr, strlen(ptr), &msg); | |
printf("ret: %d(%d)\n", msg.ret, msg.needsplit); | |
memset(&msg, 0, sizeof(message)); | |
ptr = (char *)"*3\r\n$3\r\nset\r\n$3"; | |
msg.pos = ptr; | |
parse(ptr, strlen(ptr), &msg); | |
printf("ret: %d(%d)\n", msg.ret, msg.needsplit); | |
ptr = (char *)"\r\nkey\r\n$5\r\nvalue\r\n$ab"; | |
msg.pos = ptr; | |
parse(ptr, strlen(ptr), &msg); | |
printf("ret: %d(%d)\n", msg.ret, msg.needsplit); | |
parse(msg.pos, 2, &msg); | |
printf("ret: %d(%d)\n", msg.ret, msg.needsplit); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment