Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
catwell committed Nov 5, 2011
0 parents commit 9a4df93
Show file tree
Hide file tree
Showing 7 changed files with 304 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
@@ -0,0 +1 @@
deps
36 changes: 36 additions & 0 deletions Makefile
@@ -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
26 changes: 26 additions & 0 deletions parser-test.c
@@ -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;
}
}

15 changes: 15 additions & 0 deletions parser.h
@@ -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);
70 changes: 70 additions & 0 deletions parser.rl
@@ -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;
}

43 changes: 43 additions & 0 deletions redis-cli-test.c
@@ -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;
}

113 changes: 113 additions & 0 deletions server.c
@@ -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;
}

0 comments on commit 9a4df93

Please sign in to comment.