Deferred capability notifications from modules

Reloading modules sends CAP DEL followed by an immediate CAP NEW:

    :staberinde.local CAP * DEL :account-tag
    :staberinde.local CAP * NEW :account-tag

This isn't very nice. /modrestart is particularly bad. In order to avoid
doing this, we remember the capability set at the beginning of module
operations, compare that with the set afterwards, and report only the
differences with CAP {DEL,NEW}.
This commit is contained in:
Ed Kellett 2019-07-08 03:53:29 +01:00
parent 9ac0390734
commit 28cc8bb924
No known key found for this signature in database
GPG key ID: CB9986DEF342FABC
3 changed files with 43 additions and 6 deletions

View file

@ -122,6 +122,10 @@ struct mapi_mheader_av2
void mod_add_path(const char *path); void mod_add_path(const char *path);
void mod_clear_paths(void); void mod_clear_paths(void);
/* cap-notify utilities */
extern void mod_remember_clicaps(void);
extern void mod_notify_clicaps(void);
/* load a module */ /* load a module */
extern void load_module(char *path); extern void load_module(char *path);

View file

@ -80,6 +80,29 @@ init_modules(void)
mod_add_path(ircd_paths[IRCD_PATH_AUTOLOAD_MODULES]); mod_add_path(ircd_paths[IRCD_PATH_AUTOLOAD_MODULES]);
} }
static unsigned int prev_caps;
void
mod_remember_clicaps(void)
{
prev_caps = capability_index_mask(cli_capindex);
}
void
mod_notify_clicaps(void)
{
unsigned int cur_caps = capability_index_mask(cli_capindex);
unsigned int del = prev_caps & ~cur_caps;
unsigned int new = cur_caps & ~prev_caps;
if (del)
sendto_local_clients_with_capability(CLICAP_CAP_NOTIFY, ":%s CAP * DEL :%s",
me.name, capability_index_list(cli_capindex, del));
if (new)
sendto_local_clients_with_capability(CLICAP_CAP_NOTIFY, ":%s CAP * NEW :%s",
me.name, capability_index_list(cli_capindex, new));
}
/* mod_find_path() /* mod_find_path()
* *
* input - path * input - path
@ -382,10 +405,7 @@ unload_one_module(const char *name, bool warn)
} }
if (m->cap_id != NULL) if (m->cap_id != NULL)
{
capability_orphan(idx, m->cap_name); capability_orphan(idx, m->cap_name);
sendto_local_clients_with_capability(CLICAP_CAP_NOTIFY, ":%s CAP * DEL :%s", me.name, m->cap_name);
}
} }
} }
break; break;
@ -600,10 +620,7 @@ load_a_module(const char *path, bool warn, int origin, bool core)
result = capability_put(idx, m->cap_name, m->cap_ownerdata); result = capability_put(idx, m->cap_name, m->cap_ownerdata);
if (m->cap_id != NULL) if (m->cap_id != NULL)
{
*(m->cap_id) = result; *(m->cap_id) = result;
sendto_local_clients_with_capability(CLICAP_CAP_NOTIFY, ":%s CAP * ADD :%s", me.name, m->cap_name);
}
} }
} }
} }
@ -671,6 +688,8 @@ modules_do_restart(void *unused)
unsigned int modnum = 0; unsigned int modnum = 0;
rb_dlink_node *ptr, *nptr; rb_dlink_node *ptr, *nptr;
mod_remember_clicaps();
RB_DLINK_FOREACH_SAFE(ptr, nptr, module_list.head) RB_DLINK_FOREACH_SAFE(ptr, nptr, module_list.head)
{ {
struct module *mod = ptr->data; struct module *mod = ptr->data;
@ -694,6 +713,8 @@ modules_do_restart(void *unused)
load_core_modules(false); load_core_modules(false);
rehash(false); rehash(false);
mod_notify_clicaps();
sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
"Module Restart: %u modules unloaded, %lu modules loaded", "Module Restart: %u modules unloaded, %lu modules loaded",
modnum, rb_dlink_list_length(&module_list)); modnum, rb_dlink_list_length(&module_list));

View file

@ -274,9 +274,13 @@ do_modload(struct Client *source_p, const char *module)
return; return;
} }
mod_remember_clicaps();
origin = strcmp(module, m_bn) == 0 ? MAPI_ORIGIN_CORE : MAPI_ORIGIN_EXTENSION; origin = strcmp(module, m_bn) == 0 ? MAPI_ORIGIN_CORE : MAPI_ORIGIN_EXTENSION;
load_one_module(module, origin, false); load_one_module(module, origin, false);
mod_notify_clicaps();
rb_free(m_bn); rb_free(m_bn);
} }
@ -300,9 +304,13 @@ do_modunload(struct Client *source_p, const char *module)
return; return;
} }
mod_remember_clicaps();
if(unload_one_module(m_bn, true) == false) if(unload_one_module(m_bn, true) == false)
sendto_one_notice(source_p, ":Module %s is not loaded", m_bn); sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
mod_notify_clicaps();
rb_free(m_bn); rb_free(m_bn);
} }
@ -322,6 +330,8 @@ do_modreload(struct Client *source_p, const char *module)
check_core = mod->core; check_core = mod->core;
mod_remember_clicaps();
if(unload_one_module(m_bn, true) == false) if(unload_one_module(m_bn, true) == false)
{ {
sendto_one_notice(source_p, ":Module %s is not loaded", m_bn); sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
@ -337,6 +347,8 @@ do_modreload(struct Client *source_p, const char *module)
exit(0); exit(0);
} }
mod_notify_clicaps();
rb_free(m_bn); rb_free(m_bn);
} }