diff --git a/ChangeLog b/ChangeLog index 6c230e7..d20b921 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2007-05-26 Arnaud Cornet + + * src: lot's of code cleanup and refactoring. Open door to better + dynamic config support. + 2007-02-27 Arnaud Cornet * bip: Release 0.6.0. diff --git a/src/bip.c b/src/bip.c index bfc9266..5b1dc9d 100644 --- a/src/bip.c +++ b/src/bip.c @@ -285,18 +285,17 @@ void reload_config(int i) sighup = 1; } -extern list_t *_connections; +bip_t *_bip; void bad_quit(int i) { list_iterator_t it; - for (list_it_init(_connections, &it); list_it_item(&it); + for (list_it_init(&_bip->link_list, &it); list_it_item(&it); list_it_next(&it)) { - connection_t *c = list_it_item(&it); - struct link_any *la = c->user_data; - if (c->connected == CONN_OK && la && - TYPE(la) == IRC_TYPE_SERVER) { - write_line_fast(CONN(la), "QUIT :Coyote finally " + struct link *l = list_it_item(&it); + struct link_server *ls = l->l_server; + if (ls && l->s_state == IRCS_CONNECTED) { + write_line_fast(CONN(ls), "QUIT :Coyote finally " "caught me\r\n"); } } @@ -749,7 +748,7 @@ int fireup(FILE *conf) return 1; } -void ircize(list_t *ll) +void ircize(bip_t *bip) { hash_iterator_t it; for (hash_it_init(&conf_users, &it); hash_it_item(&it); @@ -806,7 +805,7 @@ void ircize(list_t *ll) list_add_last(&link->chan_infos_order, ci); } - list_add_last(ll, link); + list_add_last(&bip->link_list, link); } else { mylog(LOG_DEBUGVERB, "old connection: \"%s\"", c->name); @@ -909,17 +908,19 @@ int main(int argc, char **argv) { FILE *conf = NULL; char *confpath = NULL; - list_t *ll = list_new(NULL); int ch; int r,fd; char buf[30]; + bip_t bip; + + bip_init(&bip); + _bip = &bip; conf_ip = strdup("0.0.0.0"); conf_port = 7778; conf_css = 0; hash_init(&adm_users, HASH_NOCASE); - hash_init(&conf_users, HASH_NOCASE); hash_init(&conf_networks, HASH_NOCASE); @@ -996,18 +997,17 @@ int main(int argc, char **argv) write(fd, buf, strlen(buf)); close(fd); - connection_t *inc; - inc = listen_new(conf_ip, conf_port, conf_css); - if (!inc) + bip.listener = listen_new(conf_ip, conf_port, conf_css); + if (!bip.listener) fatal("Could not create listening socket"); for (;;) { if (r) - ircize(ll); + ircize(&bip); if (conf_error) mylog(LOG_ERROR, "conf error: %s", conf_errstr); - irc_main(inc, ll); + irc_main(&bip); sighup = 0; diff --git a/src/connection.c b/src/connection.c index 95bcf36..4eee6a8 100644 --- a/src/connection.c +++ b/src/connection.c @@ -1383,7 +1383,6 @@ connection_t *connection_new(char *dsthostname, int dstport, char *srchostname, tmp = srcportbuf; } else tmp = NULL; - #ifdef HAVE_LIBSSL if (ssl) return _connection_new_SSL(dsthostname, dstportbuf, srchostname, diff --git a/src/irc.c b/src/irc.c index f40f32d..25883eb 100644 --- a/src/irc.c +++ b/src/irc.c @@ -338,9 +338,12 @@ void rotate_who_client(struct link *link) * parses:join part mode kick kill privmsg quit nick names * returns: -1 invalid protocol */ -int irc_dispatch_server(struct link_server *server, struct line *line) +int irc_dispatch_server(bip_t *bip, struct link_server *server, + struct line *line) { int ret = OK_COPY; + /* shut gcc up */ + (void)bip; if (line->elemc == 0) return ERR_PROTOCOL; @@ -568,14 +571,9 @@ void unbind_from_link(struct link_client *ic) fatal("unbind_from_link"); if (l->who_client == ic) { - mylog(LOG_DEBUG, "unbind_from_link: %p: %d", - l->who_client, ic->who_count); - l->who_client = NULL; - } else { - mylog(LOG_DEBUG, - "unbind_from_link: nothing to do %p != %p: %d", - ic, l->who_client, + mylog(LOG_DEBUG, "unbind_from_link: %p: %d", l->who_client, ic->who_count); + l->who_client = NULL; } for (i = i + 1; i < l->l_clientc; i++) @@ -667,8 +665,8 @@ static void irc_cli_make_join(struct link_client *ic) } } -static int irc_cli_startup(struct link_client *ic, struct line *line, - list_t *linkl) +static int irc_cli_startup(bip_t *bip, struct link_client *ic, + struct line *line) { char *init_nick; char *user, *pass, *connname; @@ -693,10 +691,11 @@ static int irc_cli_startup(struct link_client *ic, struct line *line, } list_iterator_t it; - for (list_it_init(linkl, &it); list_it_item(&it); list_it_next(&it)) { + for (list_it_init(&bip->link_list, &it); list_it_item(&it); + list_it_next(&it)) { struct link *l = list_it_item(&it); - if (strcmp(user, l->username) == 0 - && strcmp(connname, l->name) == 0) { + if (strcmp(user, l->username) == 0 && + strcmp(connname, l->name) == 0) { if (chash_cmp(pass, l->password, l->seed) == 0) { bind_to_link(l, ic); break; @@ -743,6 +742,7 @@ static int irc_cli_startup(struct link_client *ic, struct line *line, return OK_CLOSE; } + list_remove(&bip->connecting_client_list, ic); TYPE(ic) = IRC_TYPE_CLIENT; for (list_it_init(&LINK(ic)->init_strings, &it); @@ -779,7 +779,7 @@ static int irc_cli_startup(struct link_client *ic, struct line *line, return OK_FORGET; } -static int irc_cli_nick(struct link_client *ic, struct line *line, list_t *cl) +static int irc_cli_nick(bip_t *bip, struct link_client *ic, struct line *line) { if (line->elemc != 2) return ERR_PROTOCOL; @@ -793,16 +793,17 @@ static int irc_cli_nick(struct link_client *ic, struct line *line, list_t *cl) ic->init_nick = strdup(line->elemv[1]); if ((ic->state & IRCC_READY) == IRCC_READY) - return irc_cli_startup(ic, line, cl); + return irc_cli_startup(bip, ic, line); if ((ic->state & IRCC_PASS) != IRCC_PASS) WRITE_LINE2(CONN(ic), P_SERV, "NOTICE", ic->init_nick, - "You should type /QUOTE PASS your_username:your_password:your_connection_name"); + "You should type /QUOTE PASS your_username:" + "your_password:your_connection_name"); return OK_FORGET; } -static int irc_cli_user(struct link_client *ic, struct line *line, list_t *cl) +static int irc_cli_user(bip_t *bip, struct link_client *ic, struct line *line) { if (line->elemc != 5) return ERR_PROTOCOL; @@ -812,11 +813,11 @@ static int irc_cli_user(struct link_client *ic, struct line *line, list_t *cl) ic->state |= IRCC_USER; if ((ic->state & IRCC_READY) == IRCC_READY) - return irc_cli_startup(ic, line, cl); + return irc_cli_startup(bip, ic, line); return OK_FORGET; } -static int irc_cli_pass(struct link_client *ic, struct line *line, list_t *cl) +static int irc_cli_pass(bip_t *bip, struct link_client *ic, struct line *line) { if (line->elemc != 2) return ERR_PROTOCOL; @@ -829,7 +830,7 @@ static int irc_cli_pass(struct link_client *ic, struct line *line, list_t *cl) free(ic->init_pass); ic->init_pass = strdup(line->elemv[1]); if ((ic->state & IRCC_READY) == IRCC_READY) - return irc_cli_startup(ic, line, cl); + return irc_cli_startup(bip, ic, line); return OK_FORGET; } @@ -1036,7 +1037,8 @@ static int irc_dispatch_trust_client(struct link_client *ic, struct line *line) #endif int irc_cli_bip(struct link_client *ic, struct line *line); -static int irc_dispatch_client(struct link_client *ic, struct line *line) +static int irc_dispatch_client(bip_t *bip, struct link_client *ic, + struct line *line) { int r = OK_COPY; if (line->elemc == 0) @@ -1059,7 +1061,7 @@ static int irc_dispatch_client(struct link_client *ic, struct line *line) } else if (strcmp(line->elemv[0], "PART") == 0) { r = irc_cli_part(ic, line); } else if (strcmp(line->elemv[0], "NICK") == 0) { - r = irc_cli_nick(ic, line, NULL); + r = irc_cli_nick(bip, ic, line); } else if (strcmp(line->elemv[0], "QUIT") == 0) { r = irc_cli_quit(ic, line); } else if (strcmp(line->elemv[0], "PRIVMSG") == 0) { @@ -1145,34 +1147,34 @@ static void irc_copy_cli(struct link_client *src, struct link_client *dest, return; } -static int irc_dispatch_loging_client(struct link_client *ic, struct line *line, - list_t *linkl) +static int irc_dispatch_loging_client(bip_t *bip, struct link_client *ic, + struct line *line) { if (line->elemc == 0) return ERR_PROTOCOL; if (strcmp(line->elemv[0], "NICK") == 0) { - return irc_cli_nick(ic, line, linkl); + return irc_cli_nick(bip, ic, line); } else if (strcmp(line->elemv[0], "USER") == 0) { - return irc_cli_user(ic, line, linkl); + return irc_cli_user(bip, ic, line); } else if (strcmp(line->elemv[0], "PASS") == 0) { - return irc_cli_pass(ic, line, linkl); + return irc_cli_pass(bip, ic, line); } return OK_FORGET; } -int irc_dispatch(struct link_any *l, struct line *line, list_t *linkl) +int irc_dispatch(bip_t *bip, struct link_any *l, struct line *line) { switch (TYPE(l)) { case IRC_TYPE_SERVER: - return irc_dispatch_server((struct link_server*)l, line); + return irc_dispatch_server(bip, (struct link_server*)l, line); break; case IRC_TYPE_CLIENT: - return irc_dispatch_client((struct link_client*)l, line); + return irc_dispatch_client(bip, (struct link_client*)l, line); break; case IRC_TYPE_LOGING_CLIENT: - return irc_dispatch_loging_client((struct link_client*)l, - line, linkl); + return irc_dispatch_loging_client(bip, (struct link_client*)l, + line); break; #ifdef HAVE_LIBSSL case IRC_TYPE_TRUST_CLIENT: @@ -1909,13 +1911,14 @@ static void irc_close(struct link_any *l) irc_notify_disconnection(is); else LINK(is)->s_conn_attempt++; + printf("%d\n", LINK(is)->s_conn_attempt); irc_server_shutdown(is); log_disconnected(LINK(is)->log); server_next(LINK(is)); server_cleanup(is); - if (LINK(is)->last_connection && - time(NULL) - LINK(is)->last_connection + if (LINK(is)->last_connection_attempt && + time(NULL) - LINK(is)->last_connection_attempt < CONN_INTERVAL) timer = RECONN_TIMER * (LINK(is)->s_conn_attempt); mylog(LOG_ERROR, "%s dead, reconnecting in %d seconds", @@ -2166,9 +2169,6 @@ clean_oidentd: } #endif -/* do not use */ -list_t *_connections = NULL; - void timeout_clean_who_counts(list_t *conns) { list_iterator_t it; @@ -2192,36 +2192,21 @@ void timeout_clean_who_counts(list_t *conns) } } -struct link_client *reloading_client; -/* - * The main loop - * inc is the incoming connection, clientl list a list of client struct that - * represent the accepcted credentials - */ -void irc_main(connection_t *inc, list_t *ll) +void bip_init(bip_t *bip) { - list_t reconnectl; - list_t timerwaitl; - list_t connl; - list_t connecting_c; - list_t connected_c; - int timeleft = 1000; - int logflush_timer = conf_log_sync_interval; - - list_init(&reconnectl, NULL); - list_init(&timerwaitl, NULL); - list_init(&connl, list_ptr_cmp); - list_init(&connecting_c, list_ptr_cmp); - list_init(&connected_c, list_ptr_cmp); - - _connections = &connl; - - /* XXX: This one MUST be first */ - list_add_first(&connl, inc); + memset(bip, 0, sizeof(bip_t)); + list_init(&bip->link_list, list_ptr_cmp); + list_init(&bip->conn_list, list_ptr_cmp); +} +void bip_recover_sighup(bip_t *bip) +{ + /* gcc */ + (void)bip; /* * Merge with already connected data, happens on SIGHUP */ +#if 0 list_iterator_t it; for (list_it_init(ll, &it); list_it_item(&it); list_it_next(&it)) { struct link *link = list_it_item(&it); @@ -2252,191 +2237,185 @@ void irc_main(connection_t *inc, list_t *ll) conf_errstr); reloading_client = NULL; } +#endif +} +/* Called each second. */ +void bip_tick(bip_t *bip) +{ + static int logflush_timer = 0; + struct link *link; + list_iterator_t li; + + /* log flushs */ + if (logflush_timer-- <= 0) { + logflush_timer = conf_log_sync_interval; + log_flush_all(); + } + + /* handle tick for links: detect lags or start a reconnection */ + for (list_it_init(&bip->link_list, &li); (link = list_it_item(&li)); + list_it_next(&li)) { + if (link->l_server) { + if (irc_server_lag_compute(link)) { + log_ping_timeout(link->log); + list_remove(&bip->conn_list, + CONN(link->l_server)); + irc_close((struct link_any *) link->l_server); + } + } else { + if (link->recon_timer == 0) { + connection_t *conn; + conn = irc_server_connect(link); + list_add_last(&bip->conn_list, conn); + link->last_connection_attempt = time(NULL); + } else { + link->recon_timer--; + } + } + } + + /* drop lagging connecting client */ + for (list_it_init(&bip->connecting_client_list, &li); list_it_item(&li); + list_it_next(&li)) { + struct link_client *ic = list_it_item(&li); + ic->logging_timer++; + if (ic->logging_timer > LOGGING_TIMEOUT) { + list_remove(&bip->conn_list, CONN(ic)); + irc_close((struct link_any *)ic); + list_it_remove(&li); + } + } + + /* + * Cleanup lagging or dangling who_count buffers + */ + timeout_clean_who_counts(&bip->link_list); +} + +void bip_on_event(bip_t *bip, connection_t *conn) +{ + struct link_any *lc = (struct link_any *)conn->user_data; + + if (conn == bip->listener) { + struct link_client *n = irc_accept_new(conn); + if (!n) + fatal("Problem while binding local socket"); + list_add_last(&bip->conn_list, CONN(n)); + list_add_last(&bip->connecting_client_list, n); + return; + } + + /* reached only if socket is not listening */ + int err; + list_t *linel = read_lines(conn, &err); + if (err) { + if (TYPE(lc) == IRC_TYPE_SERVER) { + mylog(LOG_ERROR, "read_lines error, closing %s ...", + LINK(lc)->name); + irc_server_shutdown(LINK(lc)->l_server); + } else { + mylog(LOG_ERROR, "read_lines error, closing..."); + } + goto prot_err; + } + if (!linel) + return; + + char *line_s; + while ((line_s = list_remove_first(linel))) { + struct line *line; + mylog(LOG_DEBUG, "\"%s\"", line_s); + if (*line_s == 0) { /* irssi does that.*/ + free(line_s); + continue; + } + + line = irc_line(line_s); + if (!line) { + mylog(LOG_ERROR, "Error in protocol, closing..."); + free(line_s); + goto prot_err_lines; + } + int r; + r = irc_dispatch(bip, lc, line); + irc_line_free(line); + free(line_s); + if (r == ERR_PROTOCOL) { + mylog(LOG_ERROR, "Error in protocol, " + "closing..."); + goto prot_err_lines; + } + if (r == ERR_AUTH) + goto prot_err_lines; + /* XXX: not real error */ + if (r == OK_CLOSE) + goto prot_err_lines; + + } + list_free(linel); + return; +prot_err_lines: + while ((line_s = list_remove_first(linel))) + free(line_s); +prot_err: + list_remove(&bip->conn_list, conn); + if (linel) + list_free(linel); + if (lc) { + if (TYPE(lc) == IRC_TYPE_LOGING_CLIENT) + list_remove(&bip->connecting_client_list, lc); + irc_close(lc); + } +} + +struct link_client *reloading_client; +/* + * The main loop + * inc is the incoming connection, clientl list a list of client struct that + * represent the accepcted credentials + */ +void irc_main(bip_t *bip) +{ + int timeleft = 1000; + + /* XXX: This one MUST be first */ + /* TODO: maybe not anymore, check */ + printf("%p\n", bip->listener); + list_add_first(&bip->conn_list, bip->listener); + + bip_recover_sighup(bip); while (!sighup) { - struct link *link; connection_t *conn; if (timeleft == 0) { /* * Compute timeouts for next reconnections and lagouts */ - static int throttle_prot = S_CONN_DELAY - 1; timeleft = 1000; - - if (++throttle_prot == S_CONN_DELAY) { - throttle_prot = 0; - - /* Lauch one reconnection at a time */ - if ((link = list_remove_first(&reconnectl))) { - conn = irc_server_connect(link); - list_add_last(&connl, conn); - link->last_connection = time(NULL); - } - } - - /* log flushs */ - if (logflush_timer-- <= 0) { - logflush_timer = conf_log_sync_interval; - log_flush_all(); - } - - /* reconnects */ - list_iterator_t li; - for (list_it_init(&timerwaitl, &li); list_it_item(&li); - list_it_next(&li)) { - struct link *l = list_it_item(&li); - if (l->recon_timer <= 0) { - list_it_remove(&li); - list_add_last(&reconnectl, l); - } else { - l->recon_timer--; - } - } - - /* server lags */ - for (list_it_init(ll, &li); list_it_item(&li); - list_it_next(&li)) { - struct link *l = list_it_item(&li); - if(l->l_server && irc_server_lag_compute(l)) { - log_ping_timeout(l->log); - list_remove(&connl, CONN(l->l_server)); - irc_close((struct link_any *) - l->l_server); - list_add_last(&timerwaitl, l); - } - } - - /* drop lagging connecting client */ - for (list_it_init(&connecting_c, &li); - list_it_item(&li); list_it_next(&li)) { - struct link_client *ic = list_it_item(&li); - ic->logging_timer++; - if (ic->logging_timer > LOGGING_TIMEOUT) { - list_remove(&connl, CONN(ic)); - irc_close((struct link_any *)ic); - list_it_remove(&li); - } - } - - /* - * Cleanup lagging or dangling who_count buffers - */ - timeout_clean_who_counts(ll); + bip_tick(bip); } int nc; /* Da main loop */ - list_t *ready = wait_event(&connl, &timeleft, &nc); + list_t *ready = wait_event(&bip->conn_list, &timeleft, &nc); #ifdef HAVE_OIDENTD if (nc) - oidentd_dump(&connl); + oidentd_dump(&bip->connl); #endif while ((conn = list_remove_first(ready))) { - struct link_any *lc = - (struct link_any *)conn->user_data; - - if (conn == inc) { - struct link_client *n = irc_accept_new(conn); - if (!n) - fatal("Problem while binding local" - " socket"); - list_add_last(&connl, CONN(n)); - list_add_last(&connecting_c, n); - continue; - } - - /* reached only if socket is not listening */ - int err; - list_t *linel = read_lines(conn, &err); - if (err) { - if (TYPE(lc) == IRC_TYPE_SERVER) { - mylog(LOG_ERROR, "read_lines error, " - "closing %s ...", - LINK(lc)->name); - irc_server_shutdown(LINK(lc)->l_server); - } else { - mylog(LOG_ERROR, "read_lines error, " - "closing..."); - } - goto prot_err; - } - if (!linel) - continue; - - char *line_s; - while ((line_s = list_remove_first(linel))) { - struct line *line; - mylog(LOG_DEBUG, "\"%s\"", line_s); - if (*line_s == 0) { /* irssi does that.*/ - free(line_s); - continue; - } - - line = irc_line(line_s); - if (!line) { - mylog(LOG_ERROR, "Error in protocol, " - "closing..."); - free(line_s); - goto prot_err_lines; - } - int r; - int oldtype = TYPE(lc); - r = irc_dispatch((struct link_any*) - conn->user_data, line, ll); - irc_line_free(line); - free(line_s); - if (r == ERR_PROTOCOL) { - mylog(LOG_ERROR, "Error in protocol, " - "closing..."); - goto prot_err_lines; - } - if (r == ERR_AUTH) - goto prot_err_lines; - /* XXX: not real error */ - if (r == OK_CLOSE) - goto prot_err_lines; - - if (oldtype == IRC_TYPE_LOGING_CLIENT && - TYPE(lc) == IRC_TYPE_CLIENT) { - list_remove(&connecting_c, lc); - list_add_last(&connected_c, lc); - } - } - list_free(linel); - continue; -prot_err_lines: - while ((line_s = list_remove_first(linel))) - free(line_s); -prot_err: - list_remove(&connl, conn); - if (linel) - list_free(linel); - if (lc) { - if (TYPE(lc) == IRC_TYPE_CLIENT) - list_remove(&connected_c, lc); - if (TYPE(lc) == IRC_TYPE_LOGING_CLIENT) - list_remove(&connecting_c, lc); - if (TYPE(lc) == IRC_TYPE_SERVER) - list_add_last(&timerwaitl, LINK(lc)); - irc_close(lc); - } + bip_on_event(bip, conn); } list_free(ready); } - while (list_remove_first(&connecting_c)) + while (list_remove_first(&bip->conn_list)) ; - while (list_remove_first(&connected_c)) + while (list_remove_first(&bip->link_list)) ; - while (list_remove_first(&connl)) + while (list_remove_first(&bip->connecting_client_list)) ; - while (list_remove_first(&timerwaitl)) - ; - while (list_remove_first(&reconnectl)) - ; - _connections = NULL; return; } diff --git a/src/irc.h b/src/irc.h index e087227..4020c0b 100644 --- a/src/irc.h +++ b/src/irc.h @@ -85,7 +85,7 @@ struct link { /* connection state (reconnecting, was_connected ...) */ int recon_timer; - time_t last_connection; + time_t last_connection_attempt; /** link options */ @@ -168,6 +168,7 @@ struct link_client { #define IRCS_CONNECTED (2) #define IRCS_WAS_CONNECTED (3) #define IRCS_RECONNECTING (4) +#define IRCS_TIMER_WAIT (5) struct log; @@ -195,14 +196,26 @@ struct link_server { int lagtest_timeout; }; +typedef struct bip { + connection_t *listener; + /* all connected tcp connections */ + list_t conn_list; + /* all links */ + list_t link_list; + /* connecting clients */ + list_t connecting_client_list; +} bip_t; + +void bip_init(bip_t *bip); struct link_client *irc_client_new(void); struct link_server *irc_server_new(struct link *link, connection_t *conn); void irc_server_free(struct link_server *is); struct client *client_new(); -void irc_main(connection_t *inc, list_t *clientl); +void irc_main(bip_t *); int ischannel(char p); void irc_client_close(struct link_client *); void irc_client_free(struct link_client *); struct link *irc_link_new(); void unbind_from_link(struct link_client *ic); #endif + diff --git a/src/util.c b/src/util.c index 1a704eb..83e6494 100644 --- a/src/util.c +++ b/src/util.c @@ -188,6 +188,9 @@ static struct list_item *list_item(void *ptr) void list_add_first(list_t *list, void *ptr) { struct list_item *li; + + if (!ptr) + fatal("Cannot add NULL ptr to list."); li = list_item(ptr); if (!list->first) { list->first = list->last = li; @@ -200,6 +203,8 @@ void list_add_first(list_t *list, void *ptr) void list_add_first_uniq(list_t *list, void *ptr) { + if (!ptr) + fatal("Cannot add NULL ptr to list."); if (list_get(list, ptr)) return; list_add_first(list, ptr); @@ -208,6 +213,9 @@ void list_add_first_uniq(list_t *list, void *ptr) void list_add_last(list_t *list, void *ptr) { struct list_item *li; + + if (!ptr) + fatal("Cannot add NULL ptr to list."); li = list_item(ptr); if (!list->first) { list->first = list->last = li;