diff --git a/TODO b/TODO index 7b212fe..d6f34e0 100644 --- a/TODO +++ b/TODO @@ -1,3 +1,4 @@ +- check conn_list usage: esp wrt list_remove and closes - uid, gid - keep invites when detached ? - allow global (or per net ?) IP filtering diff --git a/src/bip.c b/src/bip.c index 3cd4e06..d6fd8cb 100644 --- a/src/bip.c +++ b/src/bip.c @@ -377,7 +377,6 @@ static int add_connection(bip_t *bip, struct user *user, list_t *data) l->untrusted_certs = sk_X509_new_null(); #endif } else { -#warning "CODEME (user switch..)" l->network = NULL; log_reinit_all(l->log); } @@ -497,6 +496,8 @@ static int add_connection(bip_t *bip, struct user *user, list_t *data) conf_die("No realname set and no default realname."); l->realname = strdup(user->default_realname); } + + l->in_use = 1; return 1; } @@ -644,6 +645,7 @@ static int add_user(bip_t *bip, list_t *data, struct historical_directives *hds) return 0; } + u->in_use = 1; return 1; } @@ -705,6 +707,61 @@ static int validate_config(bip_t *bip) return r; } +void clear_marks(bip_t *bip) +{ + list_iterator_t lit; + hash_iterator_t hit; + + for (list_it_init(&bip->link_list, &lit); list_it_item(&lit); + list_it_next(&lit)) + ((struct link *)list_it_item(&lit))->in_use = 0; + for (hash_it_init(&bip->users, &hit); hash_it_item(&hit); + hash_it_next(&hit)) + ((struct user *)hash_it_item(&hit))->in_use = 0; +} + +void user_kill(bip_t *bip, struct user *user) +{ + if (!hash_is_empty(&user->connections)) + fatal("user_kill, user still has connections"); + free(user->name); + free(user->password); + MAYFREE(user->default_nick); + MAYFREE(user->default_username); + MAYFREE(user->default_realname); + +#ifdef HAVE_LIBSSL + MAYFREE(ssl_check_store); +#endif + free(user); +} + +void sweep(bip_t *bip) +{ + list_iterator_t lit; + hash_iterator_t hit; + + for (list_it_init(&bip->link_list, &lit); list_it_item(&lit); + list_it_next(&lit)) { + struct link *l = ((struct link *)list_it_item(&lit)); + if (!l->in_use) { + mylog(LOG_INFO, "Administratively killing %s/%s", + l->user->name, l->name); + link_kill(bip, l); + list_remove_if_exists(&bip->conn_list, l); + list_it_remove(&lit); + } + } + for (hash_it_init(&bip->users, &hit); hash_it_item(&hit); + hash_it_next(&hit)) { + struct user *u = (struct user *)hash_it_item(&hit); + if (!u->in_use) { + hash_it_remove(&hit); + user_kill(bip, u); + } + } +} + int fireup(bip_t *bip, FILE *conf) { int r; @@ -712,6 +769,7 @@ int fireup(bip_t *bip, FILE *conf) int err = 0; struct historical_directives hds; + clear_marks(bip); parse_conf(conf, &err); if (err) { free_conf(root_list); @@ -790,6 +848,7 @@ int fireup(bip_t *bip, FILE *conf) root_list = NULL; validate_config(bip); + sweep(bip); return 1; out_conf_error: diff --git a/src/irc.c b/src/irc.c index f51ad6b..7cc36ee 100644 --- a/src/irc.c +++ b/src/irc.c @@ -1423,11 +1423,6 @@ static void channel_free(struct channel *c) if (c->create_ts) free(c->create_ts); -/* - char *l; - while ((l = (char *)list_remove_first(&c->bans))) - free(l); -*/ hash_iterator_t hi; for (hash_it_init(&c->nicks, &hi); hash_it_item(&hi); hash_it_next(&hi)) nick_free(hash_it_item(&hi)); @@ -1892,7 +1887,6 @@ void server_cleanup(struct link_server *server) CONN(server) = NULL; } irc_lag_init(server); - } void irc_client_close(struct link_client *ic) @@ -1989,10 +1983,21 @@ struct link_server *irc_server_new(struct link *link, connection_t *conn) void irc_server_free(struct link_server *s) { + if (CONN(s)) + connection_free(CONN(s)); if (s->nick) free(s->nick); if (s->user_mode) free(s->user_mode); + + hash_iterator_t hi; + for (hash_it_init(&s->channels, &hi); hash_it_item(&hi); + hash_it_next(&hi)) { + struct channel *chan = hash_it_item(&hi); + channel_free(chan); + + } + free(s); } @@ -2413,8 +2418,6 @@ void irc_main(bip_t *bip) bip_on_event(bip, conn); list_free(ready); } - while (list_remove_first(&bip->link_list)) - ; while (list_remove_first(&bip->connecting_client_list)) ; return; @@ -2431,12 +2434,6 @@ void irc_client_free(struct link_client *cli) free(cli); } -/* -void irc_server_free(struct link_server *is) -{ - free(is); -} -*/ struct link *irc_link_new() { struct link *link; @@ -2453,11 +2450,18 @@ struct link *irc_link_new() void link_kill(bip_t *bip, struct link *link) { + list_remove(&bip->conn_list, CONN(link->l_server)); + server_cleanup(link->l_server); + irc_server_free(link->l_server); + while (link->l_clientc) { + struct link_client *lc = link->l_clientv[0]; + list_remove(&bip->conn_list, CONN(lc)); + unbind_from_link(lc); + irc_client_free(lc); + } + hash_remove(&link->user->connections, link->name); free(link->name); - irc_close((struct link_any *)link->l_server); - while (link->l_clientc) - irc_close((struct link_any *)link->l_clientv[0]); log_free(link->log); MAYFREE(link->prev_nick); MAYFREE(link->cli_nick); @@ -2483,5 +2487,6 @@ void link_kill(bip_t *bip, struct link *link) #ifdef HAVE_LIBSSL sk_X509_free(link->untrusted_certs); #endif + free(link); } diff --git a/src/irc.h b/src/irc.h index 2267b24..6a07366 100644 --- a/src/irc.h +++ b/src/irc.h @@ -90,6 +90,7 @@ struct user { #endif hash_t connections; + int in_use; /* for mark and sweep on reload */ }; struct network @@ -157,6 +158,7 @@ struct link { int ssl_check_mode; STACK_OF(X509) *untrusted_certs; #endif + int in_use; /* for mark and sweep on reload */ }; struct link_connection { diff --git a/src/log.c b/src/log.c index 033cdc8..39b63f3 100644 --- a/src/log.c +++ b/src/log.c @@ -1171,7 +1171,7 @@ log_t *log_new(struct user *user, char *network) fatal("out of memory"); logdata->connected = 0; if (!log_all_logs) - log_all_logs = list_new(NULL); + log_all_logs = list_new(list_ptr_cmp); list_add_last(log_all_logs, logdata); return logdata; } @@ -1182,12 +1182,16 @@ void log_free(log_t *log) logfilegroup_t *lfg; logfile_t *lf; + list_remove(log_all_logs, log); + + free(log->network); + free(log->buffer); + for (hash_it_init(&log->logfgs, &it); (lfg = hash_it_item(&it)); hash_it_next(&it)) { log_reset(lfg); if ((lf = list_remove_first(&lfg->file_group))) logfile_free(lf); - free(lf); } hash_clean(&log->logfgs); free(log); diff --git a/src/util.c b/src/util.c index ee9e452..32b5c49 100644 --- a/src/util.c +++ b/src/util.c @@ -308,28 +308,6 @@ void *list_remove_last(list_t *list) return ptr; } -/* -static void *list_remove_item(list_t *l, struct list_item *li) -{ - void *ret = li->ptr; - if (!li->prev) { - if (l->first != li) - fatal("list_remove_item"); - l->first = li->next; - } else - li->prev->next = li->next; - - if (!li->next) { - if (l->last != li) - fatal("list_remove_item"); - l->last = li->prev; - } else - li->next->prev = li->prev; - free(li); - return ret; -} -*/ - void *list_remove_if_exists(list_t *list, void *ptr) { list_iterator_t li; @@ -383,12 +361,19 @@ void list_it_init(list_t *list, list_iterator_t *ti) { ti->list = list; ti->cur = list->first; + ti->next = NULL; } void list_it_next(list_iterator_t *ti) { - if (ti->cur) + if (ti->cur) { + if (ti->next) + fatal("list_it_next: inconsistent interator state"); ti->cur = ti->cur->next; + } else if (ti->next) { + ti->cur = ti->next; + ti->next = NULL; + } } void *list_it_item(list_iterator_t *ti) @@ -415,7 +400,8 @@ void *list_it_remove(list_iterator_t *li) void *ptr = li->cur->ptr; struct list_item *item = li->cur; - li->cur = li->cur->next; + li->next = li->cur->next; + li->cur = NULL; free(item); return ptr; } @@ -555,50 +541,73 @@ void *hash_remove(hash_t *hash, char *key) return ptr; } +int hash_is_empty(hash_t *h) +{ + int i; + + for (i = 0; i < 256; i++) { + if (!list_is_empty(&h->lists[i])) + return 0; + } + return 1; +} + void hash_it_init(hash_t *h, hash_iterator_t *hi) { memset(hi, 0, sizeof(hash_iterator_t)); hi->hash = h; - while (list_is_empty(&h->lists[hi->list]) && hi->list < 256) + while (hi->list < 256 && list_is_empty(&h->lists[hi->list])) hi->list++; if (hi->list < 256) - hi->cur = h->lists[hi->list].first; - else - hi->cur = NULL; + list_it_init(&h->lists[hi->list], &hi->lit); } void hash_it_next(hash_iterator_t *hi) { - hash_t *hash = hi->hash; - - hi->cur = hi->cur->next; - while (!hi->cur) { - hi->list++; - if (hi->list == 256) { - hi->cur = NULL; - return; - } - hi->cur = hash->lists[hi->list].first; + list_it_next(&hi->lit); + if (!list_it_item(&hi->lit)) { + do { + hi->list++; + if (hi->list == 256) + return; + } while (list_is_empty(&hi->hash->lists[hi->list])); + list_it_init(&hi->hash->lists[hi->list], &hi->lit); } } void *hash_it_item(hash_iterator_t *h) { - if (!h->cur) + struct hash_item *hi; + + hi = list_it_item(&h->lit); + if (!hi) return NULL; - struct hash_item *hi = h->cur->ptr; return hi->item; } char *hash_it_key(hash_iterator_t *h) { - if (!h->cur) + struct hash_item *hi; + hi = list_it_item(&h->lit); + if (!hi) return NULL; - struct hash_item *hi = h->cur->ptr; return hi->key; } +void *hash_it_remove(hash_iterator_t *hi) +{ + struct hash_item *hitem; + void *ptr; + + hitem = list_it_remove(&hi->lit); + + ptr = hitem->item; + free(hitem->key); + free(hitem); + return ptr; +} + void hash_dump(hash_t *h) { hash_iterator_t it; diff --git a/src/util.h b/src/util.h index 8dcf87c..18d50c4 100644 --- a/src/util.h +++ b/src/util.h @@ -35,6 +35,7 @@ void _mylog(int level, char *fmt, va_list ap); void fatal(char *fmt, ...); char *timestamp(void); struct list_item; +struct hash_item; typedef struct list { struct list_item *first; @@ -45,16 +46,17 @@ typedef struct list { typedef struct list_iterator { list_t *list; struct list_item *cur; + struct list_item *next; } list_iterator_t; -/* our hash is also a list */ typedef struct hash { list_t lists[256]; } hash_t; typedef struct hash_iterator { int list; - struct list_item *cur; + list_iterator_t lit; + struct hash_item *cur; hash_t *hash; } hash_iterator_t; @@ -104,10 +106,12 @@ void hash_insert(hash_t *hash, char *key, void *ptr); void *hash_get(hash_t *, char *key); void *hash_remove(hash_t *hash, char *key); void *hash_remove_if_exists(hash_t *hash, char *key); +int hash_is_empty(hash_t *h); void hash_it_init(hash_t *hash, hash_iterator_t *i); void hash_it_next(hash_iterator_t *hi); void *hash_it_item(hash_iterator_t *h); char *hash_it_key(hash_iterator_t *h); +void *hash_it_remove(hash_iterator_t *li); int is_valid_nick(char *str); int is_valid_username(char *str);