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