77678e9d2fed5fdb62898bba1037199e183af3ec
[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 "class.h"
22 #include "client.h"
23 #include "ircd.h"
24 #include "ircd_alloc.h"
25 #include "ircd_reply.h"
26 #include "list.h"
27 #include "numeric.h"
28 #include "s_conf.h"
29 #include "s_debug.h"
30 #include "send.h"
31
32 #include <assert.h>
33
34 #define BAD_CONF_CLASS          ((unsigned int)-1)
35 #define BAD_PING                ((unsigned int)-2)
36 #define BAD_CLIENT_CLASS        ((unsigned int)-3)
37
38 static struct ConnectionClass* connClassList;
39 static unsigned int connClassAllocCount;
40
41 const struct ConnectionClass* get_class_list(void)
42 {
43   return connClassList;
44 }
45
46 struct ConnectionClass* make_class(void)
47 {
48   struct ConnectionClass *tmp;
49
50   tmp = (struct ConnectionClass*) MyMalloc(sizeof(struct ConnectionClass));
51   assert(0 != tmp);
52   ++connClassAllocCount;
53   return tmp;
54 }
55
56 void free_class(struct ConnectionClass* p)
57 {
58   if (p) {
59     assert(0 == p->valid);
60     MyFree(p);
61     --connClassAllocCount;
62   }
63 }
64
65 /*
66  * init_class - initialize the class list
67  */
68 void init_class(void)
69 {
70   connClassList = (struct ConnectionClass*) make_class();
71
72   ConClass(connClassList) = 0;
73   PingFreq(connClassList) = PINGFREQUENCY;
74   ConFreq(connClassList)  = CONNECTFREQUENCY;
75   MaxLinks(connClassList) = MAXIMUM_LINKS;
76   MaxSendq(connClassList) = DEFAULTMAXSENDQLENGTH;
77   connClassList->valid    = 1;
78   Links(connClassList)    = 0;
79   connClassList->next     = 0;
80 }
81
82 /*
83  * class_mark_delete - mark classes for delete
84  * We don't delete the class table, rather mark all entries
85  * for deletion. The table is cleaned up by class_delete_marked(). - avalon
86  * XXX - This destroys data
87  */
88 void class_mark_delete(void)
89 {
90   struct ConnectionClass* p;
91   assert(0 != connClassList);
92
93   for (p = connClassList->next; p; p = p->next)
94     p->valid = 0;
95 }
96
97 /*
98  * class_delete_marked
99  * delete classes marked for deletion
100  * XXX - memory leak, no one deletes classes that become unused
101  * later
102  */
103 void class_delete_marked(void)
104 {
105   struct ConnectionClass* cl;
106   struct ConnectionClass* prev;
107
108   Debug((DEBUG_DEBUG, "Class check:"));
109
110   for (prev = cl = connClassList; cl; cl = prev->next) {
111     Debug((DEBUG_DEBUG, "Class %d : CF: %d PF: %d ML: %d LI: %d SQ: %d",
112            ConClass(cl), ConFreq(cl), PingFreq(cl), MaxLinks(cl), Links(cl), MaxSendq(cl)));
113     /*
114      * unlink marked classes, delete unreferenced ones
115      */
116     if (cl->valid)
117       prev = cl;
118     else {
119       prev->next = cl->next;
120       if (0 == cl->ref_count)
121         free_class(cl);
122     }
123   }
124 }
125
126 unsigned int get_conf_class(const struct ConfItem* aconf)
127 {
128   if ((aconf) && (aconf->conn_class))
129     return (ConfClass(aconf));
130
131   Debug((DEBUG_DEBUG, "No Class For %s", (aconf) ? aconf->name : "*No Conf*"));
132
133   return (BAD_CONF_CLASS);
134 }
135
136 int get_conf_ping(const struct ConfItem* aconf)
137 {
138   assert(0 != aconf);
139   if (aconf->conn_class)
140     return (ConfPingFreq(aconf));
141
142   Debug((DEBUG_DEBUG, "No Ping For %s", aconf->name));
143
144   return -1;
145 }
146
147 unsigned int get_client_class(struct Client *acptr)
148 {
149   struct SLink *tmp;
150   struct ConnectionClass *cl;
151   unsigned int retc = BAD_CLIENT_CLASS;
152
153   if (acptr && !IsMe(acptr) && (acptr->confs))
154     for (tmp = acptr->confs; tmp; tmp = tmp->next)
155     {
156       if (!tmp->value.aconf || !(cl = tmp->value.aconf->conn_class))
157         continue;
158       if (ConClass(cl) > retc || retc == BAD_CLIENT_CLASS)
159         retc = ConClass(cl);
160     }
161
162   Debug((DEBUG_DEBUG, "Returning Class %d For %s", retc, acptr->name));
163
164   return (retc);
165 }
166
167 unsigned int get_client_ping(struct Client *acptr)
168 {
169   unsigned int ping = 0;
170   unsigned int ping2;
171   struct ConfItem *aconf;
172   struct SLink *link;
173
174   link = acptr->confs;
175
176   if (link) {
177     while (link) {
178       aconf = link->value.aconf;
179       if (aconf->status & (CONF_CLIENT | CONF_SERVER)) {
180         ping2 = get_conf_ping(aconf);
181         if ((ping2 != BAD_PING) && ((ping > ping2) || !ping))
182           ping = ping2;
183       }
184       link = link->next;
185     }
186   }
187   else {
188     ping = PINGFREQUENCY;
189     Debug((DEBUG_DEBUG, "No Attached Confs for: %s", acptr->name));
190   }
191   if (ping <= 0)
192     ping = PINGFREQUENCY;
193   Debug((DEBUG_DEBUG, "Client %s Ping %d", acptr->name, ping));
194   return (ping);
195 }
196
197 unsigned int get_con_freq(struct ConnectionClass * clptr)
198 {
199   if (clptr)
200     return (ConFreq(clptr));
201   else
202     return (CONNECTFREQUENCY);
203 }
204
205 /*
206  * When adding a class, check to see if it is already present first.
207  * if so, then update the information for that class, rather than create
208  * a new entry for it and later delete the old entry.
209  * if no present entry is found, then create a new one and add it in
210  * immeadiately after the first one (class 0).
211  */
212 void add_class(unsigned int conClass, unsigned int ping, unsigned int confreq,
213                unsigned int maxli, unsigned int sendq)
214 {
215   struct ConnectionClass* t;
216   struct ConnectionClass* p;
217
218   t = find_class(conClass);
219   if ((t == connClassList) && (conClass != 0))
220   {
221     p = (struct ConnectionClass *) make_class();
222     p->next = t->next;
223     t->next = p;
224   }
225   else
226     p = t;
227   Debug((DEBUG_DEBUG, "Add Class %u: cf: %u pf: %u ml: %u sq: %d",
228          conClass, confreq, ping, maxli, sendq));
229   ConClass(p) = conClass;
230   ConFreq(p) = confreq;
231   PingFreq(p) = ping;
232   MaxLinks(p) = maxli;
233   MaxSendq(p) = (sendq > 0) ? sendq : DEFAULTMAXSENDQLENGTH;
234   p->valid = 1;
235   if (p != t)
236     Links(p) = 0;
237 }
238
239 struct ConnectionClass* find_class(unsigned int cclass)
240 {
241   struct ConnectionClass *cltmp;
242
243   for (cltmp = connClassList; cltmp; cltmp = cltmp->next) {
244     if (ConClass(cltmp) == cclass)
245       return cltmp;
246   }
247   return connClassList;
248 }
249
250 void report_classes(struct Client *sptr)
251 {
252   struct ConnectionClass *cltmp;
253
254   for (cltmp = connClassList; cltmp; cltmp = cltmp->next)
255     send_reply(sptr, RPL_STATSYLINE, 'Y', ConClass(cltmp), PingFreq(cltmp),
256                ConFreq(cltmp), MaxLinks(cltmp), MaxSendq(cltmp));
257 }
258
259 unsigned int get_sendq(struct Client *cptr)
260 {
261   assert(0 != cptr);
262   assert(0 != cptr->local);
263
264   if (cptr->max_sendq)
265     return cptr->max_sendq;
266
267   else if (cptr->confs) {
268     struct SLink*     tmp;
269     struct ConnectionClass* cl;
270
271     for (tmp = cptr->confs; tmp; tmp = tmp->next) {
272       if (!tmp->value.aconf || !(cl = tmp->value.aconf->conn_class))
273         continue;
274       if (ConClass(cl) != BAD_CLIENT_CLASS) {
275         cptr->max_sendq = MaxSendq(cl);
276         return cptr->max_sendq;
277       }
278     }
279   }
280   return DEFAULTMAXSENDQLENGTH;
281 }
282
283 void class_send_meminfo(struct Client* cptr)
284 {
285   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Classes: inuse: %d(%d)",
286              connClassAllocCount, connClassAllocCount * sizeof(struct ConnectionClass));
287 }
288
289