Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 9a4df93
Showing
7 changed files
with
304 additions
and
0 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
deps |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
CC=gcc | ||
CFLAGS= -Wall -Werror | ||
RAGEL=ragel -G2 | ||
|
||
CBUILD=$(CC) $(CFLAGS) | ||
|
||
all: redisk parser-test redis-cli-test | ||
|
||
deps/libuv/uv.a: | ||
$(MAKE) -C deps/libuv | ||
|
||
parser.c: parser.rl | ||
$(RAGEL) parser.rl | ||
|
||
parser.o: parser.c | ||
$(CBUILD) -c -o parser.o parser.c | ||
|
||
parser-test: parser.o parser-test.c | ||
$(CBUILD) -o parser-test parser.o parser-test.c | ||
|
||
redisk: server.c parser.o deps/libuv/uv.a | ||
$(CBUILD) -I. -Ideps/libuv/include -lrt -lm -lpthread \ | ||
-o redisk server.c parser.o deps/libuv/uv.a | ||
|
||
redis-cli-test: redis-cli-test.c | ||
$(CBUILD) -o redis-cli-test redis-cli-test.c | ||
|
||
clean: | ||
rm -f redisk | ||
rm -f parser.o | ||
rm -f parser.c | ||
rm -f parser-test | ||
rm -f redis-cli-test | ||
|
||
all-clean: clean | ||
rm -f deps/libuv/uv.a |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
#include <stdio.h> | ||
#include <string.h> | ||
#include "parser.h" | ||
|
||
#define REDIS_SET_EXAMPLE "*3\r\n$3\r\nSET\r\n$5\r\nmykey\r\n$7\r\nmyvalue\r\n" | ||
|
||
int main(int argc, char *argv[]) { | ||
redis_parser_t rparser; | ||
redis_parser_init(&rparser); | ||
redis_parser_exec(&rparser, REDIS_SET_EXAMPLE, strlen(REDIS_SET_EXAMPLE)); | ||
int finish_state = redis_parser_finish(&rparser); | ||
if (finish_state <= 0) { | ||
printf("parsing error (%d)\n", finish_state); | ||
redis_parser_free(&rparser); | ||
return 1; | ||
} | ||
else { | ||
printf("parsing ok (%d args)\n", rparser.argnum); | ||
int i; | ||
for(i=0; i<rparser.argnum; ++i) | ||
printf(" %.*s\n", (int)rparser.arg_sizes[i], rparser.args[i]); | ||
redis_parser_free(&rparser); | ||
return 0; | ||
} | ||
} | ||
|
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
#include <stdlib.h> | ||
|
||
typedef struct redis_parser_s { | ||
int argnum; | ||
int argsize; | ||
int cur_arg; | ||
int cur_arg_char; | ||
char **args; | ||
size_t *arg_sizes; | ||
} redis_parser_t; | ||
|
||
int redis_parser_init(redis_parser_t *sc); | ||
int redis_parser_exec(redis_parser_t *sc, const char *data, int len); | ||
int redis_parser_finish(redis_parser_t *sc); | ||
int redis_parser_free(redis_parser_t *sc); |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
#include <stdio.h> | ||
#include <string.h> | ||
#include <stdbool.h> | ||
#include "parser.h" | ||
|
||
static int cs; | ||
|
||
%%{ | ||
machine RedisParser; | ||
|
||
action argnum_add_digit { sc->argnum = sc->argnum * 10 + (fc-'0'); } | ||
action argsize_reset { sc->argsize = 0; } | ||
action argsize_add_digit { sc->argsize = sc->argsize * 10 + (fc-'0'); } | ||
action args_init { | ||
sc->cur_arg = -1; | ||
sc->args = (char **)malloc(sc->argnum*sizeof(char *)); | ||
sc->arg_sizes = (size_t *)malloc(sc->argnum*sizeof(size_t)); | ||
} | ||
action arg_init { | ||
sc->cur_arg++; | ||
sc->cur_arg_char = 0; | ||
sc->arg_sizes[sc->cur_arg] = sc->argsize; | ||
sc->args[sc->cur_arg] = (char *)malloc(sc->argsize); | ||
} | ||
action test_arg_len { sc->cur_arg_char < sc->argsize } | ||
action arg_add_char { | ||
sc->args[sc->cur_arg][sc->cur_arg_char] = fc; | ||
sc->cur_arg_char++; | ||
} | ||
|
||
redis_argnum = '*' ( digit @argnum_add_digit )+ '\r\n'; | ||
redis_argsize = '$' @argsize_reset ( digit @argsize_add_digit )+ '\r\n'; | ||
redis_arg = (any when test_arg_len @arg_add_char)+ '\r\n'; | ||
redis_cmd = redis_argnum @args_init ( redis_argsize @arg_init redis_arg )+; | ||
|
||
main := redis_cmd; | ||
}%% | ||
|
||
%% write data; | ||
|
||
int redis_parser_init(redis_parser_t *sc) { | ||
sc->argnum = 0; | ||
sc->argsize = 0; | ||
%% write init; | ||
return 1; | ||
} | ||
|
||
int redis_parser_free(redis_parser_t *sc) { | ||
int i; | ||
for(i=0; i<sc->argnum; ++i) free(sc->args[i]); | ||
free(sc->args); | ||
free(sc->arg_sizes); | ||
return 1; | ||
} | ||
|
||
int redis_parser_exec(redis_parser_t *sc, const char *data, int len) { | ||
const char *p = data; | ||
const char *pe = data + len; | ||
%% write exec; | ||
if (cs == RedisParser_error) return -1; | ||
else if (cs >= RedisParser_first_final) return 1; | ||
else return 0; | ||
} | ||
|
||
int redis_parser_finish(redis_parser_t *sc) { | ||
if (cs == RedisParser_error) return -1; | ||
else if (cs >= RedisParser_first_final) return 1; | ||
else return 0; | ||
} | ||
|
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
#include <stdio.h> | ||
#include <string.h> | ||
#include <stdlib.h> | ||
#include <netdb.h> | ||
#include <unistd.h> | ||
#include <sys/types.h> | ||
#include <sys/socket.h> | ||
|
||
#define REDIS_SET_EXAMPLE "*3\r\n$3\r\nSET\r\n$5\r\nmykey\r\n$7\r\nmyvalue\r\n" | ||
#define RECVBUF 1024 | ||
|
||
|
||
struct hostent *he; | ||
struct sockaddr_in server; | ||
int sockfd, opt=1; | ||
|
||
int main(int argc, char *argv[]) { | ||
if (argc != 2) { | ||
fprintf(stderr, "USAGE: redis-cli-test PORT\n"); | ||
exit(1); | ||
} | ||
int port = atoi(argv[1]); | ||
he = gethostbyname("localhost"); | ||
memcpy(&server.sin_addr, he->h_addr_list[0], he->h_length); | ||
server.sin_family = AF_INET; | ||
server.sin_port = htons(port); | ||
sockfd = socket(AF_INET, SOCK_STREAM, 0); | ||
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)); | ||
connect(sockfd, (struct sockaddr *)&server, sizeof(server)); | ||
send(sockfd, REDIS_SET_EXAMPLE, strlen(REDIS_SET_EXAMPLE), 0); | ||
char buf[RECVBUF]; | ||
recv(sockfd,buf,RECVBUF,0); | ||
printf("%s\n",buf); | ||
int i; | ||
for (i=0;i<4;++i) buf[i] = 'f'; | ||
sleep(1); | ||
send(sockfd, REDIS_SET_EXAMPLE, strlen(REDIS_SET_EXAMPLE), 0); | ||
recv(sockfd,buf,RECVBUF,0); | ||
printf("%s\n",buf); | ||
close(sockfd); | ||
return 0; | ||
} | ||
|
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
#include <stdio.h> | ||
#include <string.h> | ||
#include <stdlib.h> | ||
#include <assert.h> | ||
#include "parser.h" | ||
#include "deps/libuv/include/uv.h" | ||
|
||
#define OK_RESPONSE "+OK\r\n" | ||
|
||
static uv_loop_t *uv_loop; | ||
static uv_tcp_t server; | ||
static redis_parser_t rparser; | ||
|
||
typedef struct { | ||
uv_tcp_t handle; | ||
uv_write_t write_req; | ||
uv_buf_t buf; | ||
} client_t; | ||
|
||
void on_close(uv_handle_t *handle); | ||
void after_write(uv_write_t *req, int status); | ||
void on_read(uv_stream_t *tcp, ssize_t nread, uv_buf_t buf); | ||
void on_connect(uv_stream_t* server_handle, int status); | ||
|
||
void on_close(uv_handle_t *handle) { | ||
printf("connection closed\n"); | ||
} | ||
|
||
uv_buf_t on_alloc(uv_handle_t *client, size_t suggested_size) { | ||
uv_buf_t buf; | ||
buf.base = malloc(suggested_size); | ||
buf.len = suggested_size; | ||
return buf; | ||
} | ||
|
||
void after_write(uv_write_t *req, int status) { | ||
//client_t *client = (client_t *)client; | ||
if (status) { | ||
uv_err_t err = uv_last_error(uv_loop); | ||
fprintf(stderr, "write error: %s\n", uv_strerror(err)); | ||
exit(1); | ||
} | ||
//uv_close((uv_handle_t*)req->handle, on_close); | ||
} | ||
|
||
void on_read(uv_stream_t *tcp, ssize_t nread, uv_buf_t buf) { | ||
printf("=> reading...\n"); | ||
client_t *client = (client_t *)tcp->data; | ||
|
||
/* PARSE */ | ||
if (nread >= 0) { | ||
redis_parser_init(&rparser); | ||
redis_parser_exec(&rparser, buf.base, nread); | ||
int finish_state = redis_parser_finish(&rparser); | ||
if (finish_state <= 0) { | ||
printf("parsing error (%d)\ninput was:\n", finish_state); | ||
printf(buf.base); | ||
redis_parser_free(&rparser); | ||
exit(1); // be violent... | ||
} | ||
printf("parsing ok (%d args)\n", rparser.argnum); | ||
int i; | ||
for(i=0; i<rparser.argnum; ++i) | ||
printf(" %.*s\n", (int)rparser.arg_sizes[i], rparser.args[i]); | ||
|
||
// TODO call real methods | ||
|
||
client->buf.base = OK_RESPONSE; | ||
client->buf.len = sizeof(OK_RESPONSE); | ||
redis_parser_free(&rparser); | ||
uv_write( &client->write_req, (uv_stream_t *)&client->handle, | ||
&client->buf, 1, after_write ); | ||
} | ||
else { | ||
uv_err_t err = uv_last_error(uv_loop); | ||
if (err.code != UV_EOF) | ||
fprintf(stderr, "read error: %s\n", uv_strerror(err)); | ||
else { | ||
printf("=> received EOF\n"); | ||
uv_close((uv_handle_t*)((&client->write_req)->handle), on_close); | ||
} | ||
} | ||
|
||
free(buf.base); | ||
} | ||
|
||
void on_connect(uv_stream_t* server_handle, int status) { | ||
assert((uv_tcp_t *)server_handle == &server); | ||
client_t* client = malloc(sizeof(client_t)); | ||
printf("=> new connection\n"); | ||
uv_tcp_init(uv_loop, &client->handle); | ||
client->handle.data = client; | ||
uv_accept(server_handle, (uv_stream_t*)&client->handle); | ||
printf("=> before read_start\n"); | ||
uv_read_start((uv_stream_t *)&client->handle, on_alloc, on_read); | ||
} | ||
|
||
int main(int argc, char *argv[]) { | ||
if (argc != 2) { | ||
fprintf(stderr, "USAGE: redisk PORT\n"); | ||
exit(1); | ||
} | ||
int port = atoi(argv[1]); | ||
uv_loop = uv_default_loop(); | ||
uv_tcp_init(uv_loop, &server); | ||
struct sockaddr_in address = uv_ip4_addr("0.0.0.0", port); | ||
uv_tcp_bind(&server, address); | ||
uv_listen((uv_stream_t *)&server, 128, on_connect); | ||
printf("listening on port %d\n",port); | ||
uv_run(uv_loop); | ||
return 0; | ||
} | ||
|