"SfR Fresh" - the SfR Freeware/Shareware Archive 
Member "mod-cband-0.9.7.5/src/mod_cband.c" of archive mod-cband-0.9.7.5.tgz:
As a special service "SfR Fresh" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting with prefixed line numbers.
Alternatively you can here view or download the uninterpreted source code file.
That can be also achieved for any archive member file by clicking within an archive contents listing on the first character of the file(path) respectively on the according byte size field.
1 /*
2 * $Id: mod_cband.c,v 1.20 2006/05/28 18:58:35 dembol Exp $
3 *
4 * mod_cband - A per-user, per-virtualhost and per-destination bandwidth limiter for the Apache HTTP Server Version 2
5 *
6 * Copyright (c) 2005 Lukasz Dembinski <dembol@cband.linux.pl>
7 * All Rights Reserved
8 *
9 * Date: 2006/05/28
10 * Info: mod_cband Apache 2 module
11 * Contact: mailto: <dembol@cband.linux.pl>
12 * Version: 0.9.7.5
13 * Phase: stabilization
14 *
15 * Authors:
16 * - Lukasz Dembinski <dembol@cband.linux.pl>
17 * - Sergey V. Beduev <shaman@interdon.net>
18 * - Kyle Poulter <kyle@unixowns.us>
19 * - Adam Dawidowski <drake@oomkill.net>
20 * - Arvind Srinivasan <arvind@madtux.org>
21 *
22 * This program is free software; you can redistribute it and/or modify
23 * it under the terms of the GNU General Public License as published by
24 * the Free Software Foundation; either version 2 of the License, or
25 * (at your option) any later version.
26 *
27 * This program is distributed in the hope that it will be useful,
28 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 * GNU General Public License for more details.
31 *
32 * You should have received a copy of the GNU General Public License
33 * along with this program; if not, write to the Free Software
34 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
35 *
36 */
37
38 #include "httpd.h"
39 #include "http_main.h"
40 #include "http_core.h"
41 #include "http_config.h"
42 #include "http_request.h"
43 #include "http_protocol.h"
44 #include "http_log.h"
45 #include "apr_strings.h"
46 #include "apr_file_io.h"
47 #include "apr_file_info.h"
48 #include "apr_signal.h"
49 #include "apr_hash.h"
50 #include "apr_time.h"
51 #include "apr_pools.h"
52 #include "apr_shm.h"
53 #include "util_filter.h"
54 #include "util_cfgtree.h"
55 #include <sys/shm.h>
56 #include <sys/types.h>
57 #include <sys/ipc.h>
58 #include <sys/sem.h>
59 #include <unistd.h>
60
61 #include "mod_cband.h"
62
63 #if defined(__sun) || defined(__sun__)
64 static inline float logf (float x) { return log (x); }
65 static inline float sqrtf (float x) { return sqrt (x); }
66 static inline float floorf (float x) { return floor (x); }
67 static inline float powf (float x, float y) { return pow (x,y); }
68 #endif
69
70 #if defined(__FreeBSD__) || defined(__OpenBSD__) || \
71 defined(__sun) || defined(__sun__) // no truncf on FreeBSD, OpenBSD and SUN
72 inline float truncf (float d) {
73 return (d < 0) ? -floorf(-d) : floorf(d);
74 }
75 #endif
76
77 static mod_cband_config_header *config = NULL;
78 static const char mod_cband_filter_name[] = "CBAND_FILTER";
79 ap_filter_rec_t *mod_cband_output_filter_handle;
80 apr_status_t patricia_cleanup(void *);
81 const void mod_cband_signal_handler(int);
82 unsigned long mod_cband_conf_get_period_sec(char *period);
83 unsigned long mod_cband_conf_get_limit_kb(char *limit, unsigned int *mult);
84 unsigned long mod_cband_conf_get_speed_kbps(char *speed);
85
86 module AP_MODULE_DECLARE_DATA cband_module;
87
88 int mod_cband_shmem_seg_new(void)
89 {
90 int seg_idx;
91 int shmem_id;
92
93 seg_idx = ++config->shmem_seg_idx;
94 shmem_id = config->shmem_seg[seg_idx].shmem_id;
95
96 if (shmem_id == 0) {
97 shmem_id = shmget(IPC_PRIVATE, sizeof(mod_cband_shmem_data) * MAX_SHMEM_ENTRIES, IPC_CREAT | 0666);
98
99 if (shmem_id < 0) {
100 fprintf(stderr, "apache2_mod_cband: cannot create shared memory segment for virtual hosts\n");
101 fflush(stderr);
102 return -1;
103 }
104
105 config->shmem_seg[seg_idx].shmem_id = shmem_id;
106 config->shmem_seg[seg_idx].shmem_data = (mod_cband_shmem_data *)shmat(shmem_id, 0, 0);
107 memset(config->shmem_seg[seg_idx].shmem_data, 0, sizeof(mod_cband_shmem_data) * MAX_SHMEM_ENTRIES);
108 }
109
110 config->shmem_seg[seg_idx].shmem_entry_idx = 0;
111
112 return seg_idx;
113 }
114
115 mod_cband_shmem_data *mod_cband_shmem_init(void)
116 {
117 mod_cband_shmem_data *data;
118 int seg_idx, entry_idx;
119
120 seg_idx = config->shmem_seg_idx;
121 if ((seg_idx < 0) || (config->shmem_seg[seg_idx].shmem_entry_idx >= MAX_SHMEM_ENTRIES - 1))
122 config->shmem_seg_idx = seg_idx = mod_cband_shmem_seg_new();
123
124 if (seg_idx < 0)
125 return NULL;
126
127 entry_idx = config->shmem_seg[seg_idx].shmem_entry_idx++;
128 data = (mod_cband_shmem_data *)(config->shmem_seg[seg_idx].shmem_data + entry_idx * sizeof(mod_cband_shmem_data));
129 data->total_last_refresh = apr_time_now();
130
131 return data;
132 }
133
134 void mod_cband_shmem_remove(int shmem_id)
135 {
136 shmctl(shmem_id, IPC_RMID, 0);
137 }
138
139 void mod_cband_sem_init(int sem_id)
140 {
141 union semun arg;
142 unsigned short values[1];
143
144 values[0] = 1;
145 arg.val = 1;
146 arg.array = values;
147
148 semctl(sem_id, 0, SETALL, arg);
149
150 /*
151 * We should also set owner of the semaphore ...
152 */
153 }
154
155 void mod_cband_sem_remove(int sem_id)
156 {
157 union semun arg;
158
159 arg.val = 0;
160 semctl(sem_id, 0, IPC_RMID, arg);
161 }
162
163 void mod_cband_sem_down(int sem_id)
164 {
165 struct sembuf sops;
166
167 sops.sem_num = 0;
168 sops.sem_op = -1;
169 sops.sem_flg = SEM_UNDO;
170
171 semop(sem_id, &sops, 1);
172 }
173
174 void mod_cband_sem_up(int sem_id)
175 {
176 struct sembuf sops;
177
178 sops.sem_num = 0;
179 sops.sem_op = 1;
180 sops.sem_flg = SEM_UNDO;
181
182 semop(sem_id, &sops, 1);
183 }
184
185 int mod_cband_remote_hosts_init(void)
186 {
187 int shmem_id, sem_id;
188 int seg_size;
189
190 shmem_id = config->remote_hosts.shmem_id;
191 seg_size = sizeof(mod_cband_remote_host) * MAX_REMOTE_HOSTS;
192
193 if (shmem_id == 0) {
194 config->remote_hosts.shmem_id = shmem_id = shmget(IPC_PRIVATE, seg_size , IPC_CREAT | 0666);
195 if (shmem_id < 0) {
196 fprintf(stderr, "apache2_mod_cband: cannot create shared memory segment for remote hosts\n");
197 fflush(stderr);
198 return -1;
199 }
200
201 config->remote_hosts.hosts = (mod_cband_remote_host *)shmat(shmem_id, 0, 0);
202 }
203
204 if (config->remote_hosts.hosts != NULL)
205 memset(config->remote_hosts.hosts, 0, seg_size);
206
207 config->remote_hosts.sem_id = sem_id = semget(IPC_PRIVATE, 1, IPC_CREAT | 0666);
208 mod_cband_sem_init(sem_id);
209
210 return 0;
211 }
212
213 /**
214 * get virtualhost entry or create new one
215 */
216 mod_cband_virtualhost_config_entry *mod_cband_get_virtualhost_entry_(char *virtualhost, apr_port_t port, unsigned line, int create)
217 {
218 mod_cband_virtualhost_config_entry *entry;
219 mod_cband_virtualhost_config_entry *new_entry;
220 int i;
221
222 if (virtualhost == NULL || config == NULL)
223 return NULL;
224
225 entry = config->next_virtualhost;
226
227 while(entry != NULL) {
228
229 if (!strcmp(entry->virtual_name, virtualhost) && (line == entry->virtual_defn_line))
230 return entry;
231
232 if (entry->next == NULL)
233 break;
234
235 entry = entry->next;
236 }
237
238 if (create) {
239 if ((new_entry = apr_palloc(config->p, sizeof(mod_cband_virtualhost_config_entry))) == NULL) {
240 fprintf(stderr, "apache2_mod_cband: cannot alloc memory for virtualhost entry\n");
241 fflush(stderr);
242 return NULL;
243 }
244
245 memset(new_entry, 0, sizeof(mod_cband_virtualhost_config_entry));
246 new_entry->virtual_name = virtualhost;
247 new_entry->virtual_defn_line = line;
248 new_entry->virtual_port = port;
249 new_entry->virtual_limit_mult = 1024;
250
251 if (new_entry->shmem_data == NULL)
252 new_entry->shmem_data = mod_cband_shmem_init();
253
254 for (i = 0; i < DST_CLASS; i++)
255 new_entry->virtual_class_limit_mult[i] = 1024;
256
257 if (entry == NULL)
258 config->next_virtualhost = new_entry;
259 else
260 entry->next = new_entry;
261
262 return new_entry;
263 }
264
265 return NULL;
266 }
267
268 mod_cband_virtualhost_config_entry *mod_cband_get_virtualhost_entry(server_rec *s, ap_conf_vector_t *module_config, int create)
269 {
270 char *virtualhost;
271 apr_port_t port;
272 unsigned line;
273
274 if (s == NULL)
275 return NULL;
276
277 virtualhost = s->server_hostname;
278 port = s->port;
279 line = s->defn_line_number;
280
281 return mod_cband_get_virtualhost_entry_(virtualhost, port, line, create);
282 }
283
284 /**
285 * get user entry or create new one
286 */
287 mod_cband_user_config_entry *mod_cband_get_user_entry(char *user, ap_conf_vector_t *module_config, int create)
288 {
289 mod_cband_user_config_entry *entry;
290 mod_cband_user_config_entry *new_entry;
291 int i;
292
293 if (user == NULL || config == NULL)
294 return NULL;
295
296 entry = config->next_user;
297
298 while(entry != NULL) {
299 if (!strcmp(entry->user_name, user))
300 return entry;
301
302 if (entry->next == NULL)
303 break;
304
305 entry = entry->next;
306 }
307
308 if (create) {
309 if ((new_entry = apr_palloc(config->p, sizeof(mod_cband_user_config_entry))) == NULL) {
310 fprintf(stderr, "apache2_mod_cband: cannot alloc memory for user entry\n");
311 fflush(stderr);
312 return NULL;
313 }
314
315 memset(new_entry, 0, sizeof(mod_cband_user_config_entry));
316 new_entry->user_name = user;
317 new_entry->user_limit_mult = 1024;
318
319 if (new_entry->shmem_data == NULL)
320 new_entry->shmem_data = mod_cband_shmem_init();
321
322 for (i = 0; i < DST_CLASS; i++)
323 new_entry->user_class_limit_mult[i] = 1024;
324
325 if (entry == NULL)
326 config->next_user = new_entry;
327 else
328 entry->next = new_entry;
329
330 return new_entry;
331 }
332
333 return NULL;
334 }
335
336 /**
337 * get class entry or create new one
338 */
339 mod_cband_class_config_entry *mod_cband_get_class_entry(char *dest, ap_conf_vector_t *module_config, int create)
340 {
341 mod_cband_class_config_entry *entry;
342 mod_cband_class_config_entry *new_entry;
343
344 if (dest == NULL || config == NULL)
345 return NULL;
346
347 entry = config->next_class;
348
349 while(entry != NULL) {
350 if (!strcmp(entry->class_name, dest))
351 return entry;
352
353 if (entry->next == NULL)
354 break;
355
356 entry = entry->next;
357 }
358
359 if (create) {
360 if ((new_entry = apr_palloc(config->p, sizeof(mod_cband_class_config_entry))) == NULL) {
361 fprintf(stderr, "apache2_mod_cband: cannot alloc memory for class entry\n");
362 fflush(stderr);
363 return NULL;
364 }
365
366 memset(new_entry, 0, sizeof(mod_cband_class_config_entry));
367 new_entry->class_name = dest;
368
369 if (entry == NULL)
370 config->next_class = new_entry;
371 else
372 entry->next = new_entry;
373
374 return new_entry;
375 }
376
377 return NULL;
378 }
379
380 static char *username_arg = NULL;
381 static char *classname_arg = NULL;
382 int class_nr = -1;
383
384 int mod_cband_check_duplicate(void *ptr, const char *command, const char *arg, server_rec *s)
385 {
386 if (ptr != NULL) {
387 if (s->server_hostname != NULL)
388 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, "Duplicate command '%s' for %s:%d", (char *)command, s->server_hostname, s->defn_line_number);
389 else
390 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, "Duplicate command '%s'", (char *)command);
391
392 return 1;
393 }
394
395 return 0;
396 }
397
398 int mod_cband_check_virtualhost_command(mod_cband_virtualhost_config_entry **entry, cmd_parms *parms, const char *command)
399 {
400 if ((*entry = mod_cband_get_virtualhost_entry(parms->server, parms->server->module_config, 1)) == NULL) {
401 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, parms->server, "Invalid command '%s', undefined virtualhost name", command);
402 return 0;
403 }
404
405 return 1;
406 }
407
408 int mod_cband_check_virtualhost_class_command(mod_cband_virtualhost_config_entry **entry_virtual, mod_cband_class_config_entry **entry, cmd_parms *parms, const char *command, const char *arg)
409 {
410 if ((*entry = mod_cband_get_class_entry((char *)arg, parms->server->module_config, 0)) == NULL) {
411 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, parms->server, "Invalid command '%s', undefined class name", (char *)command);
412 return 0;
413 }
414
415 if (!mod_cband_check_virtualhost_command(entry_virtual, parms, command))
416 return 0;
417
418 return 1;
419 }
420
421 int mod_cband_check_user_command(mod_cband_user_config_entry **entry, cmd_parms *parms, const char *command, const char **err)
422 {
423 *err = NULL;
424
425 if ((*err = ap_check_cmd_context(parms, GLOBAL_ONLY)) != NULL)
426 return 0;
427
428 if ((*entry = mod_cband_get_user_entry(username_arg, parms->server->module_config, 0)) == NULL) {
429 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, parms->server, "Invalid command '%s', undefined user name", (char *)command);
430 return 0;
431 }
432
433 return 1;
434 }
435
436 static const char *mod_cband_set_default_url(cmd_parms *parms, void *mconfig, const char *arg)
437 {
438 if (!mod_cband_check_duplicate(config->default_limit_exceeded, "CBandDefaultExceededURL", arg, parms->server))
439 config->default_limit_exceeded = (char *)arg;
440
441 return NULL;
442 }
443
444 static const char *mod_cband_set_default_code(cmd_parms *parms, void *mconfig, const char *arg)
445 {
446 config->default_limit_exceeded_code = atoi((char *)arg);
447
448 return NULL;
449 }
450
451 static const char *mod_cband_set_random_pulse(cmd_parms *parms, void *mconfig, int flag)
452 {
453 const char *flag_str;
454
455 if (flag)
456 flag_str = "On";
457 else
458 flag_str = "Off";
459
460 if (!mod_cband_check_duplicate((void *)config->random_pulse, "CBandRandomPulse", flag_str, parms->server))
461 config->random_pulse = (unsigned long)flag;
462
463 return NULL;
464 }
465
466 static const char *mod_cband_set_score_flush_period(cmd_parms *parms, void *mconfig, const char *arg)
467 {
468 if (!mod_cband_check_duplicate((void *)config->score_flush_period, "CBandScoreFlushPeriod", arg, parms->server))
469 config->score_flush_period = atol((char *)arg);
470
471 return NULL;
472 }
473
474 static const char *mod_cband_set_limit(cmd_parms *parms, void *mconfig, const char *arg)
475 {
476 mod_cband_virtualhost_config_entry *entry;
477
478 if (mod_cband_check_virtualhost_command(&entry, parms, "CBandLimit") &&
479 (!mod_cband_check_duplicate((void *)entry->virtual_limit, "CBandLimit", arg, parms->server)))
480 entry->virtual_limit = mod_cband_conf_get_limit_kb((char *)arg, &entry->virtual_limit_mult);
481
482 return NULL;
483 }
484
485 static const char *mod_cband_set_period(cmd_parms *parms, void *mconfig, const char *arg)
486 {
487 mod_cband_virtualhost_config_entry *entry;
488
489 if (mod_cband_check_virtualhost_command(&entry, parms, "CBandPeriod") &&
490 (!mod_cband_check_duplicate((void *)entry->refresh_time, "CBandPeriod", arg, parms->server)))
491 entry->refresh_time = mod_cband_conf_get_period_sec((char *)arg);
492
493 return NULL;
494 }
495
496 static const char *mod_cband_set_period_slice(cmd_parms *parms, void *mconfig, const char *arg)
497 {
498 mod_cband_virtualhost_config_entry *entry;
499
500 if (mod_cband_check_virtualhost_command(&entry, parms, "CBandPeriodSlice") &&
501 (!mod_cband_check_duplicate((void *)entry->slice_len, "CBandPeriodSlice", arg, parms->server)))
502 entry->slice_len = mod_cband_conf_get_period_sec((char *)arg);
503
504 return NULL;
505 }
506
507 static const char *mod_cband_set_url(cmd_parms *parms, void *mconfig, const char *arg)
508 {
509 mod_cband_virtualhost_config_entry *entry;
510
511 if (mod_cband_check_virtualhost_command(&entry, parms, "CBandExceededURL") &&
512 (!mod_cband_check_duplicate(entry->virtual_limit_exceeded, "CBandExceededURL", arg, parms->server)))
513 entry->virtual_limit_exceeded = (char *)arg;
514
515 return NULL;
516 }
517
518 static const char *mod_cband_set_speed(cmd_parms *parms, void *mconfig, const char *arg1, const char *arg2, const char *arg3)
519 {
520 mod_cband_virtualhost_config_entry *entry;
521
522 if (mod_cband_check_virtualhost_command(&entry, parms, "CBandSpeed") &&
523 (!mod_cband_check_duplicate((void *)entry->shmem_data->max_speed.kbps, "CBandSpeed", arg1, parms->server))) {
524 entry->shmem_data->max_speed.kbps = entry->shmem_data->curr_speed.kbps = mod_cband_conf_get_speed_kbps((char *)arg1);
525 entry->shmem_data->max_speed.rps = entry->shmem_data->curr_speed.rps = atol((char *)arg2);
526 entry->shmem_data->max_speed.max_conn = entry->shmem_data->curr_speed.max_conn = atol((char *)arg3);
527 entry->shmem_data->shared_kbps = entry->shmem_data->curr_speed.kbps;
528 }
529
530 return NULL;
531 }
532
533 static const char *mod_cband_set_remote_speed(cmd_parms *parms, void *mconfig, const char *arg1, const char *arg2, const char *arg3)
534 {
535 mod_cband_virtualhost_config_entry *entry;
536
537 if (mod_cband_check_virtualhost_command(&entry, parms, "CBandRemoteSpeed") &&
538 (!mod_cband_check_duplicate((void *)entry->shmem_data->remote_speed.kbps, "CBandRemoteSpeed", arg1, parms->server))) {
539 entry->shmem_data->remote_speed.kbps = mod_cband_conf_get_speed_kbps((char *)arg1);
540 entry->shmem_data->remote_speed.rps = atol((char *)arg2);
541 entry->shmem_data->remote_speed.max_conn = atol((char *)arg3);
542 }
543
544 return NULL;
545 }
546
547 char *mod_cband_get_next_char(const char *str, char val)
548 {
549 int i;
550
551 if (str == NULL)
552 return NULL;
553
554 for (i = 0; i < strlen(str); i++) {
555 if (str[i] == val) {
556 return (char *)(str + i);
557 }
558 }
559
560 return NULL;
561 }
562
563 char *mod_cband_get_next_notchar(const char *str, char val, int offset)
564 {
565 int i;
566 char *ptr;
567
568 if (str == NULL)
569 return NULL;
570
571 if (offset)
572 str += strlen(str) + 1;
573
574 for (i = 0; i < strlen(str); i++) {
575 if (str[i] != val) {
576 if ((ptr = mod_cband_get_next_char(str, val)) != NULL)
577 *ptr = 0;
578
579 return (char *)(str + i);
580 }
581 }
582
583 return NULL;
584 }
585
586 static const char *mod_cband_set_class_remote_speed(cmd_parms *parms, void *mconfig, const char *args)
587 {
588 mod_cband_class_config_entry *entry;
589 mod_cband_virtualhost_config_entry *entry_virtual;
590 char *arg1, *arg2, *arg3, *arg4;
591
592 arg1 = mod_cband_get_next_notchar(args, ' ', 0);
593 arg2 = mod_cband_get_next_notchar((const char *)arg1, ' ', 1);
594 arg3 = mod_cband_get_next_notchar((const char *)arg2, ' ', 1);
595 arg4 = mod_cband_get_next_notchar((const char *)arg3, ' ', 1);
596
597 if (arg1 == NULL || arg2 == NULL || arg3 == NULL || arg4 == NULL) {
598 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, parms->server, "CBandClassRemoteSpeed takes four arguments");
599 return NULL;
600 }
601
602 if (mod_cband_check_virtualhost_class_command(&entry_virtual, &entry, parms, "CBandClassRemoteSpeed", arg1)) {
603 entry_virtual->virtual_class_speed[entry->class_nr].kbps = mod_cband_conf_get_speed_kbps((char *)arg2);
604 entry_virtual->virtual_class_speed[entry->class_nr].rps = atol((char *)arg3);
605 entry_virtual->virtual_class_speed[entry->class_nr].max_conn = atol((char *)arg4);
606 }
607
608 return NULL;
609 }
610
611 static const char *mod_cband_set_exceeded_speed(cmd_parms *parms, void *mconfig, const char *arg1, const char *arg2, const char *arg3)
612 {
613 mod_cband_virtualhost_config_entry *entry;
614
615 if (mod_cband_check_virtualhost_command(&entry, parms, "CBandExceededSpeed") &&
616 (!mod_cband_check_duplicate((void *)entry->shmem_data->over_speed.kbps, "CBandExceededSpeed", arg1, parms->server))) {
617 entry->shmem_data->over_speed.kbps = mod_cband_conf_get_speed_kbps((char *)arg1);
618 entry->shmem_data->over_speed.rps = atol((char *)arg2);
619 entry->shmem_data->over_speed.max_conn = atol((char *)arg3);
620 }
621
622 return NULL;
623 }
624
625 static const char *mod_cband_set_scoreboard(cmd_parms *parms, void *mconfig, const char *arg)
626 {
627 mod_cband_virtualhost_config_entry *entry;
628
629 if (mod_cband_check_virtualhost_command(&entry, parms, "CBandScoreboard") &&
630 (!mod_cband_check_duplicate(entry->virtual_scoreboard, "CBandScoreboard", arg, parms->server)))
631 entry->virtual_scoreboard = (char *)arg;
632
633 return NULL;
634 }
635
636 static const char *mod_cband_set_user(cmd_parms *parms, void *mconfig, const char *arg)
637 {
638 mod_cband_virtualhost_config_entry *entry;
639
640 if ((entry = mod_cband_get_virtualhost_entry(parms->server, parms->server->module_config, 1)) == NULL) {
641 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, parms->server, "Invalid command 'CBandUser %s', undefined virtualhost name", (char *)arg);
642 return NULL;
643 }
644
645 if (mod_cband_get_user_entry((char *)arg, parms->server->module_config, 0) == NULL) {
646 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, parms->server, "Invalid command 'CBandUser %s', undefined user", (char *)arg);
647 return NULL;
648 }
649
650 if (!mod_cband_check_duplicate(entry->virtual_user, "CBandUser", arg, parms->server))
651 entry->virtual_user = (char *)arg;
652
653 return NULL;
654 }
655
656 static const char *mod_cband_user_section(cmd_parms *parms, void *mconfig, const char *arg)
657 {
658 mod_cband_user_config_entry *entry;
659 const char *endp = ap_strrchr_c(arg, '>');
660 char *username;
661 const char *err;
662
663 if ((err = ap_check_cmd_context(parms, GLOBAL_ONLY)) != NULL)
664 return err;
665
666 if (endp == NULL)
667 return apr_pstrcat(parms->pool, parms->cmd->name, "> directive missing closing '>'", NULL);
668
669 username = apr_pstrndup(parms->pool, arg, endp - arg);
670
671 #ifdef DEBUG
672 fprintf(stderr, "apache2_mod_cband: user %s\n", username);
673 fflush(stderr);
674 #endif
675
676 if ((mod_cband_get_user_entry(username, parms->server->module_config, 0)) != NULL)
677 return apr_pstrcat(parms->pool, parms->cmd->name, " ", username, "> duplicate user definition", NULL);
678
679 if ((entry = mod_cband_get_user_entry(username, parms->server->module_config, 1)) == NULL)
680 return ap_walk_config(parms->directive->first_child, parms, parms->context);
681
682 entry->user_name = username;
683 username_arg = username;
684
685 return ap_walk_config(parms->directive->first_child, parms, parms->context);
686 }
687
688 static const char *mod_cband_set_user_limit(cmd_parms *parms, void *mconfig, const char *arg)
689 {
690 mod_cband_user_config_entry *entry;
691 const char *err;
692
693 if (mod_cband_check_user_command(&entry, parms, "CBandUserLimit", &err) &&
694 (!mod_cband_check_duplicate((void *)entry->user_limit, "CBandUserLimit", arg, parms->server)))
695 entry->user_limit = mod_cband_conf_get_limit_kb((char *)arg, &entry->user_limit_mult);
696
697 return err;
698 }
699
700 static const char *mod_cband_set_user_period(cmd_parms *parms, void *mconfig, const char *arg)
701 {
702 mod_cband_user_config_entry *entry;
703 const char *err;
704
705 if (mod_cband_check_user_command(&entry, parms, "CBandUserPeriod", &err) &&
706 (!mod_cband_check_duplicate((void *)entry->refresh_time, "CBandUserPeriod", arg, parms->server)))
707 entry->refresh_time = mod_cband_conf_get_period_sec((char *)arg);
708
709 return err;
710 }
711
712 static const char *mod_cband_set_user_period_slice(cmd_parms *parms, void *mconfig, const char *arg)
713 {
714 mod_cband_user_config_entry *entry;
715 const char *err;
716
717 if (mod_cband_check_user_command(&entry, parms, "CBandUserPeriodSlice", &err) &&
718 (!mod_cband_check_duplicate((void *)entry->slice_len, "CBandUserPeriodSlice", arg, parms->server)))
719 entry->slice_len = mod_cband_conf_get_period_sec((char *)arg);
720
721 return err;
722 }
723
724 static const char *mod_cband_set_user_url(cmd_parms *parms, void *mconfig, const char *arg)
725 {
726 mod_cband_user_config_entry *entry;
727 const char *err;
728
729 if (mod_cband_check_user_command(&entry, parms, "CBandUserExceededURL", &err) &&
730 (!mod_cband_check_duplicate(entry->user_limit_exceeded, "CBandUserExceededURL", arg, parms->server)))
731 entry->user_limit_exceeded = (char *)arg;
732
733 return err;
734 }
735
736 static const char *mod_cband_set_user_speed(cmd_parms *parms, void *mconfig, const char *arg1, const char *arg2, const char *arg3)
737 {
738 mod_cband_user_config_entry *entry;
739 const char *err;
740
741 if (mod_cband_check_user_command(&entry, parms, "CBandUserSpeed", &err) &&
742 (!mod_cband_check_duplicate((void *)entry->shmem_data->max_speed.kbps, "CBandUserSpeed", arg1, parms->server))) {
743 entry->shmem_data->max_speed.kbps = entry->shmem_data->curr_speed.kbps = mod_cband_conf_get_speed_kbps((char *)arg1);
744 entry->shmem_data->max_speed.rps = entry->shmem_data->curr_speed.rps = atol((char *)arg2);
745 entry->shmem_data->max_speed.max_conn = entry->shmem_data->curr_speed.max_conn = atol((char *)arg3);
746 entry->shmem_data->shared_kbps = entry->shmem_data->curr_speed.kbps;
747 }
748
749 return err;
750 }
751
752 static const char *mod_cband_set_user_remote_speed(cmd_parms *parms, void *mconfig, const char *arg1, const char *arg2, const char *arg3)
753 {
754 mod_cband_user_config_entry *entry;
755 const char *err;
756
757 if (mod_cband_check_user_command(&entry, parms, "CBandUserRemoteSpeed", &err) &&
758 (!mod_cband_check_duplicate((void *)entry->shmem_data->max_speed.kbps, "CBandUserRemoteSpeed", arg1, parms->server))) {
759 entry->shmem_data->remote_speed.kbps = mod_cband_conf_get_speed_kbps((char *)arg1);
760 entry->shmem_data->remote_speed.rps = atol((char *)arg2);
761 entry->shmem_data->remote_speed.max_conn = atol((char *)arg3);
762 }
763
764 return err;
765 }
766
767 static const char *mod_cband_set_user_exceeded_speed(cmd_parms *parms, void *mconfig, const char *arg1, const char *arg2, const char *arg3)
768 {
769 mod_cband_user_config_entry *entry;
770 const char *err;
771
772 if (mod_cband_check_user_command(&entry, parms, "CBandUserExceededSpeed", &err) &&
773 (!mod_cband_check_duplicate((void *)entry->shmem_data->over_speed.kbps, "CBandUserExceededSpeed", arg1, parms->server))) {
774 entry->shmem_data->over_speed.kbps = mod_cband_conf_get_speed_kbps((char *)arg1);
775 entry->shmem_data->over_speed.rps = atol((char *)arg2);
776 entry->shmem_data->over_speed.max_conn = atol((char *)arg3);
777 }
778
779 return err;
780 }
781
782 static const char *mod_cband_set_user_scoreboard(cmd_parms *parms, void *mconfig, const char *arg)
783 {
784 mod_cband_user_config_entry *entry;
785 const char *err;
786
787 if (mod_cband_check_user_command(&entry, parms, "CBandUserScoreboard", &err) &&
788 (!mod_cband_check_duplicate(entry->user_scoreboard, "CBandUserScoreboard", arg, parms->server)))
789 entry->user_scoreboard = (char *)arg;
790
791 return err;
792 }
793
794 int mod_cband_check_IP(char *addr)
795 {
796 int i;
797 int dig, dot, mask;
798 int len;
799
800 len = (strlen(addr) > MAX_DST_LEN)?MAX_DST_LEN:strlen(addr);
801
802 dig = 0;
803 dot = 0;
804 for (i = 0; i < len; i++) {
805 if (addr[i] >= '0' && addr[i] <= '9') {
806 if (++dig > 3)
807 return 0;
808 } else
809 if (addr[i] == '.') {
810 if (dig == 0)
811 return 0;
812
813 if (++dot > 3)
814 return 0;
815
816 dig = 0;
817 } else
818 if (addr[i] == '/') {
819 if (dig == 0)
820 return 0;
821
822 mask = atoi(&addr[i + 1]);
823 if (mask < 0 || mask > 32)
824 return 0;
825
826 return 1;
827 } else
828 return 0;
829 }
830
831 return 1;
832 }
833
834 static const char *mod_cband_class_section(cmd_parms *parms, void *mconfig, const char *arg)
835 {
836 mod_cband_class_config_entry *entry;
837 const char *endp = ap_strrchr_c(arg, '>');
838 char *classname;
839 const char *err;
840
841 class_nr++;
842
843 if (class_nr >= DST_CLASS)
844 return ap_walk_config(parms->directive->first_child, parms, parms->context);
845
846 if ((err = ap_check_cmd_context(parms, GLOBAL_ONLY)) != NULL)
847 return err;
848
849 if (endp == NULL)
850 return apr_pstrcat(parms->pool, parms->cmd->name, "> directive missing closing '>'", NULL);
851
852 classname = apr_pstrndup(parms->pool, arg, endp - arg);
853
854 #ifdef DEBUG
855 fprintf(stderr, "apache2_mod_cband: class %s (class %d)\n", classname, class_nr);
856 fflush(stderr);
857 #endif
858
859 if ((mod_cband_get_class_entry(classname, parms->server->module_config, 0)) != NULL)
860 return apr_pstrcat(parms->pool, parms->cmd->name, " ", classname, "> duplicate class definition", NULL);
861
862 if ((entry = mod_cband_get_class_entry(classname, parms->server->module_config, 1)) == NULL)
863 return ap_walk_config(parms->directive->first_child, parms, parms->context);
864
865 entry->class_name = classname;
866 entry->class_nr = class_nr;
867 classname_arg = classname;
868
869 return ap_walk_config(parms->directive->first_child, parms, parms->context);
870 }
871
872 static const char *mod_cband_set_class_dst(cmd_parms *parms, void *mconfig, const char *arg)
873 {
874 patricia_node_t *node;
875 char class_nr_str[MAX_CLASS_STR_LEN];
876
877 if (config->tree == NULL)
878 config->tree = New_Patricia(32);
879
880 if ((class_nr < DST_CLASS) && (mod_cband_check_IP((char *)arg))) {
881 #ifdef DEBUG
882 fprintf(stderr, "apache2_mod_cband: class dst %s (class %d)\n", (char *)arg, class_nr);
883 fflush(stderr);
884 #endif
885
886 sprintf(class_nr_str, "%d", class_nr);
887 node = make_and_lookup(config->tree, (char *)arg);
888
889 if (node)
890 node->user1 = apr_pstrdup(config->p, class_nr_str);
891 } else {
892 if (class_nr >= DST_CLASS) {
893 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, parms->server, "You can define only %d destination classes", DST_CLASS);
894 } else {
895 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, parms->server, "Invalid IP address %s", arg);
896 }
897 }
898
899 return NULL;
900 }
901
902 static const char *mod_cband_set_class_limit(cmd_parms *parms, void *mconfig, const char *arg, const char *limit)
903 {
904 mod_cband_class_config_entry *entry;
905 mod_cband_virtualhost_config_entry *entry_virtual;
906
907 if ((entry = mod_cband_get_class_entry((char *)arg, parms->server->module_config, 0)) == NULL) {
908 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, parms->server, "Invalid command 'CBandClassLimit %s %s', undefined class name", (char *)arg, (char *)limit);
909 return NULL;
910 }
911
912 if ((entry_virtual = mod_cband_get_virtualhost_entry(parms->server, parms->server->module_config, 1)) == NULL) {
913 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, parms->server, "Invalid command 'CBandClassLimit %s %s', undefined virtualhost name", (char *)arg, (char *)limit);
914 return NULL;
915 }
916
917 entry_virtual->virtual_class_limit[entry->class_nr] = mod_cband_conf_get_limit_kb((char *)limit,
918 &entry_virtual->virtual_class_limit_mult[entry->class_nr]);
919
920 return NULL;
921 }
922
923 static const char *mod_cband_set_user_class_limit(cmd_parms *parms, void *mconfig, const char *arg, const char *limit)
924 {
925 mod_cband_class_config_entry *entry;
926 mod_cband_user_config_entry *entry_user;
927 const char *err;
928
929 if ((err = ap_check_cmd_context(parms, GLOBAL_ONLY)) != NULL)
930 return err;
931
932 if ((entry = mod_cband_get_class_entry((char *)arg, parms->server->module_config, 0)) == NULL) {
933 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, parms->server, "Invalid command 'CBandUserClassLimit %s %s', undefined class name", (char *)arg, (char *)limit);
934 return NULL;
935 }
936
937 if ((entry_user = mod_cband_get_user_entry(username_arg, parms->server->module_config, 1)) == NULL) {
938 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, parms->server, "Invalid command 'CBandUserClassLimit %s %s', undefined user name", (char *)arg, (char *)limit);
939 return NULL;
940 }
941
942 entry_user->user_class_limit[entry->class_nr] = mod_cband_conf_get_limit_kb((char *)limit,
943 &entry_user->user_class_limit_mult[entry->class_nr]);
944
945 return NULL;
946 }
947
948 unsigned long mod_cband_conf_get_period_sec(char *period)
949 {
950 unsigned long val;
951 char unit;
952
953 sscanf(period, "%lu%c", &val, &unit);
954
955 if (unit == 's' || unit == 'S')
956 return val;
957 else
958 if (unit == 'm' || unit == 'M')
959 return val * 60;
960 else
961 if (unit == 'h' || unit == 'H')
962 return val * 60 * 60;
963 else
964 if (unit == 'd' || unit == 'D')
965 return val * 60 * 60 * 24;
966 else
967 if (unit == 'w' || unit == 'W')
968 return val * 60 * 60 * 24 * 7;
969
970 return atol(period);
971 }
972
973 unsigned long mod_cband_conf_get_limit_kb(char *limit, unsigned int *mult)
974 {
975 unsigned long val;
976 char unit, unit2 = 0;
977
978 sscanf(limit, "%lu%c%c", &val, &unit, &unit2);
979 if (unit2 == 'i' || unit2 == 'I')
980 *mult = 1024;
981 else
982 *mult = 1000;
983
984 if (unit == 'k' || unit == 'K')
985 return val;
986 else
987 if (unit == 'm' || unit == 'M')
988 return val * *mult;
989 else
990 if (unit == 'g' || unit == 'G')
991 return val * *mult * *mult;
992
993 return atol(limit);
994 }
995
996 unsigned long mod_cband_conf_get_speed_kbps(char *speed)
997 {
998 unsigned long val;
999 char unit1, unit2 = 'p';
1000
1001 sscanf(speed, "%lu%cb%cs", &val, &unit1, &unit2);
1002
1003 /* kibibytes per second */
1004 if (unit2 == '/')
1005 val = val*8;
1006 else if (unit2 != 'p') {
1007 /* rzucic jakims bledem :) */
1008 }
1009
1010 if (unit1 == 'k' || unit1 == 'K')
1011 return val;
1012 else
1013 if (unit1 == 'm' || unit1 == 'M')
1014 return val * 1024;
1015 else
1016 if (unit1 == 'g' || unit1 == 'G')
1017 return val * 1024 * 1024;
1018
1019 return atol(speed);
1020 }
1021
1022 char *mod_cband_create_time(apr_pool_t *p, unsigned long sec)
1023 {
1024 unsigned h, m, s, d, w;
1025 char period[MAX_PERIOD_LEN];
1026
1027 s = sec % 60;
1028 sec /= 60;
1029 m = sec % 60;
1030 sec /= 60;
1031 h = sec % 24;
1032 sec /= 24;
1033 d = sec % 7;
1034 sec /= 7;
1035 w = sec;
1036
1037 sprintf(period, "%uW ", w);
1038 sprintf(period + strlen(period), "%uD ", d);
1039 sprintf(period + strlen(period), "%02u:%02u:%02u", h, m, s);
1040
1041 return apr_pstrndup(p, period, strlen(period));
1042 }
1043
1044 char *mod_cband_create_traffic_size(apr_pool_t *p, unsigned long kb, char *unit, int mult)
1045 {
1046 char traffic[MAX_TRAFFIC_LEN];
1047 char dest_unit[3] = {0, 0, 0};
1048 float v;
1049 unsigned long vi;
1050
1051 if (mult <= 0)
1052 mult = 1000;
1053
1054 if ((unit != "" && unit[0] == 'G') || (unit == "" && kb >= mult*mult)) {
1055 dest_unit[0] = 'G';
1056 v = (float)kb / (mult * mult);
1057 } else
1058 if ((unit != "" && unit[0] == 'M') || (unit == "" && kb >= mult)) {
1059 dest_unit[0] = 'M';
1060 v = (float)kb / mult;
1061 } else {
1062 dest_unit[0] = 'K';
1063 v = kb;
1064 }
1065 if (mult == 1024)
1066 dest_unit[1] = 'i';
1067
1068 vi = (unsigned long)truncf(v * 100);
1069 v = (float)vi / 100;
1070
1071 if (vi % 100)
1072 sprintf(traffic, "%0.2f%sB", v, dest_unit);
1073 else
1074 sprintf(traffic, "%0.0f%sB", v, dest_unit);
1075
1076 return apr_pstrndup(p, traffic, strlen(traffic));
1077 }
1078
1079 char *mod_cband_create_period(apr_pool_t *p, unsigned long start, unsigned long refresh)
1080 {
1081 unsigned sec;
1082
1083 if (start == 0 || refresh == 0)
1084 return "never";
1085
1086 sec = start + refresh;
1087 sec -= (unsigned long)(apr_time_now() / 1e6);
1088
1089 return mod_cband_create_time(p, sec);
1090 }
1091
1092 static const command_rec mod_cband_cmds[] =
1093 {
1094 AP_INIT_TAKE1(
1095 "CBandDefaultExceededURL",
1096 mod_cband_set_default_url,
1097 NULL,
1098 RSRC_CONF,
1099 "CBandDefaultExceededURL - The URL to redirect when bandwidth is exceeded."
1100 ),
1101
1102 AP_INIT_TAKE1(
1103 "CBandDefaultExceededCode",
1104 mod_cband_set_default_code,
1105 NULL,
1106 RSRC_CONF,
1107 "CBandDefaultExceededCode - The http code sent to user when the limit is exceeded"
1108 ),
1109
1110 AP_INIT_FLAG(
1111 "CBandRandomPulse",
1112 mod_cband_set_random_pulse,
1113 NULL,
1114 RSRC_CONF,
1115 "CBandRandomPulse - Sets random pulse for FBS algorithm."
1116 ),
1117
1118 AP_INIT_TAKE1(
1119 "CBandScoreFlushPeriod",
1120 mod_cband_set_score_flush_period,
1121 NULL,
1122 RSRC_CONF,
1123 "CBandScoreFlushPeriod"
1124 ),
1125
1126 AP_INIT_TAKE1(
1127 "CBandLimit",
1128 mod_cband_set_limit,
1129 NULL,
1130 RSRC_CONF,
1131 "CBandLimit - The limit bandwidth in KB for virtualhost."
1132 ),
1133
1134 AP_INIT_TAKE1(
1135 "CBandPeriod",
1136 mod_cband_set_period,
1137 NULL,
1138 RSRC_CONF,
1139 "CBandPeriod - The time after the scoreboard will be cleared"
1140 ),
1141
1142 AP_INIT_TAKE1(
1143 "CBandPeriodSlice",
1144 mod_cband_set_period_slice,
1145 NULL,
1146 RSRC_CONF,
1147 "CBandPeriodSlice - Specifies number of bandwidth slices"
1148 ),
1149
1150 AP_INIT_TAKE1(
1151 "CBandExceededURL",
1152 mod_cband_set_url,
1153 NULL,
1154 RSRC_CONF,
1155 "CBandExceededURL - The URL to redirect when virtualhost's bandwidth is exceeded."
1156 ),
1157
1158 AP_INIT_TAKE3 (
1159 "CBandSpeed",
1160 mod_cband_set_speed,
1161 NULL,
1162 RSRC_CONF,
1163 "CBandSpeed - Maximal speed for virtualhost."
1164 ),
1165
1166 AP_INIT_TAKE3 (
1167 "CBandRemoteSpeed",
1168 mod_cband_set_remote_speed,
1169 NULL,
1170 RSRC_CONF,
1171 "CBandRemoteSpeed - Maximal speed for remote clients."
1172 ),
1173
1174 AP_INIT_RAW_ARGS (
1175 "CBandClassRemoteSpeed",
1176 mod_cband_set_class_remote_speed,
1177 NULL,
1178 RSRC_CONF,
1179 "CBandClassRemoteSpeed - Maximal speed for remote class."
1180 ),
1181
1182 AP_INIT_TAKE3 (
1183 "CBandExceededSpeed",
1184 mod_cband_set_exceeded_speed,
1185 NULL,
1186 RSRC_CONF,
1187 "CBandExceededSpeed - Over limit speed for virtualhost."
1188 ),
1189
1190 AP_INIT_TAKE1(
1191 "CBandScoreboard",
1192 mod_cband_set_scoreboard,
1193 NULL,
1194 RSRC_CONF,
1195 "CBandScoreboard - The path to the virtualhost's scoreboard file."
1196 ),
1197
1198 AP_INIT_TAKE1(
1199 "CBandUser",
1200 mod_cband_set_user,
1201 NULL,
1202 RSRC_CONF,
1203 "CBandUser - virtualhost user owner."
1204 ),
1205
1206 AP_INIT_RAW_ARGS(
1207 "<CBandUser",
1208 mod_cband_user_section,
1209 NULL,
1210 RSRC_CONF,
1211 "CBandUser section"
1212 ),
1213
1214 AP_INIT_TAKE1(
1215 "CBandUserLimit",
1216 mod_cband_set_user_limit,
1217 NULL,
1218 RSRC_CONF,
1219 "CBandUserLimit - The limit bandwidth in KB for user."
1220 ),
1221
1222 AP_INIT_TAKE1(
1223 "CBandUserPeriod",
1224 mod_cband_set_user_period,
1225 NULL,
1226 RSRC_CONF,
1227 "CBandUserPeriod - The time after the scoreboard will be cleared"
1228 ),
1229
1230 AP_INIT_TAKE1(
1231 "CBandUserPeriodSlice",
1232 mod_cband_set_user_period_slice,
1233 NULL,
1234 RSRC_CONF,
1235 "CBandPeriodSlice - Specifies number of bandwidth slices"
1236 ),
1237
1238 AP_INIT_TAKE1(
1239 "CBandUserExceededURL",
1240 mod_cband_set_user_url,
1241 NULL,
1242 RSRC_CONF,
1243 "CBandUserExceededURL - The URL to redirect when user's bandwidth is exceeded."
1244 ),
1245
1246 AP_INIT_TAKE3(
1247 "CBandUserSpeed",
1248 mod_cband_set_user_speed,
1249 NULL,
1250 RSRC_CONF,
1251 "CBandUserSpeed - Maximal speed for user."
1252 ),
1253
1254 AP_INIT_TAKE3(
1255 "CBandUserRemoteSpeed",
1256 mod_cband_set_user_remote_speed,
1257 NULL,
1258 RSRC_CONF,
1259 "CBandUserRemoteSpeed - Maximal remote speed for user."
1260 ),
1261
1262 AP_INIT_TAKE3(
1263 "CBandUserExceededSpeed",
1264 mod_cband_set_user_exceeded_speed,
1265 NULL,
1266 RSRC_CONF,
1267 "CBandUserExceededSpeed - Over limit speed for user."
1268 ),
1269
1270 AP_INIT_TAKE1(
1271 "CBandUserScoreboard",
1272 mod_cband_set_user_scoreboard,
1273 NULL,
1274 RSRC_CONF,
1275 "CBandUserScoreboard - The path to the user's scoreboard file."
1276 ),
1277
1278 AP_INIT_RAW_ARGS(
1279 "<CBandClass",
1280 mod_cband_class_section,
1281 NULL,
1282 RSRC_CONF,
1283 "CBandClass section"
1284 ),
1285
1286 AP_INIT_TAKE1(
1287 "CBandClassDst",
1288 mod_cband_set_class_dst,
1289 NULL,
1290 RSRC_CONF,
1291 "CBandClassDst"
1292 ),
1293
1294 AP_INIT_TAKE2(
1295 "CBandClassLimit",
1296 mod_cband_set_class_limit,
1297 NULL,
1298 RSRC_CONF,
1299 ""
1300 ),
1301
1302 AP_INIT_TAKE2(
1303 "CBandUserClassLimit",
1304 mod_cband_set_user_class_limit,
1305 NULL,
1306 RSRC_CONF,
1307 ""
1308 ),
1309
1310 {NULL}
1311 };
1312
1313 apr_status_t patricia_cleanup(void *p)
1314 {
1315 patricia_tree_t *t = (patricia_tree_t *) p;
1316 Clear_Patricia(t,NULL);
1317
1318 return APR_SUCCESS;
1319 }
1320
1321 int mod_cband_get_dst(request_rec *r)
1322 {
1323 patricia_node_t *node;
1324 prefix_t p;
1325 char *leaf;
1326
1327 if (config->tree == NULL)
1328 return -1;
1329
1330 p.bitlen = 32;
1331 p.ref_count = 0;
1332 p.family = AF_INET;
1333 p.add.sin.s_addr = inet_addr(r->connection->remote_ip);
1334
1335 node = patricia_search_best(config->tree, &p);
1336
1337 if (node) {
1338 leaf = node->user1;
1339
1340 if (leaf) {
1341 #ifdef DEBUG
1342 fprintf(stderr,"%s leaf %s\n",r->connection->remote_ip,leaf);
1343 fflush(stderr);
1344 #endif
1345 return atoi(leaf);
1346 }
1347 }
1348
1349 return -1;
1350 }
1351
1352 int mod_cband_get_remote_host(struct conn_rec *c, int create, mod_cband_virtualhost_config_entry *entry)
1353 {
1354 int i;
1355 mod_cband_remote_host *hosts;
1356 unsigned long time_now, time_delta;
1357 in_addr_t addr;
1358
1359 if (entry == NULL)
1360 return -1;
1361
1362 if (c->remote_ip != NULL)
1363 addr = inet_addr(c->remote_ip);
1364 else
1365 addr = c->remote_addr->sa.sin.sin_addr.s_addr;
1366
1367 time_now = apr_time_now();
1368 hosts = config->remote_hosts.hosts;
1369
1370 if (hosts == NULL)
1371 return -1;
1372
1373 /* BEGIN CRITICAL SECTION */
1374 mod_cband_sem_down(config->remote_hosts.sem_id);
1375 for (i = 0; i < MAX_REMOTE_HOSTS; i++) {
1376 time_delta = (time_now - hosts[i].remote_last_time) / 1e6;
1377 if (hosts[i].used && ((time_delta <= MAX_REMOTE_HOST_LIFE) || (hosts[i].remote_conn > 0)) &&
1378 (hosts[i].remote_addr == addr) && (hosts[i].virtual_name == entry->virtual_name)) {
1379 mod_cband_sem_up(config->remote_hosts.sem_id);
1380 /* END CRITICAL SECTION */
1381 return i;
1382 }
1383 }
1384
1385 if (create) {
1386 for (i = 0; i < MAX_REMOTE_HOSTS; i++) {
1387 time_delta = (time_now - hosts[i].remote_last_time) / 1e6;
1388 if ((hosts[i].used == 0) || ((time_delta > MAX_REMOTE_HOST_LIFE) && (hosts[i].remote_conn <= 0))) {
1389 memset(&hosts[i], 0, sizeof(mod_cband_remote_host));
1390 hosts[i].used = 1;
1391 hosts[i].remote_addr = addr;
1392 hosts[i].remote_last_time = time_now;
1393 hosts[i].remote_last_refresh = time_now;
1394 hosts[i].virtual_name = entry->virtual_name;
1395 mod_cband_sem_up(config->remote_hosts.sem_id);
1396 /* END CRITICAL SECTION */
1397 return i;
1398 }
1399 }
1400 }
1401 mod_cband_sem_up(config->remote_hosts.sem_id);
1402 /* END CRITICAL SECTION */
1403
1404 return -1;
1405 }
1406
1407 void mod_cband_safe_change(unsigned long *val, int diff)
1408 {
1409 if (val == NULL)
1410 return;
1411
1412 if ((diff > 0) || (diff < 0 && *val >= -diff))
1413 *val += diff;
1414 else
1415 *val = 0;
1416 }
1417
1418 int mod_cband_change_remote_connections_lock(int index, int diff)
1419 {
1420 if (index < 0)
1421 return -1;
1422
1423 /* BEGIN CRITICAL SECTION */
1424 mod_cband_sem_down(config->remote_hosts.sem_id);
1425 mod_cband_safe_change(&config->remote_hosts.hosts[index].remote_conn, diff);
1426 mod_cband_sem_up(config->remote_hosts.sem_id);
1427 /* END CRITICAL SECTION */
1428
1429 return 0;
1430 }
1431
1432 /*
1433 * Nie trzeba semafora, poniewaz operacje na liczbach 32-bit sa atomowe
1434 */
1435 int mod_cband_set_remote_request_time(int index, unsigned long time)
1436 {
1437 if (index < 0)
1438 return -1;
1439
1440 config->remote_hosts.hosts[index].remote_last_time = time;
1441
1442 return 0;
1443 }
1444
1445 /*
1446 * Nie trzeba semafora, poniewaz operacje na liczbach 32-bit sa atomowe
1447 */
1448 int mod_cband_set_remote_current_speed(int index, unsigned long kbps)
1449 {
1450 if (index < 0)
1451 return -1;
1452
1453 config->remote_hosts.hosts[index].remote_kbps = kbps;
1454
1455 return 0;
1456 }
1457
1458 /*
1459 * Nie trzeba semafora, poniewaz operacje na liczbach 32-bit sa atomowe
1460 */
1461 int mod_cband_set_remote_max_connections(int index, unsigned long max)
1462 {
1463 if (index < 0)
1464 return -1;
1465
1466 config->remote_hosts.hosts[index].remote_max_conn = max;
1467
1468 return 0;
1469 }
1470
1471 /*
1472 * Nie trzeba semafora, poniewaz operacje na liczbach 32-bit sa atomowe
1473 */
1474 int mod_cband_set_remote_last_refresh(int index, unsigned long time)
1475 {
1476 if (index < 0)
1477 return -1;
1478
1479 config->remote_hosts.hosts[index].remote_last_refresh = time;
1480
1481 return 0;
1482 }
1483
1484 /*
1485 * Nie trzeba semafora, poniewaz operacje na liczbach 32-bit sa atomowe
1486 */
1487 int mod_cband_set_remote_total_connections(int index, unsigned long set)
1488 {
1489 if (index < 0)
1490 return -1;
1491
1492 config->remote_hosts.hosts[index].remote_total_conn = set;
1493
1494 return 0;
1495 }
1496
1497 /*
1498 * Nie trzeba semafora, poniewaz operacje na liczbach 32-bit sa atomowe
1499 */
1500 int mod_cband_get_remote_total_connections(int index)
1501 {
1502 if (index < 0)
1503 return -1;
1504
1505 return config->remote_hosts.hosts[index].remote_conn;
1506 }
1507
1508 float mod_cband_get_remote_connections_speed_lock(int index)
1509 {
1510 unsigned long time_now;
1511 float time_delta;
1512 float rps = 0;
1513
1514 if (index < 0)
1515 return 0;
1516
1517 time_now = apr_time_now();
1518
1519 /* BEGIN CRITICAL SECTION */
1520 mod_cband_sem_down(config->remote_hosts.sem_id);
1521 time_delta = (float)(time_now - config->remote_hosts.hosts[index].remote_last_refresh) / 1e6;
1522 if (time_delta > 0)
1523 rps = (float)(config->remote_hosts.hosts[index].remote_total_conn) / time_delta;
1524 mod_cband_sem_up(config->remote_hosts.sem_id);
1525 /* END CRITICAL SECTION */
1526
1527 return rps;
1528 }
1529
1530 int mod_cband_change_remote_total_connections_lock(int index, unsigned long diff)
1531 {
1532 if (index < 0)
1533 return -1;
1534
1535 /* BEGIN CRITICAL SECTION */
1536 mod_cband_sem_down(config->remote_hosts.sem_id);
1537 mod_cband_safe_change(&config->remote_hosts.hosts[index].remote_total_conn, diff);
1538 mod_cband_sem_up(config->remote_hosts.sem_id);
1539 /* END CRITICAL SECTION */
1540
1541 return 0;
1542 }
1543
1544 /*
1545 * Nie trzeba semafora, poniewaz operacje na liczbach 32-bit sa atomowe
1546 */
1547 unsigned long mod_cband_get_remote_connection_time(int index)
1548 {
1549 if (index < 0)
1550 return 0;
1551
1552 return config->remote_hosts.hosts[index].remote_last_time;
1553 }
1554
1555 /*
1556 * Nie trzeba semafora, poniewaz operacje na liczbach 32-bit sa atomowe
1557 */
1558 int mod_cband_get_remote_connections(int index)
1559 {
1560 if (index < 0)
1561 return 0;
1562
1563 return config->remote_hosts.hosts[index].remote_conn;
1564 }
1565
1566 /*
1567 * Nie trzeba semafora, poniewaz operacje na liczbach 32-bit sa atomowe
1568 */
1569 int mod_cband_remove_remote_host(int index)
1570 {
1571 if (index < 0)
1572 return -1;
1573
1574 config->remote_hosts.hosts[index].used = 0;
1575
1576 return 0;
1577 }
1578
1579 int mod_cband_get_dst_speed_lock(mod_cband_virtualhost_config_entry *entry, mod_cband_user_config_entry *entry_user, unsigned long *remote_kbps, unsigned long *remote_rps, unsigned long *remote_max_conn, int dst)
1580 {
1581 unsigned long virtualhost_kbps = 0;
1582 unsigned long user_kbps = 0;
1583 unsigned long virtualhost_rps = 0;
1584 unsigned long user_rps = 0;
1585 unsigned long virtualhost_max_conn = 0;
1586 unsigned long user_max_conn = 0;
1587
1588 if (entry != NULL) {
1589 /* BEGIN CRITICAL SECTION */
1590 mod_cband_sem_down(config->sem_id);
1591 virtualhost_kbps = entry->shmem_data->remote_speed.kbps;
1592 virtualhost_rps = entry->shmem_data->remote_speed.rps;
1593 virtualhost_max_conn = entry->shmem_data->remote_speed.max_conn;
1594 mod_cband_sem_up(config->sem_id);
1595 /* BEGIN CRITICAL SECTION */
1596
1597 if (dst >= 0 && dst <= DST_CLASS) {
1598 if (entry->virtual_class_speed[dst].kbps > 0)
1599 virtualhost_kbps = entry->virtual_class_speed[dst].kbps;
1600
1601 if (entry->virtual_class_speed[dst].rps > 0)
1602 virtualhost_rps = entry->virtual_class_speed[dst].rps;
1603
1604 if (entry->virtual_class_speed[dst].max_conn > 0)
1605 virtualhost_max_conn = entry->virtual_class_speed[dst].max_conn;
1606 }
1607 }
1608
1609 if (entry_user != NULL) {
1610 /* BEGIN CRITICAL SECTION */
1611 mod_cband_sem_down(config->sem_id);
1612 user_kbps = entry_user->shmem_data->remote_speed.kbps;
1613 user_rps = entry_user->shmem_data->remote_speed.rps;
1614 user_max_conn = entry_user->shmem_data->remote_speed.max_conn;
1615 mod_cband_sem_up(config->sem_id);
1616 /* BEGIN CRITICAL SECTION */
1617
1618 if (dst >= 0 && dst <= DST_CLASS) {
1619 if (entry_user->user_class_speed[dst].kbps > 0)
1620 user_kbps = entry_user->user_class_speed[dst].kbps;
1621
1622 if (entry_user->user_class_speed[dst].rps > 0)
1623 user_rps = entry_user->user_class_speed[dst].rps;
1624
1625 if (entry_user->user_class_speed[dst].max_conn > 0)
1626 user_max_conn = entry_user->user_class_speed[dst].max_conn;
1627 }
1628 }
1629
1630 if (remote_kbps != NULL) {
1631 if ((user_kbps > 0) && (virtualhost_kbps > user_kbps))
1632 *remote_kbps = user_kbps;
1633 else
1634 if (virtualhost_kbps > 0)
1635 *remote_kbps = virtualhost_kbps;
1636 else
1637 *remote_kbps = user_kbps;
1638 }
1639
1640 if (remote_rps != NULL) {
1641 if ((user_rps > 0) && (virtualhost_rps > user_rps))
1642 *remote_rps = virtualhost_rps;
1643 else
1644 if (virtualhost_rps > 0)
1645 *remote_rps = virtualhost_rps;
1646 else
1647 *remote_rps = user_rps;
1648 }
1649
1650 if (remote_max_conn != NULL) {
1651 if ((user_max_conn > 0) && (virtualhost_max_conn > user_max_conn))
1652 *remote_max_conn = virtualhost_max_conn;
1653 else
1654 if (virtualhost_max_conn > 0)
1655 *remote_max_conn = virtualhost_max_conn;
1656 else
1657 *remote_max_conn = user_max_conn;
1658 }
1659
1660 return 0;
1661 }
1662
1663 /*
1664 * Nie trzeba semafora, poniewaz operacje na liczbach 32-bit sa atomowe
1665 */
1666 int mod_cband_get_score(server_rec *s, char *path, unsigned long long *val, int dst, mod_cband_shmem_data *shmem_data)
1667 {
1668 if (val == NULL || shmem_data == NULL)
1669 return -1;
1670
1671 if (dst < 0)
1672 *val = shmem_data->total_usage.total_bytes;
1673 else
1674 *val = shmem_data->total_usage.class_bytes[dst];
1675
1676 return 0;
1677 }
1678
1679
1680 /*
1681 * semafor opuszczany w mod_cband_update_score_cache
1682 */
1683 int mod_cband_get_score_all(server_rec *s, char *path, mod_cband_scoreboard_entry *val)
1684 {
1685 apr_file_t *fd;
1686 apr_size_t nbuf;
1687 apr_pool_t *subpool;
1688
1689 if (path == NULL || val == NULL)
1690 return -1;
1691
1692 apr_pool_create(&subpool, config->p);
1693
1694 if ((apr_file_open(&fd, path, APR_READ | APR_BINARY, 0, subpool)) != APR_SUCCESS) {
1695 apr_pool_destroy(subpool);
1696 return -1;
1697 }
1698
1699 nbuf = sizeof(mod_cband_scoreboard_entry);
1700 apr_file_read(fd, val, &nbuf);
1701 apr_file_close(fd);
1702 apr_pool_destroy(subpool);
1703
1704 return 0;
1705 }
1706
1707 /*
1708 * semafor opuszczany w mod_cband_save_score_cache i mod_cband_flush_score_lock
1709 */
1710 int mod_cband_save_score(char *path, mod_cband_scoreboard_entry *scoreboard)
1711 {
1712 apr_file_t *fd;
1713 apr_size_t nbuf;
1714 apr_pool_t *subpool;
1715
1716 if (path == NULL || scoreboard == NULL || scoreboard->was_request == 0)
1717 return -1;
1718
1719 apr_pool_create(&subpool, config->p);
1720
1721 if ((apr_file_open(&fd, path,
1722 APR_CREATE | APR_READ | APR_WRITE | APR_BINARY, APR_UREAD | APR_UWRITE, subpool)) != APR_SUCCESS) {
1723
1724 fprintf(stderr, "apache2_mod_cband: cannot open scoreboard file %s\n", path);
1725 fflush(stderr);
1726
1727 return -1;
1728 }
1729
1730 apr_file_lock(fd, APR_FLOCK_EXCLUSIVE);
1731 nbuf = sizeof(mod_cband_scoreboard_entry);
1732 apr_file_write(fd, scoreboard, &nbuf);
1733 apr_file_unlock(fd);
1734 apr_file_close(fd);
1735 apr_pool_destroy(subpool);
1736
1737 return 0;
1738 }
1739
1740 int mod_cband_flush_score_lock(char *path, mod_cband_scoreboard_entry *scoreboard)
1741 {
1742 if ((path == NULL) || (scoreboard == NULL))
1743 return -1;
1744
1745 /* BEGIN CRITICAL SECTION */
1746 mod_cband_sem_down(config->sem_id);
1747
1748 scoreboard->was_request = 1;
1749 if (--(scoreboard->score_flush_count) <= 0) {
1750 mod_cband_save_score(path, scoreboard);
1751 scoreboard->score_flush_count = config->score_flush_period;
1752 }
1753
1754 mod_cband_sem_up(config->sem_id);
1755 /* END CRITICAL SECTION */
1756
1757 return 0;
1758 }
1759
1760 /*
1761 * semafor opuszczany poza funkcje mod_cband_log_bucket
1762 */
1763 int mod_cband_update_score(char *path, unsigned long long *bytes_served, int dst, mod_cband_scoreboard_entry *scoreboard)
1764 {
1765 if (scoreboard == NULL || bytes_served == NULL)
1766 return -1;
1767
1768 scoreboard->total_bytes += (unsigned long long)(*bytes_served);
1769 if (dst >= 0)
1770 scoreboard->class_bytes[dst] += (unsigned long long)(*bytes_served);
1771
1772 return 0;
1773 }
1774
1775 int mod_cband_clear_score_lock(mod_cband_scoreboard_entry *scoreboard)
1776 {
1777 if (scoreboard == NULL)
1778 return -1;
1779
1780 /* BEGIN CRITICAL SECTION */
1781 mod_cband_sem_down(config->sem_id);
1782 memset(scoreboard, 0, sizeof(mod_cband_scoreboard_entry));
1783 mod_cband_sem_up(config->sem_id);
1784 /* END CRITICAL SECTION */
1785
1786 return 0;
1787 }
1788
1789 /* semafor opuszczany przez funkcje mod_cband_post_config */
1790 int mod_cband_update_score_cache(server_rec *s)
1791 {
1792 mod_cband_virtualhost_config_entry *entry = NULL;
1793 mod_cband_user_config_entry *entry_user = NULL;
1794
1795 entry = config->next_virtualhost;
1796 while(entry != NULL) {
1797 mod_cband_get_score_all(s, entry->virtual_scoreboard, &(entry->shmem_data->total_usage));
1798 if ((entry = entry->next) == NULL)
1799 break;
1800 }
1801
1802 entry_user = config->next_user;
1803 while(entry_user != NULL) {
1804 mod_cband_get_score_all(s, entry_user->user_scoreboard, &(entry_user->shmem_data->total_usage));
1805 if ((entry_user = entry_user->next) == NULL)
1806 break;
1807 }
1808
1809 return OK;
1810 }
1811
1812 int mod_cband_save_score_cache(void)
1813 {
1814 mod_cband_virtualhost_config_entry *entry = NULL;
1815 mod_cband_user_config_entry *entry_user = NULL;
1816
1817 entry = config->next_virtualhost;
1818 while(entry != NULL) {
1819 mod_cband_save_score(entry->virtual_scoreboard, &(entry->shmem_data->total_usage));
1820 if ((entry = entry->next) == NULL)
1821 break;
1822 }
1823
1824 entry_user = config->next_user;
1825 while(entry_user != NULL) {
1826 mod_cband_save_score(entry_user->user_scoreboard, &(entry_user->shmem_data->total_usage));
1827 if ((entry_user = entry_user->next) == NULL)
1828 break;
1829 }
1830
1831 return OK;
1832 }
1833
1834 unsigned long mod_cband_get_start_time(mod_cband_scoreboard_entry *scoreboard)
1835 {
1836 if (scoreboard == NULL)
1837 return 0;
1838
1839 return scoreboard->start_time;
1840 }
1841
1842 int mod_cband_set_start_time(mod_cband_scoreboard_entry *scoreboard, unsigned long start_time)
1843 {
1844 if (scoreboard == NULL)
1845 return 0;
1846
1847 scoreboard->start_time = start_time;
1848
1849 return 0;
1850 }
1851
1852 /*
1853 * speed aproximation function
1854 */
1855 int mod_cband_get_speed_lock(mod_cband_shmem_data *shmem_data, float *bps, float *rps)
1856 {
1857 float time_delta;
1858
1859 if (shmem_data == NULL)
1860 return -1;
1861
1862 /* BEGIN CRITICAL SECTION */
1863 mod_cband_sem_down(config->sem_id);
1864
1865 time_delta = (float)(shmem_data->time_delta) / 1e6;
1866
1867 if (time_delta <= 0)
1868 time_delta = PERIOD_LEN;
1869
1870 if (bps != NULL)
1871 *bps = ((float)(shmem_data->old_TX * 8)) / time_delta;
1872
1873 if (rps != NULL)
1874 *rps = ((float)(shmem_data->old_conn)) / time_delta;
1875
1876 mod_cband_sem_up(config->sem_id);
1877 /* END CRITICAL SECTION */
1878
1879 return 0;
1880 }
1881
1882 /*
1883 * semafor opuszczany przez funkcje check_connections_speed
1884 */
1885 int mod_cband_get_real_speed(mod_cband_shmem_data *shmem_data, float *bps, float *rps)
1886 {
1887 if (shmem_data == NULL)
1888 return -1;
1889
1890 if (bps != NULL)
1891 *bps = ((float)(shmem_data->current_TX * 8) / PERIOD_LEN);
1892
1893 if (rps != NULL)
1894 *rps = ((float)(shmem_data->current_conn) / PERIOD_LEN);
1895
1896 return 0;
1897 }
1898
1899 /*
1900 * semafor opuszczany przez mod_cband_log_bucket, mod_cband_update_speed_lock, mod_cband_check_connections_speed
1901 */
1902 int mod_cband_update_speed(mod_cband_shmem_data *shmem_data, unsigned long bytes_served, int new_connection, int remote_idx)
1903 {
1904 unsigned long time_delta;
1905 unsigned long time_last_request;
1906 unsigned long time_now;
1907 unsigned long time_delta_real;
1908
1909 if (shmem_data == NULL)
1910 return -1;
1911
1912 time_now = apr_time_now();
1913 time_delta_real = time_now - shmem_data->total_last_refresh;
1914 time_delta = (time_now - shmem_data->total_last_refresh) / 1e6;
1915 time_last_request = (time_now - shmem_data->total_last_time) / 1e6;
1916
1917 if (bytes_served > 0)
1918 shmem_data->current_TX += bytes_served;
1919
1920 if (new_connection) {
1921 shmem_data->total_last_time = time_now;
1922 mod_cband_set_remote_request_time(remote_idx, time_now);
1923 mod_cband_change_remote_total_connections_lock(remote_idx, 1);
1924 shmem_data->current_conn += new_connection;
1925 }
1926
1927 if (time_delta > PERIOD_LEN) {
1928 shmem_data->total_last_refresh = time_now;
1929 mod_cband_set_remote_total_connections(remote_idx, 0);
1930 mod_cband_set_remote_last_refresh(remote_idx, time_now);
1931 shmem_data->time_delta = time_delta_real;
1932 }
1933
1934 if (time_delta > PERIOD_LEN && time_delta < 2 * PERIOD_LEN) {
1935 shmem_data->old_TX = shmem_data->current_TX;
1936 shmem_data->old_conn = shmem_data->current_conn;
1937 shmem_data->current_TX = 0;
1938 shmem_data->current_conn = 0;
1939 } else
1940 if (time_delta >= 2 * PERIOD_LEN) {
1941 shmem_data->old_TX = shmem_data->current_TX;
1942 shmem_data->old_conn = shmem_data->current_conn;
1943 shmem_data->current_TX = 0;
1944 shmem_data->current_conn = 0;
1945 }
1946
1947 return 0;
1948 }
1949
1950 int mod_cband_update_speed_lock(mod_cband_shmem_data *shmem_data, unsigned long bytes_served, int new_connection, int remote_idx)
1951 {
1952 /* BEGIN CRITICAL SECTION */
1953 mod_cband_sem_down(config->sem_id);
1954 mod_cband_update_speed(shmem_data, bytes_served, new_connection, remote_idx);
1955 mod_cband_sem_up(config->sem_id);
1956 /* END CRITICAL SECTION */
1957
1958 return 0;
1959 }
1960
1961 int mod_cband_set_overlimit_speed(mod_cband_shmem_data *shmem_data)
1962 {
1963 if (shmem_data == NULL)
1964 return -1;
1965
1966 shmem_data->curr_speed.kbps = shmem_data->over_speed.kbps;
1967 shmem_data->curr_speed.rps = shmem_data->over_speed.rps;
1968 shmem_data->curr_speed.max_conn = shmem_data->over_speed.max_conn;
1969 shmem_data->shared_kbps = shmem_data->over_speed.kbps;
1970 shmem_data->overlimit = 1;
1971
1972 return 0;
1973 }
1974
1975 int mod_cband_set_overlimit_speed_lock(mod_cband_shmem_data *shmem_data)
1976 {
1977 if (shmem_data == NULL)
1978 return -1;
1979
1980 /* BEGIN CRITICAL SECTION */
1981 mod_cband_sem_down(config->sem_id);
1982 mod_cband_set_overlimit_speed(shmem_data);
1983 mod_cband_sem_up(config->sem_id);
1984 /* END CRITICAL SECTION */
1985
1986 return 0;
1987 }
1988
1989 int mod_cband_set_normal_speed(mod_cband_shmem_data *shmem_data)
1990 {
1991 if (shmem_data == NULL)
1992 return -1;
1993
1994 shmem_data->curr_speed.kbps = shmem_data->max_speed.kbps;
1995 shmem_data->curr_speed.rps = shmem_data->max_speed.rps;
1996 shmem_data->curr_speed.max_conn = shmem_data->max_speed.max_conn;
1997 shmem_data->shared_kbps = shmem_data->max_speed.kbps;
1998 shmem_data->overlimit = 0;
1999
2000 return 0;
2001 }
2002
2003 int mod_cband_set_normal_speed_lock(mod_cband_shmem_data *shmem_data)
2004 {
2005 if (shmem_data == NULL)
2006 return -1;
2007
2008 /* BEGIN CRITICAL SECTION */
2009 mod_cband_sem_down(config->sem_id);
2010 mod_cband_set_normal_speed(shmem_data);
2011 mod_cband_sem_up(config->sem_id);
2012 /* END CRITICAL SECTION */
2013
2014 return 0;
2015 }
2016
2017 void mod_cband_check_virtualhost_refresh(mod_cband_virtualhost_config_entry *entry_virtual, unsigned long sec)
2018 {
2019 mod_cband_scoreboard_entry *scoreboard;
2020
2021 if (entry_virtual == NULL || entry_virtual->refresh_time == 0)
2022 return;
2023
2024 scoreboard = &(entry_virtual->shmem_data->total_usage);
2025
2026 if (mod_cband_get_start_time(scoreboard) < 0)
2027 mod_cband_set_start_time(scoreboard, sec);
2028
2029 if ((mod_cband_get_start_time(scoreboard) + entry_virtual->refresh_time) < sec) {
2030 mod_cband_clear_score_lock(scoreboard);
2031 mod_cband_set_normal_speed_lock(entry_virtual->shmem_data);
2032 mod_cband_set_start_time(scoreboard, sec);
2033 }
2034 }
2035
2036 void mod_cband_check_user_refresh(mod_cband_user_config_entry *entry_user, unsigned long sec)
2037 {
2038 mod_cband_scoreboard_entry *scoreboard;
2039
2040 if (entry_user == NULL || entry_user->refresh_time == 0)
2041 return;
2042
2043 scoreboard = &(entry_user->shmem_data->total_usage);
2044
2045 if (mod_cband_get_start_time(scoreboard) < 0)
2046 mod_cband_set_start_time(scoreboard, sec);
2047
2048 if ((mod_cband_get_start_time(scoreboard) + entry_user->refresh_time) < sec) {
2049 mod_cband_clear_score_lock(scoreboard);
2050 mod_cband_set_normal_speed_lock(entry_user->shmem_data);
2051 mod_cband_set_start_time(scoreboard, sec);
2052 }
2053 }
2054
2055 int mod_cband_reset(mod_cband_shmem_data *shmem_data)
2056 {
2057 if (shmem_data == NULL)
2058 return -1;
2059
2060 mod_cband_clear_score_lock(&(shmem_data->total_usage));
2061 mod_cband_set_start_time(&(shmem_data->total_usage), (unsigned long)(apr_time_now() / 1e6));
2062 mod_cband_set_normal_speed_lock(shmem_data);
2063
2064 return 0;
2065 }
2066
2067 int mod_cband_reset_virtualhost(char *name)
2068 {
2069 mod_cband_virtualhost_config_entry *entry;
2070 char virtualhost[MAX_VIRTUALHOST_NAME];
2071 unsigned port, line;
2072
2073 if (name == NULL)
2074 return -1;
2075
2076 if (!strcasecmp(name, "all")) {
2077 entry = config->next_virtualhost;
2078
2079 while(entry != NULL) {
2080 mod_cband_reset(entry->shmem_data);
2081
2082 if (entry->next == NULL)
2083 break;
2084
2085 entry = entry->next;
2086 }
2087 } else {
2088 sscanf(name, "%[^:]:%u:%u", virtualhost, &port, &line);
2089
2090 if ((entry = mod_cband_get_virtualhost_entry_(virtualhost, (apr_port_t)port, line, 0)) != NULL)
2091 mod_cband_reset(entry->shmem_data);
2092 }
2093
2094 return 0;
2095 }
2096
2097 int mod_cband_reset_user(char *name)
2098 {
2099 mod_cband_user_config_entry *entry;
2100
2101 if (name == NULL)
2102 return -1;
2103
2104 if (!strcasecmp(name, "all")) {
2105 entry = config->next_user;
2106
2107 while(entry != NULL) {
2108 mod_cband_reset(entry->shmem_data);
2109
2110 if (entry->next == NULL)
2111 break;
2112
2113 entry = entry->next;
2114 }
2115 } else {
2116 if ((entry = mod_cband_get_user_entry(name, NULL, 0)) != NULL)
2117 mod_cband_reset(entry->shmem_data);
2118 }
2119
2120 return 0;
2121 }
2122
2123 unsigned long mod_cband_get_slice_limit(unsigned long start_time, unsigned long refresh_time,
2124 unsigned long slice_len, unsigned long limit)
2125 {
2126 unsigned long slice_limit, slice;
2127 unsigned int slice_no;
2128
2129 if (slice_len > 0 && refresh_time > 0) {
2130 slice_limit = (unsigned long)(((float)slice_len / refresh_time) * limit);
2131 slice_no = (((unsigned long)(apr_time_now() / 1e6) - start_time) / slice_len) + 1;
2132 slice = slice_no * slice_limit;
2133
2134 if (slice > limit)
2135 slice = limit;
2136
2137 return slice;
2138 }
2139
2140 return limit;
2141 }
2142
2143 void mod_cband_status_print_limit(request_rec *req, unsigned long limit, unsigned long usage, char *unit, unsigned int mult, unsigned long slice_limit)
2144 {
2145 unsigned char normal_r, normal_g, normal_b;
2146 unsigned char exceeded_r, exceeded_g, exceeded_b;
2147 unsigned char r, g, b;
2148 const char *color;
2149 float u;
2150
2151 if (slice_limit == 0)
2152 slice_limit = limit;
2153
2154 exceeded_r = 0xff;
2155 exceeded_g = 0x30;
2156 exceeded_b = 0x50;
2157 normal_r = 0x30;
2158 normal_g = 0xf0;
2159 normal_b = 0x30;
2160
2161 if (limit == (unsigned long)0)
2162 ap_rprintf(req, "<td style=\"background-color: yellow\">U/U/%s</td>\n", mod_cband_create_traffic_size(req->pool, usage, unit, mult));
2163 else {
2164 if (usage < limit) {
2165 r = normal_r;
2166 g = normal_g;
2167 b = normal_b;
2168 if (usage > 0) {
2169 u = (float)usage / limit;
2170 r += (unsigned char)((float)(exceeded_r - normal_r) * u);
2171 g -= (unsigned char)((float)(normal_g - exceeded_g) * u);
2172 b += (unsigned char)((float)(exceeded_b - normal_b) * u);
2173 }
2174 } else {
2175 r = exceeded_r;
2176 g = exceeded_g;
2177 b = exceeded_b;
2178 }
2179
2180 if (usage < limit / 2)
2181 color = "black";
2182 else
2183 color = "white";
2184
2185 ap_rprintf(req, "<td style=\"color: %s; background-color: #%02X%02X%02X\">%s/%s/%s</td>\n", color, r, g, b, mod_cband_create_traffic_size(req->pool, limit, unit, mult), mod_cband_create_traffic_size(req->pool, slice_limit, unit, mult), mod_cband_create_traffic_size(req->pool, usage, unit, mult));
2186 }
2187 }
2188
2189 void mod_cband_status_print_speed(request_rec *req, unsigned long limit, float usage)
2190 {
2191 unsigned char normal_r, normal_g, normal_b;
2192 unsigned char exceeded_r, exceeded_g, exceeded_b;
2193 unsigned char r, g, b;
2194 const char *color;
2195 float u;
2196
2197 exceeded_r = 0xff;
2198 exceeded_g = 0x20;
2199 exceeded_b = 0x20;
2200 normal_r = 0xf0;
2201 normal_g = 0xa1;
2202 normal_b = 0xa1;
2203
2204 if (limit == (unsigned long)0)
2205 ap_rprintf(req, "<td class=\"speed\">U/%0.2f</td>\n", usage);
2206 else {
2207 if (usage < limit) {
2208 r = normal_r;
2209 g = normal_g;
2210 b = normal_b;
2211
2212 if (usage > 0) {
2213 u = (float)usage / limit;
2214 g -= (unsigned char)((float)(normal_g - exceeded_g) * u);
2215 b -= (unsigned char)((float)(normal_b - exceeded_b) * u);
2216 }
2217 } else {
2218 r = exceeded_r;
2219 g = exceeded_g;
2220 b = exceeded_b;
2221 }
2222
2223 if (usage < limit / 2)
2224 color = "black";
2225 else
2226 color = "white";
2227
2228 ap_rprintf(req, "<td style=\"color: %s; background-color: #%02X%02X%02X\">%lu/%0.2f</td>\n", color, r, g, b, limit, usage);
2229 }
2230 }
2231
2232 void mod_cband_status_print_connections(request_rec *req, unsigned long limit, unsigned long usage)
2233 {
2234 unsigned char normal_r, normal_g, normal_b;
2235 unsigned char exceeded_r, exceeded_g, exceeded_b;
2236 unsigned char r, g, b;
2237 const char *color;
2238 float u;
2239
2240 exceeded_r = 0x36;
2241 exceeded_g = 0x55;
2242 exceeded_b = 0xad;
2243 normal_r = 0xb4;
2244 normal_g = 0xbf;
2245 normal_b = 0xff;
2246
2247 if (limit == (unsigned long)0)
2248 ap_rprintf(req, "<td class=remote_odd>U/%lu</td>\n", usage);
2249 else {
2250 if (usage < limit) {
2251 r = normal_r;
2252 g = normal_g;
2253 b = normal_b;
2254 if (usage > 0) {
2255 u = (float)usage / limit;
2256 r -= (unsigned char)((float)(normal_r - exceeded_r) * u);
2257 g -= (unsigned char)((float)(normal_g - exceeded_g) * u);
2258 b -= (unsigned char)((float)(normal_b - exceeded_b) * u);
2259 }
2260 } else {
2261 r = exceeded_r;
2262 g = exceeded_g;
2263 b = exceeded_b;
2264 }
2265
2266 if (usage <= limit / 2)
2267 color = "black";
2268 else
2269 color = "white";
2270
2271 ap_rprintf(req, "<td style=\"color: %s; background-color: #%02X%02X%02X\">%lu/%lu</td>\n", color, r, g, b, limit, usage);
2272 }
2273 }
2274
2275 void mod_cband_status_print_virtualhost_row(request_rec *r, mod_cband_virtualhost_config_entry *entry,
2276 int handler_type, int refresh, char *unit, unsigned long long *total_traffic) {
2277
2278 mod_cband_scoreboard_entry *virtual_usage;
2279 unsigned long slice_limit;
2280 float bps, rps;
2281 int i;
2282
2283 virtual_usage = &entry->shmem_data->total_usage;
2284
2285 ap_rputs("<tr>\n", r);
2286 ap_rprintf(r, "<td><a href=\"http://%s\">%s</a>:%d:(%d)</td>\n", entry->virtual_name, entry->virtual_name, entry->virtual_port, entry->virtual_defn_line);
2287 if (handler_type == CBAND_HANDLER_ALL)
2288 ap_rprintf(r, "<td><a href=\"?reset=%s:%d:%d&refresh=%d&unit=%s\">reset</a></td>\n", entry->virtual_name, entry->virtual_port, entry->virtual_defn_line, refresh, unit);
2289 ap_rprintf(r, "<td class=\"refresh\">%s</td>\n", mod_cband_create_period(r->pool, virtual_usage->start_time, entry->refresh_time));
2290
2291 slice_limit = mod_cband_get_slice_limit(entry->shmem_data->total_usage.start_time, entry->refresh_time, entry->slice_len, entry->virtual_limit);
2292 mod_cband_status_print_limit(r, entry->virtual_limit, (unsigned long)(virtual_usage->total_bytes / entry->virtual_limit_mult),
2293 unit, entry->virtual_limit_mult, slice_limit);
2294
2295 for (i = 0; i < DST_CLASS; i++) {
2296 slice_limit = mod_cband_get_slice_limit(entry->shmem_data->total_usage.start_time, entry->refresh_time, entry->slice_len, entry->virtual_class_limit[i]);
2297 mod_cband_status_print_limit(r, entry->virtual_class_limit[i], (unsigned long)(virtual_usage->class_bytes[i] / entry->virtual_class_limit_mult[i]),
2298 unit, entry->virtual_class_limit_mult[i], slice_limit);
2299 }
2300
2301 mod_cband_update_speed_lock(entry->shmem_data, 0, 0, -1);
2302 mod_cband_get_speed_lock(entry->shmem_data, &bps, &rps);
2303 mod_cband_status_print_speed(r, entry->shmem_data->curr_speed.kbps, bps / 1024);
2304 mod_cband_status_print_speed(r, entry->shmem_data->curr_speed.rps, rps);
2305 mod_cband_status_print_connections(r, entry->shmem_data->curr_speed.max_conn, entry->shmem_data->total_conn);
2306
2307 if (entry->virtual_user)
2308 ap_rprintf(r, "<td>%s</td>\n", entry->virtual_user);
2309 else
2310 ap_rprintf(r, "<td>none</td>\n");
2311
2312 ap_rputs("</tr>\n", r);
2313
2314 *total_traffic = virtual_usage->total_bytes;
2315 }
2316
2317 void mod_cband_status_print_user_row(request_rec *r, mod_cband_user_config_entry *entry_user,
2318 int handler_type, int refresh, char *unit) {
2319
2320 mod_cband_scoreboard_entry *user_usage;
2321 unsigned long slice_limit;
2322 float bps, rps;
2323 int i;
2324
2325 user_usage = &entry_user->shmem_data->total_usage;
2326
2327 ap_rputs("<tr>\n", r);
2328 ap_rprintf(r, "<td>%s</td>\n", entry_user->user_name);
2329 if (handler_type == CBAND_HANDLER_ALL)
2330 ap_rprintf(r, "<td><a href=\"?reset_user=%s&refresh=%d&unit=%s\">reset</a></td>\n", entry_user->user_name, refresh, unit);
2331 ap_rprintf(r, "<td class=\"refresh\">%s</td>\n", mod_cband_create_period(r->pool, user_usage->start_time, entry_user->refresh_time));
2332
2333 slice_limit = mod_cband_get_slice_limit(entry_user->shmem_data->total_usage.start_time, entry_user->refresh_time, entry_user->slice_len, entry_user->user_limit);
2334 mod_cband_status_print_limit(r, entry_user->user_limit, (unsigned long)(user_usage->total_bytes / entry_user->user_limit_mult),
2335 unit, entry_user->user_limit_mult, slice_limit);
2336
2337 for (i = 0; i < DST_CLASS; i++) {
2338 slice_limit = mod_cband_get_slice_limit(entry_user->shmem_data->total_usage.start_time, entry_user->refresh_time, entry_user->slice_len, entry_user->user_class_limit[i]);
2339 mod_cband_status_print_limit(r, entry_user->user_class_limit[i], (unsigned long)(user_usage->class_bytes[i] / entry_user->user_class_limit_mult[i]),
2340 unit, entry_user->user_class_limit_mult[i], slice_limit);
2341 }
2342
2343 mod_cband_update_speed_lock(entry_user->shmem_data, 0, 0, -1);
2344 mod_cband_get_speed_lock(entry_user->shmem_data, &bps, &rps);
2345 mod_cband_status_print_speed(r, entry_user->shmem_data->curr_speed.kbps, bps / 1024);
2346 mod_cband_status_print_speed(r, entry_user->shmem_data->curr_speed.rps, rps);
2347 mod_cband_status_print_connections(r, entry_user->shmem_data->curr_speed.max_conn, entry_user->shmem_data->total_conn);
2348
2349 ap_rputs("</tr>\n", r);
2350 }
2351
2352 void mod_cband_status_print_virtualhost_XML_row(request_rec *r, mod_cband_virtualhost_config_entry *entry,
2353 int handler_type) {
2354
2355 float bps, rps;
2356 mod_cband_class_config_entry *entry_class;
2357 mod_cband_scoreboard_entry *virtual_usage;
2358 int i;
2359
2360 virtual_usage = &entry->shmem_data->total_usage;
2361
2362 mod_cband_update_speed_lock(entry->shmem_data, 0, 0, -1);
2363 mod_cband_get_speed_lock(entry->shmem_data, &bps, &rps);
2364
2365 ap_rprintf(r, "\t\t<%s>\n", entry->virtual_name);
2366 ap_rprintf(r, "\t\t\t<port>%d</port>\n", entry->virtual_port);
2367 ap_rprintf(r, "\t\t\t<line>%d</line>\n", entry->virtual_defn_line);
2368 ap_rprintf(r, "\t\t\t<limits>\n");
2369
2370 ap_rprintf(r, "\t\t\t\t<total>%lu%s</total>\n", entry->virtual_limit,
2371 (entry->virtual_limit_mult == 1024 ? "KiB" : "KB"));
2372
2373 entry_class = config->next_class;
2374 i = 0;
2375 while(entry_class != NULL) {
2376 ap_rprintf(r, "\t\t\t\t<%s>%lu%s</%s>\n", entry_class->class_name, entry->virtual_class_limit[i],
2377 (entry->virtual_class_limit_mult[i] == 1024 ? "KiB" : "KB"), entry_class->class_name);
2378 i++;
2379 entry_class = entry_class->next;
2380 }
2381 ap_rprintf(r, "\t\t\t\t<kbps>%lu</kbps>\n", entry->shmem_data->curr_speed.kbps);
2382 ap_rprintf(r, "\t\t\t\t<rps>%lu</rps>\n", entry->shmem_data->curr_speed.rps);
2383 ap_rprintf(r, "\t\t\t\t<connections>%lu</connections>\n", entry->shmem_data->curr_speed.max_conn);
2384 ap_rprintf(r, "\t\t\t</limits>\n");
2385
2386 ap_rprintf(r, "\t\t\t<usages>\n");
2387 ap_rprintf(r, "\t\t\t\t<total>%luKiB</total>\n", (unsigned long)(virtual_usage->total_bytes / 1024));
2388 entry_class = config->next_class;
2389 i = 0;
2390 while(entry_class != NULL) {
2391 ap_rprintf(r, "\t\t\t\t<%s>%lu%s</%s>\n", entry_class->class_name,
2392 (unsigned long)(virtual_usage->class_bytes[i] / entry->virtual_class_limit_mult[i]),
2393 (entry->virtual_class_limit_mult[i] == 1024 ? "KiB" : "KB"), entry_class->class_name);
2394 i++;
2395 entry_class = entry_class->next;
2396 }
2397 ap_rprintf(r, "\t\t\t\t<kbps>%0.2f</kbps>\n", bps / 1024);
2398 ap_rprintf(r, "\t\t\t\t<rps>%0.2f</rps>\n", rps);
2399 ap_rprintf(r, "\t\t\t\t<connections>%lu</connections>\n", entry->shmem_data->total_conn);
2400 ap_rprintf(r, "\t\t\t</usages>\n");
2401
2402 ap_rprintf(r, "<time_to_refresh>%s</time_to_refresh>", mod_cband_create_period(r->pool, virtual_usage->start_time, entry->refresh_time));
2403
2404 if (entry->virtual_user)
2405 ap_rprintf(r, "\t\t\t<user>%s</user>\n", entry->virtual_user);
2406 else
2407 ap_rprintf(r, "\t\t\t<user>none</user>\n");
2408
2409 if (entry->virtual_scoreboard)
2410 ap_rprintf(r, "\t\t\t<scoreboard>%s</scoreboard>\n", entry->virtual_scoreboard);
2411 else
2412 ap_rprintf(r, "\t\t\t<scoreboard>none</scoreboard>\n");
2413
2414 if (entry->virtual_limit_exceeded)
2415 ap_rprintf(r, "\t\t\t<limit_exceeded_URL>%s</limit_exceeded_URL>\n", entry->virtual_limit_exceeded);
2416 else
2417 ap_rprintf(r, "\t\t\t<limit_exceeded_URL>none</limit_exceeded_URL>\n");
2418
2419 ap_rprintf(r, "\t\t</%s>\n", entry->virtual_name);
2420 }
2421
2422 void mod_cband_status_print_user_XML_row(request_rec *r, mod_cband_user_config_entry *entry_user,
2423 int handler_type) {
2424
2425 float bps, rps;
2426 mod_cband_class_config_entry *entry_class;
2427 mod_cband_scoreboard_entry *user_usage;
2428 int i;
2429
2430 user_usage = &entry_user->shmem_data->total_usage;
2431
2432 mod_cband_update_speed_lock(entry_user->shmem_data, 0, 0, -1);
2433 mod_cband_get_speed_lock(entry_user->shmem_data, &bps, &rps);
2434
2435 ap_rprintf(r, "\t\t<%s>\n", entry_user->user_name);
2436 ap_rprintf(r, "\t\t\t<limits>\n");
2437 ap_rprintf(r, "\t\t\t\t<total>%lu%s</total>\n", entry_user->user_limit,
2438 (entry_user->user_limit_mult == 1024 ? "KiB" : "KB"));
2439
2440 entry_class = config->next_class;
2441 i = 0;
2442 while(entry_class != NULL) {
2443 ap_rprintf(r, "\t\t\t\t<%s>%lu%s</%s>\n", entry_class->class_name, entry_user->user_class_limit[i],
2444 (entry_user->user_class_limit_mult[i] == 1024 ? "KiB" : "KB"), entry_class->class_name);
2445 i++;
2446 entry_class = entry_class->next;
2447 }
2448
2449 ap_rprintf(r, "\t\t\t\t<kbps>%lu</kbps>\n", entry_user->shmem_data->curr_speed.kbps);
2450 ap_rprintf(r, "\t\t\t\t<rps>%lu</rps>\n", entry_user->shmem_data->curr_speed.rps);
2451 ap_rprintf(r, "\t\t\t\t<connections>%lu</connections>\n", entry_user->shmem_data->curr_speed.max_conn);
2452 ap_rprintf(r, "\t\t\t</limits>\n");
2453
2454 ap_rprintf(r, "\t\t\t<usages>\n");
2455 ap_rprintf(r, "\t\t\t\t<total>%luKiB</total>\n", (unsigned long)(user_usage->total_bytes / 1024));
2456 entry_class = config->next_class;
2457 i = 0;
2458 while(entry_class != NULL) {
2459 ap_rprintf(r, "\t\t\t\t<%s>%lu%s</%s>\n", entry_class->class_name,
2460 (unsigned long)(user_usage->class_bytes[i] / entry_user->user_class_limit_mult[i]),
2461 (entry_user->user_class_limit_mult[i] == 1024 ? "KiB" : "KB"), entry_class->class_name);
2462 i++;
2463 entry_class = entry_class->next;
2464 }
2465 ap_rprintf(r, "\t\t\t\t<kbps>%0.2f</kbps>\n", bps / 1024);
2466 ap_rprintf(r, "\t\t\t\t<rps>%0.2f</rps>\n", rps);
2467 ap_rprintf(r, "\t\t\t\t<connections>%lu</connections>\n", entry_user->shmem_data->total_conn);
2468 ap_rprintf(r, "\t\t\t</usages>\n");
2469
2470 ap_rprintf(r, "<time_to_refresh>%s</time_to_refresh>", mod_cband_create_period(r->pool, user_usage->start_time, entry_user->refresh_time));
2471
2472 if (entry_user->user_limit_exceeded)
2473 ap_rprintf(r, "\t\t\t<limit_exceeded_URL>%s</limit_exceeded_URL>\n", entry_user->user_limit_exceeded);
2474 else
2475 ap_rprintf(r, "\t\t\t<limit_exceeded_URL>none</limit_exceeded_URL>\n");
2476
2477 if (entry_user->user_scoreboard)
2478 ap_rprintf(r, "\t\t\t<scoreboard>%s</scoreboard>\n", entry_user->user_scoreboard);
2479 else
2480 ap_rprintf(r, "\t\t\t<scoreboard>none</scoreboard>\n");
2481
2482 ap_rprintf(r, "\t\t</%s>\n", entry_user->user_name);
2483 }
2484
2485 static const char mod_cband_status_handler_style[] =
2486 "\n<style type=\"text/css\">\n"
2487 "body { font-family: sans-serif; font-size: 0.6em; }\n"
2488 "table { font-family: tachoma, helvetica, verdana, sans-serif; border: 1px solid #d0d0d0; }\n"
2489 "tr { font-family: tachoma, helvetica, verdana, sans-serif; border: 1px solid #d0d0d0; }\n"
2490 "td { padding-left: 0.5em; padding-right: 0.5em; }\n"
2491 "td.refresh { background-color: #0de2cb; text-align: right; }\n"
2492 "td.speed { background-color: #ffa1a1; text-align: left; }\n"
2493 "td.speedc { background-color: #ffb1b1; text-align: left; }\n"
2494 "td.remote_odd { background-color: #b4bfff; text-align: left; }\n"
2495 "td.remote_even { background-color: #bfcfff; text-align: left; }\n"
2496 "a { text-decoration: none; color: #606060; }\n"
2497 "a:hover { text-decoration: underline; }\n"
2498 "h1, h2 { font-family: tachoma, helvetica, verdana, sans-serif}\n"
2499 ".small { font-size: smaller; }\n"
2500 "div.section { margin-top: 1.5em; margin-bottom: 0.5em; }\n"
2501 "div.footer { margin-top: 2.5em; text-align: center; font-size: smaller; }\n"
2502 "</style>\n\n";
2503
2504 static const char mod_cband_status_handler_foot[] =
2505 "\n<div class=\"footer\"><br>\n"
2506 "<p><a href=\"http://cband.linux.pl\">mod_cband 0.9.7.5</a><br>\n"
2507 "Copyright 2005 by <a href=\"mailto: dembol _at_ cband.linux.pl\">Lukasz Dembinski</a><br>\n"
2508 "All rights reserved.<br>\n"
2509 "<br><a href=\"http://validator.w3.org/check?uri=http%3A%2F%2Fdembol.nasa.pl%2Fcband-status\">[HTML 4.0 Strict]</a>\n"
2510 "</p></div>\n";
2511
2512 /**
2513 * /cband-status handler output in HTML
2514 */
2515 static int mod_cband_status_handler_HTML (request_rec *r, int handler_type)
2516 {
2517 mod_cband_virtualhost_config_entry *entry = NULL, *entry_me = NULL;
2518 mod_cband_user_config_entry *entry_user, *entry_user_me = NULL;
2519 mod_cband_class_config_entry *entry_class;
2520 unsigned long uptime, sec;
2521 unsigned i;
2522 char *arg;
2523 char *val, *key;
2524 int refresh = -1;
2525 char *unit = "";
2526 int vhosts_number = 0, users_number = 0;
2527 unsigned long long traffic, total_traffic = 0;
2528 unsigned long total_connections = 0;
2529 float bps, current_speed_bps = 0;
2530 float rps, current_speed_rps = 0;
2531 struct in_addr remote_addr;
2532 unsigned long time_now, time_delta;
2533 int odd = 0, ok = 0;
2534 const char *odd_str;
2535
2536 if (r->args != NULL) {
2537
2538 arg = r->args;
2539 while(*arg != 0) {
2540 val = ap_getword_nc(r->pool, &arg, '&');
2541
2542 if (val == NULL)
2543 break;
2544
2545 key = ap_getword_nc(r->pool, &val, '=');
2546
2547 if (key == NULL)
2548 break;
2549
2550 apr_table_setn(r->notes, key, val);
2551 }
2552 }
2553
2554 if ((arg = (char *)apr_table_get(r->notes, "refresh")) != NULL)
2555 refresh = atoi(arg);
2556
2557 if ((arg = (char *)apr_table_get(r->notes, "unit")) != NULL) {
2558 if (arg[0] == 'G' || arg[0] == 'g' || arg[0] == 'M' || arg[0] == 'm' || arg[0] == 'K' || arg[0] == 'k') {
2559 arg[0] = toupper(arg[0]);
2560 if (arg[1] == 'I' || arg[1] == 'i') {
2561 arg[1] = 'i';
2562 arg[2] = 0;
2563 unit = arg;
2564 } else {
2565 arg[1] = 0;
2566 unit = arg;
2567 }
2568 }
2569 }
2570
2571 if (refresh < 0)
2572 refresh = DEFAULT_REFRESH;
2573
2574 if (handler_type == CBAND_HANDLER_ALL) {
2575 if ((arg = (char *)apr_table_get(r->notes, "reset")) != NULL) {
2576 mod_cband_reset_virtualhost(arg);
2577
2578 apr_table_setn(r->headers_out, "Location", apr_psprintf(r->pool, "%s?refresh=%d&unit=%s", r->uri, refresh, unit));
2579 return HTTP_MOVED_PERMANENTLY;
2580 }
2581
2582 if ((arg = (char *)apr_table_get(r->notes, "reset_user")) != NULL) {
2583 mod_cband_reset_user(arg);
2584
2585 apr_table_setn(r->headers_out, "Location", apr_psprintf(r->pool, "%s?refresh=%d&unit=%s", r->uri, refresh, unit));
2586 return HTTP_MOVED_PERMANENTLY;
2587 }
2588 } else {
2589 if ((entry_me = mod_cband_get_virtualhost_entry(r->server, r->server->module_config, 0)) != NULL) {
2590 if (entry_me->virtual_user != NULL)
2591 entry_user_me = mod_cband_get_user_entry(entry_me->virtual_user, r->server->module_config, 0);
2592 else
2593 entry_user_me = NULL;
2594 }
2595 }
2596
2597 sec = (unsigned long)(apr_time_now() / 1e6);
2598 uptime = (unsigned long)(sec - config->start_time);
2599
2600 apr_table_setn(r->headers_out, "Refresh", apr_psprintf(r->pool, "%d", refresh));
2601 ap_set_content_type(r, "text/html");
2602
2603 ap_rputs(DOCTYPE_HTML_4_0S "<html>\n<head>\n<title>mod_cband status</title>\n", r);
2604 ap_rputs("<meta http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8\">\n", r);
2605 ap_rputs(mod_cband_status_handler_style, r);
2606 ap_rputs("</head>\n", r);
2607 ap_rputs("<body>\n", r);
2608 ap_rputs("<h1 style=\"text-align: center\"><a href=\"http://cband.linux.pl\">mod_cband</a> status page</h1>\n", r);
2609 ap_rprintf(r, "<h2 style=\"text-align: center\">Server uptime %s</h2>\n", mod_cband_create_time(r->pool, uptime));
2610 ap_rputs("<div class=\"section\">", r);
2611 ap_rputs("<h2 style=\"display: inline;\">Virtual hosts</h2>\n", r);
2612 ap_rprintf(r, "<p style=\"display: inline;\"><a href=\"?refresh=%d&unit=%s\">[refresh]</a> <a href=\"?refresh=%d\">[human-readable]</a> <a href=\"?refresh=%d&unit=G\">[GB]</a> <a href=\"?refresh=%d&unit=M\">[MB]</a> <a href=\"?refresh=%d&unit=K\">[KB]</a></p>\n", refresh, unit, refresh, refresh, refresh, refresh);
2613 ap_rputs("</div>\n", r);
2614
2615 if (((handler_type == CBAND_HANDLER_ME) && (entry_me == NULL)) ||
2616 ((handler_type == CBAND_HANDLER_ALL) && (config->next_virtualhost == NULL)))
2617 ap_rputs("<p>There are no limits set for virtual hosts.</p>\n", r);
2618 else {
2619 ap_rputs("<table cellspacing=\"0\" cellpadding=\"0\">\n", r);
2620 ap_rputs("<tr>\n<td>Virtual host name</td>\n", r);
2621
2622 if (handler_type == CBAND_HANDLER_ALL) {
2623 ap_rputs("<td>", r);
2624 ap_rprintf(r, "<a href=\"?reset=all&refresh=%d&unit=%s\">reset all</a></td>\n", refresh, unit);
2625 }
2626
2627 ap_rputs("<td>time to refresh</td>\n", r);
2628 ap_rprintf(r,"<td>Total<br>Limit/Slice/Used</td>\n");
2629 entry_class = config->next_class;
2630
2631 i = 0;
2632 while(entry_class != NULL) {
2633 ap_rprintf(r,"<td>%s<br>Limit/Slice/Used</td>\n", entry_class->class_name);
2634
2635 entry_class = entry_class->next;
2636 i++;
2637 }
2638
2639 for (; i < DST_CLASS; i++)
2640 ap_rprintf(r,"<td>Class %d<br>Limit/Slice/Used</td>\n",i);
2641
2642 ap_rprintf(r,"<td>kbps<br>Limit/Current</td>\n");
2643 ap_rprintf(r,"<td>rps<br>Limit/Current</td>\n");
2644 ap_rprintf(r,"<td>Connections<br>Limit/Current</td>\n");
2645
2646 ap_rputs("<td>user</td>\n", r);
2647 ap_rputs("</tr>\n", r);
2648
2649 current_speed_bps = 0;
2650 current_speed_rps = 0;
2651 if (handler_type == CBAND_HANDLER_ALL) {
2652 entry = config->next_virtualhost;
2653 while(entry != NULL) {
2654 mod_cband_check_virtualhost_refresh(entry, sec);
2655 mod_cband_status_print_virtualhost_row(r, entry, handler_type, refresh, unit, &traffic);
2656 total_traffic += traffic;
2657 total_connections += entry->shmem_data->total_conn;
2658 vhosts_number++;
2659
2660 mod_cband_get_speed_lock(entry->shmem_data, &bps, &rps);
2661 current_speed_bps += bps;
2662 current_speed_rps += rps;
2663
2664 if ((entry = entry->next) == NULL)
2665 break;
2666 }
2667 } else {
2668 if ((entry_user_me != NULL) && (entry_user_me->user_name != NULL)) {
2669 entry = config->next_virtualhost;
2670 while(entry != NULL) {
2671 if ((entry->virtual_user != NULL) && !strcasecmp(entry->virtual_user, entry_user_me->user_name)) {
2672 mod_cband_check_virtualhost_refresh(entry, sec);
2673 mod_cband_status_print_virtualhost_row(r, entry, handler_type, refresh, unit, &traffic);
2674 }
2675
2676 if ((entry = entry->next) == NULL)
2677 break;
2678 }
2679 } else
2680 if (entry_me != NULL) {
2681 mod_cband_check_virtualhost_refresh(entry_me, sec);
2682 mod_cband_status_print_virtualhost_row(r, entry_me, handler_type, refresh, unit, &traffic);
2683 }
2684 }
2685
2686 ap_rputs("</table>\n", r);
2687 }
2688
2689 ap_rputs("<div class=\"section\">", r);
2690 ap_rputs("<br><h2 style=\"display: inline;\">Users</h2>\n", r);
2691 ap_rprintf(r, "<p style=\"display: inline;\"><a href=\"?refresh=%d&unit=%s\">[refresh]</a> <a href=\"?refresh=%d\">[human-readable]</a> <a href=\"?refresh=%d&unit=G\">[GB]</a> <a href=\"?refresh=%d&unit=M\">[MB]</a> <a href=\"?refresh=%d&unit=K\">[KB]</a></p>\n", refresh, unit, refresh, refresh, refresh, refresh);
2692 ap_rputs("</div>\n", r);
2693
2694 if (((handler_type == CBAND_HANDLER_ME) && (entry_user_me == NULL)) ||
2695 ((handler_type == CBAND_HANDLER_ALL) && (config->next_user == NULL)))
2696 ap_rputs("<p>There are no limits set for users.</p>\n", r);
2697 else {
2698 ap_rputs("<table cellspacing=\"0\" cellpadding=\"0\">\n", r);
2699 ap_rputs("<tr>\n<td>Username</td>\n", r);
2700
2701 if (handler_type == CBAND_HANDLER_ALL) {
2702 ap_rputs("<td>", r);
2703 ap_rprintf(r, "<a href=\"?reset_user=all&refresh=%d&unit=%s\">reset all</a></td>\n", refresh, unit);
2704 }
2705
2706 ap_rputs("<td>time to refresh</td>\n", r);
2707 ap_rprintf(r,"<td>Total<br>Limit/Slice/Used</td>\n");
2708 entry_class = config->next_class;
2709
2710 i = 0;
2711 while(entry_class != NULL) {
2712 ap_rprintf(r,"<td>%s<br>Limit/Slice/Used</td>\n", entry_class->class_name);
2713
2714 entry_class = entry_class->next;
2715 i++;
2716 }
2717
2718 for (; i < DST_CLASS; i++)
2719 ap_rprintf(r,"<td>Class %d<br>Limit/Slice/Used</td>\n",i);
2720
2721 ap_rprintf(r,"<td>kbps<br>Limit/Current</td>\n");
2722 ap_rprintf(r,"<td>rps<br>Limit/Current</td>\n");
2723 ap_rprintf(r,"<td>Connections<br>Limit/Current</td>\n");
2724
2725 ap_rputs("</tr>\n", r);
2726
2727 if (handler_type == CBAND_HANDLER_ALL) {
2728 entry_user = config->next_user;
2729
2730 while(entry_user != NULL) {
2731 mod_cband_check_user_refresh(entry_user, sec);
2732 mod_cband_status_print_user_row(r, entry_user, handler_type, refresh, unit);
2733 users_number++;
2734
2735 if ((entry_user = entry_user->next) == NULL)
2736 break;
2737 }
2738 } else {
2739 if (entry_user_me != NULL) {
2740 mod_cband_check_user_refresh(entry_user_me, sec);
2741 mod_cband_status_print_user_row(r, entry_user_me, handler_type, refresh, unit);
2742 }
2743 }
2744
2745 ap_rputs("</table>\n", r);
2746 }
2747
2748 ap_rputs("<table width=\"100%\" cellspacing=\"0\" cellpadding=\"0\" style=\"border: 0; margin: 0; padding: 0\">", r);
2749 ap_rputs("<tr>", r);
2750 ap_rputs("<td valign=top>", r);
2751
2752 ap_rputs("<div class=\"section\">", r);
2753 ap_rputs("<br><h2 style=\"display: inline;\">Remote clients</h2>\n", r);
2754 ap_rprintf(r, "<p style=\"display: inline;\"><a href=\"?refresh=%d&unit=%s\">[refresh]</a> <a href=\"?refresh=%d\">[human-readable]</a> <a href=\"?refresh=%d&unit=G\">[GB]</a> <a href=\"?refresh=%d&unit=M\">[MB]</a> <a href=\"?refresh=%d&unit=K\">[KB]</a></p>\n", refresh, unit, refresh, refresh, refresh, refresh);
2755 ap_rputs("</div>", r);
2756 ap_rputs("<table width=500 cellspacing=\"0\" cellpadding=\"0\">", r);
2757
2758 ap_rputs("<tr>", r);
2759 ap_rprintf(r, "<td>Remote IP</td>");
2760 ap_rprintf(r, "<td>Virtualhost</td>");
2761 ap_rprintf(r, "<td>Connections<br>Limit/Current</td>");
2762 ap_rprintf(r, "<td>Last speed/conn [kbps]</td>");
2763 ap_rputs("</tr>", r);
2764
2765 time_now = apr_time_now();
2766 for (i = 0; i < MAX_REMOTE_HOSTS; i++) {
2767 time_delta = (time_now - config->remote_hosts.hosts[i].remote_last_time) / 1e6;
2768
2769 if ((!config->remote_hosts.hosts[i].used) || ((time_delta > MAX_REMOTE_HOST_LIFE) && (config->remote_hosts.hosts[i].remote_conn <= 0)))
2770 continue;
2771
2772 if (handler_type != CBAND_HANDLER_ALL) {
2773 ok = 0;
2774
2775 if ((entry_user_me != NULL) && (entry_user_me->user_name != NULL)) {
2776
2777 entry = config->next_virtualhost;
2778 while(entry != NULL) {
2779
2780 if ((entry->virtual_name != NULL) && (config->remote_hosts.hosts[i].virtual_name != NULL) &&
2781 (entry->virtual_user != NULL) &&
2782 (!strcasecmp(entry->virtual_name, config->remote_hosts.hosts[i].virtual_name)) &&
2783 (!strcasecmp(entry_user_me->user_name, entry->virtual_user))) {
2784 ok = 1;
2785 break;
2786 }
2787
2788 if ((entry = entry->next) == NULL)
2789 break;
2790 }
2791 } else
2792 if (!strcasecmp(r->server->server_hostname, config->remote_hosts.hosts[i].virtual_name))
2793 ok = 1;
2794
2795 if (!ok)
2796 continue;
2797 }
2798
2799 if (odd == 0) {
2800 odd_str = "even";
2801 odd = 1;
2802 } else {
2803 odd_str = "odd";
2804 odd = 0;
2805 }
2806
2807 remote_addr.s_addr = config->remote_hosts.hosts[i].remote_addr;
2808 ap_rputs("<tr>", r);
2809 ap_rprintf(r, "<td class=remote_%s>%s</td>", odd_str, inet_ntoa((struct in_addr)remote_addr));
2810 ap_rprintf(r, "<td class=remote_%s>%s</td>", odd_str, config->remote_hosts.hosts[i].virtual_name);
2811 mod_cband_status_print_connections(r, config->remote_hosts.hosts[i].remote_max_conn, config->remote_hosts.hosts[i].remote_conn);
2812
2813 ap_rprintf(r, "<td class=remote_%s>%lu</td>", odd_str, config->remote_hosts.hosts[i].remote_kbps);
2814 ap_rputs("</tr>", r);
2815
2816 if ((time_delta > (MAX_REMOTE_HOST_LIFE / 3)) && (config->remote_hosts.hosts[i].remote_conn <= 0))
2817 mod_cband_set_remote_current_speed(i, 0);
2818
2819 }
2820 ap_rputs("</table>", r);
2821 ap_rputs("</td>", r);
2822
2823 ap_rputs("<td valign=top>", r);
2824 if (handler_type == CBAND_HANDLER_ALL) {
2825 ap_rputs("<div class=\"section\">", r);
2826 ap_rputs("<br><h2 style=\"display: inline;\">Server summary</h2>\n", r);
2827 ap_rprintf(r, "<p style=\"display: inline;\"><a href=\"?refresh=%d&unit=%s\">[refresh]</a> <a href=\"?refresh=%d\">[human-readable]</a> <a href=\"?refresh=%d&unit=G\">[GB]</a> <a href=\"?refresh=%d&unit=M\">[MB]</a> <a href=\"?refresh=%d&unit=K\">[KB]</a></p>\n", refresh, unit, refresh, refresh, refresh, refresh);
2828 ap_rputs("</div>", r);
2829 ap_rputs("<table width=400>", r);
2830
2831 ap_rputs("<tr>", r);
2832 ap_rputs("<td>Server uptime</td>", r);
2833 ap_rprintf(r, "<td>%s</td>", mod_cband_create_time(r->pool, uptime));
2834 ap_rputs("</tr>", r);
2835
2836 ap_rputs("<tr>", r);
2837 ap_rputs("<td>Total virtualhosts</td>", r);
2838 ap_rprintf(r, "<td>%d</td>", vhosts_number);
2839 ap_rputs("</tr>", r);
2840
2841 ap_rputs("<tr>", r);
2842 ap_rputs("<td>Total users</td>", r);
2843 ap_rprintf(r, "<td>%d</td>", users_number);
2844 ap_rputs("</tr>", r);
2845
2846 ap_rputs("<tr>", r);
2847 ap_rputs("<td>Total connections</td>", r);
2848 ap_rprintf(r, "<td>%lu</td>", total_connections);
2849 ap_rputs("</tr>", r);
2850
2851 ap_rputs("<tr>", r);
2852 ap_rputs("<td>Total traffic</td>", r);
2853 ap_rprintf(r, "<td>%s</td>", mod_cband_create_traffic_size(r->pool, total_traffic / 1000, unit, 1000));
2854 ap_rputs("</tr>", r);
2855
2856 ap_rputs("<tr>", r);
2857 ap_rputs("<td>Current speed</td>", r);
2858 ap_rprintf(r, "<td>%0.2f kbps / %0.2f rps</td>", current_speed_bps / 1024, current_speed_rps);
2859 ap_rputs("</tr>", r);
2860 ap_rputs("</table>", r);
2861 }
2862
2863 ap_rputs("</td>", r);
2864 ap_rputs("</tr>", r);
2865 ap_rputs("</table>", r);
2866
2867 ap_rputs(mod_cband_status_handler_foot, r);
2868 ap_rputs("</body>\n</html>\n", r);
2869
2870 return OK;
2871 }
2872
2873 /**
2874 * /cband-status handler output in XML
2875 */
2876 static int mod_cband_status_handler_XML (request_rec *r, int handler_type)
2877 {
2878 mod_cband_virtualhost_config_entry *entry, *entry_me = NULL;
2879 mod_cband_user_config_entry *entry_user, *entry_user_me = NULL;
2880 unsigned long sec, uptime;
2881
2882 if (handler_type == CBAND_HANDLER_ME) {
2883 if ((entry_me = mod_cband_get_virtualhost_entry(r->server, r->server->module_config, 0)) != NULL) {
2884 if (entry_me->virtual_user != NULL)
2885 entry_user_me = mod_cband_get_user_entry(entry_me->virtual_user, r->server->module_config, 0);
2886 }
2887 }
2888
2889 sec = (unsigned long)(apr_time_now() / 1e6);
2890 uptime = (unsigned long)(sec - config->start_time);
2891
2892 ap_set_content_type(r, "text/xml");
2893
2894 ap_rputs("<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n", r);
2895 ap_rputs("<mod_cband>\n", r);
2896 ap_rputs("\t<Server>\n", r);
2897 ap_rprintf(r, "\t\t<uptime>%s</uptime>\n", mod_cband_create_time(r->pool, uptime));
2898 ap_rputs("\t</Server>\n", r);
2899
2900 ap_rputs("\t<Virtualhosts>\n", r);
2901 if (handler_type == CBAND_HANDLER_ALL) {
2902 entry = config->next_virtualhost;
2903
2904 while(entry != NULL) {
2905 mod_cband_check_virtualhost_refresh(entry, sec);
2906 mod_cband_status_print_virtualhost_XML_row(r, entry, handler_type);
2907
2908 if ((entry = entry->next) == NULL)
2909 break;
2910 }
2911 } else {
2912 if ((entry_user_me != NULL) && (entry_user_me->user_name != NULL)) {
2913 entry = config->next_virtualhost;
2914 while(entry != NULL) {
2915 if ((entry->virtual_user != NULL) && !strcasecmp(entry->virtual_user, entry_user_me->user_name)) {
2916 mod_cband_check_virtualhost_refresh(entry, sec);
2917 mod_cband_status_print_virtualhost_XML_row(r, entry, handler_type);
2918 }
2919
2920 if ((entry = entry->next) == NULL)
2921 break;
2922 }
2923 } else
2924 if (entry_me != NULL) {
2925 mod_cband_check_virtualhost_refresh(entry_me, sec);
2926 mod_cband_status_print_virtualhost_XML_row(r, entry_me, handler_type);
2927 }
2928 }
2929
2930 ap_rputs("\t</Virtualhosts>\n", r);
2931 ap_rputs("\t<Users>\n", r);
2932
2933 if (handler_type == CBAND_HANDLER_ALL) {
2934 entry_user = config->next_user;
2935
2936 while(entry_user != NULL) {
2937 mod_cband_check_user_refresh(entry_user, sec);
2938 mod_cband_status_print_user_XML_row(r, entry_user, handler_type);
2939
2940 if ((entry_user = entry_user->next) == NULL)
2941 break;
2942 }
2943 } else {
2944 if (entry_user_me != NULL) {
2945 mod_cband_check_user_refresh(entry_user_me, sec);
2946 mod_cband_status_print_user_XML_row(r, entry_user_me, handler_type);
2947 }
2948 }
2949
2950 ap_rputs("\t</Users>\n", r);
2951 ap_rputs("</mod_cband>", r);
2952
2953 return OK;
2954 }
2955
2956 int mod_cband_check_connections_speed(mod_cband_virtualhost_config_entry *entry, mod_cband_user_config_entry *entry_user, request_rec *r, int dst)
2957 {
2958 float virtualhost_rps, virtualhost_curr_rps;
2959 float user_rps, user_curr_rps;
2960 float remote_rps;
2961 unsigned long max_remote_kbps, remote_curr_rps, remote_max_conn, remote_total_conn;
2962 int remote_idx;
2963 unsigned long time_now;
2964 int loops;
2965 int overlimit;
2966
2967 remote_idx = mod_cband_get_remote_host(r->connection, 1, entry);
2968 mod_cband_get_dst_speed_lock(entry, entry_user, &max_remote_kbps, &remote_curr_rps, &remote_max_conn, dst);
2969 mod_cband_set_remote_max_connections(remote_idx, remote_max_conn);
2970
2971 virtualhost_curr_rps = 0;
2972 user_curr_rps = 0;
2973 virtualhost_rps = 0;
2974 user_rps = 0;
2975 remote_rps = 0;
2976 time_now = apr_time_now();
2977
2978 loops = 0;
2979 do {
2980 /* BEGIN CRITICAL SECTION */
2981 mod_cband_sem_down(config->sem_id);
2982
2983 if (entry != NULL) {
2984
2985 mod_cband_update_speed(entry->shmem_data, 0, 0, remote_idx);
2986 if ((entry->shmem_data->curr_speed.max_conn > 0) &&
2987 (entry->shmem_data->total_conn >= entry->shmem_data->curr_speed.max_conn)) {
2988
2989 mod_cband_sem_up(config->sem_id);
2990 /* END CRITICAL SECTION */
2991
2992 return HTTP_SERVICE_UNAVAILABLE;
2993 }
2994
2995 mod_cband_get_real_speed(entry->shmem_data, NULL, &virtualhost_rps);
2996 virtualhost_curr_rps = entry->shmem_data->curr_speed.rps;
2997 }
2998
2999 if (entry_user != NULL) {
3000
3001 mod_cband_update_speed(entry_user->shmem_data, 0, 0, remote_idx);
3002 if ((entry_user->shmem_data->curr_speed.max_conn > 0) &&
3003 (entry_user->shmem_data->total_conn >= entry_user->shmem_data->curr_speed.max_conn)) {
3004
3005 mod_cband_sem_up(config->sem_id);
3006 /* END CRITICAL SECTION */
3007
3008 return HTTP_SERVICE_UNAVAILABLE;
3009 }
3010
3011 mod_cband_get_real_speed(entry_user->shmem_data, NULL, &user_rps);
3012 user_curr_rps = entry_user->shmem_data->curr_speed.rps;
3013 }
3014
3015 if (remote_idx >= 0) {
3016 if (remote_max_conn > 0) {
3017 remote_total_conn = mod_cband_get_remote_total_connections(remote_idx);
3018
3019 if ((remote_total_conn > 0) && (remote_max_conn <= remote_total_conn)) {
3020
3021 mod_cband_sem_up(config->sem_id);
3022 /* END CRITICAL SECTION */
3023
3024 return HTTP_SERVICE_UNAVAILABLE;
3025 }
3026 }
3027
3028 /* semafor na remote_hosts */
3029 remote_rps = mod_cband_get_remote_connections_speed_lock(remote_idx);
3030 }
3031
3032 overlimit = 0;
3033 if ((entry != NULL) && (virtualhost_curr_rps > 0) && (virtualhost_rps > virtualhost_curr_rps))
3034 overlimit = 1;
3035
3036 if ((entry_user != NULL) && (user_curr_rps > 0) && (user_rps > user_curr_rps))
3037 overlimit = 1;
3038
3039 if ((remote_idx >= 0) && (remote_curr_rps > 0) && (remote_rps > remote_curr_rps))
3040 overlimit = 1;
3041
3042 if (overlimit) {
3043 mod_cband_sem_up(config->sem_id);
3044 /* END CRITICAL SECTION */
3045
3046 usleep(MAX_SLEEP_TIME + (rand() % MAX_SLEEP_TIME));
3047 }
3048
3049 mod_cband_sem_up(config->sem_id);
3050 /* END CRITICAL SECTION */
3051
3052 loops++;
3053 } while (overlimit && loops <= MAX_DELAY_LOOPS);
3054
3055 if (loops > MAX_DELAY_LOOPS)
3056 return HTTP_SERVICE_UNAVAILABLE;
3057
3058 return OK;
3059 }
3060
3061 /*
3062 * /cband-status handler
3063 */
3064 static int mod_cband_status_handler (request_rec *r)
3065 {
3066 mod_cband_virtualhost_config_entry *entry = NULL;
3067 mod_cband_user_config_entry *entry_user = NULL;
3068 unsigned long remote_max_conn;
3069 int handler_type;
3070 int remote_idx, dst;
3071
3072 if (strcmp(r->handler, "cband-status") && strcmp(r->handler, "cband-status-me"))
3073 return DECLINED;
3074
3075 entry = mod_cband_get_virtualhost_entry(r->server, r->server->module_config, 0);
3076
3077 if ((entry != NULL) && (entry->virtual_user != NULL))
3078 entry_user = mod_cband_get_user_entry(entry->virtual_user, r->server->module_config, 0);
3079
3080 dst = mod_cband_get_dst(r);
3081 remote_idx = mod_cband_get_remote_host(r->connection, 1, entry);
3082 mod_cband_get_dst_speed_lock(entry, entry_user, NULL, NULL, &remote_max_conn, dst);
3083 mod_cband_set_remote_max_connections(remote_idx, remote_max_conn);
3084
3085 ap_add_output_filter("mod_cband", NULL, r, r->connection);
3086
3087 if (!strcmp(r->handler, "cband-status"))
3088 handler_type = CBAND_HANDLER_ALL;
3089 else
3090 handler_type = CBAND_HANDLER_ME;
3091
3092 if ((r->args != NULL) && (!strcasecmp(r->args, "xml")))
3093 return mod_cband_status_handler_XML(r, handler_type);
3094 else
3095 return mod_cband_status_handler_HTML(r, handler_type);
3096 }
3097
3098 int mod_cband_check_limit(request_rec *r, mod_cband_shmem_data *shmem_data, unsigned long limit, unsigned long slice_limit, unsigned int mult, unsigned long long usage, char *limit_exceeded)
3099 {
3100 /* Check if the bandwidth limit has been reached */
3101 if ((limit > 0) && ((((unsigned long long)limit * (unsigned long long)mult) < usage) ||
3102 (((unsigned long long)slice_limit * (unsigned long long)mult) < usage))) {
3103
3104 if (limit_exceeded != NULL) {
3105 apr_table_setn(r->headers_out, "Location", limit_exceeded);
3106 return HTTP_MOVED_PERMANENTLY;
3107 }
3108 else
3109 if ((shmem_data->over_speed.kbps > (unsigned long)0) || (shmem_data->over_speed.rps > (unsigned long)0))
3110 mod_cband_set_overlimit_speed_lock(shmem_data);
3111 else
3112 if (config->default_limit_exceeded != NULL) {
3113 apr_table_setn(r->headers_out, "Location", config->default_limit_exceeded);
3114 return HTTP_MOVED_PERMANENTLY;
3115 } else
3116 return config->default_limit_exceeded_code;
3117 }
3118
3119 return OK;
3120 }
3121
3122 int mod_cband_get_virtualhost_limits(mod_cband_virtualhost_config_entry *entry, mod_cband_limits_usages *lu, int dst)
3123 {
3124 if (entry == NULL || lu == NULL)
3125 return -1;
3126
3127 lu->limit = entry->virtual_limit;
3128 lu->limit_mult = entry->virtual_limit_mult;
3129 lu->slice_limit = mod_cband_get_slice_limit(entry->shmem_data->total_usage.start_time,
3130 entry->refresh_time, entry->slice_len, entry->virtual_limit);
3131 lu->limit_exceeded = entry->virtual_limit_exceeded;
3132 lu->scoreboard = entry->virtual_scoreboard;
3133
3134 if (dst >= 0) {
3135 lu->clas