diff options
author | Laurent Ghigonis <laurent@p1sec.com> | 2013-09-15 22:16:31 +0200 |
---|---|---|
committer | Laurent Ghigonis <laurent@p1sec.com> | 2013-09-15 22:16:31 +0200 |
commit | a9ba061bd111ea8e133666dc3a8cd2ac0f7c522e (patch) | |
tree | afd98cce26385a01c5655c357286c2acd9fb6c4f | |
parent | work on modules (diff) | |
download | glouglou-a9ba061bd111ea8e133666dc3a8cd2ac0f7c522e.tar.xz glouglou-a9ba061bd111ea8e133666dc3a8cd2ac0f7c522e.zip |
modviz && redis notifications
-rwxr-xr-x | v3/Makefile | 1 | ||||
-rw-r--r-- | v3/glougloud/Makefile | 6 | ||||
-rw-r--r-- | v3/glougloud/glougloud.c | 2 | ||||
-rw-r--r-- | v3/glougloud/glougloud.h | 58 | ||||
-rw-r--r-- | v3/glougloud/glougloud_internal.h | 35 | ||||
-rw-r--r-- | v3/glougloud/glougloud_mod_net/Makefile | 22 | ||||
-rw-r--r-- | v3/glougloud/glougloud_mod_net/glougloud_mod_net.c | 41 | ||||
-rw-r--r-- | v3/glougloud/glougloud_modules.h | 22 | ||||
-rw-r--r-- | v3/glougloud/probes.c | 26 | ||||
-rw-r--r-- | v3/glougloud/redis.c | 2 | ||||
-rw-r--r-- | v3/glougloud/viz.c | 168 | ||||
-rw-r--r-- | v3/libglouglou/libglouglou.h | 15 | ||||
-rw-r--r-- | v3/libglouglou/log.c | 4 | ||||
-rw-r--r-- | v3/libglouglou/tests/test_parse_redis_keyspace_notification.c | 50 | ||||
-rw-r--r-- | v3/libglouglou/tests/test_tcp_server.c | 25 | ||||
-rw-r--r-- | v3/libglouglou/utils.c | 125 |
16 files changed, 395 insertions, 207 deletions
diff --git a/v3/Makefile b/v3/Makefile index 8f8b8cc..8b5d98e 100755 --- a/v3/Makefile +++ b/v3/Makefile @@ -13,3 +13,4 @@ install: test: make -j5 clean && make -j5 && sudo make -j5 install && sudo ./glougloud/glougloud -Dvv + #make -j5 clean && make -j5 && sudo make -j5 install && sudo gdb ./glougloud/glougloud diff --git a/v3/glougloud/Makefile b/v3/glougloud/Makefile index 8cf198b..b0e5233 100644 --- a/v3/glougloud/Makefile +++ b/v3/glougloud/Makefile @@ -1,4 +1,5 @@ PROG = glougloud +HEADERS = glougloud.h SOURCES = glougloud.c probes.c redis.c viz.c OBJECTS = $(SOURCES:.c=.o) CFLAGS+=-Wall -g @@ -9,11 +10,13 @@ GLOUGLOUD_HOME = "/var/lib/glougloud" GLOUGLOUD_CHROOT = "$(GLOUGLOUD_HOME)/chroot" PREFIX=/usr/local +INCLUDEDIR=$(PREFIX)/include BINDIR=$(PREFIX)/sbin all: make $(OBJECTS) $(CC) $(OBJECTS) -o $(PROG) $(LDFLAGS) + make -C glougloud_mod_net/ install: $(PROG) @echo "creating 2 users: $(USER_PROBES), $(USER_VIZ)" @@ -34,7 +37,10 @@ install: $(PROG) @echo done @echo "installation of $(PROG)" mkdir -p $(BINDIR) + mkdir -p $(INCLUDEDIR) install -m 0755 $(PROG) $(BINDIR) + install -m 0644 $(HEADERS) $(INCLUDEDIR) + make -C glougloud_mod_net/ install clean: rm -f $(PROG) $(OBJECTS) *~ diff --git a/v3/glougloud/glougloud.c b/v3/glougloud/glougloud.c index 8942d94..b6efc36 100644 --- a/v3/glougloud/glougloud.c +++ b/v3/glougloud/glougloud.c @@ -7,7 +7,7 @@ #include <event.h> #include <libglouglou.h> -#include "glougloud.h" +#include "glougloud_internal.h" struct event_base *ev_base; diff --git a/v3/glougloud/glougloud.h b/v3/glougloud/glougloud.h index 468c341..618db9e 100644 --- a/v3/glougloud/glougloud.h +++ b/v3/glougloud/glougloud.h @@ -1,16 +1,15 @@ -/* glougloud internal */ +/* + * Public header for glougloud and glougloud modules + * (both probes and viz modules) + */ -#include <dnet.h> -#include <event.h> -#include <hiredis/hiredis.h> -#include <hiredis/async.h> - -#define GLOUGLOUD_VERSION 3 +#if defined(__OpenBSD__) +#include <sys/queue.h> +#else +#include <bsd/sys/queue.h> +#endif -#define GLOUGLOUD_USER_PROBES "_ggdprobe" -#define GLOUGLOUD_USER_VIZ "_ggdviz" -#define GLOUGLOUD_LOGFILE "/var/log/glougloud.log" -#define GLOUGLOUD_MOD_PATH "/lib/glougloud/modules/" +#include <dnet.h> struct glougloud { int daemonize; @@ -31,22 +30,29 @@ struct glougloud { } viz; }; -/* redis.c */ - -int redis_init(struct glougloud *); -void redis_shutdown(void); - -redisAsyncContext *redis_connect(struct event_base *, - void (*cb_connect)(const redisAsyncContext *, int), - void (*cb_disconnect)(const redisAsyncContext *, int)); -void redis_disconnect(redisAsyncContext *); +enum ggdviz_cli_type { + GGDVIZ_CLI_TCP = 0, + GGDVIZ_CLI_WS = 1 +}; -/* probes.c */ +struct ggdviz_cli { + LIST_ENTRY(ggdviz_cli) entry; + int id; + enum ggdviz_cli_type type; + union { + struct { + struct bufferevent *bev; + struct addr addr; + } tcp; + }; +}; -int probes_init(struct glougloud *); -void probes_shutdown(void); +struct ggdprobe_cli { + LIST_ENTRY(ggprobe_cli) entry; + int id; +}; -/* viz.c */ +struct ggdmodviz_conf { + int id; +}; -int viz_init(struct glougloud *); -void viz_shutdown(void); diff --git a/v3/glougloud/glougloud_internal.h b/v3/glougloud/glougloud_internal.h new file mode 100644 index 0000000..9d83a43 --- /dev/null +++ b/v3/glougloud/glougloud_internal.h @@ -0,0 +1,35 @@ +/* glougloud internal */ + +#include <dnet.h> +#include <event.h> +#include <hiredis/hiredis.h> +#include <hiredis/async.h> + +#define GLOUGLOUD_VERSION 3 + +#define GLOUGLOUD_USER_PROBES "_ggdprobe" +#define GLOUGLOUD_USER_VIZ "_ggdviz" +#define GLOUGLOUD_LOGFILE "/var/log/glougloud.log" +#define GLOUGLOUD_MOD_PATH "/modules/" + +#include "glougloud.h" + +/* redis.c */ + +int redis_init(struct glougloud *); +void redis_shutdown(void); + +redisAsyncContext *redis_connect(struct event_base *, + void (*cb_connect)(const redisAsyncContext *, int), + void (*cb_disconnect)(const redisAsyncContext *, int)); +void redis_disconnect(redisAsyncContext *); + +/* probes.c */ + +int probes_init(struct glougloud *); +void probes_shutdown(void); + +/* viz.c */ + +int viz_init(struct glougloud *); +void viz_shutdown(void); diff --git a/v3/glougloud/glougloud_mod_net/Makefile b/v3/glougloud/glougloud_mod_net/Makefile new file mode 100644 index 0000000..8bdcf2f --- /dev/null +++ b/v3/glougloud/glougloud_mod_net/Makefile @@ -0,0 +1,22 @@ +#CFLAGS += -Wall -O2 -fPIC -shared -g +CFLAGS += -Wall -O0 -fPIC -shared -g + +LIBDIR=/var/lib/glougloud/chroot/modules/ +LIBNAME=glougloud_mod_net + +TARGET = ${LIBNAME}.so +SOURCES = glougloud_mod_net.c +OBJECTS = $(SOURCES:.c=.o) + +all: $(TARGET) + +$(TARGET): $(OBJECTS) + $(CC) $(CFLAGS) -o $(TARGET) $(OBJECTS) + +install: + @echo "installation of $(LIBNAME)" + mkdir -p $(LIBDIR) + install -m 0644 $(TARGET) $(LIBDIR) + +clean: + rm -f $(TARGET) $(OBJECTS) diff --git a/v3/glougloud/glougloud_mod_net/glougloud_mod_net.c b/v3/glougloud/glougloud_mod_net/glougloud_mod_net.c index ec6d93c..758767b 100644 --- a/v3/glougloud/glougloud_mod_net/glougloud_mod_net.c +++ b/v3/glougloud/glougloud_mod_net/glougloud_mod_net.c @@ -1,26 +1,51 @@ #include <glougloud.h> -char * -ggdmodviz_text_get(struct glougloud_cli *cli, char *op, char *target) +#include <libglouglou.h> + +#define GLOUGLOUD_MOD_NET_ID 1 + +struct ggdmodviz_conf * +ggdmodviz_init(struct glougloud *ggd) { + struct ggdmodviz_conf *mod; + + log_debug("glougloud_mod_net: viz init"); + mod = xcalloc(1, sizeof(struct ggdmodviz_conf)); + mod->id = GLOUGLOUD_MOD_NET_ID; + + return mod; } -void * -ggdmodviz_netstream_get(struct glougloud_cli *cli, char *notification) +char * +ggdmodviz_text_get(struct ggdviz_cli *cli, char *op, char *target) { + log_debug("glougloud_mod_net:\nop: %s\ntarget: %s"); + return NULL; +} +void * +ggdmodviz_netstream_get(struct ggdviz_cli *cli, char *notification) +{ + return NULL; } int -ggdmodviz_conf_set(struct glougloud_cli *cli, void *conf) +ggdmodviz_conf_set(struct ggdviz_cli *cli, void *conf) { + return -1; +} +int +ggmodprobe_init(struct glougloud *ggd) +{ + log_debug("glougloud_mod_net: probe init"); + return 0; } char * -ggdmodprobe_redis_get(struct glougloud_probe *prb, - struct glouglou_packet *pkt) +ggdmodprobe_redis_get(struct ggdprobe_cli *prb, + struct gg_packet *pkt) { - + return NULL; } diff --git a/v3/glougloud/glougloud_modules.h b/v3/glougloud/glougloud_modules.h deleted file mode 100644 index 732fb08..0000000 --- a/v3/glougloud/glougloud_modules.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Header for glougloud modules - * (both probes and viz modules) - */ - -enum ggdviz_cli_type { - GGDVIZ_CLI_TCP = 0, - GGDVIZ_CLI_WS = 1 -}; - -struct ggdviz_cli { - LIST_ENTRY(servtcp_cli) entry; - int id; - enum ggdviz_cli_type type; - union { - struct tcp { - struct bufferevent *bev; - struct addr addr; - }; - } -}; - diff --git a/v3/glougloud/probes.c b/v3/glougloud/probes.c index f282f39..a744c98 100644 --- a/v3/glougloud/probes.c +++ b/v3/glougloud/probes.c @@ -2,12 +2,20 @@ #include <libglouglou.h> -#include "glougloud.h" +#include "glougloud_internal.h" + +struct modprobe { + LIST_ENTRY(mod) entry; + void *handle; + char *name; + int id; + char (*ggdmodprobe_redis_get)(struct ggdprobe_cli *prb, struct gg_packet *pkt); +}; struct glougloud_probes { int pid; struct event_base *evb; - struct modules *mods; + LIST_HEAD(, modprobe) mods; redisAsyncContext *rc; struct gg_server *server; }; @@ -49,6 +57,12 @@ prb_handle_packet(struct gg_server *srv, struct gg_user *usr, struct gg_packet * return 0; } +static int +_modules_load(void) +{ + return 0; +} + int probes_init(struct glougloud *ggd) { _ggd = ggd; @@ -60,7 +74,9 @@ probes_init(struct glougloud *ggd) { droppriv(GLOUGLOUD_USER_PROBES, 1, NULL); _probes->evb = event_base_new(); - _probes->mods = modules_load(GLOUGLOUD_MOD_PATH, NULL); + + if (_modules_load() < 0) + goto err; _probes->rc = redis_connect(_probes->evb, cb_connect, cb_disconnect); if (_probes->rc->err) @@ -79,6 +95,10 @@ probes_init(struct glougloud *ggd) { gg_server_stop(_probes->server); return 0; + +err: + probes_shutdown(); + return -1; } void diff --git a/v3/glougloud/redis.c b/v3/glougloud/redis.c index 12f531a..b786057 100644 --- a/v3/glougloud/redis.c +++ b/v3/glougloud/redis.c @@ -8,7 +8,7 @@ #include <libglouglou.h> -#include "glougloud.h" +#include "glougloud_internal.h" struct glougloud_redis { int pid; diff --git a/v3/glougloud/viz.c b/v3/glougloud/viz.c index c8265ba..35a14ab 100644 --- a/v3/glougloud/viz.c +++ b/v3/glougloud/viz.c @@ -7,15 +7,26 @@ #include <event2/listener.h> #include <event2/bufferevent.h> #include <event2/buffer.h> +#include <dirent.h> +#include <dlfcn.h> -#include "glougloud.h" +#include "glougloud_internal.h" #define MSG_WELCOME "Welcome to glougloud\n" +struct ggdmodviz { + LIST_ENTRY(ggdmodviz) entry; + void *handle; + char *name; + struct ggdmodviz_conf *conf; + struct ggdmodviz_conf *(*ggdmodviz_init)(struct glougloud *); + char *(*ggdmodviz_text_get)(struct ggdviz_cli *, char *, char *); +}; + struct glougloud_viz { int pid; struct event_base *evb; - struct modules *mods; + LIST_HEAD(, ggdmodviz) mods; redisAsyncContext *rc; /* clients list */ LIST_HEAD(, ggdviz_cli) clients; @@ -27,48 +38,82 @@ struct glougloud_viz { } servtcp; }; -struct modviz_dl { - int id; - char (*ggdmodviz_text_get)(struct glougloud_cli *, char *); -}; - struct glougloud *_ggd; struct glougloud_viz *_viz; -void * -_modules_cb_dlsym(void *handle) -{ - struct modviz_dl *dl = NULL; - void *sym; - - dl = xcalloc(1, sizeof(struct modviz_dl)); - if (!(sym = dlsym(handle, "glougloud_module_id"))) - goto err; - dl->id = *((uint *)sym); - dlerror(); // clear errors - if (!(sym = dlsym(handle, "ggdmodviz_text_get"))) - goto err; - dl->ggdmodviz_text_get = sym; - dlerror(); // clear errors - - return dl; -err: - if (dl) - free(dl); - return NULL; -} - -int +static int _modules_load(void) { - _viz->evb = event_base_new(); - _viz->mods = modules_load(GLOUGLOUD_MOD_PATH, _modules_cb_dlsym); + struct ggdmodviz *mod; + DIR *d = NULL; + struct dirent *ent; + int n; + void *handle, *sym; + char path[MAXPATHLEN]; + char *dir; + struct ggdmodviz_conf *modconf; + struct ggdmodviz_conf *(*fn_ggdmodviz_init)(struct glougloud *); + char *(*fn_ggdmodviz_text_get)(struct ggdviz_cli *, char *, char *); + + dir = GLOUGLOUD_MOD_PATH; + d = opendir(dir); + if (!d) + goto err; + while ((ent = readdir(d))) { + n = strnlen(ent->d_name, sizeof(ent->d_name)); + if (!n || n < 2 || (ent->d_name[0] == '.')) + continue; + log_debug("viz: module %s to load", ent->d_name); + snprintf(path, sizeof(path), "%s/%s", dir, ent->d_name); + handle = dlopen(path, RTLD_LAZY); + log_tmp("m 1"); + if (!handle) + continue; + dlerror(); // clear errors + + log_tmp("m 2"); + if (!(sym = dlsym(handle, "ggdmodviz_init"))) + continue; + fn_ggdmodviz_init = sym; + dlerror(); // clear errors + + log_tmp("m 3"); + if (!(sym = dlsym(handle, "ggdmodviz_text_get"))) + continue; + fn_ggdmodviz_text_get = sym; + dlerror(); // clear errors + + log_tmp("m 4"); + modconf = fn_ggdmodviz_init(_ggd); + if (!modconf) + continue; + + log_tmp("m 5"); + mod = xcalloc(1, sizeof(struct ggdmodviz)); + mod->handle = handle; + mod->name = strdup(ent->d_name); + mod->conf = modconf; + mod->ggdmodviz_init = fn_ggdmodviz_init; + mod->ggdmodviz_text_get = fn_ggdmodviz_text_get; + LIST_INSERT_HEAD(&_viz->mods, mod, entry); + + log_debug("viz: module %s done, id %d", mod->name, mod->conf->id); + } + closedir(d); return 0; + +err: + log_warn("viz: modules load failed"); + if (d) + closedir(d); + return -1; } /* - * XXX notify modules + * Redis notification callback + * + * algo to notify modules: * notif = extract reply->str * foreach module * if ! module match dbname @@ -81,38 +126,32 @@ static void _redis_cb_notification(redisAsyncContext *c, void *r, void *privdata) { redisReply *reply; - struct mod *m; - char *ntf_type, *ntf_pattern, *ntf_event, *ntf_target, *ntf_event_type, *ntf_op; - uint ntf_db; - int i; + struct ggdviz_cli *cli; + struct ggdmodviz *m; + char *ntf_type, *ntf_pattern, *ntf_event_type, *ntf_op, *ntf_target; + int ntf_db, res; reply = r; if (!reply) return; - - notification = reply->str; - i = sscanf(reply->str, "\"%s\",\"%s\",\"%s\",\"%s\", - &ntf_type, &ntf_pattern, &ntf_event, &ntf_target); - if (i <= 3) { - log_notice("viz: error parsing redis notification !"); - return; - } - i = sscanf(ntf_event, "__%s@%d__:%s", - &ntf_event_type, &ntf_db, &ntf_op); - if (i <= 3) { - log_notice("viz: error parsing redis notification event type !"); - return; - } + log_debug("viz: _redis_cb_notification: %s", reply->str); + res = parse_redis_keyspace_notification(reply->str, + &ntf_type, &ntf_pattern, &ntf_event_type, &ntf_db, &ntf_op, &ntf_target); + if (res < 0) { + log_info("viz: could not parse redis keyspace notification (%d) !\n" + "Notification was: %s", res, reply->str); + return; + } LIST_FOREACH(m, &_viz->mods, entry) { - if (m->dl->id != ntf_id) + if (m->conf->id != ntf_db) continue; LIST_FOREACH(cli, &_viz->clients, entry) { - m->dl->ggdmodviz_text_get(cli, ntf_op, ntf_target); + if (cli->type == GGDVIZ_CLI_TCP) + m->ggdmodviz_text_get(cli, ntf_op, ntf_target); } } - log_debug("viz: redis cb_notification: %s", reply->str); } @@ -152,12 +191,13 @@ _redis_connect(void) void _redis_disconnect(void) { - redis_disconnect(_viz->rc); + if (_viz->rc) + redis_disconnect(_viz->rc); _viz->rc = NULL; } -struct servtcp_cli * +struct ggdviz_cli * _servtcp_cli_add(struct sockaddr *sa, struct bufferevent *bev) { struct ggdviz_cli *cli; @@ -171,7 +211,7 @@ _servtcp_cli_add(struct sockaddr *sa, struct bufferevent *bev) LIST_INSERT_HEAD(&_viz->clients, cli, entry); log_debug("viz: _servtcp_cli_add, cli %d %s", - cli->id, addr_ntoa(&cli->addr)); + cli->id, addr_ntoa(&cli->tcp.addr)); bufferevent_write(bev, MSG_WELCOME, strlen(MSG_WELCOME)); return cli; @@ -180,7 +220,7 @@ _servtcp_cli_add(struct sockaddr *sa, struct bufferevent *bev) void _servtcp_cli_del(struct ggdviz_cli *cli) { - bufferevent_free(cli->bev); + bufferevent_free(cli->tcp.bev); LIST_REMOVE(cli, entry); _viz->clients_count--; free(cli); @@ -198,7 +238,7 @@ _servtcp_cb_read(struct bufferevent *bev, void *user_data) buf = bufferevent_get_input(bev); line = evbuffer_readln(buf, &len, EVBUFFER_EOL_CRLF); log_debug("viz: _servtcp_cb_read, cli %d %s, len %d: %s", - cli->id, addr_ntoa(&cli->addr), len, line); + cli->id, addr_ntoa(&cli->tcp.addr), len, line); } static void @@ -264,7 +304,7 @@ _servtcp_start(void) void _servtcp_stop(void) { - struct servtcp_cli *cli, *clitmp; + struct ggdviz_cli *cli, *clitmp; if (_viz->servtcp.listener) evconnlistener_free(_viz->servtcp.listener); @@ -286,6 +326,7 @@ viz_init(struct glougloud *ggd) setprocname("viz"); droppriv(GLOUGLOUD_USER_VIZ, 1, NULL); + _viz->evb = event_base_new(); if (_modules_load() < 0) goto err; if (_redis_connect() < 0) @@ -295,11 +336,12 @@ viz_init(struct glougloud *ggd) event_base_dispatch(_viz->evb); - return 0; + exit(0); err: viz_shutdown(); - return -1; + log_fatal("viz error"); + exit(-1); /* UNREACHED */ } void diff --git a/v3/libglouglou/libglouglou.h b/v3/libglouglou/libglouglou.h index 9d615c4..a46edce 100644 --- a/v3/libglouglou/libglouglou.h +++ b/v3/libglouglou/libglouglou.h @@ -111,27 +111,18 @@ void log_fatal(const char *, ...); /* utils.c */ -struct mod { - LIST_ENTRY(mod) entry; - void *handle; - char *name; - void *dl; -}; -struct modules { - LIST_HEAD(, mod) list; - int count; -}; - void *xmalloc(size_t); void *xcalloc(size_t, size_t); void fd_nonblock(int); void addrcpy(struct sockaddr_in *, struct sockaddr_in *); int addrcmp(struct sockaddr_in *, struct sockaddr_in *); void droppriv(char *, int, char *); -struct modules *modules_load(char *, char *); int exec_pipe(char *, char **, char *, char **); void kill_wait(pid_t, int); struct event *udp_server_create(struct event_base *, struct addr *, int, event_callback_fn, void *); void setprocname(const char *); +int parse_redis_keyspace_notification(char *notification, + char **ntf_type, char **ntf_pattern, char **ntf_event_type, + int *ntf_db, char **ntf_op, char **ntf_target); #endif /* _LIBGLOUGLOU_H_ */ diff --git a/v3/libglouglou/log.c b/v3/libglouglou/log.c index 0f86a7d..7979751 100644 --- a/v3/libglouglou/log.c +++ b/v3/libglouglou/log.c @@ -83,7 +83,7 @@ log_warn(const char *msg, ...) va_list ap; va_start(ap, msg); - logit(LOG_WARN, "", msg, ap); + logit(LOG_WARN, "WARN: ", msg, ap); va_end(ap); } @@ -97,7 +97,7 @@ log_fatal(const char *msg, ...) va_list ap; va_start(ap, msg); - logit(LOG_FATAL, "fatal: ", msg, ap); + logit(LOG_FATAL, "FATAL: ", msg, ap); va_end(ap); exit(1); diff --git a/v3/libglouglou/tests/test_parse_redis_keyspace_notification.c b/v3/libglouglou/tests/test_parse_redis_keyspace_notification.c new file mode 100644 index 0000000..7d5a96d --- /dev/null +++ b/v3/libglouglou/tests/test_parse_redis_keyspace_notification.c @@ -0,0 +1,50 @@ +#include <string.h> + +#include "../libglouglou.h" + +int +main(int argc, char **argv) +{ + char *ntf_type = NULL, *ntf_pattern = NULL, *ntf_event_type = NULL, *ntf_op = NULL, *ntf_target = NULL; + int ntf_db = -1; + int res; + +#define test_name "test 1" + res = parse_redis_keyspace_notification( + strdup("\"pmessage\",\"__key*__:*\",\"__keyevent@0__:set\",\"foo\""), + &ntf_type, &ntf_pattern, + &ntf_event_type, &ntf_db, &ntf_op, &ntf_target); + if ( res < 0 + || strcmp(ntf_type, "pmessage") + || strcmp(ntf_pattern, "__key*__:*") + || strcmp(ntf_event_type, "keyevent") + || (ntf_db != 0) + || strcmp(ntf_op, "set") + || strcmp(ntf_target, "foo") ) { + printf("Error on %s (%d): %s %s %s %d %s %s\n", test_name, res, + ntf_type, ntf_pattern, ntf_event_type, ntf_db, ntf_op, ntf_target); + return 1; + } + +#define test_name "test 2" + res = parse_redis_keyspace_notification( + strdup("toto"), + &ntf_type, &ntf_pattern, + &ntf_event_type, &ntf_db, &ntf_op, &ntf_target); + if ( res != -1 ) { + printf("False positive on %s (%d)", test_name, res); + return 2; + } + +#define test_name "test 3" + res = parse_redis_keyspace_notification( + strdup("toto tata titi tutu toutoutou"), + &ntf_type, &ntf_pattern, + &ntf_event_type, &ntf_db, &ntf_op, &ntf_target); + if ( res != -2 ) { + printf("False positive on %s (%d)", test_name, res); + return 2; + } + + return 0; +} diff --git a/v3/libglouglou/tests/test_tcp_server.c b/v3/libglouglou/tests/test_tcp_server.c deleted file mode 100644 index 9e1180c..0000000 --- a/v3/libglouglou/tests/test_tcp_server.c +++ /dev/null @@ -1,25 +0,0 @@ -#include "../libglouglou.h" - -void -cb_conn(evutil_socket_t listener, short event, void *arg) -{ - -} - -int -main(void) -{ - struct event_base *evb; - struct event *ev; - struct addr ip; - int port; - - addr_aton("127.0.0.1", &ip); - port = 12345; - evb = event_base_new(); - - ev = tcp_server_create(evb, &ip, port, cb_conn, NULL); - if (ev) - return 0; - return 1; -} diff --git a/v3/libglouglou/utils.c b/v3/libglouglou/utils.c index 60601e1..bf0ebc5 100644 --- a/v3/libglouglou/utils.c +++ b/v3/libglouglou/utils.c @@ -15,8 +15,6 @@ #include <pwd.h> #include <grp.h> #include <string.h> -#include <dlfcn.h> -#include <dirent.h> #include <signal.h> #include <sys/wait.h> #include <sys/socket.h> @@ -107,48 +105,6 @@ droppriv(char *user, int do_chroot, char *chroot_path) endpwent(); } -/* Loads modules from path and returns a list of handles - * If cb_dlsym() is not null, it is called for every module */ -struct modules * -modules_load(char *path, void *(cb_dlsym)(void *)) { - struct modules *modules; - struct mod *mod; - DIR *d; - struct dirent *ent; - int n, sym_ok, modid; - void *handle, *dl; - - modules = xcalloc(1, sizeof(struct modules)); - - d = opendir(path); - if (!d) - goto err; - while ((ent = readdir(d))) { - n = strnlen(ent->d_name, sizeof(ent->d_name)); - if (!n) - continue; - handle = dlopen(ent->d_name, RTLD_LAZY); - if (!handle) - continue; - dlerror(); // clear errors - if (cb_dlsym) - dl = cb_dlsym(handle); - mod = xcalloc(1, sizeof(struct mod)); - mod->handle = handle; - mod->name = strdup(ent->d_name); - mod->dl = dl; - LIST_INSERT_HEAD(&modules->list, mod, entry); - modules->count++; - } - - closedir(d); - return modules; - -err: - free(modules); - return NULL; -} - /* pipe cmd1 stdout in cmd2 stdin * return only on error (execve cmd2) */ int @@ -238,3 +194,84 @@ setprocname(const char *name) prctl(PR_SET_NAME, newname, 0, 0, 0); #endif } + +/* Parse redis keyspace notification message + * WARNING: modifies notification string + * + * Example notification string: + * '"pmessage","__key*__:*","__keyevent@0__:set","foo"' + */ +int +parse_redis_keyspace_notification(char *notification, + char **ntf_type, char **ntf_pattern, char **ntf_event_type, + int *ntf_db, char **ntf_op, char **ntf_target) +{ + int i, notification_len; + char *pos, *pos2; + const char *nextsep, *end; + + if (!notification) + return -1; + notification_len = strlen(notification); + if (notification_len < 10) + return -1; + + pos = notification; + nextsep = "\""; + for (i=1; i<=6; i++) { + if (nextsep) { + pos = strstr(pos, nextsep); + if (!pos || (pos > (notification + notification_len) - 2)) + return -2; + pos++; /* point after the separation */ + } + + switch (i) { + case 1: + *ntf_type = pos; + end = "\""; + nextsep = "\""; + break; + case 2: + *ntf_pattern = pos; + end = "\""; + nextsep = "\""; + break; + case 3: + pos = pos + 2; + *ntf_event_type = pos; + end = "@"; + nextsep = NULL; + break; + case 4: + pos2 = strstr(pos, "_"); + if (!pos2) + return -3; + *pos2 = '\0'; + *ntf_db = atoi(pos); + pos = pos2 + 1; + end = NULL; + nextsep = ":"; + break; + case 5: + *ntf_op = pos; + end = "\""; + nextsep = "\""; + break; + case 6: + *ntf_target = pos; + end = "\""; + /* no nextsep because we stop at 6 */ + break; + } + if (end) { + pos = strstr(pos, end); + if (!pos || (pos > (notification + notification_len))) + return -4; + *pos = '\0'; + pos++; + } + } + + return 0; +} |