aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaurent Ghigonis <laurent@p1sec.com>2013-09-15 22:16:31 +0200
committerLaurent Ghigonis <laurent@p1sec.com>2013-09-15 22:16:31 +0200
commita9ba061bd111ea8e133666dc3a8cd2ac0f7c522e (patch)
treeafd98cce26385a01c5655c357286c2acd9fb6c4f
parentwork on modules (diff)
downloadglouglou-a9ba061bd111ea8e133666dc3a8cd2ac0f7c522e.tar.xz
glouglou-a9ba061bd111ea8e133666dc3a8cd2ac0f7c522e.zip
modviz && redis notifications
-rwxr-xr-xv3/Makefile1
-rw-r--r--v3/glougloud/Makefile6
-rw-r--r--v3/glougloud/glougloud.c2
-rw-r--r--v3/glougloud/glougloud.h58
-rw-r--r--v3/glougloud/glougloud_internal.h35
-rw-r--r--v3/glougloud/glougloud_mod_net/Makefile22
-rw-r--r--v3/glougloud/glougloud_mod_net/glougloud_mod_net.c41
-rw-r--r--v3/glougloud/glougloud_modules.h22
-rw-r--r--v3/glougloud/probes.c26
-rw-r--r--v3/glougloud/redis.c2
-rw-r--r--v3/glougloud/viz.c168
-rw-r--r--v3/libglouglou/libglouglou.h15
-rw-r--r--v3/libglouglou/log.c4
-rw-r--r--v3/libglouglou/tests/test_parse_redis_keyspace_notification.c50
-rw-r--r--v3/libglouglou/tests/test_tcp_server.c25
-rw-r--r--v3/libglouglou/utils.c125
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;
+}