From 4ec455bf0641f471eaa765c27dbbad85b9259fdc Mon Sep 17 00:00:00 2001 From: k4be Date: Wed, 21 Jul 2021 18:04:01 +0200 Subject: [PATCH] Add selective watch removal. Clean up linked list item deleting. --- include/h.h | 4 +- src/api-efunctions.c | 4 +- src/modules/watch-backend.c | 199 ++++++++++++++++++------------------ src/modules/watch.c | 10 +- 4 files changed, 107 insertions(+), 110 deletions(-) diff --git a/include/h.h b/include/h.h index abe58ab52..6eabb2829 100644 --- a/include/h.h +++ b/include/h.h @@ -770,8 +770,8 @@ extern MODVAR void (*labeled_response_set_context)(void *ctx); extern MODVAR void (*labeled_response_force_end)(void); extern MODVAR void (*kick_user)(MessageTag *mtags, Channel *channel, Client *client, Client *victim, char *comment); extern MODVAR int (*watch_add)(char *nick, Client *client, int flags); -extern MODVAR int (*watch_del)(char *nick, Client *client); -extern MODVAR int (*watch_del_list)(Client *client); +extern MODVAR int (*watch_del)(char *nick, Client *client, int flags); +extern MODVAR int (*watch_del_list)(Client *client, int flags); extern MODVAR Watch *(*watch_get)(char *nick); extern MODVAR int (*watch_check)(Client *client, int reply); /* /Efuncs */ diff --git a/src/api-efunctions.c b/src/api-efunctions.c index 1781fbebd..b8be57474 100644 --- a/src/api-efunctions.c +++ b/src/api-efunctions.c @@ -122,8 +122,8 @@ void (*labeled_response_set_context)(void *ctx); void (*labeled_response_force_end)(void); void (*kick_user)(MessageTag *mtags, Channel *channel, Client *client, Client *victim, char *comment); int (*watch_add)(char *nick, Client *client, int flags); -int (*watch_del)(char *nick, Client *client); -int (*watch_del_list)(Client *client); +int (*watch_del)(char *nick, Client *client, int flags); +int (*watch_del_list)(Client *client, int flags); Watch *(*watch_get)(char *nick); int (*watch_check)(Client *client, int reply); diff --git a/src/modules/watch-backend.c b/src/modules/watch-backend.c index f5a908aca..5dca14c1a 100644 --- a/src/modules/watch-backend.c +++ b/src/modules/watch-backend.c @@ -36,21 +36,22 @@ static char siphashkey_watch[SIPHASH_KEY_LENGTH]; void dummy_free(ModData *md); void watch_free(ModData *md); +int watch_backend_user_quit(Client *client, MessageTag *mtags, char *comment); int add_to_watch_hash_table(char *nick, Client *client, int flags); int hash_check_watch(Client *client, int reply); Watch *hash_get_watch(char *nick); -int del_from_watch_hash_table(char *nick, Client *client); -int hash_del_watch_list(Client *client); +int del_from_watch_hash_table(char *nick, Client *client, int flags); +int hash_del_watch_list(Client *client, int flags); uint64_t hash_watch_nick_name(const char *name); ModuleHeader MOD_HEADER - = { += { "watch-backend", "5.0", "backend for /watch", "UnrealIRCd Team", "unrealircd-5", - }; +}; MOD_TEST() { @@ -69,6 +70,7 @@ MOD_INIT() ModDataInfo mreq; MARK_AS_OFFICIAL_MODULE(modinfo); + ModuleSetOptions(modinfo->handle, MOD_OPT_PERM_RELOADABLE, 1); /* or do a complex memory freeing algorithm instead */ if (!watch_initialized) { @@ -99,6 +101,8 @@ MOD_INIT() return MOD_FAILED; } + HookAdd(modinfo->handle, HOOKTYPE_LOCAL_QUIT, 0, watch_backend_user_quit); + return MOD_SUCCESS; } @@ -118,7 +122,16 @@ void dummy_free(ModData *md) void watch_free(ModData *md) { -#warning do proper free + /* it should have been never requested to free as the module is PERM */ + if (md) + ircd_log(LOG_WARNING, "MEMORY LEAK: watchList moddata was not freed!"); +} + +int watch_backend_user_quit(Client *client, MessageTag *mtags, char *comment) +{ + /* Clean out list and watch structures -Donwulff */ + watch_del_list(client, 0); + return 0; } /* @@ -127,8 +140,8 @@ void watch_free(ModData *md) int add_to_watch_hash_table(char *nick, Client *client, int flags) { unsigned int hashv; - Watch *watch; - Link *lp; + Watch *watch; + Link *lp; /* Get the right bucket... */ @@ -136,7 +149,7 @@ int add_to_watch_hash_table(char *nick, Client *client, int flags) /* Find the right nick (header) in the bucket, or NULL... */ if ((watch = (Watch *)watchTable[hashv])) - while (watch && mycmp(watch->nick, nick)) + while (watch && mycmp(watch->nick, nick)) watch = watch->hnext; /* If found NULL (no header for this nick), make one... */ @@ -152,7 +165,7 @@ int add_to_watch_hash_table(char *nick, Client *client, int flags) } /* Is this client already on the watch-list? */ if ((lp = watch->watch)) - while (lp && (lp->value.client != client)) + while (lp && (lp->value.client != client)) lp = lp->next; /* No it isn't, so add it in the bucket and client addint it */ @@ -175,23 +188,23 @@ int add_to_watch_hash_table(char *nick, Client *client, int flags) } /* - * hash_check_watch + * hash_check_watch */ int hash_check_watch(Client *client, int reply) { unsigned int hashv; - Watch *watch; - Link *lp; + Watch *watch; + Link *lp; /* Get us the right bucket */ hashv = hash_watch_nick_name(client->name); /* Find the right header in this bucket */ if ((watch = (Watch *)watchTable[hashv])) - while (watch && mycmp(watch->nick, client->name)) + while (watch && mycmp(watch->nick, client->name)) watch = watch->hnext; if (!watch) - return 0; /* This nick isn't on watch */ + return 0; /* This nick isn't on watch */ /* Update the time of last change to item */ watch->lasttime = TStime(); @@ -211,12 +224,12 @@ int hash_check_watch(Client *client, int reply) Watch *hash_get_watch(char *nick) { unsigned int hashv; - Watch *watch; + Watch *watch; hashv = hash_watch_nick_name(nick); if ((watch = (Watch *)watchTable[hashv])) - while (watch && mycmp(watch->nick, nick)) + while (watch && mycmp(watch->nick, nick)) watch = watch->hnext; return watch; @@ -225,71 +238,62 @@ Watch *hash_get_watch(char *nick) /* * del_from_watch_hash_table */ -int del_from_watch_hash_table(char *nick, Client *client) +int del_from_watch_hash_table(char *nick, Client *client, int flags) { unsigned int hashv; - Watch *watch, *nlast = NULL; - Link *lp, *last = NULL; + Watch **watch, *wprev; + Link **lp, *prev; /* Get the bucket for this nick... */ hashv = hash_watch_nick_name(nick); /* Find the right header, maintaining last-link pointer... */ - if ((watch = (Watch *)watchTable[hashv])) - while (watch && mycmp(watch->nick, nick)) { - nlast = watch; - watch = watch->hnext; - } - if (!watch) - return 0; /* No such watch */ + watch = (Watch **)&watchTable[hashv]; + while (*watch && mycmp((*watch)->nick, nick)) + watch = &(*watch)->hnext; + if (!*watch) + return 0; /* No such watch */ /* Find this client from the list of notifies... with last-ptr. */ - if ((lp = watch->watch)) - while (lp && (lp->value.client != client)) { - last = lp; - lp = lp->next; - } - if (!lp) - return 0; /* No such client to watch */ + lp = &(*watch)->watch; + while (*lp) + { + if ((*lp)->value.client == client && ((*lp)->flags & flags) == flags) + break; + lp = &(*lp)->next; + } + if (!*lp) + return 0; /* No such client to watch */ /* Fix the linked list under header, then remove the watch entry */ - if (!last) - watch->watch = lp->next; - else - last->next = lp->next; - free_link(lp); + prev = *lp; + *lp = prev->next; + free_link(prev); /* Do the same regarding the links in client-record... */ - last = NULL; - if ((lp = WATCH(client))) - while (lp && (lp->value.wptr != watch)) { - last = lp; - lp = lp->next; - } + lp = (Link **)&WATCH(client); + while (*lp && ((*lp)->value.wptr != *watch)) + lp = &(*lp)->next; /* * Give error on the odd case... probobly not even neccessary * No error checking in ircd is unneccessary ;) -Cabal95 */ - if (!lp) - sendto_ops("WATCH debug error: del_from_watch_hash_table " + if (!*lp) + sendto_ops("WATCH debug error: del_from_watch_hash_table " "found a watch entry with no client " "counterpoint processing nick %s on client %p!", nick, client->user); else { - if (!last) /* First one matched */ - WATCH(client) = lp->next; - else - last->next = lp->next; - free_link(lp); + prev = *lp; + *lp = prev->next; + free_link(prev); } /* In case this header is now empty of notices, remove it */ - if (!watch->watch) { - if (!nlast) - watchTable[hashv] = watch->hnext; - else - nlast->hnext = watch->hnext; - safe_free(watch); + if (!(*watch)->watch) { + wprev = *watch; + *watch = wprev->hnext; + safe_free(wprev); } /* Update count of notifies on nick */ @@ -301,69 +305,68 @@ int del_from_watch_hash_table(char *nick, Client *client) /* * hash_del_watch_list */ -int hash_del_watch_list(Client *client) +int hash_del_watch_list(Client *client, int flags) { - unsigned int hashv; - Watch *watch; - Link *np, *lp, *last; + unsigned int hashv; + Watch *watch; + Link **np, **lp, *prev; + np = (Link **)&WATCH(client); - if (!(np = WATCH(client))) - return 0; /* Nothing to do */ - - WATCH(client) = NULL; /* Break the watch-list for client */ - while (np) { - /* Find the watch-record from hash-table... */ - watch = np->value.wptr; - last = NULL; - for (lp = watch->watch; lp && (lp->value.client != client); - lp = lp->next) - last = lp; + while (*np) { + if (((*np)->flags & flags) != flags) + { + /* this entry is not fitting requested flags */ + np = &(*np)->next; + continue; + } + WATCHES(client)--; + + /* Find the watch-record from hash-table... */ + watch = (*np)->value.wptr; + lp = &(watch->watch); + while (*lp && ((*lp)->value.client != client)) + lp = &(*lp)->next; + /* Not found, another "worst case" debug error */ - if (!lp) - sendto_ops("WATCH Debug error: hash_del_watch_list " - "found a WATCH entry with no table " - "counterpoint processing client %s!", - client->name); + if (!*lp) + sendto_ops("WATCH Debug error: hash_del_watch_list " + "found a WATCH entry with no table " + "counterpoint processing client %s!", + client->name); else { /* Fix the watch-list and remove entry */ - if (!last) - watch->watch = lp->next; - else - last->next = lp->next; - free_link(lp); + Link *prev = *lp; + *lp = prev->next; + free_link(prev); /* * If this leaves a header without notifies, * remove it. Need to find the last-pointer! */ if (!watch->watch) { - Watch *np2, *nl; + Watch **np2, *wprev; hashv = hash_watch_nick_name(watch->nick); - nl = NULL; - np2 = watchTable[hashv]; - while (np2 != watch) { - nl = np2; - np2 = np2->hnext; - } - - if (nl) - nl->hnext = watch->hnext; - else - watchTable[hashv] = watch->hnext; + np2 = &watchTable[hashv]; + while (*np2 && *np2 != watch) + np2 = &(*np2)->hnext; + + *np2 = watch->hnext; + safe_free(watch); } } - lp = np; /* Save last pointer processed */ - np = np->next; /* Jump to the next pointer */ - free_link(lp); /* Free the previous */ + prev = *np; /* Save last pointer processed */ + *np = prev->next; /* Jump to the next pointer */ + free_link(prev); /* Free the previous */ } - WATCHES(client) = 0; + if (!flags) + WATCHES(client) = 0; return 0; } diff --git a/src/modules/watch.c b/src/modules/watch.c index 0bdfc0d65..99f487127 100644 --- a/src/modules/watch.c +++ b/src/modules/watch.c @@ -184,7 +184,7 @@ CMD_FUNC(cmd_watch) { if (!*(s+1)) continue; - watch_del(s + 1, client); + watch_del(s + 1, client, WATCH_FLAG_TYPE_WATCH); show_watch(client, s + 1, RPL_WATCHOFF, RPL_WATCHOFF, 0); continue; @@ -196,8 +196,7 @@ CMD_FUNC(cmd_watch) */ if (*s == 'C' || *s == 'c') { - watch_del_list(client); -#warning remove only my entries + watch_del_list(client, WATCH_FLAG_TYPE_WATCH); continue; } @@ -311,11 +310,6 @@ int watch_user_quit(Client *client, MessageTag *mtags, char *comment) { if (IsUser(client)) watch_check(client, RPL_LOGOFF); - - if (MyConnect(client)) - /* Clean out list and watch structures -Donwulff */ - watch_del_list(client); - return 0; }