1 /*
2  *   Unreal Internet Relay Chat Daemon, src/modules/m_htm.c
3  *   (C) 2000-2001 Carsten V. Munk and the UnrealIRCd Team
4  *   Moved to modules by Fish (Justin Hammond)
5  *
6  *   This program is free software; you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation; either version 1, or (at your option)
9  *   any later version.
10  *
11  *   This program is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *   GNU General Public License for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with this program; if not, write to the Free Software
18  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20 
21 #include "config.h"
22 #include "struct.h"
23 #include "common.h"
24 #include "sys.h"
25 #include "numeric.h"
26 #include "msg.h"
27 #include "channel.h"
28 #include <time.h>
29 #include <sys/stat.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #ifdef _WIN32
34 #include <io.h>
35 #endif
36 #include <fcntl.h>
37 #include "h.h"
38 #include "proto.h"
39 #ifdef STRIPBADWORDS
40 #include "badwords.h"
41 #endif
42 #ifdef _WIN32
43 #include "version.h"
44 #endif
45 
46 
47 DLLFUNC int m_htm(aClient *cptr, aClient *sptr, int parc, char *parv[]);
48 EVENT(lcf_check);
49 EVENT(htm_calc);
50 Event *e_lcf, *e_htmcalc;
51 
52 /* Place includes here */
53 #define MSG_HTM         "HTM"
54 #define TOK_HTM         "BH"
55 
56 DLLFUNC int htm_config_test(ConfigFile *, ConfigEntry *, int, int *);
57 DLLFUNC int htm_config_run(ConfigFile *, ConfigEntry *, int);
58 DLLFUNC int htm_stats(aClient *, char *);
59 
60 ModuleInfo *HtmModInfo;
61 static Hook *ConfTest, *ConfRun, *ServerStats;
62 
63 ModuleHeader MOD_HEADER(m_htm)
64   = {
65 	"htm",	/* Name of module */
66 	"$Id$", /* Version */
67 	"command /htm", /* Short description of module */
68 	"3.2-b8-1",
69 	NULL
70     };
71 
MOD_TEST(m_htm)72 DLLFUNC int MOD_TEST(m_htm)(ModuleInfo *modinfo)
73 {
74 	/*
75 	 * We call our add_Command crap here
76 	*/
77 	HtmModInfo = modinfo;
78 	ConfTest = HookAddEx(HtmModInfo->handle, HOOKTYPE_CONFIGTEST, htm_config_test);
79 	return MOD_SUCCESS;
80 }
81 
82 
83 /* This is called on module init, before Server Ready */
MOD_INIT(m_htm)84 DLLFUNC int MOD_INIT(m_htm)(ModuleInfo *modinfo)
85 {
86 	/*
87 	 * We call our add_Command crap here
88 	*/
89 	add_Command(MSG_HTM, TOK_HTM, m_htm, MAXPARA);
90 	ConfRun = HookAddEx(HtmModInfo->handle, HOOKTYPE_CONFIGRUN, htm_config_run);
91 	ServerStats = HookAddEx(HtmModInfo->handle, HOOKTYPE_STATS, htm_stats);
92 #ifndef NO_FDLIST
93 	LockEventSystem();
94 	e_lcf = EventAddEx(HtmModInfo->handle, "lcf", LCF, 0, lcf_check, NULL);
95 	e_htmcalc = EventAddEx(HtmModInfo->handle, "htmcalc", 1, 0, htm_calc, NULL);
96 	UnlockEventSystem();
97 #endif
98 	MARK_AS_OFFICIAL_MODULE(modinfo);
99 	return MOD_SUCCESS;
100 }
101 
102 /* Is first run when server is 100% ready */
MOD_LOAD(m_htm)103 DLLFUNC int MOD_LOAD(m_htm)(int module_load)
104 {
105 	return MOD_SUCCESS;
106 }
107 
108 
109 /* Called when module is unloaded */
MOD_UNLOAD(m_htm)110 DLLFUNC int MOD_UNLOAD(m_htm)(int module_unload)
111 {
112 	if (del_Command(MSG_HTM, TOK_HTM, m_htm) < 0)
113 	{
114 		sendto_realops("Failed to delete commands when unloading %s",
115 				MOD_HEADER(m_htm).name);
116 	}
117 #ifndef NO_FDLIST
118 	LockEventSystem();
119 	EventDel(e_lcf);
120 	EventDel(e_htmcalc);
121 	UnlockEventSystem();
122 #endif
123 	return MOD_SUCCESS;
124 }
125 
126 /* m_htm recoded by griever
127 parameters
128 
129 HTM [server] [command] [param]
130 */
131 
m_htm(aClient * cptr,aClient * sptr,int parc,char * parv[])132 DLLFUNC int m_htm(aClient *cptr, aClient *sptr, int parc, char *parv[])
133 {
134 	int  x = HUNTED_NOSUCH;
135 	char *command, *param;
136 	if (!IsOper(sptr))
137 	{
138 		sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, sptr->name);
139 		return 0;
140 	}
141 
142 	switch(parc) {
143 		case 1:
144 			break;
145 		case 2:
146 			x = hunt_server_token_quiet(cptr, sptr, MSG_HTM, TOK_HTM, "%s", 1, parc, parv);
147 			break;
148 		case 3:
149 			x = hunt_server_token_quiet(cptr, sptr, MSG_HTM, TOK_HTM, "%s %s", 1, parc, parv);
150 			break;
151 		default:
152 			x = hunt_server_token_quiet(cptr, sptr, MSG_HTM, TOK_HTM, "%s %s %s", 1, parc, parv);
153 	}
154 
155 	switch (x) {
156 		case HUNTED_NOSUCH:
157 			command = (parv[1]);
158 			param = (parv[2]);
159 			break;
160 		case HUNTED_ISME:
161 			command = (parv[2]);
162 			param = (parv[3]);
163 			break;
164 		default:
165 			return 0;
166 	}
167 
168 #ifndef NO_FDLIST
169 
170 	if (!command)
171 	{
172 		sendto_one(sptr,
173 		    ":%s NOTICE %s :*** Current incoming rate: %0.2f kb/s",
174 		    me.name, parv[0], currentrate);
175 		sendto_one(sptr,
176 		    ":%s NOTICE %s :*** Current outgoing rate: %0.2f kb/s",
177 		    me.name, parv[0], currentrate2);
178 		sendto_one(sptr,
179 		    ":%s NOTICE %s :*** Highest incoming rate: %0.2f kb/s",
180 		    me.name, parv[0], highest_rate);
181 		sendto_one(sptr,
182 		    ":%s NOTICE %s :*** Highest outgoing rate: %0.2f kb/s",
183 		    me.name, parv[0], highest_rate2);
184 		sendto_one(sptr,
185 		    ":%s NOTICE %s :*** High traffic mode is currently \2%s\2",
186 		    me.name, parv[0], (lifesux ? "ON" : "OFF"));
187 		sendto_one(sptr,
188 		    ":%s NOTICE %s :*** High traffic mode is currently in \2%s\2 mode",
189 		    me.name, parv[0], (noisy_htm ? "NOISY" : "QUIET"));
190 		sendto_one(sptr,
191 		    ":%s NOTICE %s :*** HTM will be activated if incoming > %i kb/s",
192 		    me.name, parv[0], LRV);
193 	}
194 
195 	else
196 	{
197 		if (!stricmp(command, "ON"))
198 		{
199 			EventInfo mod;
200 			lifesux = 1;
201 			sendto_one(sptr,
202 			    ":%s NOTICE %s :High traffic mode is now ON.",
203 			    me.name, parv[0]);
204 			sendto_ops
205 			    ("%s (%s@%s) forced High traffic mode to activate",
206 			    parv[0], sptr->user->username,
207 			    GetHost(sptr));
208 			LCF = 60;	/* 60 seconds */
209 			mod.flags = EMOD_EVERY;
210 			mod.every = LCF;
211 			LockEventSystem();
212 			EventMod(e_lcf, &mod);
213 			UnlockEventSystem();
214 		}
215 		else if (!stricmp(command, "OFF"))
216 		{
217 			EventInfo mod;
218 			lifesux = 0;
219 			LCF = LOADCFREQ;
220 			mod.flags = EMOD_EVERY;
221 			mod.every = LCF;
222 			LockEventSystem();
223 			EventMod(e_lcf, &mod);
224 			UnlockEventSystem();
225 			sendto_one(sptr,
226 			    ":%s NOTICE %s :High traffic mode is now OFF.",
227 			    me.name, parv[0]);
228 			sendto_ops
229 			    ("%s (%s@%s) forced High traffic mode to deactivate",
230 			    parv[0], sptr->user->username,
231 			    GetHost(sptr));
232 		}
233 		else if (!stricmp(command, "TO"))
234 		{
235 			if (!param)
236 				sendto_one(sptr,
237 				    ":%s NOTICE %s :You must specify an integer value",
238 				    me.name, parv[0]);
239 			else
240 			{
241 				int  new_val = atoi(param);
242 				if (new_val < 10)
243 					sendto_one(sptr,
244 					    ":%s NOTICE %s :New value must be > 10",
245 					    me.name, parv[0]);
246 				else
247 				{
248 					LRV = new_val;
249 					sendto_one(sptr,
250 					    ":%s NOTICE %s :New max rate is %dkb/s",
251 					    me.name, parv[0], LRV);
252 					sendto_ops
253 					    ("%s (%s@%s) changed the High traffic mode max rate to %dkb/s",
254 					    parv[0], sptr->user->username,
255 					    GetHost(sptr), LRV);
256 				}
257 			}
258 		}
259 		else if (!stricmp(command, "QUIET"))
260 		{
261 			noisy_htm = 0;
262 			sendto_one(sptr,
263 			    ":%s NOTICE %s :High traffic mode is now QUIET",
264 			    me.name, parv[0]);
265 			sendto_ops("%s (%s@%s) set High traffic mode to QUIET",
266 			    parv[0], sptr->user->username,
267 			    GetHost(sptr));
268 		}
269 
270 		else if (!stricmp(command, "NOISY"))
271 		{
272 			noisy_htm = 1;
273 			sendto_one(sptr,
274 			    ":%s NOTICE %s :High traffic mode is now NOISY",
275 			    me.name, parv[0]);
276 			sendto_ops("%s (%s@%s) set High traffic mode to NOISY",
277 			    parv[0], sptr->user->username,
278 			    GetHost(sptr));
279 		}
280 		else
281 			sendto_one(sptr, ":%s NOTICE %s :Unknown option: %s",
282 			    me.name, parv[0], command);
283 	}
284 
285 
286 #else
287 	sendto_one(sptr,
288 	    ":%s NOTICE %s :*** High traffic mode and fdlists are not enabled on this server",
289 	    me.name, sptr->name);
290 #endif
291 	return 0;
292 }
293 
294 #ifndef NO_FDLIST
295 
EVENT(lcf_check)296 EVENT(lcf_check)
297 {
298 	static int lrv;
299 
300 	lrv = LRV * LCF;
301 	if ((me.receiveK - lrv >= lastrecvK) || HTMLOCK == 1)
302 	{
303 		if (!lifesux)
304 		{
305 
306 			lifesux = 1;
307 			if (noisy_htm)
308 				sendto_realops
309 					    ("Entering high-traffic mode (incoming = %0.2f kb/s (LRV = %dk/s, outgoing = %0.2f kb/s currently)",
310 					    currentrate, LRV,
311 						   currentrate2);}
312 			else
313 			{
314 				EventInfo mod;
315 				lifesux++;	/* Ok, life really sucks! */
316 				LCF += 2;	/* wait even longer */
317 				mod.flags = EMOD_EVERY;
318 				mod.every = LCF;
319 				EventMod(e_lcf, &mod);
320 				if (noisy_htm)
321 					sendto_realops
322 					    ("Still high-traffic mode %d%s (%d delay): %0.2f kb/s",
323 					    lifesux,
324 					    (lifesux >
325 					    9) ? " (TURBO)" :
326 					    "", (int)LCF, currentrate);
327 				/* Reset htm here, because its been on a little too long.
328 				 * Bad Things(tm) tend to happen with HTM on too long -epi */
329 				if (lifesux > 15)
330 				{
331 					EventInfo mod;
332 					if (noisy_htm)
333 						sendto_realops
334 						    ("Resetting HTM and raising limit to: %dk/s\n",
335 						    LRV + 5);
336 					LCF = LOADCFREQ;
337 					mod.flags = EMOD_EVERY;
338 					mod.every = LCF;
339 					EventMod(e_lcf, &mod);
340 					lifesux = 0;
341 					LRV += 5;
342 				}
343 			}
344 		}
345 		else
346 		{
347 			EventInfo mod;
348 			LCF = LOADCFREQ;
349 			mod.flags = EMOD_EVERY;
350 			mod.every = LCF;
351 			EventMod(e_lcf, &mod);
352 			if (lifesux)
353 			{
354 				lifesux = 0;
355 				if (noisy_htm)
356 					sendto_realops
357 					    ("Resuming standard operation (incoming = %0.2f kb/s, outgoing = %0.2f kb/s now)",
358 					    currentrate, currentrate2);
359 			}
360 		}
361 }
362 
EVENT(htm_calc)363 EVENT(htm_calc)
364 {
365 	static time_t last = 0;
366 	if (last == 0)
367 		last = TStime();
368 
369 	if (timeofday - last == 0)
370 		return;
371 
372 	currentrate =
373 		   ((float)(me.receiveK -
374 		    lastrecvK)) / ((float)(timeofday - last));
375 	currentrate2 =
376 		   ((float)(me.sendK -
377 			 lastsendK)) / ((float)(timeofday - last));
378 	if (currentrate > highest_rate)
379 			highest_rate = currentrate;
380 	if (currentrate2 > highest_rate2)
381 			highest_rate2 = currentrate2;
382 	last = TStime();
383 }
384 #endif
385 
htm_config_test(ConfigFile * cf,ConfigEntry * ce,int type,int * errs)386 DLLFUNC int htm_config_test(ConfigFile *cf, ConfigEntry *ce, int type, int *errs) {
387 	ConfigEntry *cep;
388 	int errors = 0;
389 
390 	if (type != CONFIG_SET)
391 		return 0;
392 
393 	if (!strcmp(ce->ce_varname, "htm"))
394 	{
395 		for (cep = ce->ce_entries; cep; cep = cep->ce_next)
396 		{
397 			if (!cep->ce_varname)
398 			{
399 				config_error("%s:%i: blank set::htm item",
400 					cep->ce_fileptr->cf_filename,
401 					cep->ce_varlinenum);
402 				errors++;
403 				continue;
404 			}
405 			if (!cep->ce_vardata)
406 			{
407 				config_error("%s:%i: set::htm::%s item without value",
408 					cep->ce_fileptr->cf_filename,
409 					cep->ce_varlinenum, cep->ce_varname);
410 				errors++;
411 				continue;
412 			}
413 			if (!strcmp(cep->ce_varname, "mode"))
414 			{
415 
416 				if (stricmp(cep->ce_vardata, "noisy") && stricmp(cep->ce_vardata, "quiet"))
417 				{
418 					config_error("%s%i: set::htm::mode: illegal mode",
419 						cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
420 					errors++;
421 				}
422 			}
423 			else if (!strcmp(cep->ce_varname, "incoming-rate"))
424 			{
425 				int value = config_checkval(cep->ce_vardata, CFG_SIZE);
426 				if (value < 10240)
427 				{
428 					config_error("%s%i: set::htm::incoming-rate: must be at least 10kb",
429 						cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
430 					errors++;
431 				}
432 			}
433 			else
434 			{
435 				config_error("%s:%i: unknown directive set::htm::%s",
436 					cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
437 					cep->ce_varname);
438 				errors++;
439 			}
440 
441 		}
442 		*errs = errors;
443 		return errors ? -1 : 1;
444 	}
445 	else
446 		return 0;
447 }
448 
htm_config_run(ConfigFile * cf,ConfigEntry * ce,int type)449 DLLFUNC int htm_config_run(ConfigFile *cf, ConfigEntry *ce, int type) {
450 	ConfigEntry *cep;
451 
452 	if (type != CONFIG_SET)
453 		return 0;
454 	if (!strcmp(ce->ce_varname, "htm"))
455 	{
456 		for (cep = ce->ce_entries; cep; cep = cep->ce_next)
457 		{
458 			if (!strcmp(cep->ce_varname, "mode"))
459 			{
460 				if (!stricmp(cep->ce_vardata, "noisy"))
461 					noisy_htm = 1;
462 				else
463 					noisy_htm = 0;
464 			}
465 			else if (!strcmp(cep->ce_varname, "incoming-rate"))
466 			{
467 				LRV = config_checkval(cep->ce_vardata, CFG_SIZE);
468 				LRV /= 1024;
469 			}
470 		}
471 		return 1;
472 	}
473 	return 0;
474 }
475 
htm_stats(aClient * sptr,char * stats)476 DLLFUNC int htm_stats(aClient *sptr, char *stats) {
477 	if (*stats == 'S') {
478 		sendto_one(sptr, ":%s %i %s :htm::mode: %s", me.name, RPL_TEXT,
479 			   sptr->name, noisy_htm ? "noisy" : "quiet");
480 		sendto_one(sptr, ":%s %i %s :htm::incoming-rate: %d kb/s", me.name, RPL_TEXT,
481 			   sptr->name, LRV);
482 	}
483         return 0;
484 }
485