Author: Bleep <helveytw@home.com>
[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 "IPcheck.h"
27 #include "ircd.h"
28 #include "ircd_alloc.h"
29 #include "ircd_reply.h"
30 #include "ircd_string.h"
31 #include "listener.h"
32 #include "match.h"
33 #include "numeric.h"
34 #include "res.h"
35 #include "s_bsd.h"
36 #include "s_conf.h"
37 #include "s_debug.h"
38 #include "s_misc.h"
39 #include "s_user.h"
40 #include "send.h"
41 #include "struct.h"
42 #include "support.h"
43 #include "whowas.h"
44
45 #include <assert.h>
46 #include <stddef.h>  /* offsetof */
47 #include <unistd.h>  /* close */
48 #include <string.h>
49
50 #ifdef DEBUGMODE
51 static struct liststats {
52   int inuse;
53 } cloc, crem, users, servs, links, classs;
54 #endif
55
56 static unsigned int localClientAllocCount;
57 static struct Client* localClientFreeList;
58
59 static unsigned int remoteClientAllocCount;
60 static struct Client* remoteClientFreeList;
61
62 static unsigned int slinkAllocCount;
63 static struct SLink* slinkFreeList;
64
65 void init_list(void)
66 {
67   struct Client* cptr;
68   int i;
69   /*
70    * pre-allocate MAXCONNECTIONS local clients
71    */
72   for (i = 0; i < MAXCONNECTIONS; ++i) {
73     cptr = (struct Client*) MyMalloc(CLIENT_LOCAL_SIZE);
74     cptr->next = localClientFreeList;
75     localClientFreeList = cptr;
76     ++localClientAllocCount;
77   }
78
79 #ifdef DEBUGMODE
80   memset(&cloc, 0, sizeof(cloc));
81   memset(&crem, 0, sizeof(crem));
82   memset(&users, 0, sizeof(users));
83   memset(&servs, 0, sizeof(servs));
84   memset(&links, 0, sizeof(links));
85   memset(&classs, 0, sizeof(classs));
86 #endif
87 }
88
89 /*
90  * Create a new struct Client structure and set it to initial state.
91  *
92  *   from == NULL,   create local client (a client connected to a socket).
93  *
94  *   from != NULL,   create remote client (behind a socket associated with
95  *                   the client defined by 'from').
96  *                   ('from' is a local client!!).
97  */
98 struct Client* make_client(struct Client *from, int status)
99 {
100   struct Client* cptr = 0;
101   /*
102    * Check freelists first to see if we can grab a client without
103    * having to call malloc.
104    */
105   if (from) {
106     /*
107      * remote client
108      */
109     if ((cptr = remoteClientFreeList))
110       remoteClientFreeList = cptr->next;
111     else {
112       cptr = (struct Client*) MyMalloc(CLIENT_REMOTE_SIZE);
113       ++remoteClientAllocCount;
114     }
115     assert(0 != cptr);
116     /*
117      * NOTE: Do not remove this, a lot of code depends on the entire
118      * structure being zeroed out
119      */
120     memset(cptr, 0, CLIENT_REMOTE_SIZE);        /* All variables are 0 by default */
121     cptr->from = from;
122   }
123   else {
124     /*
125      * local client
126      */
127     if ((cptr = localClientFreeList))
128       localClientFreeList = cptr->next;
129     else {
130       cptr = (struct Client*) MyMalloc(CLIENT_LOCAL_SIZE);
131       ++localClientAllocCount;
132     }
133     assert(0 != cptr);
134     /*
135      * NOTE: Do not remove this, a lot of code depends on the entire
136      * structure being zeroed out
137      */
138     memset(cptr, 0, CLIENT_LOCAL_SIZE);        /* All variables are 0 by default */
139     cptr->fd = -1;
140     cptr->local = 1;
141     cptr->since = cptr->lasttime = cptr->firsttime = CurrentTime;
142     cptr->lastnick = TStime();
143     cptr->nextnick = CurrentTime - NICK_DELAY;
144     cptr->nexttarget = CurrentTime - (TARGET_DELAY * (STARTTARGETS - 1));
145     cptr->handler = UNREGISTERED_HANDLER;
146     cptr->from = cptr;      /* 'from' of local client is self! */
147   }
148   cptr->status = status;
149   cptr->hnext = cptr;
150   strcpy(cptr->username, "unknown");
151
152 #ifdef  DEBUGMODE
153   if (from)
154     crem.inuse++;
155   else
156     cloc.inuse++;
157 #endif
158
159   return cptr;
160 }
161
162 void free_client(struct Client* cptr)
163 {
164   if (!cptr)
165     return;
166   /*
167    * forget to remove the client from the hash table?
168    */
169   assert(cptr->hnext == cptr);
170
171 #ifdef  DEBUGMODE
172   if (cptr->local)
173     --cloc.inuse;
174   else
175     --crem.inuse;
176 #endif
177
178   if (cptr->local) {
179     /*
180      * make sure we have cleaned up local resources
181      */
182     if (cptr->dns_reply)
183       --cptr->dns_reply->ref_count;
184     if (-1 < cptr->fd) {
185       ip_registry_local_disconnect(cptr);
186       close(cptr->fd);
187     }
188     DBufClear(&cptr->sendQ);
189     DBufClear(&cptr->recvQ);
190     if (cptr->listener)
191       release_listener(cptr->listener);
192     cptr->next = localClientFreeList;
193     localClientFreeList = cptr;
194   }    
195   else {
196     cptr->next = remoteClientFreeList;
197     remoteClientFreeList = cptr;
198   }
199 }
200
201 struct Server *make_server(struct Client *cptr)
202 {
203   struct Server *serv = cptr->serv;
204
205   if (!serv)
206   {
207     serv = (struct Server*) MyMalloc(sizeof(struct Server));
208     assert(0 != serv);
209     memset(serv, 0, sizeof(struct Server)); /* All variables are 0 by default */
210 #ifdef  DEBUGMODE
211     servs.inuse++;
212 #endif
213     cptr->serv = serv;
214     cptr->serv->lag = 60000;
215     *serv->by = '\0';
216     DupString(serv->last_error_msg, "<>");      /* String must be non-empty */
217   }
218   return cptr->serv;
219 }
220
221 /*
222  * Taken the code from ExitOneClient() for this and placed it here.
223  * - avalon
224  */
225 void remove_client_from_list(struct Client *cptr)
226 {
227   if (cptr->prev)
228     cptr->prev->next = cptr->next;
229   else {
230     GlobalClientList = cptr->next;
231     GlobalClientList->prev = 0;
232   }
233   if (cptr->next)
234     cptr->next->prev = cptr->prev;
235
236   cptr->next = cptr->prev = 0;
237
238   if (IsUser(cptr) && cptr->user) {
239     add_history(cptr, 0);
240     off_history(cptr);
241   }
242   if (cptr->user) {
243     free_user(cptr->user);
244     cptr->user = 0;
245   }
246
247   if (cptr->serv) {
248     if (cptr->serv->user) {
249       free_user(cptr->serv->user);
250       cptr->serv->user = 0;
251     }
252     if (cptr->serv->client_list)
253       MyFree(cptr->serv->client_list);
254     MyFree(cptr->serv->last_error_msg);
255     MyFree(cptr->serv);
256 #ifdef  DEBUGMODE
257     --servs.inuse;
258 #endif
259   }
260   free_client(cptr);
261 }
262
263 /*
264  * Although only a small routine, it appears in a number of places
265  * as a collection of a few lines...functions like this *should* be
266  * in this file, shouldnt they ?  after all, this is list.c, isn't it ?
267  * -avalon
268  */
269 void add_client_to_list(struct Client *cptr)
270 {
271   /*
272    * Since we always insert new clients to the top of the list,
273    * this should mean the "me" is the bottom most item in the list.
274    * XXX - don't always count on the above, things change
275    */
276   cptr->prev = 0;
277   cptr->next = GlobalClientList;
278   GlobalClientList = cptr;
279   if (cptr->next)
280     cptr->next->prev = cptr;
281 }
282
283 /*
284  * Look for ptr in the linked listed pointed to by link.
285  */
286 struct SLink *find_user_link(struct SLink *lp, struct Client *ptr)
287 {
288   if (ptr) {
289     while (lp) {
290       if (lp->value.cptr == ptr)
291         return (lp);
292       lp = lp->next;
293     }
294   }
295   return NULL;
296 }
297
298 struct SLink* make_link(void)
299 {
300   struct SLink* lp = slinkFreeList;
301   if (lp)
302     slinkFreeList = lp->next;
303   else {
304     lp = (struct SLink*) MyMalloc(sizeof(struct SLink));
305     ++slinkAllocCount;
306   }
307   assert(0 != lp);
308 #ifdef  DEBUGMODE
309   links.inuse++;
310 #endif
311   return lp;
312 }
313
314 void free_link(struct SLink* lp)
315 {
316   if (lp) {
317     lp->next = slinkFreeList;
318     slinkFreeList = lp;
319   }
320 #ifdef  DEBUGMODE
321   links.inuse--;
322 #endif
323 }
324
325 struct DLink *add_dlink(struct DLink **lpp, struct Client *cp)
326 {
327   struct DLink* lp = (struct DLink*) MyMalloc(sizeof(struct DLink));
328   assert(0 != lp);
329   lp->value.cptr = cp;
330   lp->prev = 0;
331   if ((lp->next = *lpp))
332     lp->next->prev = lp;
333   *lpp = lp;
334   return lp;
335 }
336
337 void remove_dlink(struct DLink **lpp, struct DLink *lp)
338 {
339   assert(0 != lpp);
340   assert(0 != lp);
341
342   if (lp->prev) {
343     if ((lp->prev->next = lp->next))
344       lp->next->prev = lp->prev;
345   }
346   else if ((*lpp = lp->next))
347     lp->next->prev = NULL;
348   MyFree(lp);
349 }
350
351 struct ConfClass *make_class(void)
352 {
353   struct ConfClass *tmp;
354
355   tmp = (struct ConfClass*) MyMalloc(sizeof(struct ConfClass));
356   assert(0 != tmp);
357 #ifdef  DEBUGMODE
358   classs.inuse++;
359 #endif
360   return tmp;
361 }
362
363 void free_class(struct ConfClass * tmp)
364 {
365   MyFree(tmp);
366 #ifdef  DEBUGMODE
367   classs.inuse--;
368 #endif
369 }
370
371 #ifdef  DEBUGMODE
372 void send_listinfo(struct Client *cptr, char *name)
373 {
374   int inuse = 0, mem = 0, tmp = 0;
375
376   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Local: inuse: %d(%d)",
377              inuse += cloc.inuse, tmp = cloc.inuse * CLIENT_LOCAL_SIZE);
378   mem += tmp;
379   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Remote: inuse: %d(%d)",
380              crem.inuse, tmp = crem.inuse * CLIENT_REMOTE_SIZE);
381   mem += tmp;
382   inuse += crem.inuse;
383   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Users: inuse: %d(%d)",
384              users.inuse, tmp = users.inuse * sizeof(struct User));
385   mem += tmp;
386   inuse += users.inuse;
387   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Servs: inuse: %d(%d)",
388              servs.inuse, tmp = servs.inuse * sizeof(struct Server));
389   mem += tmp;
390   inuse += servs.inuse;
391   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Links: inuse: %d(%d)",
392              links.inuse, tmp = links.inuse * sizeof(struct SLink));
393   mem += tmp;
394   inuse += links.inuse;
395   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Classes: inuse: %d(%d)",
396              classs.inuse, tmp = classs.inuse * sizeof(struct ConfClass));
397   mem += tmp;
398   inuse += classs.inuse;
399   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Confs: inuse: %d(%d)",
400              GlobalConfCount, tmp = GlobalConfCount * sizeof(struct ConfItem));
401   mem += tmp;
402   inuse += GlobalConfCount;
403   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Totals: inuse %d %d",
404              inuse, mem);
405 }
406
407 #endif