Author: Thomas Helvey <tom.helvey@cox.net> Message: Add hasher, fix bugster
[ircu2.10.12-pk.git] / ircd / class.c
1 /*
2  * IRC - Internet Relay Chat, ircd/class.c
3  * Copyright (C) 1990 Darren Reed
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 1, or (at your option)
8  * any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  *
19  * $Id$
20  */
21 #include "config.h"
22
23 #include "class.h"
24 #include "client.h"
25 #include "ircd.h"
26 #include "ircd_alloc.h"
27 #include "ircd_features.h"
28 #include "ircd_reply.h"
29 #include "ircd_string.h"
30 #include "list.h"
31 #include "numeric.h"
32 #include "s_conf.h"
33 #include "s_debug.h"
34 #include "send.h"
35
36 #include <assert.h>
37
38 #define BAD_CONF_CLASS          ((unsigned int)-1)
39 #define BAD_PING                ((unsigned int)-2)
40 #define BAD_CLIENT_CLASS        ((unsigned int)-3)
41
42 static struct ConnectionClass* connClassList = 0;
43 static unsigned int connClassAllocCount;
44
45 const struct ConnectionClass* get_class_list(void)
46 {
47   return connClassList;
48 }
49
50 struct ConnectionClass* make_class(void)
51 {
52   struct ConnectionClass *tmp;
53
54   tmp = (struct ConnectionClass*) MyMalloc(sizeof(struct ConnectionClass));
55   tmp->ref_count = 1;
56   assert(0 != tmp);
57   ++connClassAllocCount;
58   return tmp;
59 }
60
61 void free_class(struct ConnectionClass* p)
62 {
63   if (p)
64   {
65     assert(0 == p->valid);
66     if (p->cc_name)
67       MyFree(p->cc_name);
68     MyFree(p);
69     --connClassAllocCount;
70   }
71 }
72
73 /*
74  * init_class - initialize the class list
75  */
76 void init_class(void)
77 {
78   if (!connClassList)
79     connClassList = (struct ConnectionClass*) make_class();
80
81   /* We had better not try and free this... */
82   ConClass(connClassList) = "default";
83   PingFreq(connClassList) = feature_int(FEAT_PINGFREQUENCY);
84   ConFreq(connClassList)  = feature_int(FEAT_CONNECTFREQUENCY);
85   MaxLinks(connClassList) = feature_int(FEAT_MAXIMUM_LINKS);
86   MaxSendq(connClassList) = feature_int(FEAT_DEFAULTMAXSENDQLENGTH);
87   connClassList->valid    = 1;
88   Links(connClassList)    = 0;
89   connClassList->next     = 0;
90 }
91
92 /*
93  * class_mark_delete - mark classes for delete
94  * We don't delete the class table, rather mark all entries
95  * for deletion. The table is cleaned up by class_delete_marked(). - avalon
96  * XXX - This destroys data
97  */
98 void class_mark_delete(void)
99 {
100   struct ConnectionClass* p;
101   assert(0 != connClassList);
102
103   for (p = connClassList->next; p; p = p->next)
104     p->valid = 0;
105 }
106
107 /*
108  * class_delete_marked
109  * delete classes marked for deletion
110  * XXX - memory leak, no one deletes classes that become unused
111  * later
112  */
113 void class_delete_marked(void)
114 {
115   struct ConnectionClass* cl;
116   struct ConnectionClass* prev;
117
118   Debug((DEBUG_DEBUG, "Class check:"));
119
120   for (prev = cl = connClassList; cl; cl = prev->next) {
121     Debug((DEBUG_DEBUG, "Class %s : CF: %d PF: %d ML: %d LI: %d SQ: %d",
122            ConClass(cl), ConFreq(cl), PingFreq(cl), MaxLinks(cl),
123            Links(cl), MaxSendq(cl)));
124     /*
125      * unlink marked classes, delete unreferenced ones
126      */
127     if (cl->valid)
128       prev = cl;
129     else
130     {
131       prev->next = cl->next;
132       if (0 == --cl->ref_count)
133         free_class(cl);
134     }
135   }
136 }
137
138 char*
139 get_conf_class(const struct ConfItem* aconf)
140 {
141   if ((aconf) && (aconf->conn_class))
142     return (ConfClass(aconf));
143
144   Debug((DEBUG_DEBUG, "No Class For %s", (aconf) ? aconf->name : "*No Conf*"));
145
146   return NULL;
147 }
148
149 int get_conf_ping(const struct ConfItem* aconf)
150 {
151   assert(0 != aconf);
152   if (aconf->conn_class)
153     return (ConfPingFreq(aconf));
154
155   Debug((DEBUG_DEBUG, "No Ping For %s", aconf->name));
156
157   return -1;
158 }
159
160 char*
161 get_client_class(struct Client *acptr)
162 {
163   struct SLink *tmp;
164   struct ConnectionClass *cl;
165
166   /* Return the most recent(first on LL) client class... */
167   if (acptr && !IsMe(acptr) && (cli_confs(acptr)))
168     for (tmp = cli_confs(acptr); tmp; tmp = tmp->next)
169     {
170       if (tmp->value.aconf && (cl = tmp->value.aconf->conn_class))
171         return ConClass(cl);
172     }
173   return "(null-class)";
174 }
175
176 unsigned int get_con_freq(struct ConnectionClass * clptr)
177 {
178   if (clptr)
179     return (ConFreq(clptr));
180   else
181     return feature_int(FEAT_CONNECTFREQUENCY);
182 }
183
184 /*
185  * When adding a class, check to see if it is already present first.
186  * if so, then update the information for that class, rather than create
187  * a new entry for it and later delete the old entry.
188  * if no present entry is found, then create a new one and add it in
189  * immeadiately after the first one (class 0).
190  */
191 void add_class(char *name, unsigned int ping, unsigned int confreq,
192                unsigned int maxli, unsigned int sendq)
193 {
194   struct ConnectionClass* t;
195   struct ConnectionClass* p;
196
197   t = find_class(name);
198   if ((t == connClassList) && (name != NULL))
199   {
200     p = (struct ConnectionClass *) make_class();
201     p->next = t->next;
202     t->next = p;
203   }
204   else
205   {
206     if (ConClass(t) != NULL)
207       MyFree(ConClass(t));
208     p = t;
209   }
210   Debug((DEBUG_DEBUG, "Add Class %s: cf: %u pf: %u ml: %u sq: %d",
211          name, confreq, ping, maxli, sendq));
212   ConClass(p) = name;
213   ConFreq(p) = confreq;
214   PingFreq(p) = ping;
215   MaxLinks(p) = maxli;
216   MaxSendq(p) = (sendq > 0) ?
217      sendq : feature_int(FEAT_DEFAULTMAXSENDQLENGTH);
218   p->valid = 1;
219   if (p != t)
220     Links(p) = 0;
221 }
222
223 struct ConnectionClass* find_class(const char *name)
224 {
225   struct ConnectionClass *cltmp;
226
227   for (cltmp = connClassList; cltmp; cltmp = cltmp->next) {
228     if (!ircd_strcmp(ConClass(cltmp), name))
229       return cltmp;
230   }
231   return connClassList;
232 }
233
234 void
235 report_classes(struct Client *sptr, struct StatDesc *sd, int stat,
236                char *param)
237 {
238   struct ConnectionClass *cltmp;
239
240   for (cltmp = connClassList; cltmp; cltmp = cltmp->next)
241     send_reply(sptr, RPL_STATSYLINE, 'Y', ConClass(cltmp), PingFreq(cltmp),
242                ConFreq(cltmp), MaxLinks(cltmp), MaxSendq(cltmp),
243                Links(cltmp));
244 }
245
246 unsigned int
247 get_sendq(struct Client *cptr)
248 {
249   assert(0 != cptr);
250   assert(0 != cli_local(cptr));
251
252   if (cli_max_sendq(cptr))
253     return cli_max_sendq(cptr);
254
255   else if (cli_confs(cptr)) {
256     struct SLink*     tmp;
257     struct ConnectionClass* cl;
258
259     for (tmp = cli_confs(cptr); tmp; tmp = tmp->next) {
260       if (!tmp->value.aconf || !(cl = tmp->value.aconf->conn_class))
261         continue;
262       if (ConClass(cl) != NULL) {
263         cli_max_sendq(cptr) = MaxSendq(cl);
264         return cli_max_sendq(cptr);
265       }
266     }
267   }
268   return feature_int(FEAT_DEFAULTMAXSENDQLENGTH);
269 }
270
271 void class_send_meminfo(struct Client* cptr)
272 {
273   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Classes: inuse: %d(%d)",
274              connClassAllocCount,
275              connClassAllocCount * sizeof(struct ConnectionClass));
276 }
277
278