void hub_disconnect_user(struct hub_info* hub, struct hub_user* user, int reason) { struct event_data post; int need_notify = 0; /* is user already being disconnected ? */ if (user_is_disconnecting(user)) { return; } /* stop reading from user */ net_shutdown_r(net_con_get_sd(user->connection)); net_con_close(user->connection); user->connection = 0; LOG_TRACE("hub_disconnect_user(), user=%p, reason=%d, state=%d", user, reason, user->state); need_notify = user_is_logged_in(user) && hub->status == hub_status_running; 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 { hub_schedule_destroy_user(hub, user); } }
void hub_disconnect_all(struct hub_info* hub) { struct event_data post; memset(&post, 0, sizeof(post)); post.id = UHUB_EVENT_HUB_SHUTDOWN; post.ptr = 0; event_queue_post(hub->queue, &post); }
int msg_pool_post(msg_pool_t* mp, int ch, void* msg) { int ret; if ((ret = event_queue_post(&mp->equeue[ch], msg)) >= 0) { if (mp->efd[ch] >= 0) { if ((ret = msg_pool_efd_trypost(mp->efd[ch])) < 0) perror("msg_pool_efd_trypost"); } } return ret; }
void hub_schedule_destroy_user(struct hub_info* hub, struct hub_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); if (user->id.sid) { sid_free(hub->users->sids, user->id.sid); } }
/* * If user is in the connecting state, we need to do fairly * strict checking of all arguments. * This means we disconnect users when they provide invalid data * during the login sequence. * When users are merely updating their data after successful login * we can just ignore any invalid data and not broadcast it. * * The data we need to check is: * - nick name (valid, not taken, etc) * - CID/PID (valid, not taken, etc). * - IP addresses (IPv4 and IPv6) */ int hub_handle_info(struct hub_info* hub, struct hub_user* user, const struct adc_message* cmd_unmodified) { int ret; struct adc_message* cmd = adc_msg_copy(cmd_unmodified); if (!cmd) return -1; /* OOM */ cmd->priority = 1; hub_handle_info_common(user, cmd); /* If user is logging in, perform more checks, otherwise only a few things need to be checked. */ if (user_is_connecting(user)) { /* * Don't allow the user to send multiple INF messages in this stage! * Since that can have serious side-effects. */ if (user->info) { adc_msg_free(cmd); return 0; } ret = hub_handle_info_login(hub, user, cmd); if (ret < 0) { on_login_failure(hub, user, ret); adc_msg_free(cmd); return -1; } else { /* Post a message, the user has joined */ struct event_data post; memset(&post, 0, sizeof(post)); post.id = UHUB_EVENT_USER_JOIN; post.ptr = user; post.flags = ret; /* 0 - all OK, 1 - need authentication */ event_queue_post(hub->queue, &post); adc_msg_free(cmd); return 0; } } else { /* These must not be allowed updated, let's remove them! */ adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_PRIVATE_ID); adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_CLIENT_ID); /* * If the nick is not accepted, do not relay it. * Otherwise, the nickname will be updated. */ if (adc_msg_has_named_argument(cmd, ADC_INF_FLAG_NICK)) { #ifdef ALLOW_CHANGE_NICK if (!check_nick(hub, user, cmd)) #endif adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_NICK); } ret = check_limits(hub, user, cmd); if (ret < 0) { on_update_failure(hub, user, ret); adc_msg_free(cmd); return -1; } strip_network(user, cmd); hub_handle_info_low_bandwidth(hub, user, cmd); user_update_info(user, cmd); if (!adc_msg_is_empty(cmd)) { route_message(hub, user, cmd); } adc_msg_free(cmd); } return 0; }