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
20 #ifndef lint
21 static const volatile char rcsid[] = "@(#)$Id: class.c,v 1.28 2008/06/22 16:09:07 chopin Exp $";
22 #endif
23
24 #include "os.h"
25 #include "s_defines.h"
26 #define CLASS_C
27 #include "s_externs.h"
28 #undef CLASS_C
29 #ifdef ENABLE_CIDR_LIMITS
30 #include "patricia_ext.h"
31 #endif
32
33 #define BAD_CONF_CLASS -1
34 #define BAD_PING -2
35 #define BAD_CLIENT_CLASS -3
36
37 aClass *classes;
38
get_conf_class(aConfItem * aconf)39 int get_conf_class(aConfItem *aconf)
40 {
41 if ((aconf) && Class(aconf))
42 return (ConfClass(aconf));
43
44 Debug((DEBUG_DEBUG,"No Class For %s",
45 (aconf) ? aconf->name : "*No Conf*"));
46
47 return (BAD_CONF_CLASS);
48
49 }
50
get_conf_ping(aConfItem * aconf)51 static int get_conf_ping(aConfItem *aconf)
52 {
53 if ((aconf) && Class(aconf))
54 return (ConfPingFreq(aconf));
55
56 Debug((DEBUG_DEBUG,"No Ping For %s",
57 (aconf) ? aconf->name : "*No Conf*"));
58
59 return (BAD_PING);
60 }
61
62
63
get_client_class(aClient * acptr)64 int get_client_class(aClient *acptr)
65 {
66 Reg Link *tmp;
67 Reg aClass *cl;
68 int retc = BAD_CLIENT_CLASS;
69
70 if (acptr && !IsMe(acptr) && (acptr->confs))
71 for (tmp = acptr->confs; tmp; tmp = tmp->next)
72 {
73 if (!tmp->value.aconf ||
74 !(cl = tmp->value.aconf->class))
75 continue;
76 retc = Class(cl);
77 break;
78 }
79
80 Debug((DEBUG_DEBUG,"Returning Class %d For %s",retc,acptr->name));
81
82 return (retc);
83 }
84
get_client_ping(aClient * acptr)85 int get_client_ping(aClient *acptr)
86 {
87 int ping = 0, ping2;
88 aConfItem *aconf;
89 Link *link;
90
91 link = acptr->confs;
92
93 if (link)
94 while (link)
95 {
96 aconf = link->value.aconf;
97 if (aconf->status & (CONF_CLIENT|CONF_CONNECT_SERVER|
98 CONF_NOCONNECT_SERVER|
99 CONF_ZCONNECT_SERVER))
100 {
101 ping2 = get_conf_ping(aconf);
102 if ((ping2 != BAD_PING) && ((ping > ping2) ||
103 !ping))
104 ping = ping2;
105 }
106 link = link->next;
107 }
108 else
109 {
110 ping = PINGFREQUENCY;
111 Debug((DEBUG_DEBUG,"No Attached Confs"));
112 }
113 if (ping <= 0)
114 ping = PINGFREQUENCY;
115 Debug((DEBUG_DEBUG,"Client %s Ping %d", acptr->name, ping));
116 return (ping);
117 }
118
get_con_freq(aClass * clptr)119 int get_con_freq(aClass *clptr)
120 {
121 if (clptr)
122 return (MAX(60, ConFreq(clptr)));
123 else
124 return (CONNECTFREQUENCY);
125 }
126
127 /*
128 * When adding a class, check to see if it is already present first.
129 * if so, then update the information for that class, rather than create
130 * a new entry for it and later delete the old entry.
131 * if no present entry is found, then create a new one and add it in
132 * immeadiately after the first one (class 0).
133 */
add_class(int class,int ping,int confreq,int maxli,int sendq,int bsendq,int hlocal,int uhlocal,int hglobal,int uhglobal,char * cidrlen_s)134 void add_class(int class, int ping, int confreq, int maxli, int sendq,
135 int bsendq, int hlocal, int uhlocal, int hglobal, int uhglobal
136 #ifdef ENABLE_CIDR_LIMITS
137 , char *cidrlen_s
138 #endif
139 )
140 {
141 aClass *t, *p;
142 #ifdef ENABLE_CIDR_LIMITS
143 char *tmp;
144 int cidrlen = 0, cidramount = 0;
145
146 if(cidrlen_s)
147 {
148 if((tmp = index(cidrlen_s, '/')))
149 {
150 *tmp++ = '\0';
151
152 cidramount = atoi(cidrlen_s);
153 cidrlen = atoi(tmp);
154 }
155 }
156 #endif
157
158 t = find_class(class);
159 if ((t == classes) && (class != 0))
160 {
161 p = (aClass *)make_class();
162 NextClass(p) = NextClass(t);
163 NextClass(t) = p;
164 MaxSendq(p) = QUEUELEN;
165 #ifdef ENABLE_CIDR_LIMITS
166 CidrLen(p) = 0;
167 p->ip_limits = NULL;
168 #endif
169 istat.is_class++;
170 }
171 else
172 p = t;
173 Debug((DEBUG_DEBUG,
174 "Add Class %d: p %x t %x - cf: %d pf: %d ml: %d sq: %d.%d ml: %d.%d mg: %d.%d",
175 class, p, t, confreq, ping, maxli, sendq, bsendq, hlocal, uhlocal,
176 hglobal, uhglobal));
177 Class(p) = class;
178 ConFreq(p) = confreq;
179 PingFreq(p) = ping;
180 MaxLinks(p) = maxli;
181 if (sendq)
182 MaxSendq(p) = sendq;
183 MaxBSendq(p) = bsendq ? bsendq : 0;
184 MaxHLocal(p) = hlocal;
185 MaxUHLocal(p) = uhlocal;
186 MaxHGlobal(p) = hglobal;
187 MaxUHGlobal(p) = uhglobal;
188
189 #ifdef ENABLE_CIDR_LIMITS
190 if (cidrlen > 0 && CidrLen(p) == 0 && p->ip_limits == NULL)
191 {
192 CidrLen(p) = cidrlen;
193 # ifdef INET6
194 p->ip_limits = (struct _patricia_tree_t *) patricia_new(128);
195 # else
196 p->ip_limits = (struct _patricia_tree_t *) patricia_new(32);
197 # endif
198 }
199 if (CidrLen(p) != cidrlen)
200 {
201 /* Hmpf, sendto_somewhere maybe to warn? --B. */
202 Debug((DEBUG_NOTICE,
203 "Cannot change cidrlen on the fly (class %d)",
204 Class(p)));
205 }
206 if (CidrLen(p) > 0)
207 MaxCidrAmount(p) = cidramount;
208 #endif
209 if (p != t)
210 Links(p) = 0;
211 }
212
find_class(int cclass)213 aClass *find_class(int cclass)
214 {
215 aClass *cltmp;
216
217 for (cltmp = FirstClass(); cltmp; cltmp = NextClass(cltmp))
218 if (Class(cltmp) == cclass)
219 return cltmp;
220 return classes;
221 }
222
check_class(void)223 void check_class(void)
224 {
225 Reg aClass *cltmp, *cltmp2;
226
227 Debug((DEBUG_DEBUG, "Class check:"));
228
229 for (cltmp2 = cltmp = FirstClass(); cltmp; cltmp = NextClass(cltmp2))
230 {
231 Debug((DEBUG_DEBUG,
232 "Class %d : CF: %d PF: %d ML: %d LI: %d SQ: %ld",
233 Class(cltmp), ConFreq(cltmp), PingFreq(cltmp),
234 MaxLinks(cltmp), Links(cltmp), MaxSendq(cltmp)));
235 if (MaxLinks(cltmp) < 0)
236 {
237 NextClass(cltmp2) = NextClass(cltmp);
238 if (Links(cltmp) <= 0)
239 {
240 free_class(cltmp);
241 istat.is_class--;
242 }
243 }
244 else
245 cltmp2 = cltmp;
246 }
247 }
248
initclass(void)249 void initclass(void)
250 {
251 classes = (aClass *)make_class();
252 istat.is_class++;
253
254 Class(FirstClass()) = 0;
255 ConFreq(FirstClass()) = CONNECTFREQUENCY;
256 PingFreq(FirstClass()) = PINGFREQUENCY;
257 MaxLinks(FirstClass()) = MAXIMUM_LINKS;
258 MaxSendq(FirstClass()) = QUEUELEN;
259 MaxBSendq(FirstClass()) = 0;
260 Links(FirstClass()) = 0;
261 NextClass(FirstClass()) = NULL;
262 MaxHLocal(FirstClass()) = 1;
263 MaxUHLocal(FirstClass()) = 1;
264 MaxHGlobal(FirstClass()) = 1;
265 MaxUHGlobal(FirstClass()) = 1;
266 #ifdef ENABLE_CIDR_LIMITS
267 CidrLen(FirstClass()) = 0;
268 FirstClass()->ip_limits = NULL;
269 #endif
270 }
271
report_classes(aClient * sptr,char * to)272 void report_classes(aClient *sptr, char *to)
273 {
274 Reg aClass *cltmp;
275 char tmp[64] = "";
276
277 for (cltmp = FirstClass(); cltmp; cltmp = NextClass(cltmp))
278 {
279 #ifdef ENABLE_CIDR_LIMITS
280 if (MaxCidrAmount(cltmp) > 0 && CidrLen(cltmp) > 0)
281 /* leading space is important */
282 snprintf(tmp, sizeof(tmp), " %d/%d",
283 MaxCidrAmount(cltmp), CidrLen(cltmp));
284 else
285 tmp[0] = '\0';
286 #endif
287 sendto_one(sptr, replies[RPL_STATSYLINE], ME, BadTo(to), 'Y',
288 Class(cltmp), PingFreq(cltmp), ConFreq(cltmp),
289 MaxLinks(cltmp), MaxSendq(cltmp), MaxBSendq(cltmp),
290 MaxHLocal(cltmp), MaxUHLocal(cltmp),
291 MaxHGlobal(cltmp), MaxUHGlobal(cltmp), Links(cltmp), tmp);
292 }
293 }
294
get_sendq(aClient * cptr,int bursting)295 int get_sendq(aClient *cptr, int bursting)
296 {
297 Reg int sendq = QUEUELEN;
298 Reg Link *tmp;
299 Reg aClass *cl;
300
301 if (cptr->serv && cptr->serv->nline)
302 sendq = bursting && MaxBSendq(cptr->serv->nline->class) ?
303 MaxBSendq(cptr->serv->nline->class) :
304 MaxSendq(cptr->serv->nline->class);
305 else if (cptr && !IsMe(cptr) && (cptr->confs))
306 for (tmp = cptr->confs; tmp; tmp = tmp->next)
307 {
308 if (!tmp->value.aconf ||
309 !(cl = tmp->value.aconf->class))
310 continue;
311 sendq = bursting && MaxBSendq(cl) ?
312 MaxBSendq(cl) : MaxSendq(cl);
313 break;
314 }
315 return sendq;
316 }
317
318