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