1
0
mirror of https://github.com/unrealircd/unrealircd.git synced 2026-07-04 08:43:14 +02:00

- refactor exit_client()

This commit is contained in:
William Pitcock
2013-05-24 20:44:20 +00:00
parent 5cc6b4ae9b
commit 751306f3e3
2 changed files with 175 additions and 194 deletions
+4
View File
@@ -235,6 +235,8 @@ int del_from_client_hash_table(char *name, aClient *cptr)
if (!list_empty(&cptr->client_hash))
list_del(&cptr->client_hash);
INIT_LIST_HEAD(&cptr->client_hash);
return 0;
}
@@ -243,6 +245,8 @@ int del_from_id_hash_table(char *name, aClient *cptr)
if (!list_empty(&cptr->id_hash))
list_del(&cptr->id_hash);
INIT_LIST_HEAD(&cptr->id_hash);
return 0;
}
+171 -194
View File
@@ -37,6 +37,7 @@ Computing Center and Jarkko Oikarinen";
#include "numeric.h"
#include <sys/stat.h>
#include <fcntl.h>
#include <assert.h>
#if !defined(ULTRIX) && !defined(SGI) && \
!defined(__convex__) && !defined(_WIN32)
# include <sys/param.h>
@@ -58,9 +59,7 @@ Computing Center and Jarkko Oikarinen";
extern ircstats IRCstats;
extern char *me_hash;
static void exit_one_client(aClient *, aClient *, aClient *, char *, int);
extern void exit_one_client_in_split(aClient *, aClient *, aClient *,
char *);
static void exit_one_client(aClient *, const char *);
static char *months[] = {
"January", "February", "March", "April",
@@ -442,6 +441,152 @@ int found;
}
}
/*
* Recursively send QUITs and SQUITs for cptr and all of it's dependent
* clients. A server needs the client QUITs if it does not support NOQUIT.
* - kaniini
*/
static void
recurse_send_quits(aClient *cptr, aClient *sptr, aClient *from, aClient *to,
const char *comment, const char *splitstr)
{
aClient *acptr, *next;
if (!CHECKPROTO(to, PROTO_NOQUIT))
{
list_for_each_entry_safe(acptr, next, &client_list, client_node)
{
if (acptr->srvptr != sptr)
continue;
sendto_one(to, ":%s QUIT :%s", acptr->name, splitstr);
}
}
list_for_each_entry_safe(acptr, next, &global_server_list, client_node)
{
if (acptr->srvptr != sptr)
continue;
recurse_send_quits(cptr, acptr, from, to, comment, splitstr);
}
if ((cptr == sptr && to != from) || !CHECKPROTO(to, PROTO_NOQUIT))
sendto_one(to, "SQUIT %s :%s", sptr->name, comment);
}
/*
* Remove all clients that depend on source_p; assumes all (S)QUITs have
* already been sent. we make sure to exit a server's dependent clients
* and servers before the server itself; exit_one_client takes care of
* actually removing things off llists. tweaked from +CSr31 -orabidoo
*/
static void
recurse_remove_clients(aClient *sptr, const char *comment)
{
aClient *acptr, *next;
list_for_each_entry_safe(acptr, next, &client_list, client_node)
{
if (acptr->srvptr != sptr)
continue;
exit_one_client(acptr, comment);
}
list_for_each_entry_safe(acptr, next, &global_server_list, client_node)
{
if (acptr->srvptr != sptr)
continue;
recurse_remove_clients(acptr, comment);
exit_one_client(acptr, comment);
}
}
/*
** Remove *everything* that depends on source_p, from all lists, and sending
** all necessary QUITs and SQUITs. source_p itself is still on the lists,
** and its SQUITs have been sent except for the upstream one -orabidoo
*/
static void
remove_dependents(aClient *sptr, aClient *from, const char *comment, const char *splitstr)
{
aClient *acptr;
list_for_each_entry(acptr, &global_server_list, client_node)
recurse_send_quits(sptr, sptr, from, acptr, comment, splitstr);
recurse_remove_clients(sptr, splitstr);
}
/*
** Exit one client, local or remote. Assuming all dependants have
** been already removed, and socket closed for local client.
*/
/* DANGER: Ugly hack follows. */
/* Yeah :/ */
static void exit_one_client(aClient *sptr, const char *comment)
{
aClient *acptr;
int i;
Link *lp;
Membership *mp;
assert(!IsMe(sptr));
if (IsClient(sptr))
{
sendto_common_channels(sptr, ":%s QUIT :%s",
sptr->name, comment);
if (!MyClient(sptr))
{
RunHook2(HOOKTYPE_REMOTE_QUIT, sptr, comment);
}
#ifdef JOINTHROTTLE
cmodej_deluserentries(sptr);
#endif
while ((mp = sptr->user->channel))
remove_user_from_channel(sptr, mp->chptr);
/* Clean up invitefield */
while ((lp = sptr->user->invited))
del_invite(sptr, lp->value.chptr);
/* again, this is all that is needed */
/* Clean up silencefield */
while ((lp = sptr->user->silence))
(void)del_silence(sptr, lp->value.cp);
/* Clean up dccallow list and (if needed) notify other clients
* that have this person on DCCALLOW that the user just left/got removed.
*/
remove_dcc_references(sptr);
/* For remote clients, we need to check for any outstanding async
* connects attached to this 'sptr', and set those records to NULL.
* Why not for local? Well, we already do that in close_connection ;)
*/
if (!MyConnect(sptr))
unrealdns_delreq_bycptr(sptr);
}
/* Remove sptr from the client list */
if (*sptr->id)
del_from_id_hash_table(sptr->id, sptr);
if (*sptr->name)
if (del_from_client_hash_table(sptr->name, sptr) != 1)
Debug((DEBUG_ERROR, "%#x !in tab %s[%s] %#x %#x %#x %d %d %#x",
sptr, sptr->name,
sptr->from ? sptr->from->sockhost : "??host",
sptr->from, sptr->next, sptr->prev, sptr->fd,
sptr->status, sptr->user));
if (IsRegisteredUser(sptr))
hash_check_watch(sptr, RPL_LOGOFF);
remove_client_from_list(sptr);
}
/*
** exit_client
@@ -470,7 +615,6 @@ int exit_client(aClient *cptr, aClient *sptr, aClient *from, char *comment)
aClient *next;
time_t on_for;
ConfigItem_listen *listen_conf;
static char comment1[HOSTLEN + HOSTLEN + 2];
static int recurse = 0;
if (MyConnect(sptr))
@@ -571,214 +715,47 @@ int exit_client(aClient *cptr, aClient *sptr, aClient *from, char *comment)
*/
close_connection(sptr);
}
else if (IsPerson(sptr) && !IsULine(sptr))
{
if (sptr->srvptr != &me)
sendto_fconnectnotice(sptr->name, sptr->user, sptr, 1, comment);
}
/*
* Recurse down the client list and get rid of clients who are no
* longer connected to the network (from my point of view)
* Only do this expensive stuff if exited==server -Donwulff
*/
if (IsServer(sptr))
{
/*
* Is this right? Not recreateing the split message if
* we have been called recursivly? I hope so, cuz thats
* the only way I could make this give the right servers
* in the quit msg. -Cabal95
*/
if (cptr && !recurse)
ircsnprintf(comment1, sizeof(comment1), "%s %s", sptr->srvptr->name, sptr->name);
/*
* First, remove the clients on the server itself.
*/
list_for_each_entry_safe(acptr, next, &client_list, client_node)
{
if (IsClient(acptr) && (acptr->srvptr == sptr))
exit_one_client(NULL, acptr,
&me, comment1, 1);
}
char splitstr[HOSTLEN + HOSTLEN + 2];
assert(sptr->serv != NULL && sptr->srvptr != NULL);
if (FLAT_MAP)
strlcpy(splitstr, "*.net *.split", sizeof splitstr);
else
ircsnprintf(splitstr, sizeof splitstr, "%s %s", sptr->srvptr->name, sptr->name);
remove_dependents(sptr, cptr, comment, splitstr);
/*
* Now, go SQUIT off the servers which are down-stream of
* the one we just lost.
*/
recurse++;
list_for_each_entry_safe(acptr, next, &global_server_list, client_node)
{
if (IsServer(acptr) && acptr->srvptr == sptr)
exit_client(sptr, acptr, sptr, comment1); /* RECURSION */
/*
* I am not masking SQUITS like I do QUITs. This
* is probobly something we could easily do, but
* how much savings is there really in something
* like that?
*/
#ifdef DEBUGMODE
else if (IsServer(acptr) &&
(find_server(acptr->serv->up, NULL) == sptr))
{
sendto_ops("WARNING, srvptr!=sptr but "
"find_server did! Server %s on "
"%s thought it was on %s while "
"losing %s. Tell coding team.",
acptr->name, acptr->serv->up,
acptr->srvptr ? acptr->
srvptr->name : "<noserver>", sptr->name);
exit_client(sptr, acptr, sptr, comment1);
}
#endif
}
recurse--;
RunHook(HOOKTYPE_SERVER_QUIT, sptr);
}
else if (IsClient(sptr) && !(sptr->flags & FLAGS_KILLED))
{
sendto_server(cptr, PROTO_SID, 0,
":%s QUIT :%s", ID(sptr), comment);
sendto_server(cptr, 0, PROTO_SID,
":%s QUIT :%s", sptr->name, comment);
}
/*
* Finally, clear out the server we lost itself
*/
exit_one_client(cptr, sptr, from, comment, recurse);
exit_one_client(sptr, comment);
return cptr == sptr ? FLUSH_BUFFER : 0;
}
/*
** Exit one client, local or remote. Assuming all dependants have
** been already removed, and socket closed for local client.
*/
/* DANGER: Ugly hack follows. */
/* Yeah :/ */
static void exit_one_client(aClient *cptr, aClient *sptr, aClient *from, char *comment, int split)
{
aClient *acptr;
int i;
Link *lp;
Membership *mp;
/*
** For a server or user quitting, propagage the information to
** other servers (except to the one where is came from (cptr))
*/
if (IsMe(sptr))
{
sendto_ops("ERROR: tried to exit me! : %s", comment);
return; /* ...must *never* exit self!! */
}
else if (IsServer(sptr))
{
/*
** Old sendto_serv_but_one() call removed because we now
** need to send different names to different servers
** (domain name matching)
*/
list_for_each_entry(acptr, &server_list, special_node)
{
if (acptr == cptr || IsMe(acptr) || (DontSendQuit(acptr) && split))
continue;
/*
** SQUIT going "upstream". This is the remote
** squit still hunting for the target. Use prefixed
** form. "from" will be either the oper that issued
** the squit or some server along the path that
** didn't have this fix installed. --msa
*/
if (sptr->from == acptr)
{
sendto_one(acptr, ":%s SQUIT %s :%s", from->name, sptr->name, comment);
}
else
{
sendto_one(acptr, "SQUIT %s :%s", sptr->name, comment);
}
}
}
else if (!(IsPerson(sptr)))
/* ...this test is *dubious*, would need
** some thougth.. but for now it plugs a
** nasty hole in the server... --msa
*/
; /* Nothing */
else if (sptr->name[0]) /* ...just clean all others with QUIT... */
{
/*
** If this exit is generated from "m_kill", then there
** is no sense in sending the QUIT--KILL's have been
** sent instead.
*/
if ((sptr->flags & FLAGS_KILLED) == 0)
{
if (split == 0)
sendto_server(cptr, 0, 0, ":%s QUIT :%s", sptr->name, comment);
else
/*
* Then this is a split, only old (stupid)
* clients need to get quit messages
*/
sendto_server(cptr, 0, PROTO_NOQUIT, ":%s QUIT :%s",
sptr->name, comment);
}
/*
** If a person is on a channel, send a QUIT notice
** to every client (person) on the same channel (so
** that the client can show the "**signoff" message).
** (Note: The notice is to the local clients *only*)
*/
if (sptr->user)
{
sendto_common_channels(sptr, ":%s QUIT :%s",
sptr->name, comment);
if (!IsULine(sptr) && !split)
if (sptr->user->server != me_hash)
sendto_fconnectnotice(sptr->name, sptr->user, sptr, 1, comment);
if (!MyClient(sptr))
{
RunHook2(HOOKTYPE_REMOTE_QUIT, sptr, comment);
}
#ifdef JOINTHROTTLE
cmodej_deluserentries(sptr);
#endif
while ((mp = sptr->user->channel))
remove_user_from_channel(sptr, mp->chptr);
/* Clean up invitefield */
while ((lp = sptr->user->invited))
del_invite(sptr, lp->value.chptr);
/* again, this is all that is needed */
/* Clean up silencefield */
while ((lp = sptr->user->silence))
(void)del_silence(sptr, lp->value.cp);
/* Clean up dccallow list and (if needed) notify other clients
* that have this person on DCCALLOW that the user just left/got removed.
*/
remove_dcc_references(sptr);
/* For remote clients, we need to check for any outstanding async
* connects attached to this 'sptr', and set those records to NULL.
* Why not for local? Well, we already do that in close_connection ;)
*/
if (!MyConnect(sptr))
unrealdns_delreq_bycptr(sptr);
}
}
/* Remove sptr from the client list */
if (*sptr->id)
del_from_id_hash_table(sptr->id, sptr);
if (del_from_client_hash_table(sptr->name, sptr) != 1)
Debug((DEBUG_ERROR, "%#x !in tab %s[%s] %#x %#x %#x %d %d %#x",
sptr, sptr->name,
sptr->from ? sptr->from->sockhost : "??host",
sptr->from, sptr->next, sptr->prev, sptr->fd,
sptr->status, sptr->user));
if (IsRegisteredUser(sptr))
hash_check_watch(sptr, RPL_LOGOFF);
remove_client_from_list(sptr);
return;
}
void checklist(void)
{
if (!(bootopt & BOOT_AUTODIE))