diff --git a/autotest/test_hub.tcc b/autotest/test_hub.tcc index d29fe5c..0c1acec 100644 --- a/autotest/test_hub.tcc +++ b/autotest/test_hub.tcc @@ -67,5 +67,5 @@ EXO_TEST(hub_service_shutdown, { }); EXO_TEST(hub_net_shutdown, { - return (net_shutdown() != -1); + return (net_destroy() != -1); }); diff --git a/autotest/test_ipfilter.tcc b/autotest/test_ipfilter.tcc index 0bb4e4e..ad8f069 100644 --- a/autotest/test_ipfilter.tcc +++ b/autotest/test_ipfilter.tcc @@ -595,5 +595,5 @@ EXO_TEST(ip6_bitwise_OR_3, { }); EXO_TEST(shutdown_network, { - return net_shutdown() == 0; + return net_destroy() == 0; }); diff --git a/autotest/test_usermanager.tcc b/autotest/test_usermanager.tcc new file mode 100644 index 0000000..a767aed --- /dev/null +++ b/autotest/test_usermanager.tcc @@ -0,0 +1,105 @@ +#include + +#define MAX_USERS 64 + +static struct hub_info um_hub; +static struct user um_user[MAX_USERS]; + +EXO_TEST(um_test_setup, { + int i = 0; + memset(&um_hub, 0, sizeof(um_hub)); + + for (i = 0; i < MAX_USERS; i++) + { + memset(&um_user[i], 0, sizeof(struct user)); + um_user[i].id.sid = i+1; + um_user[i].sd = -1; + } + return 1; +}); + +EXO_TEST(um_init_1, { + return uman_init(0) != 0; +}); + +EXO_TEST(um_init_2, { + return uman_init(&um_hub) == 0; +}); + +EXO_TEST(um_shutdown_1, { + return uman_shutdown(0) == -1; +}); + +EXO_TEST(um_shutdown_2, { + return uman_shutdown(&um_hub) == 0; +}); + +EXO_TEST(um_shutdown_3, { + return uman_shutdown(&um_hub) == -1; +}); + +EXO_TEST(um_init_3, { + return uman_init(&um_hub) == 0; +}); + +EXO_TEST(um_add_1, { + return uman_add(&um_hub, &um_user[0]) == 0; +}); + +EXO_TEST(um_size_1, { + return hub_get_user_count(&um_hub) == 1; +}); + + +EXO_TEST(um_remove_1, { + return uman_remove(&um_hub, &um_user[0]) == 0; +}); + +EXO_TEST(um_size_2, { + return hub_get_user_count(&um_hub) == 0; +}); + + +EXO_TEST(um_add_2, { + int i; + for (i = 0; i < MAX_USERS; i++) + { + if (uman_add(&um_hub, &um_user[i]) != 0) + return 0; + } + return 1; +}); + +EXO_TEST(um_size_3, { + return hub_get_user_count(&um_hub) == MAX_USERS; +}); + +EXO_TEST(um_add_3, { + return uman_add(&um_hub, &um_user[5]) != 0; +}); + +EXO_TEST(um_remove_2, { + int i; + for (i = 0; i < MAX_USERS; i++) + { + if (uman_remove(&um_hub, &um_user[i]) != 0) + return 0; + } + return 1; +}); + + + + + + + + + + + + +/* Last test */ +EXO_TEST(um_shutdown_4, { + return uman_shutdown(&um_hub) == 0; +}); diff --git a/src/commands.c b/src/commands.c index 2f3ac44..5259cd0 100644 --- a/src/commands.c +++ b/src/commands.c @@ -37,7 +37,7 @@ static void send_message(struct hub_info* hub, struct user* user, const char* me char* buffer = adc_msg_escape(message); struct adc_message* command = adc_msg_construct(ADC_CMD_IMSG, strlen(buffer) + 6); adc_msg_add_argument(command, buffer); - route_to_user(user, command); + route_to_user(hub, user, command); adc_msg_free(command); hub_free(buffer); } @@ -154,7 +154,7 @@ static int command_kick(struct hub_info* hub, struct user* user, const char* mes return command_status(hub, user, "kick", "Cannot kick yourself"); } - user_disconnect(target, quit_kicked); + hub_disconnect_user(hub, target, quit_kicked); return command_status(hub, user, "kick", nick); } diff --git a/src/hub.c b/src/hub.c index f088b9e..5faa5ba 100644 --- a/src/hub.c +++ b/src/hub.c @@ -19,6 +19,8 @@ #include "uhub.h" +struct hub_info* g_hub = 0; + int hub_handle_message(struct hub_info* hub, struct user* u, const char* line, size_t length) { int ret = 0; @@ -70,7 +72,7 @@ int hub_handle_message(struct hub_info* hub, struct user* u, const char* line, s default: if (user_is_logged_in(u)) { - ret = route_message(u, cmd); + ret = route_message(hub, u, cmd); } else { @@ -148,7 +150,7 @@ int hub_handle_support(struct hub_info* hub, struct user* u, struct adc_message* else { /* disconnect user. Do not send crap during initial handshake! */ - user_disconnect(u, quit_logon_error); + hub_disconnect_user(hub, u, quit_logon_error); ret = -1; } } @@ -195,7 +197,7 @@ int hub_handle_chat_message(struct hub_info* hub, struct user* u, struct adc_mes if (relay && user_is_logged_in(u)) { /* adc_msg_remove_named_argument(cmd, "PM"); */ - ret = route_message(u, cmd); + ret = route_message(hub, u, cmd); } free(message); @@ -206,7 +208,7 @@ void hub_send_support(struct hub_info* hub, struct user* u) { if (user_is_connecting(u) || user_is_logged_in(u)) { - route_to_user(u, hub->command_support); + route_to_user(hub, u, hub->command_support); } } @@ -219,7 +221,7 @@ void hub_send_sid(struct hub_info* hub, struct user* u) command = adc_msg_construct(ADC_CMD_ISID, 10); u->id.sid = uman_get_free_sid(hub); adc_msg_add_argument(command, (const char*) sid_to_string(u->id.sid)); - route_to_user(u, command); + route_to_user(hub, u, command); adc_msg_free(command); } } @@ -233,7 +235,7 @@ void hub_send_ping(struct hub_info* hub, struct user* user) ping->cache[1] = 0; ping->length = 1; ping->priority = 1; - route_to_user(user, ping); + route_to_user(hub, user, ping); adc_msg_free(ping); } @@ -293,14 +295,14 @@ void hub_send_hubinfo(struct hub_info* hub, struct user* u) if (user_is_connecting(u) || user_is_logged_in(u)) { - route_to_user(u, info); + route_to_user(hub, u, info); } adc_msg_free(info); /* Only send banner when connecting */ if (hub->config->show_banner && user_is_connecting(u)) { - route_to_user(u, hub->command_banner); + route_to_user(hub, u, hub->command_banner); } } @@ -320,7 +322,7 @@ void hub_send_motd(struct hub_info* hub, struct user* u) { if (hub->command_motd) { - route_to_user(u, hub->command_motd); + route_to_user(hub, u, hub->command_motd); } } @@ -330,7 +332,7 @@ void hub_send_password_challenge(struct hub_info* hub, struct user* u) igpa = adc_msg_construct(ADC_CMD_IGPA, 38); adc_msg_add_argument(igpa, password_generate_challenge(u)); user_set_state(u, state_verify); - route_to_user(u, igpa); + route_to_user(hub, u, igpa); adc_msg_free(igpa); } @@ -362,9 +364,9 @@ static void hub_event_dispatcher(void* callback_data, struct event_data* message case UHUB_EVENT_USER_QUIT: { uman_remove(hub, (struct user*) message->ptr); - uman_send_quit_message((struct user*) message->ptr); + uman_send_quit_message(hub, (struct user*) message->ptr); on_logout_user(hub, (struct user*) message->ptr); - user_schedule_destroy((struct user*) message->ptr); + hub_schedule_destroy_user(hub, (struct user*) message->ptr); break; } @@ -514,6 +516,7 @@ struct hub_info* hub_start_service(struct hub_config* config) hub->status = hub_status_running; + g_hub = hub; return hub; } @@ -530,6 +533,7 @@ void hub_shutdown_service(struct hub_info* hub) event_base_free(hub->evbase); hub_free(hub); hub = 0; + g_hub = 0; } #define SERVER "" PRODUCT "/" VERSION "" @@ -707,7 +711,7 @@ void hub_send_status(struct hub_info* hub, struct user* user, enum status_messag adc_msg_add_argument(cmd, flag); } - route_to_user(user, cmd); + route_to_user(hub, user, cmd); adc_msg_free(cmd); } @@ -887,3 +891,56 @@ void hub_event_loop(struct hub_info* hub) } while (hub->status == hub_status_running || hub->status == hub_status_disabled); } + +void hub_schedule_destroy_user(struct hub_info* hub, struct user* user) +{ + struct event_data post; + memset(&post, 0, sizeof(post)); + post.id = UHUB_EVENT_USER_DESTROY; + post.ptr = user; + event_queue_post(hub->queue, &post); +} + +void hub_disconnect_user(struct hub_info* hub, struct user* user, int reason) +{ + struct event_data post; + int need_notify = 0; + + /* is user already being disconnected ? */ + if (user_is_disconnecting(user)) + { + return; + } + + /* dont read more data from this user */ + /* FIXME: Remove this from here! */ + if (user->ev_read) + { + event_del(user->ev_read); + hub_free(user->ev_read); + user->ev_read = 0; + } + + /* this should be enough? */ + net_shutdown_r(user->sd); + + hub_log(log_trace, "hub_disconnect_user(), user=%p, reason=%d, state=%d", user, reason, user->state); + + need_notify = user_is_logged_in(user); + user->quit_reason = reason; + user_set_state(user, state_cleanup); + + if (need_notify) + { + memset(&post, 0, sizeof(post)); + post.id = UHUB_EVENT_USER_QUIT; + post.ptr = user; + event_queue_post(hub->queue, &post); + } + else + { + user->quit_reason = quit_unknown; + hub_schedule_destroy_user(hub, user); + } +} + diff --git a/src/hub.h b/src/hub.h index f6d849f..18c684b 100644 --- a/src/hub.h +++ b/src/hub.h @@ -318,6 +318,16 @@ extern void hub_schedule_runslice(struct hub_info* hub); */ extern void hub_event_loop(struct hub_info* hub); +/** + * Schedule destroying a user. + */ +extern void hub_schedule_destroy_user(struct hub_info* hub, struct user* user); + +/** + * Disconnect a user from the hub. + */ +extern void hub_disconnect_user(struct hub_info* hub, struct user* user, int reason); + #endif /* HAVE_UHUB_HUB_H */ diff --git a/src/hubevent.c b/src/hubevent.c index 8f852f9..1c6b226 100644 --- a/src/hubevent.c +++ b/src/hubevent.c @@ -52,7 +52,7 @@ void on_login_success(struct hub_info* hub, struct user* u) struct timeval timeout = { TIMEOUT_IDLE, 0 }; /* Send user list of all existing users */ - if (!uman_send_user_list(u)) + if (!uman_send_user_list(hub, u)) return; /* Mark as being in the normal state, and add user to the user list */ @@ -64,7 +64,7 @@ void on_login_success(struct hub_info* hub, struct user* u) /* Announce new user to all connected users */ if (user_is_logged_in(u)) - route_info_message(u); + route_info_message(hub, u); /* Send message of the day (if any) */ if (user_is_logged_in(u)) /* Previous send() can fail! */ @@ -79,7 +79,7 @@ void on_login_failure(struct hub_info* hub, struct user* u, enum status_message { log_user_login_error(u, msg); hub_send_status(hub, u, msg, status_level_fatal); - user_disconnect(u, quit_logon_error); + hub_disconnect_user(hub, u, quit_logon_error); } void on_nick_change(struct hub_info* hub, struct user* u, const char* nick) diff --git a/src/inf.c b/src/inf.c index 2d29767..0e7822f 100644 --- a/src/inf.c +++ b/src/inf.c @@ -339,7 +339,7 @@ static int check_logged_in(struct hub_info* hub, struct user* user, struct adc_m if (lookup1 == lookup2) { hub_log(log_debug, "check_logged_in: exact same user is logged in: %s", user->id.nick); - user_disconnect(lookup1, quit_ghost_timeout); + hub_disconnect_user(hub, lookup1, quit_ghost_timeout); return 0; } else @@ -702,17 +702,22 @@ int hub_perform_login_checks(struct hub_info* hub, struct user* user, struct adc return 0; } +/** + * Perform additional INF checks used at time of login. + * + * @return 0 if success, <0 if error, >0 if authentication needed. + */ int hub_handle_info_login(struct hub_info* hub, struct user* user, struct adc_message* cmd) { - int need_auth = 0; + int code = 0; INF_CHECK(hub_perform_login_checks, hub, user, cmd); /* Private ID must never be broadcasted - drop it! */ adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_PRIVATE_ID); - /* FIXME: This needs some cleaning up */ - need_auth = set_credentials(hub, user, cmd); + + code = set_credentials(hub, user, cmd); /* Note: this must be done *after* set_credentials. */ if (check_is_hub_full(hub, user)) @@ -733,7 +738,7 @@ int hub_handle_info_login(struct hub_info* hub, struct user* user, struct adc_me /* Set initial user info */ user_set_info(user, cmd); - return need_auth; + return code; } /* @@ -820,7 +825,7 @@ int hub_handle_info(struct hub_info* hub, struct user* user, const struct adc_me if (!adc_msg_is_empty(cmd)) { - route_message(user, cmd); + route_message(hub, user, cmd); } adc_msg_free(cmd); diff --git a/src/main.c b/src/main.c index 42d387e..322d613 100644 --- a/src/main.c +++ b/src/main.c @@ -157,7 +157,7 @@ int main_loop() hub_shutdown_service(hub); } - net_shutdown(); + net_destroy(); hub_log_shutdown(); return 0; } diff --git a/src/netevent.c b/src/netevent.c index 651c88b..176ab4e 100644 --- a/src/netevent.c +++ b/src/netevent.c @@ -19,6 +19,8 @@ #include "uhub.h" +/* FIXME: This should not be needed! */ +extern struct hub_info* g_hub; void net_on_read(int fd, short ev, void *arg) { @@ -145,7 +147,7 @@ void net_on_read(int fd, short ev, void *arg) if (flag_close) { - user_disconnect(user, flag_close); + hub_disconnect_user(g_hub, user, flag_close); return; } @@ -248,7 +250,7 @@ void net_on_write(int fd, short ev, void *arg) if (close_flag) { - user_disconnect(user, close_flag); + hub_disconnect_user(g_hub, user, close_flag); } else { diff --git a/src/network.c b/src/network.c index 6eb328f..0074765 100644 --- a/src/network.c +++ b/src/network.c @@ -59,7 +59,7 @@ int net_initialize() } -int net_shutdown() +int net_destroy() { if (net_initialized) { @@ -235,6 +235,20 @@ int net_close(int fd) return ret; } +int net_shutdown_r(int fd) +{ + return shutdown(fd, SHUT_RD); +} + +int net_shutdown_w(int fd) +{ + return shutdown(fd, SHUT_WR); +} + +int net_shutdown_rw(int fd) +{ + return shutdown(fd, SHUT_RDWR); +} int net_accept(int fd, struct ip_addr_encap* ipaddr) { diff --git a/src/network.h b/src/network.h index 7629844..e51b51b 100644 --- a/src/network.h +++ b/src/network.h @@ -47,7 +47,7 @@ extern int net_initialize(); * * @return -1 on error, 0 on success */ -extern int net_shutdown(); +extern int net_destroy(); /** * @return the number of sockets currrently being monitored. @@ -81,6 +81,10 @@ extern int net_socket_create(int af, int type, int protocol); */ extern int net_close(int fd); +extern int net_shutdown_r(int fd); +extern int net_shutdown_w(int fd); +extern int net_shutdown_rw(int fd); + /** * A wrapper for the accept() function call. * @param fd socket descriptor diff --git a/src/route.c b/src/route.c index 1f2d567..ace68f9 100644 --- a/src/route.c +++ b/src/route.c @@ -20,35 +20,35 @@ #include "uhub.h" -int route_message(struct user* u, struct adc_message* msg) +int route_message(struct hub_info* hub, struct user* u, struct adc_message* msg) { struct user* target = NULL; switch (msg->cache[0]) { case 'B': /* Broadcast to all logged in clients */ - route_to_all(u->hub, msg); + route_to_all(hub, msg); break; case 'D': - target = uman_get_user_by_sid(u->hub, msg->target); + target = uman_get_user_by_sid(hub, msg->target); if (target) { - route_to_user(target, msg); + route_to_user(hub, target, msg); } break; case 'E': - target = uman_get_user_by_sid(u->hub, msg->target); + target = uman_get_user_by_sid(hub, msg->target); if (target) { - route_to_user(target, msg); - route_to_user(u, msg); + route_to_user(hub, target, msg); + route_to_user(hub, u, msg); } break; case 'F': - route_to_subscribers(u->hub, msg); + route_to_subscribers(hub, msg); break; default: @@ -111,7 +111,7 @@ static int check_send_queue(struct user* user, struct adc_message* msg) return 1; } -int route_to_user(struct user* user, struct adc_message* msg) +int route_to_user(struct hub_info* hub, struct user* user, struct adc_message* msg) { int ret; @@ -141,7 +141,7 @@ int route_to_user(struct user* user, struct adc_message* msg) else { /* A socket error occured */ - user_disconnect(user, quit_socket_error); + hub_disconnect_user(hub, user, quit_socket_error); return 0; } } @@ -152,7 +152,7 @@ int route_to_user(struct user* user, struct adc_message* msg) if (ret == -1) { /* User is not able to swallow the data, let's cut our losses and disconnect. */ - user_disconnect(user, quit_send_queue); + hub_disconnect_user(hub, user, quit_send_queue); } else if (ret == 1) { @@ -177,7 +177,7 @@ int route_to_all(struct hub_info* hub, struct adc_message* command) /* iterate u struct user* user = (struct user*) list_get_first(hub->users->list); while (user) { - route_to_user(user, command); + route_to_user(hub, user, command); user = (struct user*) list_get_next(hub->users->list); } @@ -226,7 +226,7 @@ int route_to_subscribers(struct hub_info* hub, struct adc_message* command) /* i if (do_send) { - route_to_user(user, command); + route_to_user(hub, user, command); } } user = (struct user*) list_get_next(hub->users->list); @@ -235,11 +235,11 @@ int route_to_subscribers(struct hub_info* hub, struct adc_message* command) /* i return 0; } -int route_info_message(struct user* u) +int route_info_message(struct hub_info* hub, struct user* u) { if (!user_is_nat_override(u)) { - return route_to_all(u->hub, u->info); + return route_to_all(hub, u->info); } else { @@ -250,15 +250,15 @@ int route_info_message(struct user* u) adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_IPV4_ADDR); adc_msg_add_named_argument(cmd, ADC_INF_FLAG_IPV4_ADDR, address); - user = (struct user*) list_get_first(u->hub->users->list); + user = (struct user*) list_get_first(hub->users->list); while (user) { if (user_is_nat_override(user)) - route_to_user(user, cmd); + route_to_user(hub, user, cmd); else - route_to_user(user, u->info); + route_to_user(hub, user, u->info); - user = (struct user*) list_get_next(u->hub->users->list); + user = (struct user*) list_get_next(hub->users->list); } adc_msg_free(cmd); } diff --git a/src/route.h b/src/route.h index 6e69e8d..a2be8d8 100644 --- a/src/route.h +++ b/src/route.h @@ -23,12 +23,12 @@ /** * Route a message by sending it to it's final destination. */ -extern int route_message(struct user* u, struct adc_message* msg); +extern int route_message(struct hub_info* hub, struct user* u, struct adc_message* msg); /** * Transmit message directly to one user. */ -extern int route_to_user(struct user*, struct adc_message* command); +extern int route_to_user(struct hub_info* hub, struct user*, struct adc_message* command); /** * Broadcast message to all users. @@ -45,7 +45,7 @@ extern int route_to_subscribers(struct hub_info* hub, struct adc_message* comman * This will ensure the correct IP is seen by other users * in case nat override is in use. */ -extern int route_info_message(struct user* user); +extern int route_info_message(struct hub_info* hub, struct user* user); #endif /* HAVE_UHUB_ROUTE_H */ diff --git a/src/user.c b/src/user.c index fa9b505..ff89bde 100644 --- a/src/user.c +++ b/src/user.c @@ -232,51 +232,8 @@ void user_support_remove(struct user* user, int fourcc) user->flags &= ~feature_mask; } -void user_schedule_destroy(struct user* user) -{ - struct event_data post; - memset(&post, 0, sizeof(post)); - post.id = UHUB_EVENT_USER_DESTROY; - post.ptr = user; - event_queue_post(user->hub->queue, &post); -} - void user_disconnect(struct user* user, int reason) { - struct event_data post; - int need_notify = 0; - - if (user_is_disconnecting(user)) - { - return; - } - - /* dont read more data from this user */ - if (user->ev_read) - { - event_del(user->ev_read); - hub_free(user->ev_read); - user->ev_read = 0; - } - - hub_log(log_trace, "user_disconnect(), user=%p, reason=%d, state=%d", user, reason, user->state); - - need_notify = user_is_logged_in(user); - user->quit_reason = reason; - user_set_state(user, state_cleanup); - - if (need_notify) - { - memset(&post, 0, sizeof(post)); - post.id = UHUB_EVENT_USER_QUIT; - post.ptr = user; - event_queue_post(user->hub->queue, &post); - } - else - { - user->quit_reason = quit_unknown; - user_schedule_destroy(user); - } } diff --git a/src/user.h b/src/user.h index 2b7da8e..3b4933b 100644 --- a/src/user.h +++ b/src/user.h @@ -146,11 +146,6 @@ extern struct user* user_create(struct hub_info* hub, int sd); */ extern void user_destroy(struct user* user); -/** - * Will post a message that will delete the user later. - */ -extern void user_schedule_destroy(struct user* user); - /** * Disconnect a user. * This will mark the user connection ready for being terminated. diff --git a/src/usermanager.c b/src/usermanager.c index df723b8..089fd6f 100644 --- a/src/usermanager.c +++ b/src/usermanager.c @@ -210,20 +210,20 @@ struct user* uman_get_user_by_nick(struct hub_info* hub, const char* nick) } -int uman_send_user_list(struct user* target) +int uman_send_user_list(struct hub_info* hub, struct user* target) { int ret = 1; user_flag_set(target, flag_user_list); - struct user* user = (struct user*) list_get_first(target->hub->users->list); /* iterate users - only on INF or PAS msg */ + struct user* user = (struct user*) list_get_first(hub->users->list); /* iterate users - only on INF or PAS msg */ while (user) { if (user_is_logged_in(user)) { - ret = route_to_user(target, user->info); + ret = route_to_user(hub, target, user->info); if (!ret) break; } - user = (struct user*) list_get_next(user->hub->users->list); + user = (struct user*) list_get_next(hub->users->list); } if (!target->send_queue_size) @@ -234,7 +234,7 @@ int uman_send_user_list(struct user* target) } -void uman_send_quit_message(struct user* leaving) +void uman_send_quit_message(struct hub_info* hub, struct user* leaving) { struct adc_message* command = adc_msg_construct(ADC_CMD_IQUI, 6); adc_msg_add_argument(command, (const char*) sid_to_string(leaving->id.sid)); @@ -244,7 +244,7 @@ void uman_send_quit_message(struct user* leaving) adc_msg_add_argument(command, ADC_QUI_FLAG_DISCONNECT); } - route_to_all(leaving->hub, command); + route_to_all(hub, command); adc_msg_free(command); } diff --git a/src/usermanager.h b/src/usermanager.h index 705ec76..5c4162e 100644 --- a/src/usermanager.h +++ b/src/usermanager.h @@ -105,13 +105,13 @@ extern struct user* uman_get_user_by_nick(struct hub_info* hub, const char* nick * * @return 1 if sending the user list succeeded, 0 otherwise. */ -extern int uman_send_user_list(struct user* user); +extern int uman_send_user_list(struct hub_info* hub, struct user* user); /** * Send a quit message to all connected users when 'user' is * leaving the hub (for whatever reason). */ -extern void uman_send_quit_message(struct user* user); +extern void uman_send_quit_message(struct hub_info* hub, struct user* user); #endif /* HAVE_UHUB_USER_MANAGER_H */