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