00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include <stdio.h>
00033 #include <stdlib.h>
00034 #include <sys/types.h>
00035 #include <regex.h>
00036 #include <math.h>
00037
00038 #include "../../mem/mem.h"
00039 #include "../../mem/shm_mem.h"
00040 #include "../../sr_module.h"
00041 #include "../../dprint.h"
00042 #include "../../timer.h"
00043 #include "../../ut.h"
00044 #include "../../locking.h"
00045 #include "../../mod_fix.h"
00046 #include "../../data_lump.h"
00047 #include "../../data_lump_rpl.h"
00048 #include "../../statistics.h"
00049 #include "../sl/sl_api.h"
00050
00051 MODULE_VERSION
00052
00053 #define MAX_PIPES 16
00054 #define MAX_QUEUES 10
00055
00056
00057
00058
00059 #define RL_TIMER_INTERVAL 10
00060
00061 #define RXLS(m, str, i) (m)[i].rm_eo - (m)[i].rm_so, (str) + (m)[i].rm_so
00062 #define RXL(m, str, i) (m)[i].rm_eo - (m)[i].rm_so
00063 #define RXS(m, str, i) (str) + (m)[i].rm_so
00064
00065
00066 struct sl_binds slb;
00067
00068 static inline int str_cmp(const str * a, const str * b);
00069 static inline int str_i_cmp(const str * a, const str * b);
00070
00071 typedef struct str_map {
00072 str str;
00073 int id;
00074 } str_map_t;
00075
00076 static int str_map_str(const str_map_t * map, const str * key, int * ret);
00077 static int str_map_int(const str_map_t * map, int key, str * ret);
00078
00079
00080
00081
00082
00083
00084 enum {
00085 PIPE_ALGO_NOP = 0,
00086 PIPE_ALGO_RED,
00087 PIPE_ALGO_TAILDROP,
00088 PIPE_ALGO_FEEDBACK,
00089 PIPE_ALGO_NETWORK
00090 };
00091
00092 str_map_t algo_names[] = {
00093 {str_init("NOP"), PIPE_ALGO_NOP},
00094 {str_init("RED"), PIPE_ALGO_RED},
00095 {str_init("TAILDROP"), PIPE_ALGO_TAILDROP},
00096 {str_init("FEEDBACK"), PIPE_ALGO_FEEDBACK},
00097 {str_init("NETWORK"), PIPE_ALGO_NETWORK},
00098 {{0, 0}, 0},
00099 };
00100
00101
00102
00103
00104
00105
00106
00107 enum {
00108 LOAD_SOURCE_CPU,
00109 LOAD_SOURCE_EXTERNAL
00110 };
00111
00112 str_map_t source_names[] = {
00113 {str_init("cpu"), LOAD_SOURCE_CPU},
00114 {str_init("external"), LOAD_SOURCE_EXTERNAL},
00115 {{0, 0}, 0},
00116 };
00117
00118 static int rl_drop_code = 503;
00119 static str rl_drop_reason = str_init("Server Unavailable");
00120
00121 typedef struct pipe {
00122
00123 int * algo;
00124 int algo_mp;
00125 int * limit;
00126 int limit_mp;
00127
00128
00129 int * counter;
00130 int * last_counter;
00131 int * load;
00132 } pipe_t;
00133
00134 typedef struct rl_queue {
00135 int * pipe;
00136 int pipe_mp;
00137 str * method;
00138 str method_mp;
00139 } rl_queue_t;
00140
00141
00142 gen_lock_t * rl_lock;
00143
00144 static double * load_value;
00145 static double * pid_kp, * pid_ki, * pid_kd, * pid_setpoint;
00146 static int * drop_rate;
00147
00148 static int * network_load_value;
00149
00150
00151 static int load_source_mp = LOAD_SOURCE_CPU;
00152 static int * load_source;
00153
00154 typedef struct pipe_params {
00155 int no;
00156 int algo;
00157 int limit;
00158 } pipe_params_t;
00159
00160 typedef struct rl_queue_params {
00161 int pipe;
00162 str method;
00163 } rl_queue_params_t;
00164
00165 static pipe_t pipes[MAX_PIPES];
00166 static rl_queue_t queues[MAX_QUEUES];
00167
00168 static int nqueues_mp = 0;
00169 static int * nqueues;
00170
00171 static str * rl_dbg_str = NULL;
00172
00173
00174 static int timer_interval = RL_TIMER_INTERVAL;
00175 static int cfg_setpoint;
00176
00177
00178 #ifndef RL_DEBUG_LOCKS
00179 # define LOCK_GET lock_get
00180 # define LOCK_RELEASE lock_release
00181 #else
00182 # define LOCK_GET(l) do { \
00183 LM_INFO("%d: + get\n", __LINE__); \
00184 lock_get(l); \
00185 LM_INFO("%d: - get\n", __LINE__); \
00186 } while (0)
00187
00188 # define LOCK_RELEASE(l) do { \
00189 LM_INFO("%d: + release\n", __LINE__); \
00190 lock_release(l); \
00191 LM_INFO("%d: - release\n", __LINE__); \
00192 } while (0)
00193 #endif
00194
00195 static int params_inited = 0;
00196 static regex_t pipe_params_regex;
00197 static regex_t queue_params_regex;
00198
00199
00200 static int mod_init(void);
00201 static void rl_timer(unsigned int, void *);
00202 static int w_rl_check_default(struct sip_msg*, char *, char *);
00203 static int w_rl_check_forced(struct sip_msg*, char *, char *);
00204 static int w_rl_check_forced_pipe(struct sip_msg*, char *, char *);
00205 static int w_rl_drop_default(struct sip_msg*, char *, char *);
00206 static int w_rl_drop_forced(struct sip_msg*, char *, char *);
00207 static int w_rl_drop(struct sip_msg*, char *, char *);
00208 static int add_queue_params(modparam_t, void *);
00209 static int add_pipe_params(modparam_t, void *);
00210
00211
00212
00213 void destroy(void);
00214
00215 static cmd_export_t cmds[]={
00216 {"rl_check", (cmd_function)w_rl_check_default, 0, 0, 0, REQUEST_ROUTE|LOCAL_ROUTE},
00217 {"rl_check", (cmd_function)w_rl_check_forced, 1, fixup_pvar_null,
00218 fixup_free_pvar_null, REQUEST_ROUTE|LOCAL_ROUTE},
00219 {"rl_check_pipe", (cmd_function)w_rl_check_forced_pipe, 1, fixup_uint_null, 0, REQUEST_ROUTE|LOCAL_ROUTE},
00220 {"rl_drop", (cmd_function)w_rl_drop_default, 0, 0, 0, REQUEST_ROUTE|LOCAL_ROUTE},
00221 {"rl_drop", (cmd_function)w_rl_drop_forced, 1, fixup_uint_null, 0, REQUEST_ROUTE|LOCAL_ROUTE},
00222 {"rl_drop", (cmd_function)w_rl_drop, 2, fixup_uint_uint, 0, REQUEST_ROUTE|LOCAL_ROUTE},
00223 {0,0,0,0,0,0}
00224 };
00225 static param_export_t params[]={
00226 {"timer_interval", INT_PARAM, &timer_interval},
00227 {"queue", STR_PARAM|USE_FUNC_PARAM, (void *)add_queue_params},
00228 {"pipe", STR_PARAM|USE_FUNC_PARAM, (void *)add_pipe_params},
00229 {"reply_code", INT_PARAM, &rl_drop_code},
00230 {"reply_reason", STR_PARAM, &rl_drop_reason.s},
00231
00232
00233
00234 {0,0,0}
00235 };
00236
00237 struct mi_root* mi_stats(struct mi_root* cmd_tree, void* param);
00238 struct mi_root* mi_set_pipe(struct mi_root* cmd_tree, void* param);
00239 struct mi_root* mi_get_pipes(struct mi_root* cmd_tree, void* param);
00240 struct mi_root* mi_set_queue(struct mi_root* cmd_tree, void* param);
00241 struct mi_root* mi_get_queues(struct mi_root* cmd_tree, void* param);
00242 struct mi_root* mi_set_pid(struct mi_root* cmd_tree, void* param);
00243 struct mi_root* mi_get_pid(struct mi_root* cmd_tree, void* param);
00244 struct mi_root* mi_push_load(struct mi_root* cmd_tree, void* param);
00245 struct mi_root* mi_set_dbg(struct mi_root* cmd_tree, void* param);
00246
00247 static mi_export_t mi_cmds [] = {
00248 {"rl_stats", mi_stats, MI_NO_INPUT_FLAG, 0, 0},
00249 {"rl_set_pipe", mi_set_pipe, 0, 0, 0},
00250 {"rl_get_pipes", mi_get_pipes, MI_NO_INPUT_FLAG, 0, 0},
00251 {"rl_set_queue", mi_set_queue, 0, 0, 0},
00252 {"rl_get_queues", mi_get_queues, MI_NO_INPUT_FLAG, 0, 0},
00253 {"rl_set_pid", mi_set_pid, 0, 0, 0},
00254 {"rl_get_pid", mi_get_pid, MI_NO_INPUT_FLAG, 0, 0},
00255 {"rl_push_load", mi_push_load, 0, 0, 0},
00256 {"rl_set_dbg", mi_set_dbg, 0, 0, 0},
00257 {0,0,0,0,0}
00258 };
00259
00260
00261 struct module_exports exports= {
00262 "ratelimit",
00263 DEFAULT_DLFLAGS,
00264 cmds,
00265 params,
00266 0,
00267 mi_cmds,
00268 0,
00269 0,
00270 mod_init,
00271 0,
00272 (destroy_function) destroy,
00273 0
00274 };
00275
00276
00277
00278
00279
00280
00281 static int str_map_str(const str_map_t * map, const str * key, int * ret)
00282 {
00283 for (; map->str.s; map++)
00284 if (! str_cmp(&map->str, key)) {
00285 *ret = map->id;
00286 return 0;
00287 }
00288 LM_DBG("str_map_str() failed map=%p key=%.*s\n", map, key->len, key->s);
00289 return -1;
00290 }
00291
00292
00293
00294
00295
00296 static int str_map_int(const str_map_t * map, int key, str * ret)
00297 {
00298 for (; map->str.s; map++)
00299 if (map->id == key) {
00300 *ret = map->str;
00301 return 0;
00302 }
00303 LM_DBG("str_map_str() failed map=%p key=%d\n", map, key);
00304 return -1;
00305 }
00306
00307
00308
00309
00310
00311 static int str_cpy(str * dest, str * src)
00312 {
00313 dest->len = src->len;
00314 dest->s = shm_malloc(src->len);
00315 if (! dest->s) {
00316 LM_ERR("oom: '%.*s'\n", src->len, src->s);
00317 return -1;
00318 }
00319 memcpy(dest->s, src->s, src->len);
00320 return 0;
00321 }
00322
00323
00324 static int get_cpuload(double * load)
00325 {
00326 static
00327 long long o_user, o_nice, o_sys, o_idle, o_iow, o_irq, o_sirq, o_stl;
00328 long long n_user, n_nice, n_sys, n_idle, n_iow, n_irq, n_sirq, n_stl;
00329 static int first_time = 1;
00330 FILE * f = fopen("/proc/stat", "r");
00331
00332 if (! f) {
00333 LM_ERR("could not open /proc/stat\n");
00334 return -1;
00335 }
00336 if (fscanf(f, "cpu %lld%lld%lld%lld%lld%lld%lld%lld",
00337 &n_user, &n_nice, &n_sys, &n_idle, &n_iow, &n_irq, &n_sirq, &n_stl) < 0) {
00338 LM_ERR("could not parse load informations\n");
00339 return -1;
00340 }
00341 fclose(f);
00342
00343 if (first_time) {
00344 first_time = 0;
00345 *load = 0;
00346 } else {
00347 long long d_total = (n_user - o_user) +
00348 (n_nice - o_nice) +
00349 (n_sys - o_sys) +
00350 (n_idle - o_idle) +
00351 (n_iow - o_iow) +
00352 (n_irq - o_irq) +
00353 (n_sirq - o_sirq) +
00354 (n_stl - o_stl);
00355 long long d_idle = (n_idle - o_idle);
00356
00357 *load = 1.0 - ((double)d_idle) / (double)d_total;
00358 }
00359
00360 o_user = n_user;
00361 o_nice = n_nice;
00362 o_sys = n_sys;
00363 o_idle = n_idle;
00364 o_iow = n_iow;
00365 o_irq = n_irq;
00366 o_sirq = n_sirq;
00367 o_stl = n_stl;
00368
00369 return 0;
00370 }
00371
00372 static double int_err = 0.0;
00373 static double last_err = 0.0;
00374
00375
00376
00377
00378 static void do_update_load(void)
00379 {
00380 static char spcs[51];
00381 int load;
00382 double err, dif_err, output;
00383
00384
00385 err = *pid_setpoint - *load_value;
00386
00387 dif_err = err - last_err;
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397 if (int_err < 0 || err < 0)
00398 int_err += err;
00399
00400 output = (*pid_kp) * err +
00401 (*pid_ki) * int_err +
00402 (*pid_kd) * dif_err;
00403 last_err = err;
00404
00405 *drop_rate = (output > 0) ? output : 0;
00406
00407 load = 0.5 + 100.0 * *load_value;
00408
00409 memset(spcs, '-', load / 4);
00410 spcs[load / 4] = 0;
00411
00412
00413
00414
00415
00416 }
00417
00418 static void update_cpu_load(void)
00419 {
00420 if (get_cpuload(load_value))
00421 return;
00422
00423 do_update_load();
00424 }
00425
00426
00427 static int mod_init(void)
00428 {
00429 int i;
00430
00431 rl_lock = lock_alloc();
00432 if (! rl_lock) {
00433 LM_ERR("oom in lock_alloc()\n");
00434 return -1;
00435 }
00436
00437 if (lock_init(rl_lock)==0) {
00438 LM_ERR("failed to init lock\n");
00439 return -1;
00440 }
00441
00442
00443 if (register_timer_process(rl_timer, NULL, timer_interval, TIMER_PROC_INIT_FLAG) < 0) {
00444 LM_ERR("could not register timer function\n");
00445 return -1;
00446 }
00447
00448
00449 if (load_sl_api(&slb)!=0) {
00450 LM_ERR("failed to load SL API\n");
00451 return -1;
00452 }
00453
00454 network_load_value = shm_malloc(sizeof(int));
00455 if (network_load_value==NULL) {
00456 LM_ERR("oom for network_load_value\n");
00457 return -1;
00458 }
00459
00460 load_value = shm_malloc(sizeof(double));
00461 if (load_value==NULL) {
00462 LM_ERR("oom for load_value\n");
00463 return -1;
00464 }
00465 load_source = shm_malloc(sizeof(int));
00466 if (load_source==NULL) {
00467 LM_ERR("oom for load_source\n");
00468 return -1;
00469 }
00470 pid_kp = shm_malloc(sizeof(double));
00471 if (pid_kp==NULL) {
00472 LM_ERR("oom for pid_kp\n");
00473 return -1;
00474 }
00475 pid_ki = shm_malloc(sizeof(double));
00476 if (pid_ki==NULL) {
00477 LM_ERR("oom for pid_ki\n");
00478 return -1;
00479 }
00480 pid_kd = shm_malloc(sizeof(double));
00481 if (pid_kd==NULL) {
00482 LM_ERR("oom for pid_kd\n");
00483 return -1;
00484 }
00485 pid_setpoint = shm_malloc(sizeof(double));
00486 if (pid_setpoint==NULL) {
00487 LM_ERR("oom for pid_setpoint\n");
00488 return -1;
00489 }
00490 drop_rate = shm_malloc(sizeof(int));
00491 if (drop_rate==NULL) {
00492 LM_ERR("oom for drop_rate\n");
00493 return -1;
00494 }
00495 nqueues = shm_malloc(sizeof(int));
00496 if (nqueues==NULL) {
00497 LM_ERR("oom for nqueues\n");
00498 return -1;
00499 }
00500 rl_dbg_str = shm_malloc(sizeof(str));
00501 if (rl_dbg_str==NULL) {
00502 LM_ERR("oom for rl_dbg_str\n");
00503 return -1;
00504 }
00505
00506 *network_load_value = 0;
00507 *load_value = 0.0;
00508 *load_source = load_source_mp;
00509 *pid_kp = 0.0;
00510 *pid_ki = -25.0;
00511 *pid_kd = 0.0;
00512 *pid_setpoint = 0.01 * (double)cfg_setpoint;
00513 *drop_rate = 0;
00514 *nqueues = nqueues_mp;
00515 rl_dbg_str->s = NULL;
00516 rl_dbg_str->len = 0;
00517
00518 for (i=0; i<MAX_PIPES; i++) {
00519 pipes[i].algo = shm_malloc(sizeof(int));
00520 if (pipes[i].algo==NULL) {
00521 LM_ERR("oom for pipes[%d].algo\n", i);
00522 return -1;
00523 }
00524 pipes[i].limit = shm_malloc(sizeof(int));
00525 if (pipes[i].limit==NULL) {
00526 LM_ERR("oom for pipes[%d].limit\n", i);
00527 return -1;
00528 }
00529 pipes[i].load = shm_malloc(sizeof(int));
00530 if (pipes[i].load==NULL) {
00531 LM_ERR("oom for pipes[%d].load\n", i);
00532 return -1;
00533 }
00534 pipes[i].counter = shm_malloc(sizeof(int));
00535 if (pipes[i].counter==NULL) {
00536 LM_ERR("oom for pipes[%d].counter\n", i);
00537 return -1;
00538 }
00539 pipes[i].last_counter = shm_malloc(sizeof(int));
00540 if (pipes[i].last_counter==NULL) {
00541 LM_ERR("oom for pipes[%d].last_counter\n", i);
00542 return -1;
00543 }
00544 *pipes[i].algo = pipes[i].algo_mp;
00545 *pipes[i].limit = pipes[i].limit_mp;
00546 *pipes[i].load = 0;
00547 *pipes[i].counter = 0;
00548 *pipes[i].last_counter = 0;
00549 }
00550
00551 for (i=0; i<*nqueues; i++) {
00552 queues[i].pipe = shm_malloc(sizeof(int));
00553 if (queues[i].pipe==NULL) {
00554 LM_ERR("oom for queues[%d].pipe\n", i);
00555 return -1;
00556 }
00557 queues[i].method = shm_malloc(sizeof(str));
00558 if (queues[i].method==NULL) {
00559 LM_ERR("oom for queues[%d].method\n", i);
00560 return -1;
00561 }
00562
00563 *queues[i].pipe = queues[i].pipe_mp;
00564 if (queues[i].method_mp.s == NULL) {
00565 LM_ERR("unexpected NULL method for queues[%d].method_mp\n", i);
00566 return -1;
00567 }
00568 if(str_cpy(queues[i].method, &queues[i].method_mp)) {
00569 LM_ERR("oom str_cpy(queues[%d].method\n", i);
00570 return -1;
00571 }
00572 pkg_free(queues[i].method_mp.s);
00573 queues[i].method_mp.s = NULL;
00574 queues[i].method_mp.len = 0;
00575 }
00576
00577 rl_drop_reason.len = strlen(rl_drop_reason.s);
00578
00579 return 0;
00580 }
00581
00582
00583 void destroy(void)
00584 {
00585 int i;
00586
00587 regfree(&pipe_params_regex);
00588 regfree(&queue_params_regex);
00589
00590 for (i=0; i<MAX_PIPES; i++) {
00591 if (pipes[i].algo) {
00592 shm_free(pipes[i].algo);
00593 pipes[i].algo = NULL;
00594 }
00595 if (pipes[i].load) {
00596 shm_free(pipes[i].load);
00597 pipes[i].load = NULL;
00598 }
00599 if (pipes[i].counter) {
00600 shm_free(pipes[i].counter);
00601 pipes[i].counter = NULL;
00602 }
00603 if (pipes[i].last_counter) {
00604 shm_free(pipes[i].last_counter);
00605 pipes[i].last_counter = NULL;
00606 }
00607 if (pipes[i].limit) {
00608 shm_free(pipes[i].limit);
00609 pipes[i].limit = NULL;
00610 }
00611 }
00612
00613 if (nqueues) {
00614 for (i=0; i<*nqueues; i++) {
00615 if (queues[i].pipe) {
00616 shm_free(queues[i].pipe);
00617 queues[i].pipe = NULL;
00618 }
00619 if (queues[i].method) {
00620 if (queues[i].method->s) {
00621 shm_free(queues[i].method->s);
00622 queues[i].method->s = NULL;
00623 queues[i].method->len = 0;
00624 }
00625 shm_free(queues[i].method);
00626 queues[i].method = NULL;
00627 }
00628 }
00629 }
00630
00631 if (network_load_value) {
00632 shm_free(network_load_value);
00633 network_load_value = NULL;
00634 }
00635 if (load_value) {
00636 shm_free(load_value);
00637 load_value = NULL;
00638 }
00639 if (load_source) {
00640 shm_free(load_source);
00641 load_source = NULL;
00642 }
00643 if (pid_kp) {
00644 shm_free(pid_kp);
00645 pid_kp= NULL;
00646 }
00647 if (pid_ki) {
00648 shm_free(pid_ki);
00649 pid_ki = NULL;
00650 }
00651 if (pid_kd) {
00652 shm_free(pid_kd);
00653 pid_kd = NULL;
00654 }
00655 if (pid_setpoint) {
00656 shm_free(pid_setpoint);
00657 pid_setpoint = NULL;
00658 }
00659 if (drop_rate) {
00660 shm_free(drop_rate);
00661 drop_rate = NULL;
00662 }
00663 if (nqueues) {
00664 shm_free(nqueues);
00665 nqueues = NULL;
00666 }
00667 if (rl_dbg_str) {
00668 if (rl_dbg_str->s) {
00669 shm_free(rl_dbg_str->s);
00670 rl_dbg_str->s = NULL;
00671 rl_dbg_str->len = 0;
00672 }
00673 shm_free(rl_dbg_str);
00674 rl_dbg_str = NULL;
00675 }
00676
00677 if (rl_lock) {
00678 lock_destroy(rl_lock);
00679 lock_dealloc((void *)rl_lock);
00680 }
00681 }
00682
00683
00684 static int rl_drop(struct sip_msg * msg, unsigned int low, unsigned int high)
00685 {
00686 str hdr;
00687 int ret;
00688
00689 LM_DBG("(%d, %d)\n", low, high);
00690
00691 if (slb.send_reply != 0) {
00692 if (low != 0 && high != 0) {
00693 hdr.s = (char *)pkg_malloc(64);
00694 if (hdr.s == 0) {
00695 LM_ERR("Can't allocate memory for Retry-After header\n");
00696 return 0;
00697 }
00698 hdr.len = 0;
00699 if (! hdr.s) {
00700 LM_ERR("no memory for hdr\n");
00701 return 0;
00702 }
00703
00704 if (high == low) {
00705 hdr.len = snprintf(hdr.s, 63, "Retry-After: %d\r\n", low);
00706 } else {
00707 hdr.len = snprintf(hdr.s, 63, "Retry-After: %d\r\n",
00708 low + rand() % (high - low + 1));
00709 }
00710
00711 if (add_lump_rpl(msg, hdr.s, hdr.len, LUMP_RPL_HDR)==0) {
00712 LM_ERR("Can't add header\n");
00713 pkg_free(hdr.s);
00714 return 0;
00715 }
00716
00717 ret = slb.send_reply(msg, rl_drop_code, &rl_drop_reason);
00718
00719 pkg_free(hdr.s);
00720 } else {
00721 ret = slb.send_reply(msg, rl_drop_code, &rl_drop_reason);
00722 }
00723 } else {
00724 LM_ERR("Can't send reply\n");
00725 return 0;
00726 }
00727 return ret;
00728 }
00729
00730 static int w_rl_drop(struct sip_msg* msg, char *p1, char *p2)
00731 {
00732 unsigned int low, high;
00733
00734 low = (unsigned int)(unsigned long)p1;
00735 high = (unsigned int)(unsigned long)p2;
00736
00737 if (high < low) {
00738 return rl_drop(msg, low, low);
00739 } else {
00740 return rl_drop(msg, low, high);
00741 }
00742 }
00743
00744 static int w_rl_drop_forced(struct sip_msg* msg, char *p1, char *p2)
00745 {
00746 unsigned int i;
00747
00748 if (p1) {
00749 i = (unsigned int)(unsigned long)p1;
00750 LM_DBG("send retry in %d s\n", i);
00751 } else {
00752 i = 5;
00753 LM_DBG("send default retry in %d s\n", i);
00754 }
00755 return rl_drop(msg, i, i);
00756 }
00757
00758 static int w_rl_drop_default(struct sip_msg* msg, char *p1, char *p2)
00759 {
00760 return rl_drop(msg, 0, 0);
00761 }
00762
00763 static inline int str_cmp(const str * a , const str * b)
00764 {
00765 return ! (a->len == b->len && ! strncmp(a->s, b->s, a->len));
00766 }
00767
00768 static inline int str_i_cmp(const str * a, const str * b)
00769 {
00770 return ! (a->len == b->len && ! strncasecmp(a->s, b->s, a->len));
00771 }
00772
00773 str queue_other = str_init("*");
00774
00775
00776
00777
00778
00779
00780 static int find_queue(struct sip_msg * msg, int * queue)
00781 {
00782 str method = msg->first_line.u.request.method;
00783 int i;
00784
00785 *queue = -1;
00786 for (i=0; i<*nqueues; i++)
00787 if (! str_i_cmp(queues[i].method, &method)) {
00788 *queue = i;
00789 return 0;
00790 } else if (! str_i_cmp(queues[i].method, &queue_other)) {
00791 *queue = i;
00792 }
00793
00794 if (*queue >= 0)
00795 return 0;
00796
00797 LM_INFO("no queue matches\n");
00798 return -1;
00799 }
00800
00801
00802
00803
00804 int hash[100] = {18, 50, 51, 39, 49, 68, 8, 78, 61, 75, 53, 32, 45, 77, 31,
00805 12, 26, 10, 37, 99, 29, 0, 52, 82, 91, 22, 7, 42, 87, 43, 73, 86, 70,
00806 69, 13, 60, 24, 25, 6, 93, 96, 97, 84, 47, 79, 64, 90, 81, 4, 15, 63,
00807 44, 57, 40, 21, 28, 46, 94, 35, 58, 11, 30, 3, 20, 41, 74, 34, 88, 62,
00808 54, 33, 92, 76, 85, 5, 72, 9, 83, 56, 17, 95, 55, 80, 98, 66, 14, 16,
00809 38, 71, 23, 2, 67, 36, 65, 27, 1, 19, 59, 89, 48};
00810
00811
00812
00813
00814
00815
00816
00817 static int pipe_push(struct sip_msg * msg, int id)
00818 {
00819 int ret;
00820
00821 (*pipes[id].counter)++;
00822
00823 switch (*pipes[id].algo) {
00824 case PIPE_ALGO_NOP:
00825 LM_ERR("no algorithm defined for pipe %d\n", id);
00826 ret = 1;
00827 break;
00828 case PIPE_ALGO_TAILDROP:
00829 ret = (*pipes[id].counter <= *pipes[id].limit * timer_interval) ? 1 : -1;
00830 break;
00831 case PIPE_ALGO_RED:
00832 if (*pipes[id].load == 0)
00833 ret = 1;
00834 else
00835 ret = (! (*pipes[id].counter % *pipes[id].load)) ? 1 : -1;
00836 break;
00837 case PIPE_ALGO_FEEDBACK:
00838 ret = (hash[*pipes[id].counter % 100] < *drop_rate) ? -1 : 1;
00839 break;
00840 case PIPE_ALGO_NETWORK:
00841 ret = -1 * *pipes[id].load;
00842 break;
00843 default:
00844 LM_ERR("unknown ratelimit algorithm: %d\n", *pipes[id].algo);
00845 ret = 1;
00846 }
00847
00848 return ret;
00849 }
00850
00851
00852
00853
00854
00855
00856
00857 static int rl_check(struct sip_msg * msg, int forced_pipe)
00858 {
00859 int que_id, pipe_id, ret;
00860 str method = msg->first_line.u.request.method;
00861
00862 LOCK_GET(rl_lock);
00863 if (forced_pipe < 0) {
00864 if (find_queue(msg, &que_id)) {
00865 pipe_id = que_id = 0;
00866 ret = 1;
00867 goto out_release;
00868 }
00869 pipe_id = *queues[que_id].pipe;
00870 } else {
00871 que_id = 0;
00872 pipe_id = forced_pipe;
00873 }
00874
00875 ret = pipe_push(msg, pipe_id);
00876 out_release:
00877 LOCK_RELEASE(rl_lock);
00878
00879
00880 LM_DBG("meth=%.*s queue=%d pipe=%d algo=%d limit=%d pkg_load=%d counter=%d "
00881 "load=%2.1lf network_load=%d => %s\n",
00882 method.len, method.s, que_id, pipe_id,
00883 *pipes[pipe_id].algo, *pipes[pipe_id].limit,
00884 *pipes[pipe_id].load, *pipes[pipe_id].counter,
00885 *load_value, *network_load_value, (ret == 1) ? "ACCEPT" : "DROP");
00886
00887 return ret;
00888 }
00889
00890 static int w_rl_check_forced(struct sip_msg* msg, char *p1, char *p2)
00891 {
00892 int pipe = -1;
00893 pv_value_t pv_val;
00894
00895 if (p1 && (pv_get_spec_value(msg, (pv_spec_t *)p1, &pv_val) == 0)) {
00896 if (pv_val.flags & PV_VAL_INT) {
00897 pipe = pv_val.ri;
00898 LM_DBG("pipe=%d\n", pipe);
00899 } else if (pv_val.flags & PV_VAL_STR) {
00900 if(str2int(&(pv_val.rs), (unsigned int*)&pipe) != 0) {
00901 LM_ERR("Unable to get pipe from pv '%.*s'"
00902 "=> defaulting to method type checking\n",
00903 pv_val.rs.len, pv_val.rs.s);
00904 pipe = -1;
00905 }
00906 } else {
00907 LM_ERR("pv not a str or int => defaulting to method type checking\n");
00908 pipe = -1;
00909 }
00910 } else {
00911 LM_ERR("Unable to get pipe from pv:%p"
00912 " => defaulting to method type checking\n", p1);
00913 pipe = -1;
00914 }
00915 return rl_check(msg, pipe);
00916 }
00917 static int w_rl_check_forced_pipe(struct sip_msg* msg, char *p1, char *p2)
00918 {
00919 int pipe;
00920
00921 if (p1) {
00922 pipe = (int)(unsigned int)(unsigned long)p1;
00923 LM_DBG("trying pipe %d\n", pipe);
00924 } else {
00925 pipe = -1;
00926 }
00927
00928 return rl_check(msg, pipe);
00929 }
00930
00931 static int w_rl_check_default(struct sip_msg* msg, char *p1, char *p2)
00932 {
00933 return rl_check(msg, -1);
00934 }
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950
00951
00952
00953
00954
00955
00956
00957
00958 static int init_params(void)
00959 {
00960 if (regcomp(&pipe_params_regex, "^([0-9]+):([^: ]+):([0-9]+)$", REG_EXTENDED|REG_ICASE) ||
00961 regcomp(&queue_params_regex, "^([0-9]+):([^: ]+)$", REG_EXTENDED|REG_ICASE)) {
00962 LM_ERR("can't compile modparam regexes\n");
00963 return -1;
00964 }
00965
00966 memset(pipes, 0, sizeof(pipes));
00967 memset(queues, 0, sizeof(queues));
00968
00969 params_inited = 1;
00970 return 0;
00971 }
00972
00973
00974
00975
00976
00977
00978 static int parse_pipe_params(char * line, pipe_params_t * params)
00979 {
00980 regmatch_t m[4];
00981 str algo_str;
00982
00983 if (! params_inited && init_params())
00984 return -1;
00985 if (regexec(&pipe_params_regex, line, 4, m, 0)) {
00986 LM_ERR("invalid param tuple: %s\n", line);
00987 return -1;
00988 }
00989 LM_DBG("pipe: [%.*s|%.*s|%.*s]\n",
00990 RXLS(m, line, 1), RXLS(m, line, 2), RXLS(m, line, 3));
00991
00992 params->no = atoi(RXS(m, line, 1));
00993 params->limit = atoi(RXS(m, line, 3));
00994
00995 algo_str.s = RXS(m, line, 2);
00996 algo_str.len = RXL(m, line, 2);
00997 if (str_map_str(algo_names, &algo_str, ¶ms->algo))
00998 return -1;
00999
01000 return 0;
01001 }
01002
01003
01004
01005
01006
01007 static int parse_queue_params(char * line, rl_queue_params_t * params)
01008 {
01009 regmatch_t m[3];
01010 int len;
01011
01012 if (! params_inited && init_params())
01013 return -1;
01014 if (regexec(&queue_params_regex, line, 3, m, 0)) {
01015 LM_ERR("invalid param tuple: %s\n", line);
01016 return -1;
01017 }
01018 LM_DBG("queue: [%.*s|%.*s]\n",
01019 RXLS(m, line, 1), RXLS(m, line, 2));
01020
01021 params->pipe = atoi(RXS(m, line, 1));
01022
01023 len = RXL(m, line, 2);
01024 params->method.s = (char *)pkg_malloc(len+1);
01025 if (params->method.s == 0) {
01026 LM_ERR("no memory left for method in params\n");
01027 return -1;
01028 }
01029 params->method.len = len;
01030 memcpy(params->method.s, RXS(m, line, 2), len+1);
01031
01032 return 0;
01033 }
01034
01035
01036
01037
01038
01039
01040
01041
01042 static int check_feedback_setpoints(int modparam)
01043 {
01044 int i, sp;
01045
01046 cfg_setpoint = -1;
01047
01048 for (i=0; i<MAX_PIPES; i++)
01049 if (pipes[i].algo_mp == PIPE_ALGO_FEEDBACK) {
01050 sp = modparam ? pipes[i].limit_mp : *pipes[i].limit;
01051
01052 if (sp < 0 || sp > 100) {
01053 LM_ERR("FEEDBACK cpu load must be >=0 and <= 100\n");
01054 return -1;
01055 } else if (cfg_setpoint == -1) {
01056 cfg_setpoint = sp;
01057 } else if (sp != cfg_setpoint) {
01058 LM_ERR("pipe %d: FEEDBACK cpu load values must "
01059 "be equal for all pipes\n", i);
01060 return -1;
01061 }
01062 }
01063
01064 return 0;
01065 }
01066
01067
01068 static int add_pipe_params(modparam_t type, void * val)
01069 {
01070 char * param_line = val;
01071 pipe_params_t params;
01072
01073 if (parse_pipe_params(param_line, ¶ms))
01074 return -1;
01075
01076 if (params.no < 0 || params.no >= MAX_PIPES) {
01077 LM_ERR("pipe number %d not allowed (MAX_PIPES=%d, 0-based)\n",
01078 params.no, MAX_PIPES);
01079 return -1;
01080 }
01081
01082 pipes[params.no].algo_mp = params.algo;
01083 pipes[params.no].limit_mp = params.limit;
01084
01085 return check_feedback_setpoints(1);
01086 }
01087
01088 static int add_queue_params(modparam_t type, void * val)
01089 {
01090 char * param_line = val;
01091 rl_queue_params_t params;
01092
01093 if (nqueues_mp >= MAX_QUEUES) {
01094 LM_ERR("MAX_QUEUES reached (%d)\n", MAX_QUEUES);
01095 return -1;
01096 }
01097
01098 if (parse_queue_params(param_line, ¶ms))
01099 return -1;
01100
01101 if (params.pipe >= MAX_PIPES) {
01102 LM_ERR("pipe number %d not allowed (MAX_PIPES=%d, 0-based)\n",
01103 params.pipe, MAX_PIPES);
01104 return -1;
01105 }
01106
01107 queues[nqueues_mp].pipe_mp = params.pipe;
01108 queues[nqueues_mp].method_mp = params.method;
01109 nqueues_mp++;
01110
01111 return 0;
01112 }
01113
01114
01115
01116 static void rl_timer(unsigned int ticks, void *param)
01117 {
01118 int i, len;
01119 char *c, *p;
01120
01121 LOCK_GET(rl_lock);
01122 switch (*load_source) {
01123 case LOAD_SOURCE_CPU:
01124 update_cpu_load();
01125 break;
01126 }
01127
01128 *network_load_value = get_total_bytes_waiting();
01129
01130 if (rl_dbg_str->s) {
01131 c = p = rl_dbg_str->s;
01132 memset(c, ' ', rl_dbg_str->len);
01133 for (i=0; i<MAX_PIPES; i++) {
01134 c = int2str(*pipes[i].counter, &len);
01135 if (len < 4) {
01136 memcpy( p + (5-len), c, len );
01137 } else {
01138 memset(p, '*', 5);
01139 LM_WARN("Counter pipes[%d] to big: %d\n",
01140 i, *pipes[i].counter);
01141 }
01142 p = p + 5;
01143 }
01144 LM_WARN("%.*s\n", rl_dbg_str->len, rl_dbg_str->s);
01145 }
01146
01147 for (i=0; i<MAX_PIPES; i++) {
01148 if( *pipes[i].algo == PIPE_ALGO_NETWORK ) {
01149 *pipes[i].load = ( *network_load_value > *pipes[i].limit ) ? 1 : -1;
01150 } else if (*pipes[i].limit && timer_interval) {
01151 *pipes[i].load = *pipes[i].counter / (*pipes[i].limit * timer_interval);
01152 }
01153 *pipes[i].last_counter = *pipes[i].counter;
01154 *pipes[i].counter = 0;
01155 }
01156 LOCK_RELEASE(rl_lock);
01157 }
01158
01159
01160
01161
01162
01163
01164
01165
01166
01167
01168 struct mi_root* mi_stats(struct mi_root* cmd_tree, void* param)
01169 {
01170 struct mi_root *rpl_tree;
01171 struct mi_node *node=NULL, *rpl=NULL;
01172 struct mi_attr* attr;
01173 char* p;
01174 int i, len;
01175
01176 rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
01177 if (rpl_tree==0)
01178 return 0;
01179 rpl = &rpl_tree->node;
01180
01181 LOCK_GET(rl_lock);
01182 for (i=0; i<MAX_PIPES; i++) {
01183 if (*pipes[i].algo != PIPE_ALGO_NOP) {
01184 node = add_mi_node_child(rpl, 0, "PIPE", 4, 0, 0);
01185 if(node == NULL)
01186 goto error;
01187
01188 p = int2str((unsigned long)(i), &len);
01189 attr = add_mi_attr(node, MI_DUP_VALUE, "id", 2, p, len);
01190 if(attr == NULL)
01191 goto error;
01192
01193 p = int2str((unsigned long)(*pipes[i].load), &len);
01194 attr = add_mi_attr(node, MI_DUP_VALUE, "load", 4, p, len);
01195 if(attr == NULL)
01196 goto error;
01197
01198 p = int2str((unsigned long)(*pipes[i].last_counter), &len);
01199 attr = add_mi_attr(node, MI_DUP_VALUE, "counter", 7, p, len);
01200 if(attr == NULL)
01201 goto error;
01202 }
01203 }
01204
01205 p = int2str((unsigned long)(*drop_rate), &len);
01206 node = add_mi_node_child(rpl, MI_DUP_VALUE, "DROP_RATE", 9, p, len);
01207
01208 LOCK_RELEASE(rl_lock);
01209 return rpl_tree;
01210 error:
01211 LOCK_RELEASE(rl_lock);
01212 LM_ERR("Unable to create reply\n");
01213 free_mi_tree(rpl_tree);
01214 return 0;
01215 }
01216
01217 struct mi_root* mi_get_pipes(struct mi_root* cmd_tree, void* param)
01218 {
01219 struct mi_root *rpl_tree;
01220 struct mi_node *node=NULL, *rpl=NULL;
01221 struct mi_attr* attr;
01222 str algo;
01223 char* p;
01224 int i, len;
01225
01226 rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
01227 if (rpl_tree==0)
01228 return 0;
01229 rpl = &rpl_tree->node;
01230
01231 LOCK_GET(rl_lock);
01232 for (i=0; i<MAX_PIPES; i++) {
01233 if (*pipes[i].algo != PIPE_ALGO_NOP) {
01234 node = add_mi_node_child(rpl, 0, "PIPE", 4, 0, 0);
01235 if(node == NULL)
01236 goto error;
01237
01238 p = int2str((unsigned long)(i), &len);
01239 attr = add_mi_attr(node, MI_DUP_VALUE, "id" , 2, p, len);
01240 if(attr == NULL)
01241 goto error;
01242
01243 p = int2str((unsigned long)(*pipes[i].algo), &len);
01244 if (str_map_int(algo_names, *pipes[i].algo, &algo))
01245 goto error;
01246 attr = add_mi_attr(node, 0, "algorithm", 9, algo.s, algo.len);
01247 if(attr == NULL)
01248 goto error;
01249
01250 p = int2str((unsigned long)(*pipes[i].limit), &len);
01251 attr = add_mi_attr(node, MI_DUP_VALUE, "limit", 5, p, len);
01252 if(attr == NULL)
01253 goto error;
01254
01255 p = int2str((unsigned long)(*pipes[i].counter), &len);
01256 attr = add_mi_attr(node, MI_DUP_VALUE, "counter", 7, p, len);
01257 if(attr == NULL)
01258 goto error;
01259 }
01260 }
01261 LOCK_RELEASE(rl_lock);
01262 return rpl_tree;
01263 error:
01264 LOCK_RELEASE(rl_lock);
01265 LM_ERR("Unable to create reply\n");
01266 free_mi_tree(rpl_tree);
01267 return 0;
01268 }
01269
01270 struct mi_root* mi_set_pipe(struct mi_root* cmd_tree, void* param)
01271 {
01272 struct mi_node *node;
01273 unsigned int pipe_no = MAX_PIPES, algo_id, limit = 0;
01274
01275
01276 node = cmd_tree->node.kids;
01277 if (node == NULL) return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
01278 if ( !node->value.s || !node->value.len || strno2int(&node->value,&pipe_no)<0)
01279 goto bad_syntax;
01280
01281 node = node->next;
01282 if ( !node->value.s || !node->value.len)
01283 goto bad_syntax;
01284 if (str_map_str(algo_names, &(node->value), (int*)&algo_id)) {
01285 LM_ERR("unknown algorithm: '%.*s'\n", node->value.len, node->value.s);
01286 goto bad_syntax;
01287 }
01288
01289 node = node->next;
01290 if ( !node->value.s || !node->value.len || strno2int(&node->value,&limit)<0)
01291 goto bad_syntax;
01292
01293 LM_DBG("set_pipe: %d:%d:%d\n", pipe_no, algo_id, limit);
01294
01295 if (pipe_no >= MAX_PIPES) {
01296 LM_ERR("wrong pipe_no: %d\n", pipe_no);
01297 goto bad_syntax;
01298 }
01299
01300 LOCK_GET(rl_lock);
01301 *pipes[pipe_no].algo = algo_id;
01302 *pipes[pipe_no].limit = limit;
01303
01304 if (check_feedback_setpoints(0)) {
01305 LM_ERR("feedback limits don't match\n");
01306 goto error;
01307 } else {
01308 *pid_setpoint = 0.01 * (double)cfg_setpoint;
01309 }
01310
01311 LOCK_RELEASE(rl_lock);
01312
01313 return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
01314 error:
01315 LOCK_RELEASE(rl_lock);
01316 bad_syntax:
01317 return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
01318 }
01319
01320 struct mi_root* mi_get_queues(struct mi_root* cmd_tree, void* param)
01321 {
01322 struct mi_root *rpl_tree;
01323 struct mi_node *node=NULL, *rpl=NULL;
01324 struct mi_attr* attr;
01325 char* p;
01326 int i, len;
01327
01328 rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
01329 if (rpl_tree==0)
01330 return 0;
01331 rpl = &rpl_tree->node;
01332
01333 LOCK_GET(rl_lock);
01334 for (i=0; i<MAX_QUEUES; i++) {
01335 if (queues[i].pipe) {
01336 node = add_mi_node_child(rpl, 0, "QUEUE", 5, 0, 0);
01337 if(node == NULL)
01338 goto error;
01339
01340 p = int2str((unsigned long)(i), &len);
01341 attr = add_mi_attr(node, MI_DUP_VALUE, "id" , 2, p, len);
01342 if(attr == NULL)
01343 goto error;
01344
01345 p = int2str((unsigned long)(*queues[i].pipe), &len);
01346 attr = add_mi_attr(node, MI_DUP_VALUE, "pipe" , 4, p, len);
01347 if(attr == NULL)
01348 goto error;
01349
01350 attr = add_mi_attr(node, 0, "method", 6,
01351 (*queues[i].method).s, (*queues[i].method).len);
01352 if(attr == NULL)
01353 goto error;
01354 }
01355 }
01356 LOCK_RELEASE(rl_lock);
01357
01358 return rpl_tree;
01359 error:
01360 LOCK_RELEASE(rl_lock);
01361 LM_ERR("Unable to create reply\n");
01362 free_mi_tree(rpl_tree);
01363 return 0;
01364 }
01365
01366 struct mi_root* mi_set_queue(struct mi_root* cmd_tree, void* param)
01367 {
01368 struct mi_node *node;
01369 unsigned int queue_no = MAX_QUEUES, pipe_no = MAX_PIPES;
01370 str method;
01371
01372 node = cmd_tree->node.kids;
01373 if (node == NULL) return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
01374 if ( !node->value.s || !node->value.len || strno2int(&node->value,&queue_no)<0)
01375 goto bad_syntax;
01376
01377 node = node->next;
01378 if ( !node->value.s || !node->value.len )
01379 goto bad_syntax;
01380 if (str_cpy(&method, &(node->value))) {
01381 LM_ERR("out of memory\n");
01382 goto early_error;
01383 }
01384
01385 node = node->next;
01386 if ( !node->value.s || !node->value.len || strno2int(&node->value,&pipe_no)<0)
01387 goto early_error;
01388 if (pipe_no >= MAX_PIPES) {
01389 LM_ERR("invalid pipe number: %d\n", pipe_no);
01390 goto early_error;
01391 }
01392
01393 LOCK_GET(rl_lock);
01394 if (queue_no >= *nqueues) {
01395 LM_ERR("MAX_QUEUES reached for queue: %d\n", queue_no);
01396 goto error;
01397 }
01398
01399 *queues[queue_no].pipe = pipe_no;
01400 if (!queues[queue_no].method->s)
01401 shm_free(queues[queue_no].method->s);
01402 queues[queue_no].method->s = method.s;
01403 queues[queue_no].method->len = method.len;
01404 LOCK_RELEASE(rl_lock);
01405
01406 return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
01407 error:
01408 LOCK_RELEASE(rl_lock);
01409 early_error:
01410 shm_free(method.s);
01411 bad_syntax:
01412 return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
01413 }
01414
01415 struct mi_root* mi_get_pid(struct mi_root* cmd_tree, void* param)
01416 {
01417 struct mi_root *rpl_tree;
01418 struct mi_node *node=NULL, *rpl=NULL;
01419 struct mi_attr* attr;
01420
01421 rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
01422 if (rpl_tree==0)
01423 return 0;
01424 rpl = &rpl_tree->node;
01425 node = add_mi_node_child(rpl, 0, "PID", 3, 0, 0);
01426 if(node == NULL)
01427 goto error;
01428 LOCK_GET(rl_lock);
01429 attr= addf_mi_attr(node, 0, "ki", 2, "%0.3f", *pid_ki);
01430 if(attr == NULL)
01431 goto error;
01432 attr= addf_mi_attr(node, 0, "kp", 2, "%0.3f", *pid_kp);
01433 if(attr == NULL)
01434 goto error;
01435 attr= addf_mi_attr(node, 0, "kd", 2, "%0.3f", *pid_kd);
01436 LOCK_RELEASE(rl_lock);
01437 if(attr == NULL)
01438 goto error;
01439
01440 return rpl_tree;
01441
01442 error:
01443 LOCK_RELEASE(rl_lock);
01444 LM_ERR("Unable to create reply\n");
01445 free_mi_tree(rpl_tree);
01446 return 0;
01447 }
01448
01449 struct mi_root* mi_set_pid(struct mi_root* cmd_tree, void* param)
01450 {
01451 struct mi_node *node;
01452 char i[5], p[5], d[5];
01453
01454 node = cmd_tree->node.kids;
01455 if (node == NULL) return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
01456 if ( !node->value.s || !node->value.len || node->value.len >= 5)
01457 goto bad_syntax;
01458 memcpy(i, node->value.s, node->value.len);
01459 i[node->value.len] = '\0';
01460
01461 node = node->next;
01462 if ( !node->value.s || !node->value.len || node->value.len >= 5)
01463 goto bad_syntax;
01464 memcpy(p, node->value.s, node->value.len);
01465 p[node->value.len] = '\0';
01466
01467 node = node->next;
01468 if ( !node->value.s || !node->value.len || node->value.len >= 5)
01469 goto bad_syntax;
01470 memcpy(d, node->value.s, node->value.len);
01471 d[node->value.len] = '\0';
01472
01473 LOCK_GET(rl_lock);
01474 *pid_ki = strtod(i, NULL);
01475 *pid_kp = strtod(p, NULL);
01476 *pid_kd = strtod(d, NULL);
01477 LOCK_RELEASE(rl_lock);
01478
01479 return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
01480 bad_syntax:
01481 return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
01482 }
01483
01484 struct mi_root* mi_push_load(struct mi_root* cmd_tree, void* param)
01485 {
01486 struct mi_node *node;
01487 double value;
01488 char c[5];
01489
01490 node = cmd_tree->node.kids;
01491 if (node == NULL) return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
01492 if ( !node->value.s || !node->value.len || node->value.len >= 5)
01493 goto bad_syntax;
01494 memcpy(c, node->value.s, node->value.len);
01495 c[node->value.len] = '\0';
01496 value = strtod(c, NULL);
01497 if (value < 0.0 || value > 1.0) {
01498 LM_ERR("value out of range: %0.3f in not in [0.0,1.0]\n", value);
01499 goto bad_syntax;
01500 }
01501 LOCK_GET(rl_lock);
01502 *load_value = value;
01503 LOCK_RELEASE(rl_lock);
01504
01505 do_update_load();
01506
01507 return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
01508 bad_syntax:
01509 return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
01510 }
01511
01512 struct mi_root* mi_set_dbg(struct mi_root* cmd_tree, void* param)
01513 {
01514 struct mi_node *node;
01515 unsigned int dbg_mode = 0;
01516
01517 node = cmd_tree->node.kids;
01518 if (node == NULL) return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
01519 if ( !node->value.s || !node->value.len || strno2int(&node->value,&dbg_mode)<0)
01520 goto bad_syntax;
01521
01522 LOCK_GET(rl_lock);
01523 if (dbg_mode) {
01524 if (!rl_dbg_str->s) {
01525 rl_dbg_str->len = (MAX_PIPES * 5 * sizeof(char));
01526 rl_dbg_str->s = (char *)shm_malloc(rl_dbg_str->len);
01527 if (!rl_dbg_str->s) {
01528 rl_dbg_str->len = 0;
01529 LM_ERR("oom: %d\n", rl_dbg_str->len);
01530 }
01531 }
01532 } else {
01533 if (rl_dbg_str->s) {
01534 shm_free(rl_dbg_str->s);
01535 rl_dbg_str->s = NULL;
01536 rl_dbg_str->len = 0;
01537 }
01538 }
01539 LOCK_RELEASE(rl_lock);
01540
01541 return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
01542 bad_syntax:
01543 return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
01544 }
01545