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