"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&amp;refresh=%d&amp;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&amp;refresh=%d&amp;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&amp;unit=%s\">[refresh]</a> &nbsp; <a href=\"?refresh=%d\">[human-readable]</a> <a href=\"?refresh=%d&amp;unit=G\">[GB]</a> <a href=\"?refresh=%d&amp;unit=M\">[MB]</a> <a href=\"?refresh=%d&amp;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&amp;refresh=%d&amp;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&amp;unit=%s\">[refresh]</a> &nbsp; <a href=\"?refresh=%d\">[human-readable]</a> <a href=\"?refresh=%d&amp;unit=G\">[GB]</a> <a href=\"?refresh=%d&amp;unit=M\">[MB]</a> <a href=\"?refresh=%d&amp;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&amp;refresh=%d&amp;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&amp;unit=%s\">[refresh]</a> &nbsp; <a href=\"?refresh=%d\">[human-readable]</a> <a href=\"?refresh=%d&amp;unit=G\">[GB]</a> <a href=\"?refresh=%d&amp;unit=M\">[MB]</a> <a href=\"?refresh=%d&amp;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&amp;unit=%s\">[refresh]</a> &nbsp; <a href=\"?refresh=%d\">[human-readable]</a> <a href=\"?refresh=%d&amp;unit=G\">[GB]</a> <a href=\"?refresh=%d&amp;unit=M\">[MB]</a> <a href=\"?refresh=%d&amp;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