*
* $Id$
*/
-#include "list.h"
+#include "config.h"
+#include "list.h"
#include "client.h"
#include "ircd.h"
#include "ircd_alloc.h"
+#include "ircd_events.h"
#include "ircd_reply.h"
#include "ircd_string.h"
#include "listener.h"
#include "match.h"
#include "numeric.h"
#include "res.h"
+#include "s_auth.h"
#include "s_bsd.h"
#include "s_conf.h"
#include "s_debug.h"
#include "s_user.h"
#include "send.h"
#include "struct.h"
-#include "support.h"
#include "whowas.h"
#include <assert.h>
static void dealloc_client(struct Client* cptr)
{
+ assert(cli_verify(cptr));
+ assert(0 == cli_connect(cptr));
+
#ifdef DEBUGMODE
--clients.inuse;
#endif
cli_next(cptr) = clientFreeList;
clientFreeList = cptr;
+
+ cli_magic(cptr) = 0;
}
static struct Connection* alloc_connection(void)
#endif
memset(con, 0, sizeof(struct Connection));
+ timer_init(&(con_proc(con)));
return con;
}
static void dealloc_connection(struct Connection* con)
{
- if (con_dns_reply(con))
- --(con_dns_reply(con)->ref_count);
+ assert(con_verify(con));
+ assert(!t_active(&(con_proc(con))));
+ assert(!t_onqueue(&(con_proc(con))));
+
+ Debug((DEBUG_LIST, "Deallocating connection %p", con));
+
+
+ if (con_dns_reply(con)) {
+ MyFree(con_dns_reply(con));
+ con_dns_reply(con) = 0;
+ }
if (-1 < con_fd(con))
close(con_fd(con));
MsgQClear(&(con_sendQ(con)));
con_next(con) = connectionFreeList;
connectionFreeList = con;
+
+ con_magic(con) = 0;
}
/*
struct Client* cptr = 0;
struct Connection* con = 0;
+ assert(!from || cli_verify(from));
+
cptr = alloc_client();
assert(0 != cptr);
+ assert(!cli_magic(cptr));
+ assert(0 == from || 0 != cli_connect(from));
if (!from) { /* local client, allocate a struct Connection */
con = alloc_connection();
assert(0 != con);
+ assert(!con_magic(con));
+ con_magic(con) = CONNECTION_MAGIC;
con_fd(con) = -1; /* initialize struct Connection */
+ con_freeflag(con) = 0;
con_nextnick(con) = CurrentTime - NICK_DELAY;
con_nexttarget(con) = CurrentTime - (TARGET_DELAY * (STARTTARGETS - 1));
con_handler(con) = UNREGISTERED_HANDLER;
con = cli_connect(from); /* use 'from's connection */
assert(0 != con);
+ assert(con_verify(con));
+ cli_magic(cptr) = CLIENT_MAGIC;
cli_connect(cptr) = con; /* set the connection and other fields */
cli_status(cptr) = status;
cli_hnext(cptr) = cptr;
return cptr;
}
+void free_connection(struct Connection* con)
+{
+ if (!con)
+ return;
+
+ assert(con_verify(con));
+ assert(0 == con_client(con));
+
+ dealloc_connection(con); /* deallocate the connection */
+}
+
void free_client(struct Client* cptr)
{
if (!cptr)
/*
* forget to remove the client from the hash table?
*/
+ assert(cli_verify(cptr));
assert(cli_hnext(cptr) == cptr);
+ /* or from linked list? */
+ assert(cli_next(cptr) == 0);
+ assert(cli_prev(cptr) == 0);
+
+ Debug((DEBUG_LIST, "Freeing client %s [%p], connection %p", cli_name(cptr),
+ cptr, cli_connect(cptr)));
+
+ if (cli_auth(cptr))
+ destroy_auth_request(cli_auth(cptr), 0);
+
+ /* Make sure we didn't magically get re-added to the list */
+ assert(cli_next(cptr) == 0);
+ assert(cli_prev(cptr) == 0);
+
+ if (cli_from(cptr) == cptr) { /* in other words, we're local */
+ cli_from(cptr) = 0;
+ /* timer must be marked as not active */
+ if (!cli_freeflag(cptr) && !t_active(&(cli_proc(cptr))))
+ dealloc_connection(cli_connect(cptr)); /* connection not open anymore */
+ else {
+ if (-1 < cli_fd(cptr) && cli_freeflag(cptr) & FREEFLAG_SOCKET)
+ socket_del(&(cli_socket(cptr))); /* queue a socket delete */
+ if (cli_freeflag(cptr) & FREEFLAG_TIMER)
+ timer_del(&(cli_proc(cptr))); /* queue a timer delete */
+ }
+ }
- if (cli_from(cptr) == cptr) /* in other words, we're local */
- dealloc_connection(cli_connect(cptr)); /* deallocate the connection... */
- dealloc_client(cptr); /* deallocate the client */
+ cli_connect(cptr) = 0;
+
+ dealloc_client(cptr); /* actually destroy the client */
}
struct Server *make_server(struct Client *cptr)
{
struct Server *serv = cli_serv(cptr);
+ assert(cli_verify(cptr));
+
if (!serv)
{
serv = (struct Server*) MyMalloc(sizeof(struct Server));
*/
void remove_client_from_list(struct Client *cptr)
{
- if (cli_prev(cptr))
- cli_next(cli_prev(cptr)) = cli_next(cptr);
- else {
- GlobalClientList = cli_next(cptr);
- cli_prev(GlobalClientList) = 0;
- }
- if (cli_next(cptr))
+ assert(cli_verify(cptr));
+ assert(con_verify(cli_connect(cptr)));
+ assert(!cli_prev(cptr) || cli_verify(cli_prev(cptr)));
+ assert(!cli_next(cptr) || cli_verify(cli_next(cptr)));
+ assert(!IsMe(cptr));
+
+ /* Only try remove cptr from the list if it IS in the list.
+ * cli_next(cptr) cannot be NULL here, as &me is always the end
+ * the list, and we never remove &me. -GW
+ */
+ if(cli_next(cptr))
+ {
+ if (cli_prev(cptr))
+ cli_next(cli_prev(cptr)) = cli_next(cptr);
+ else {
+ GlobalClientList = cli_next(cptr);
+ cli_prev(GlobalClientList) = 0;
+ }
cli_prev(cli_next(cptr)) = cli_prev(cptr);
-
+ }
cli_next(cptr) = cli_prev(cptr) = 0;
if (IsUser(cptr) && cli_user(cptr)) {
*/
void add_client_to_list(struct Client *cptr)
{
+ assert(cli_verify(cptr));
+ assert(cli_next(cptr) == 0);
+ assert(cli_prev(cptr) == 0);
+
/*
* Since we always insert new clients to the top of the list,
* this should mean the "me" is the bottom most item in the list.
cli_prev(cli_next(cptr)) = cptr;
}
+#if 0
+/* WARNING: Major CPU sink!
+ *
+ * This is a debugging routine meant to verify the integrity of the client
+ * linked list. It is meant to be comprehensive, to detect *any* corruption
+ * of that list. This means that it will be majorly CPU-intensive, and
+ * should *only* be enabled on servers that have DEBUGMODE enabled. Ignore
+ * this warning at your peril!
+ */
+void verify_client_list(void)
+{
+ struct Client *client, *prev = 0, *sentinel = 0;
+ extern unsigned int ircrandom(void);
+
+ for (client = GlobalClientList; client; client = cli_next(client)) {
+ /* Verify that this is a valid client, not a free'd one */
+ assert(cli_verify(client));
+ /* Verify that the list hasn't suddenly jumped around */
+ assert(cli_prev(client) == prev);
+ /* Verify that the list hasn't become circular */
+ assert(cli_next(client) != GlobalClientList);
+ assert(!sentinel || client != sentinel);
+
+ prev = client; /* Remember what should preceed us */
+ if (!(ircrandom() % 50)) /* probabilistic loop detector */
+ sentinel = client;
+ }
+}
+#endif /* DEBUGMODE */
+
/*
* Look for ptr in the linked listed pointed to by link.
*/