]>
Commit | Line | Data |
---|---|---|
189935b1 | 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 | /** @file | |
20 | * @brief Implementation of connection class handling functions. | |
21 | * @version $Id: class.c,v 1.34.2.3 2005/10/06 00:37:31 entrope Exp $ | |
22 | */ | |
23 | #include "config.h" | |
24 | ||
25 | #include "class.h" | |
26 | #include "client.h" | |
27 | #include "ircd.h" | |
28 | #include "ircd_alloc.h" | |
29 | #include "ircd_features.h" | |
30 | #include "ircd_log.h" | |
31 | #include "ircd_reply.h" | |
32 | #include "ircd_string.h" | |
33 | #include "list.h" | |
34 | #include "numeric.h" | |
35 | #include "s_conf.h" | |
36 | #include "s_debug.h" | |
37 | #include "send.h" | |
38 | ||
39 | /* #include <assert.h> -- Now using assert in ircd_log.h */ | |
40 | ||
41 | /** List of all connection classes. */ | |
42 | static struct ConnectionClass* connClassList; | |
43 | /** Number of allocated connection classes. */ | |
44 | static unsigned int connClassAllocCount; | |
45 | ||
46 | /** Get start of connection class linked list. */ | |
47 | const struct ConnectionClass* get_class_list(void) | |
48 | { | |
49 | return connClassList; | |
50 | } | |
51 | ||
52 | /** Allocate a new connection class. | |
53 | * If #connClassList is not null, insert the new class just after it. | |
54 | * @return Newly allocated connection class structure. | |
55 | */ | |
56 | struct ConnectionClass* make_class(void) | |
57 | { | |
58 | struct ConnectionClass *tmp; | |
59 | ||
60 | tmp = (struct ConnectionClass*) MyCalloc(1, sizeof(struct ConnectionClass)); | |
61 | assert(0 != tmp); | |
62 | tmp->ref_count = 1; | |
63 | if (connClassList) | |
64 | { | |
65 | tmp->next = connClassList->next; | |
66 | connClassList->next = tmp; | |
67 | } | |
68 | ++connClassAllocCount; | |
69 | return tmp; | |
70 | } | |
71 | ||
72 | /** Dereference a connection class. | |
73 | * @param[in] p Connection class to dereference. | |
74 | */ | |
75 | void free_class(struct ConnectionClass* p) | |
76 | { | |
77 | if (p) | |
78 | { | |
79 | assert(0 == p->valid); | |
80 | MyFree(p->cc_name); | |
81 | MyFree(p->default_umode); | |
82 | MyFree(p); | |
83 | --connClassAllocCount; | |
84 | } | |
85 | } | |
86 | ||
87 | /** Initialize the connection class list. | |
88 | * A connection class named "default" is created, with ping frequency, | |
89 | * connection frequency, maximum links and max SendQ values from the | |
90 | * corresponding configuration features. | |
91 | */ | |
92 | void init_class(void) | |
93 | { | |
94 | if (!connClassList) { | |
95 | connClassList = (struct ConnectionClass*) make_class(); | |
96 | connClassList->next = 0; | |
97 | } | |
98 | ||
99 | /* We had better not try and free this... */ | |
100 | ConClass(connClassList) = "default"; | |
101 | PingFreq(connClassList) = feature_int(FEAT_PINGFREQUENCY); | |
102 | ConFreq(connClassList) = feature_int(FEAT_CONNECTFREQUENCY); | |
103 | MaxLinks(connClassList) = feature_int(FEAT_MAXIMUM_LINKS); | |
104 | MaxSendq(connClassList) = feature_int(FEAT_DEFAULTMAXSENDQLENGTH); | |
105 | connClassList->valid = 1; | |
106 | Links(connClassList) = 1; | |
107 | } | |
108 | ||
109 | /** Mark current connection classes as invalid. | |
110 | */ | |
111 | void class_mark_delete(void) | |
112 | { | |
113 | struct ConnectionClass* p; | |
114 | assert(0 != connClassList); | |
115 | ||
116 | for (p = connClassList->next; p; p = p->next) | |
117 | p->valid = 0; | |
118 | } | |
119 | ||
120 | /** Unlink (and dereference) invalid connection classes. | |
121 | * This is used in combination with class_mark_delete() during rehash | |
122 | * to get rid of connection classes that are no longer in the | |
123 | * configuration. | |
124 | */ | |
125 | void class_delete_marked(void) | |
126 | { | |
127 | struct ConnectionClass* cl; | |
128 | struct ConnectionClass* prev; | |
129 | ||
130 | Debug((DEBUG_DEBUG, "Class check:")); | |
131 | ||
132 | for (prev = cl = connClassList; cl; cl = prev->next) { | |
133 | Debug((DEBUG_DEBUG, "Class %s : CF: %d PF: %d ML: %d LI: %d SQ: %d", | |
134 | ConClass(cl), ConFreq(cl), PingFreq(cl), MaxLinks(cl), | |
135 | Links(cl), MaxSendq(cl))); | |
136 | /* | |
137 | * unlink marked classes, delete unreferenced ones | |
138 | */ | |
139 | if (cl->valid || Links(cl) > 1) | |
140 | prev = cl; | |
141 | else | |
142 | { | |
143 | prev->next = cl->next; | |
144 | free_class(cl); | |
145 | } | |
146 | } | |
147 | } | |
148 | ||
149 | /** Get connection class name for a configuration item. | |
150 | * @param[in] aconf Configuration item to check. | |
151 | * @return Name of connection class associated with \a aconf. | |
152 | */ | |
153 | char* | |
154 | get_conf_class(const struct ConfItem* aconf) | |
155 | { | |
156 | if ((aconf) && (aconf->conn_class)) | |
157 | return (ConfClass(aconf)); | |
158 | ||
159 | Debug((DEBUG_DEBUG, "No Class For %s", (aconf) ? aconf->name : "*No Conf*")); | |
160 | ||
161 | return NULL; | |
162 | } | |
163 | ||
164 | /** Get ping time for a configuration item. | |
165 | * @param[in] aconf Configuration item to check. | |
166 | * @return Ping time for connection class associated with \a aconf. | |
167 | */ | |
168 | int get_conf_ping(const struct ConfItem* aconf) | |
169 | { | |
170 | assert(0 != aconf); | |
171 | if (aconf->conn_class) | |
172 | return (ConfPingFreq(aconf)); | |
173 | ||
174 | Debug((DEBUG_DEBUG, "No Ping For %s", aconf->name)); | |
175 | ||
176 | return -1; | |
177 | } | |
178 | ||
179 | /** Get connection class name for a particular client. | |
180 | * @param[in] acptr Client to check. | |
181 | * @return Name of connection class to which \a acptr belongs. | |
182 | */ | |
183 | char* | |
184 | get_client_class(struct Client *acptr) | |
185 | { | |
186 | struct SLink *tmp; | |
187 | struct ConnectionClass *cl; | |
188 | ||
189 | /* Return the most recent(first on LL) client class... */ | |
190 | if (acptr && !IsMe(acptr) && (cli_confs(acptr))) | |
191 | for (tmp = cli_confs(acptr); tmp; tmp = tmp->next) | |
192 | { | |
193 | if (tmp->value.aconf && (cl = tmp->value.aconf->conn_class)) | |
194 | return ConClass(cl); | |
195 | } | |
196 | return "(null-class)"; | |
197 | } | |
198 | ||
199 | /** Make sure we have a connection class named \a name. | |
200 | * If one does not exist, create it. Then set its ping frequency, | |
201 | * connection frequency, maximum link count, and max SendQ according | |
202 | * to the parameters. | |
203 | * @param[in] name Connection class name. | |
204 | * @param[in] ping Ping frequency for clients in this class. | |
205 | * @param[in] confreq Connection frequency for clients. | |
206 | * @param[in] maxli Maximum link count for class. | |
207 | * @param[in] sendq Max SendQ for clients. | |
208 | */ | |
209 | void add_class(char *name, unsigned int ping, unsigned int confreq, | |
210 | unsigned int maxli, unsigned int sendq) | |
211 | { | |
212 | struct ConnectionClass* p; | |
213 | ||
214 | Debug((DEBUG_DEBUG, "Add Class %s: cf: %u pf: %u ml: %u sq: %d", | |
215 | name, confreq, ping, maxli, sendq)); | |
216 | assert(name != NULL); | |
217 | p = do_find_class(name, 1); | |
218 | if (!p) | |
219 | p = make_class(); | |
220 | else | |
221 | MyFree(ConClass(p)); | |
222 | ConClass(p) = name; | |
223 | ConFreq(p) = confreq; | |
224 | PingFreq(p) = ping; | |
225 | MaxLinks(p) = maxli; | |
226 | MaxSendq(p) = (sendq > 0) ? | |
227 | sendq : feature_int(FEAT_DEFAULTMAXSENDQLENGTH); | |
228 | p->valid = 1; | |
229 | } | |
230 | ||
231 | /** Find a connection class by name. | |
232 | * @param[in] name Name of connection class to search for. | |
233 | * @param[in] extras If non-zero, include unreferenced classes. | |
234 | * @return Pointer to connection class structure (or NULL if none match). | |
235 | */ | |
236 | struct ConnectionClass* do_find_class(const char *name, int extras) | |
237 | { | |
238 | struct ConnectionClass *cltmp; | |
239 | ||
240 | for (cltmp = connClassList; cltmp; cltmp = cltmp->next) { | |
241 | if (!cltmp->valid && !extras) | |
242 | continue; | |
243 | if (!ircd_strcmp(ConClass(cltmp), name)) | |
244 | return cltmp; | |
245 | } | |
246 | return NULL; | |
247 | } | |
248 | ||
249 | /** Report connection classes to a client. | |
250 | * @param[in] sptr Client requesting statistics. | |
251 | * @param[in] sd Stats descriptor for request (ignored). | |
252 | * @param[in] param Extra parameter from user (ignored). | |
253 | */ | |
254 | void | |
255 | report_classes(struct Client *sptr, const struct StatDesc *sd, | |
256 | char *param) | |
257 | { | |
258 | struct ConnectionClass *cltmp; | |
259 | ||
260 | for (cltmp = connClassList; cltmp; cltmp = cltmp->next) | |
261 | send_reply(sptr, RPL_STATSYLINE, (cltmp->valid ? 'Y' : 'y'), | |
262 | ConClass(cltmp), PingFreq(cltmp), ConFreq(cltmp), | |
263 | MaxLinks(cltmp), MaxSendq(cltmp), Links(cltmp) - 1); | |
264 | } | |
265 | ||
266 | /** Return maximum SendQ length for a client. | |
267 | * @param[in] cptr Local client to check. | |
268 | * @return Number of bytes allowed in SendQ for \a cptr. | |
269 | */ | |
270 | unsigned int | |
271 | get_sendq(struct Client *cptr) | |
272 | { | |
273 | assert(0 != cptr); | |
274 | assert(0 != cli_local(cptr)); | |
275 | ||
276 | if (cli_max_sendq(cptr)) | |
277 | return cli_max_sendq(cptr); | |
278 | ||
279 | else if (cli_confs(cptr)) { | |
280 | struct SLink* tmp; | |
281 | struct ConnectionClass* cl; | |
282 | ||
283 | for (tmp = cli_confs(cptr); tmp; tmp = tmp->next) { | |
284 | if (!tmp->value.aconf || !(cl = tmp->value.aconf->conn_class)) | |
285 | continue; | |
286 | if (ConClass(cl) != NULL) { | |
287 | cli_max_sendq(cptr) = MaxSendq(cl); | |
288 | return cli_max_sendq(cptr); | |
289 | } | |
290 | } | |
291 | } | |
292 | return feature_int(FEAT_DEFAULTMAXSENDQLENGTH); | |
293 | } | |
294 | ||
295 | /** Report connection class memory statistics to a client. | |
296 | * Send number of classes and number of bytes allocated for them. | |
297 | * @param[in] cptr Client requesting statistics. | |
298 | */ | |
299 | void class_send_meminfo(struct Client* cptr) | |
300 | { | |
301 | send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Classes: inuse: %d(%d)", | |
302 | connClassAllocCount, | |
303 | connClassAllocCount * sizeof(struct ConnectionClass)); | |
304 | } | |
305 | ||
306 |