TARGET := ircd
SOURCES := \
- src/main.c \
- src/irc.c \
- src/ircfmt.c \
- src/net.c \
- src/netpoll.c \
- src/netsock.c \
- src/passwd.c \
- src/trie.c \
+ src/main.c \
+ src/irc.c \
+ src/ircfmt.c \
+ src/net.c \
+ src/netpoll.c \
+ src/netsock.c \
+ src/passwd.c \
src/util.c
+SOURCES += src/trie.c
HEADERS := \
- src/common.h \
- src/config.h \
- src/irc.h \
- src/ircfmt.h \
- src/net.h \
- src/netpoll.h \
- src/netsock.h \
- src/passwd.h \
- src/trie.h \
+ src/common.h \
+ src/config.h \
+ src/irc.h \
+ src/ircfmt.h \
+ src/net.h \
+ src/netpoll.h \
+ src/netsock.h \
+ src/passwd.h \
+ src/trie.h \
+ src/map_dynarr.h \
src/util.h
-include config.mk
--- /dev/null
+{
+ <tls_init>
+ Memcheck:Leak
+ match-leak-kinds: reachable
+ ...
+ fun:tls_init
+ fun:main
+}
#include "netsock.h"
#include "netpoll.h"
#include "config.h"
+#ifdef USE_MAP_DYNARR
+#include "map_dynarr.h"
+#else
#include "trie.h"
+#endif
#include <time.h>
#ifdef HAS_TLS
#include <tls.h>
size_t wbufLen;
char umode;
char regstate;
- struct trie_node *channels;
- struct trie_node *invites;
+ map_t channels;
+ map_t invites;
int cookie;
time_t signon;
time_t lastactivity;
char *topic_who;
time_t topic_when;
time_t creation;
- struct trie_node *members;
- struct trie_node *o;
- struct trie_node *v;
+ map_t members;
+ map_t o;
+ map_t v;
int member_count;
char dmode;
- struct trie_node *listb;
- struct trie_node *liste;
- struct trie_node *listI;
- struct trie_node *listq;
- struct trie_node *listwo;
- struct trie_node *listwv;
- struct trie_node *invitees;
+ map_t listb;
+ map_t liste;
+ map_t listI;
+ map_t listq;
+ map_t listwo;
+ map_t listwv;
+ map_t invitees;
char *chankey;
int member_limit;
};
#define DMODE_TOPICPROT 32
#define is_chanop(chan, client) (!!trie_get(&(chan)->o, (client)->key))
#define is_chanvoice(chan, client) (!!trie_get(&(chan)->v, (client)->key))
-extern struct trie_node *client_map;
-extern struct trie_node *channel_map;
-extern struct trie_node *autojoin;
+extern map_t client_map;
+extern map_t channel_map;
+extern map_t autojoin;
extern struct client_data *clients;
extern struct client_data *dyingclients;
struct dynarr databuf;
-struct trie_node *client_map = NULL;
-struct trie_node *channel_map = NULL;
-struct trie_node *autojoin = NULL;
+map_t client_map = {0};
+map_t channel_map = {0};
+map_t autojoin = {0};
const char *hostname = IRCDHOSTNAME;
#define is_registered(cl) ((cl)->regstate == REG_REGISTERED)
void sendbuf_chan(struct channel *chan) {
sendbuf_chan_caps(chan, 0, 0);
}
-void sendbuf_list_sans_self_caps(struct client_data *client, struct trie_node **ls, int cookie, int positive, int negative) {
+void sendbuf_list_sans_self_caps(struct client_data *client, map_t *ls, int cookie, int positive, int negative) {
struct trie_find *f = NULL;
if (trie_findfirst(&f, ls) == 1)
do {
}
} while (trie_findnext(&f) == 1);
}
-void sendbuf_list_sans_self(struct client_data *client, struct trie_node **ls, int cookie) {
+void sendbuf_list_sans_self(struct client_data *client, map_t *ls, int cookie) {
sendbuf_list_sans_self_caps(client, ls, cookie, 0, 0);
}
int get_cookie() {
*p++ = '\0';
return umodes;
}
-int match_list(struct client_data *cl, struct trie_node **list)
+int match_list(struct client_data *cl, map_t *list)
{
struct trie_find *f = NULL;
if (trie_findfirst(&f, list) == 1)
case '-': is_plus = 0; break;
default: goto unknown;
}
- struct trie_node **list;
+ map_t *list;
char **argp = &args[2];
while (*p) {
switch (*p) {
trie_set(&chan->o, client->key, NULL, NULL);
trie_set(&chan->v, client->key, NULL, NULL);
chan->member_count--;
- if (!chan->member_count && !(chan->dmode & DMODE_PERSIST)) {
- trie_set(&channel_map, chan->key, NULL, NULL);
- struct trie_find *f = NULL;
- if (trie_findfirst(&f, &chan->invitees) == 1)
- do {
- struct client_data *cl = f->n->value;
- trie_set(&cl->invites, chan->key, NULL, NULL);
- } while(trie_findnext(&f) == 1);
- free(chan->key);
- free(chan->name);
- free(chan->topic);
- free(chan->topic_who);
- trie_free(&chan->members);
- trie_free(&chan->o);
- trie_free(&chan->v);
- trie_free(&chan->listb);
- trie_free(&chan->liste);
- trie_free(&chan->listI);
- trie_free(&chan->listq);
- trie_free(&chan->listwo);
- trie_free(&chan->listwv);
- trie_free(&chan->invitees);
- free(chan->chankey);
- free(chan);
- }
+ if (!chan->member_count && !(chan->dmode & DMODE_PERSIST))
+ channel_kill(chan);
+}
+void channel_kill(struct channel *chan)
+{
+ trie_set(&channel_map, chan->key, NULL, NULL);
+ struct trie_find *f = NULL;
+ if (trie_findfirst(&f, &chan->invitees) == 1)
+ do {
+ struct client_data *cl = f->n->value;
+ trie_set(&cl->invites, chan->key, NULL, NULL);
+ } while(trie_findnext(&f) == 1);
+ free(chan->key);
+ free(chan->name);
+ free(chan->topic);
+ free(chan->topic_who);
+ trie_free(&chan->members);
+ trie_free(&chan->o);
+ trie_free(&chan->v);
+ trie_free(&chan->listb);
+ trie_free(&chan->liste);
+ trie_free(&chan->listI);
+ trie_free(&chan->listq);
+ trie_free(&chan->listwo);
+ trie_free(&chan->listwv);
+ trie_free(&chan->invitees);
+ free(chan->chankey);
+ free(chan);
}
struct client_data *findClient(const char *nickname)
{
void channel_sendnames(struct client_data *client, struct channel *chan);
void channel_join(struct client_data *client, const char *channel, const char *chankey);
void channel_part(struct client_data *client, struct channel *chan, const char *reason, struct client_data *kicker);
+void channel_kill(struct channel *chan);
extern struct dynarr databuf;
#endif
tls_free(tls_ctx);
#endif
free(databuf.buf);
+ /* free any persisten channels */
+ {
+ struct trie_find *f = NULL;
+ while (trie_findfirst(&f, &channel_map) == 1) {
+ struct channel *chan = f->n->value;
+ channel_kill(chan);
+ }
+ free(f);
+ }
+ trie_free(&client_map);
+ trie_free(&channel_map);
trie_free(&autojoin);
+ if (fchanlog)
+ fclose(fchanlog);
return 0;
}
--- /dev/null
+#include "map_dynarr.h"
+#include <stdlib.h>
+#include <string.h>
+static int ent_find(map_t *root, const char *key, int *found)
+{
+ int lo = 0;
+ int hi = root->len;
+ while (lo != hi) {
+ int mid = (lo+hi)/2;
+ int cmp = strcmp(root->ptr[mid].key, key);
+ if (cmp == 0) {
+ *found = 1;
+ return mid;
+ } if (cmp > 0) {
+ hi = mid;
+ } else {
+ lo = mid+1;
+ }
+ }
+ *found = 0;
+ return lo;
+}
+void *trie_get(map_t *root, const char *key)
+{
+ int found;
+ int i = ent_find(root, key, &found);
+ return found ? root->ptr[i].value : 0;
+}
+int trie_set(map_t *root, const char *key, const void *value, void **oldvalue)
+{
+ int found;
+ int i = ent_find(root, key, &found);
+ if (found) {
+ if (oldvalue)
+ *oldvalue = root->ptr[i].value;
+ if (!value) {
+ free(root->ptr[i].key);
+ memmove(root->ptr+i, root->ptr+i+1, sizeof(struct map_dynarr_value)*(root->len-(i+1)));
+ root->len--;
+ } else {
+ root->ptr[i].value = (void *)value;
+ }
+ } else {
+ if (oldvalue)
+ *oldvalue = 0;
+ if (value) {
+ if (root->len == root->cap) {
+ int ncap = root->cap ? root->cap*2 : 2;
+ struct map_dynarr_value *nptr = realloc(root->ptr, sizeof(struct map_dynarr_value)*ncap);
+ if (!nptr)
+ return -1;
+ root->ptr = nptr;
+ root->cap = ncap;
+ }
+ int slen = strlen(key)+1;
+ char *nkey = malloc(slen);
+ if (!nkey)
+ return -1;
+ memcpy(nkey, key, slen);
+ memmove(root->ptr+i+1, root->ptr+i, sizeof(struct map_dynarr_value)*(root->len-i));
+ root->len++;
+ root->ptr[i].key = nkey;
+ root->ptr[i].value = (void *)value;
+ }
+ }
+ return 0;
+}
+void trie_free(map_t *root)
+{
+ while (root->len) {
+ free(root->ptr[--root->len].key);
+ }
+ free(root->ptr);
+ root->ptr = 0;
+ root->len = root->cap = 0;
+}
+static int fill(struct trie_find **pf, int index)
+{
+ struct trie_find *f = *pf;
+ int keylen = strlen(f->_root->ptr[index].key)+1;
+ if (keylen > f->_cap) {
+ while (keylen > f->_cap)
+ f->_cap *= 2;
+ struct trie_find *nf = realloc(f, sizeof(struct trie_find)+f->_cap);
+ if (!nf) {
+ *pf = 0;
+ free(f);
+ return -1;
+ }
+ *pf = f = nf;
+ f->key = (char*)&f[1];
+ f->n = &f->_n;
+ }
+ memcpy(f->key, f->_root->ptr[index].key, keylen);
+ f->n->value = f->_root->ptr[index].value;
+ return 1;
+}
+int trie_findfirst(struct trie_find **pf, map_t *root)
+{
+ if (!root->len)
+ return 0;
+ struct trie_find *f;
+ if (!*pf) {
+ f = malloc(sizeof(struct trie_find)+32);
+ if (!f)
+ return -1;
+ f->key = (char*)&f[1];
+ f->key[0] = 0;
+ f->n = &f->_n;
+ f->_cap = 32;
+ *pf = f;
+ } else {
+ f = *pf;
+ }
+ f->_root = root;
+ return fill(pf, 0);
+}
+int trie_findnext(struct trie_find **pf)
+{
+ struct trie_find *f = *pf;
+ int found;
+ int i = ent_find(f->_root, f->key, &found);
+ i += found;
+ if (f->_root->len == (size_t)i) {
+ *pf = 0;
+ free(f);
+ return 0;
+ }
+ return fill(pf, i);
+}
--- /dev/null
+#ifndef MAP_DYNARR_H_
+#define MAP_DYNARR_H_
+#include <stddef.h>
+struct map_dynarr_value {
+ char *key;
+ void *value;
+};
+struct map_dynarr {
+ struct map_dynarr_value *ptr;
+ size_t len, cap;
+};
+typedef struct map_dynarr map_t;
+void *trie_get(map_t *root, const char *key);
+int trie_set(map_t *root, const char *key, const void *value, void **oldvalue);
+void trie_free(map_t *root);
+struct trie_find {
+ char *key;
+ struct { void *value; } *n, _n;
+ map_t *_root;
+ int _cap;
+};
+int trie_findfirst(struct trie_find **pf, map_t *root);
+int trie_findnext(struct trie_find **pf);
+#endif
update_poll_reg(cl);
/* Part all channels */
struct trie_find *f = NULL;
- if (trie_findfirst(&f, &cl->channels) == 1)
- do {
- struct channel *chan = f->n->value;
- channel_part(cl, chan, NULL, NULL);
- } while(trie_findfirst(&f, &cl->channels) == 1);
- /* Get rid of the pending invites */
+ while (trie_findfirst(&f, &cl->channels) == 1) {
+ struct channel *chan = f->n->value;
+ channel_part(cl, chan, NULL, NULL);
+ }
+ free(f);
+ /* Remove from client_map and get rid of the pending invites */
if (cl->key) {
trie_set(&client_map, cl->key, NULL, NULL);
struct trie_find *f = NULL;
trie_set(&chan->invitees, cl->key, NULL, NULL);
} while(trie_findnext(&f) == 1);
}
+ trie_free(&cl->channels);
+ trie_free(&cl->invites);
killConnectionPart2(cl);
}
void killConnectionPart2(struct client_data *cl)
return lo;
}
// get value from trie O(n log s)
-void *trie_get(struct trie_node **root, const char *key)
+void *trie_get(map_t *root, const char *key)
{
struct trie_node *n = *root;
if (!n)
return n->value;
}
// set value in trie O(ns)
-int trie_set(struct trie_node **root, const char *key, const void *value, void **oldvalue)
+int trie_set(map_t *root, const char *key, const void *value, void **oldvalue)
{
int rv = 0;
if (oldvalue)
return rv;
}
// free a trie
-void trie_free(struct trie_node **root) {
+void trie_free(map_t *root) {
struct trie_node *n = *root;
while (n) {
if (n->len) {
}
}
}
-int trie_findfirst(struct trie_find **pf, struct trie_node **root) {
+int trie_findfirst(struct trie_find **pf, map_t *root) {
if (!*root)
return 0;
struct trie_find *f;
struct trie_node *parent;
struct trie_node *data[1];
};
+typedef struct trie_node *map_t;
// get value from trie O(n log s)
-void *trie_get(struct trie_node **root, const char *key);
+void *trie_get(map_t *root, const char *key);
// set value in trie O(ns)
-int trie_set(struct trie_node **root, const char *key, const void *value, void **oldvalue);
+int trie_set(map_t *root, const char *key, const void *value, void **oldvalue);
// free a trie
-void trie_free(struct trie_node **root);
+void trie_free(map_t *root);
struct trie_find {
struct trie_node *n;
size_t len;
size_t cap;
char key[1];
};
-int trie_findfirst(struct trie_find **pf, struct trie_node **root);
+int trie_findfirst(struct trie_find **pf, map_t *root);
int trie_findnext(struct trie_find **pf);
#ifdef __cplusplus
}
--- /dev/null
+#!/bin/sh
+exec valgrind --leak-check=full --show-leak-kinds=all -s --suppressions=libtls.suppressions ./ircd