fb86192e2b9ea85bd776038586eefcdec9f646f3
[ircu2.10.12-pk.git] / ircd / list.c
1 /*
2  * IRC - Internet Relay Chat, ircd/list.c
3  * Copyright (C) 1990 Jarkko Oikarinen and
4  *                    University of Oulu, Finland
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 1, or (at your option)
9  * any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  *
20  * $Id$
21  */
22 #include "list.h"
23
24 #include "class.h"
25 #include "client.h"
26 #include "ircd.h"
27 #include "ircd_alloc.h"
28 #include "ircd_reply.h"
29 #include "ircd_string.h"
30 #include "listener.h"
31 #include "match.h"
32 #include "numeric.h"
33 #include "res.h"
34 #include "s_bsd.h"
35 #include "s_conf.h"
36 #include "s_debug.h"
37 #include "s_misc.h"
38 #include "s_user.h"
39 #include "send.h"
40 #include "struct.h"
41 #include "support.h"
42 #include "whowas.h"
43
44 #include <assert.h>
45 #include <stddef.h>  /* offsetof */
46 #include <unistd.h>  /* close */
47 #include <string.h>
48
49 #ifdef DEBUGMODE
50 static struct liststats {
51   int inuse;
52 } cloc, crem, users, servs, links, classs;
53 #endif
54
55 void init_list(void)
56 {
57 #ifdef DEBUGMODE
58   memset(&cloc, 0, sizeof(cloc));
59   memset(&crem, 0, sizeof(crem));
60   memset(&users, 0, sizeof(users));
61   memset(&servs, 0, sizeof(servs));
62   memset(&links, 0, sizeof(links));
63   memset(&classs, 0, sizeof(classs));
64 #endif
65 }
66
67 /*
68  * Create a new struct Client structure and set it to initial state.
69  *
70  *   from == NULL,   create local client (a client connected to a socket).
71  *
72  *   from != NULL,   create remote client (behind a socket associated with
73  *                   the client defined by 'from').
74  *                   ('from' is a local client!!).
75  */
76 struct Client* make_client(struct Client *from, int status)
77 {
78   struct Client *cptr = NULL;
79   size_t size = CLIENT_REMOTE_SIZE;
80
81   /*
82    * Check freelists first to see if we can grab a client without
83    * having to call malloc.
84    */
85   if (!from)
86     size = CLIENT_LOCAL_SIZE;
87
88   cptr = (struct Client*) MyMalloc(size);
89   assert(0 != cptr);
90   /*
91    * NOTE: Do not remove this, a lot of code depends on the entire
92    * structure being zeroed out
93    */
94   memset(cptr, 0, size);        /* All variables are 0 by default */
95
96 #ifdef  DEBUGMODE
97   if (size == CLIENT_LOCAL_SIZE)
98     cloc.inuse++;
99   else
100     crem.inuse++;
101 #endif
102
103   /* Note: structure is zero (memset) */
104   cptr->from = from ? from : cptr;      /* 'from' of local client is self! */
105   cptr->status = status;
106   cptr->hnext = cptr;
107   strcpy(cptr->username, "unknown");
108
109   if (CLIENT_LOCAL_SIZE == size) {
110     cptr->fd = -1;
111     cptr->local = 1;
112     cptr->since = cptr->lasttime = cptr->firsttime = CurrentTime;
113     cptr->lastnick = TStime();
114     cptr->nextnick = CurrentTime - NICK_DELAY;
115     cptr->nexttarget = CurrentTime - (TARGET_DELAY * (STARTTARGETS - 1));
116     cptr->handler = UNREGISTERED_HANDLER;
117   }
118   return cptr;
119 }
120
121 void free_client(struct Client *cptr)
122 {
123   if (cptr && cptr->local) {
124     /*
125      * make sure we have cleaned up local resources
126      */
127     if (cptr->dns_reply)
128       --cptr->dns_reply->ref_count;
129     if (-1 < cptr->fd) {
130       ip_registry_local_disconnect(cptr);
131       close(cptr->fd);
132     }
133     DBufClear(&cptr->sendQ);
134     DBufClear(&cptr->recvQ);
135     if (cptr->listener)
136       release_listener(cptr->listener);
137   }    
138   /*
139    * forget to remove the client from the hash table?
140    */
141   assert(cptr->hnext == cptr);
142
143   MyFree(cptr);
144 }
145
146 struct Server *make_server(struct Client *cptr)
147 {
148   struct Server *serv = cptr->serv;
149
150   if (!serv)
151   {
152     serv = (struct Server*) MyMalloc(sizeof(struct Server));
153     assert(0 != serv);
154     memset(serv, 0, sizeof(struct Server)); /* All variables are 0 by default */
155 #ifdef  DEBUGMODE
156     servs.inuse++;
157 #endif
158     cptr->serv = serv;
159     cptr->serv->lag = 60000;
160     *serv->by = '\0';
161     DupString(serv->last_error_msg, "<>");      /* String must be non-empty */
162   }
163   return cptr->serv;
164 }
165
166 /*
167  * Taken the code from ExitOneClient() for this and placed it here.
168  * - avalon
169  */
170 void remove_client_from_list(struct Client *cptr)
171 {
172   if (cptr->prev)
173     cptr->prev->next = cptr->next;
174   else {
175     GlobalClientList = cptr->next;
176     GlobalClientList->prev = 0;
177   }
178   if (cptr->next)
179     cptr->next->prev = cptr->prev;
180
181   cptr->next = cptr->prev = 0;
182
183   if (IsUser(cptr) && cptr->user) {
184     add_history(cptr, 0);
185     off_history(cptr);
186   }
187   if (cptr->user) {
188     free_user(cptr->user);
189     cptr->user = 0;
190   }
191
192   if (cptr->serv) {
193     if (cptr->serv->user) {
194       free_user(cptr->serv->user);
195       cptr->serv->user = 0;
196     }
197     if (cptr->serv->client_list)
198       MyFree(cptr->serv->client_list);
199     MyFree(cptr->serv->last_error_msg);
200     MyFree(cptr->serv);
201 #ifdef  DEBUGMODE
202     --servs.inuse;
203 #endif
204   }
205 #ifdef  DEBUGMODE
206   if (cptr->local)
207     --cloc.inuse;
208   else
209     --crem.inuse;
210 #endif
211   free_client(cptr);
212 }
213
214 /*
215  * Although only a small routine, it appears in a number of places
216  * as a collection of a few lines...functions like this *should* be
217  * in this file, shouldnt they ?  after all, this is list.c, isn't it ?
218  * -avalon
219  */
220 void add_client_to_list(struct Client *cptr)
221 {
222   /*
223    * Since we always insert new clients to the top of the list,
224    * this should mean the "me" is the bottom most item in the list.
225    * XXX - don't always count on the above, things change
226    */
227   cptr->prev = 0;
228   cptr->next = GlobalClientList;
229   GlobalClientList = cptr;
230   if (cptr->next)
231     cptr->next->prev = cptr;
232 }
233
234 /*
235  * Look for ptr in the linked listed pointed to by link.
236  */
237 struct SLink *find_user_link(struct SLink *lp, struct Client *ptr)
238 {
239   if (ptr)
240     while (lp)
241     {
242       if (lp->value.cptr == ptr)
243         return (lp);
244       lp = lp->next;
245     }
246   return NULL;
247 }
248
249 struct SLink *make_link(void)
250 {
251   struct SLink *lp;
252
253   lp = (struct SLink*) MyMalloc(sizeof(struct SLink));
254   assert(0 != lp);
255 #ifdef  DEBUGMODE
256   links.inuse++;
257 #endif
258   return lp;
259 }
260
261 void free_link(struct SLink *lp)
262 {
263   MyFree(lp);
264 #ifdef  DEBUGMODE
265   links.inuse--;
266 #endif
267 }
268
269 struct DLink *add_dlink(struct DLink **lpp, struct Client *cp)
270 {
271   struct DLink* lp = (struct DLink*) MyMalloc(sizeof(struct DLink));
272   assert(0 != lp);
273   lp->value.cptr = cp;
274   lp->prev = 0;
275   if ((lp->next = *lpp))
276     lp->next->prev = lp;
277   *lpp = lp;
278   return lp;
279 }
280
281 void remove_dlink(struct DLink **lpp, struct DLink *lp)
282 {
283   assert(0 != lpp);
284   assert(0 != lp);
285
286   if (lp->prev) {
287     if ((lp->prev->next = lp->next))
288       lp->next->prev = lp->prev;
289   }
290   else if ((*lpp = lp->next))
291     lp->next->prev = NULL;
292   MyFree(lp);
293 }
294
295 struct ConfClass *make_class(void)
296 {
297   struct ConfClass *tmp;
298
299   tmp = (struct ConfClass*) MyMalloc(sizeof(struct ConfClass));
300   assert(0 != tmp);
301 #ifdef  DEBUGMODE
302   classs.inuse++;
303 #endif
304   return tmp;
305 }
306
307 void free_class(struct ConfClass * tmp)
308 {
309   MyFree(tmp);
310 #ifdef  DEBUGMODE
311   classs.inuse--;
312 #endif
313 }
314
315 #ifdef  DEBUGMODE
316 void send_listinfo(struct Client *cptr, char *name)
317 {
318   int inuse = 0, mem = 0, tmp = 0;
319
320   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Local: inuse: %d(%d)",
321              inuse += cloc.inuse, tmp = cloc.inuse * CLIENT_LOCAL_SIZE);
322   mem += tmp;
323   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Remote: inuse: %d(%d)",
324              crem.inuse, tmp = crem.inuse * CLIENT_REMOTE_SIZE);
325   mem += tmp;
326   inuse += crem.inuse;
327   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Users: inuse: %d(%d)",
328              users.inuse, tmp = users.inuse * sizeof(struct User));
329   mem += tmp;
330   inuse += users.inuse;
331   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Servs: inuse: %d(%d)",
332              servs.inuse, tmp = servs.inuse * sizeof(struct Server));
333   mem += tmp;
334   inuse += servs.inuse;
335   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Links: inuse: %d(%d)",
336              links.inuse, tmp = links.inuse * sizeof(struct SLink));
337   mem += tmp;
338   inuse += links.inuse;
339   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Classes: inuse: %d(%d)",
340              classs.inuse, tmp = classs.inuse * sizeof(struct ConfClass));
341   mem += tmp;
342   inuse += classs.inuse;
343   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Confs: inuse: %d(%d)",
344              GlobalConfCount, tmp = GlobalConfCount * sizeof(struct ConfItem));
345   mem += tmp;
346   inuse += GlobalConfCount;
347   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Totals: inuse %d %d",
348              inuse, mem);
349 }
350
351 #endif