/* * Copyright (c) 2011 Alexandria Wolcott * Released under the same terms as Atheme itself. * * Netsplit monitor * */ #include "atheme.h" DECLARE_MODULE_V1("statserv/netsplit", false, _modinit, _moddeinit, PACKAGE_STRING, VENDOR_STRING); static void ss_cmd_netsplit(sourceinfo_t * si, int parc, char *parv[]); static void ss_cmd_netsplit_list(sourceinfo_t * si, int parc, char *parv[]); static void ss_cmd_netsplit_remove(sourceinfo_t * si, int parc, char *parv[]); command_t ss_netsplit = { "NETSPLIT", N_("Monitor network splits."), PRIV_SERVER_AUSPEX, 2, ss_cmd_netsplit, {.path = "statserv/netsplit"} }; command_t ss_netsplit_list = { "LIST", N_("List currently split servers."), PRIV_SERVER_AUSPEX, 1, ss_cmd_netsplit_list, {.path = ""} }; command_t ss_netsplit_remove = { "REMOVE", N_("Remove a server from the netsplit list."), PRIV_JUPE, 2, ss_cmd_netsplit_remove, {.path = ""} }; mowgli_patricia_t *ss_netsplit_cmds; mowgli_patricia_t *splitlist; mowgli_heap_t *split_heap; typedef struct { char *name; time_t disconnected_since; unsigned int flags; } split_t; static void netsplit_delete_serv(split_t *s) { mowgli_patricia_delete(splitlist, s->name); free(s->name); mowgli_heap_free(split_heap, s); } static void netsplit_server_add(server_t *s) { split_t *serv = mowgli_patricia_retrieve(splitlist, s->name); if (serv != NULL) { netsplit_delete_serv(serv); } } static void netsplit_server_delete(hook_server_delete_t *serv) { split_t *s; s = mowgli_heap_alloc(split_heap); s->name = sstrdup(serv->s->name); s->disconnected_since = CURRTIME; s->flags = serv->s->flags; mowgli_patricia_add(splitlist, s->name, s); } static void ss_cmd_netsplit(sourceinfo_t * si, int parc, char *parv[]) { command_t *c; char *cmd = parv[0]; if (!cmd) { command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "NETSPLIT"); command_fail(si, fault_needmoreparams, _("Syntax: NETSPLIT [LIST|REMOVE] [parameters]")); return; } c = command_find(ss_netsplit_cmds, cmd); if (c == NULL) { command_fail(si, fault_badparams, _("Invalid command. Use \2/%s%s help\2 for a command listing."), (ircd->uses_rcommand == false) ? "msg " : "", si->service->disp); return; } command_exec(si->service, si, c, parc - 1, parv + 1); } static void ss_cmd_netsplit_list(sourceinfo_t * si, int parc, char *parv[]) { split_t *s; mowgli_patricia_iteration_state_t state; int i = 0; MOWGLI_PATRICIA_FOREACH(s, &state, splitlist) { i++; command_success_nodata(si, _("%d: %s [Split %s ago]"), i, s->name, time_ago(s->disconnected_since)); } command_success_nodata(si, _("End of netsplit list.")); } static void ss_cmd_netsplit_remove(sourceinfo_t * si, int parc, char *parv[]) { char *name = parv[0]; split_t *s; if (!name) { command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "NETSPLIT REMOVE"); command_fail(si, fault_needmoreparams, _("Syntax: NETSPLIT REMOVE ")); return; } s = mowgli_patricia_retrieve(splitlist, name); if (s != NULL) { netsplit_delete_serv(s); command_success_nodata(si, _("%s removed from the netsplit list."), name); } else command_fail(si, fault_nosuch_target, _("The server \2%s\2 does is not a split server."), name); } void _modinit(module_t * m) { service_named_bind_command("statserv", &ss_netsplit); ss_netsplit_cmds = mowgli_patricia_create(strcasecanon); command_add(&ss_netsplit_list, ss_netsplit_cmds); command_add(&ss_netsplit_remove, ss_netsplit_cmds); hook_add_event("server_add"); hook_add_event("server_delete"); hook_add_server_add(netsplit_server_add); hook_add_server_delete(netsplit_server_delete); split_heap = mowgli_heap_create(sizeof(split_t), 30, BH_NOW); if (split_heap == NULL) { slog(LG_INFO, "statserv/netsplit _modinit(): block allocator failure."); exit(EXIT_FAILURE); } splitlist = mowgli_patricia_create(irccasecanon); } void _moddeinit(module_unload_intent_t intent) { mowgli_patricia_iteration_state_t state; split_t *s; MOWGLI_PATRICIA_FOREACH(s, &state, splitlist) netsplit_delete_serv(s); mowgli_heap_destroy(split_heap); service_named_unbind_command("statserv", &ss_netsplit); command_delete(&ss_netsplit_list, ss_netsplit_cmds); command_delete(&ss_netsplit_remove, ss_netsplit_cmds); hook_del_event("server_add"); hook_del_event("server_delete"); hook_del_server_add(netsplit_server_add); hook_del_server_delete(netsplit_server_delete); mowgli_patricia_destroy(ss_netsplit_cmds, NULL, NULL); mowgli_patricia_destroy(splitlist, NULL, NULL); }