int init_rl_table(unsigned int size) { unsigned int i; rl_htable.maps = shm_malloc(sizeof(map_t) * size); if (!rl_htable.maps) { LM_ERR("no more shm memory\n"); return -1; } memset(rl_htable.maps, 0, sizeof(map_t) * size); for (i = 0; i < size; i++) { rl_htable.maps[i] = map_create(AVLMAP_SHARED); if (!rl_htable.maps[i]) { LM_ERR("cannot create map index %d\n", i); goto error; } rl_htable.size++; } if (!rl_default_algo_s.s) { LM_ERR("Default algorithm was not specified\n"); return -1; } /* resolve the default algorithm */ rl_default_algo = get_rl_algo(rl_default_algo_s); if (rl_default_algo < 0) { LM_ERR("unknown algoritm <%.*s>\n", rl_default_algo_s.len, rl_default_algo_s.s); return -1; } LM_DBG("default algorithm is %.*s [ %d ]\n", rl_default_algo_s.len, rl_default_algo_s.s, rl_default_algo); /* if at least 25% of the size locks can't be allocated * we return an error */ for ( i = size; i > size / 4; i--) { rl_htable.locks = lock_set_alloc(i); if (!rl_htable.locks) continue; if (!lock_set_init(rl_htable.locks)) { lock_set_dealloc(rl_htable.locks); rl_htable.locks = 0; continue; } break; } if (!rl_htable.locks) { LM_ERR("unable to allocted at least %d locks for the hash table\n", size/4); goto error; } rl_htable.locks_no = i; LM_DBG("%d locks allocated for %d hashsize\n", rl_htable.locks_no, rl_htable.size); return 0; error: mod_destroy(); return -1; }
int w_rl_check_3(struct sip_msg *_m, char *_n, char *_l, char *_a) { str name; int limit = 0, ret = 1, should_update = 0; str algorithm; unsigned int hash_idx; rl_pipe_t **pipe; rl_algo_t algo = -1; /* retrieve and check parameters */ if (!_n || !_l) { LM_ERR("invalid parameters\n"); goto end; } if (fixup_get_svalue(_m, (gparam_p)_n, &name) < 0) { LM_ERR("cannot retrieve identifier\n"); goto end; } if (fixup_get_ivalue(_m, (gparam_p)_l, &limit) < 0) { LM_ERR("cannot retrieve limit\n"); goto end; } algorithm.s = 0; if (!_a || fixup_get_svalue(_m, (gparam_p)_a, &algorithm) < 0 || (algo = get_rl_algo(algorithm)) < 0) { algo = PIPE_ALGO_NOP; } /* get limit for FEEDBACK algorithm */ if (algo == PIPE_ALGO_FEEDBACK) { lock_get(rl_lock); if (*rl_feedback_limit) { if (*rl_feedback_limit != limit) { LM_WARN("FEEDBACK limit should be the same for all pipes, but" " new limit %d differs - setting to %d\n", limit, *rl_feedback_limit); limit = *rl_feedback_limit; } } else { if (limit <= 0 || limit >= 100) { LM_ERR("invalid limit for FEEDBACK algorithm " "(must be between 0 and 100)\n"); lock_release(rl_lock); goto end; } *rl_feedback_limit = limit; pid_setpoint_limit(limit); } lock_release(rl_lock); } hash_idx = RL_GET_INDEX(name); RL_GET_LOCK(hash_idx); /* try to get the value */ pipe = RL_GET_PIPE(hash_idx, name); if (!pipe) { LM_ERR("cannot get the index\n"); goto release; } if (!*pipe) { /* allocate new pipe */ *pipe = shm_malloc(sizeof(rl_pipe_t) + rl_dests_nr * sizeof(rl_repl_counter_t)); if (!*pipe) { LM_ERR("no more shm memory\n"); goto release; } memset(*pipe, 0, sizeof(rl_pipe_t) + rl_dests_nr * sizeof(rl_repl_counter_t)); (*pipe)->dsts = (rl_repl_counter_t *)((*pipe) + 1); LM_DBG("Pipe %.*s doens't exist, but was created %p\n", name.len, name.s, *pipe); if (algo == PIPE_ALGO_NETWORK) should_update = 1; (*pipe)->algo = (algo == PIPE_ALGO_NOP) ? rl_default_algo : algo; } else { LM_DBG("Pipe %.*s found: %p - last used %lu\n", name.len, name.s, *pipe, (*pipe)->last_used); if (algo != PIPE_ALGO_NOP && (*pipe)->algo != algo) { LM_WARN("algorithm %d different from the initial one %d for pipe " "%.*s", algo, (*pipe)->algo, name.len, name.s); } } /* set/update the limit */ (*pipe)->limit = limit; /* set the last used time */ (*pipe)->last_used = time(0); if (RL_USE_CDB(*pipe)) { /* release the counter for a while */ if (rl_change_counter(&name, *pipe, 1) < 0) { LM_ERR("cannot increase counter\n"); goto end; } } else { (*pipe)->counter++; } ret = rl_pipe_check(*pipe); LM_DBG("Pipe %.*s counter:%d load:%d limit:%d should %sbe blocked (%p)\n", name.len, name.s, (*pipe)->counter, (*pipe)->load, (*pipe)->limit, ret == 1? "NOT " : "", *pipe); release: RL_RELEASE_LOCK(hash_idx); if (should_update) { lock_get(rl_lock); (*rl_network_count)++; lock_release(rl_lock); } end: return ret; }
int w_rl_check(struct sip_msg *_m, str *name, int *limit, str *algorithm) { int ret = 1, should_update = 0; unsigned int hash_idx; rl_pipe_t **pipe; rl_algo_t algo = -1; if (!algorithm || (algo = get_rl_algo(*algorithm)) == PIPE_ALGO_NOP) { algo = PIPE_ALGO_NOP; } /* get limit for FEEDBACK algorithm */ if (algo == PIPE_ALGO_FEEDBACK) { lock_get(rl_lock); if (*rl_feedback_limit) { if (*rl_feedback_limit != *limit) { LM_WARN("FEEDBACK limit should be the same for all pipes, but" " new limit %d differs - setting to %d\n", *limit, *rl_feedback_limit); *limit = *rl_feedback_limit; } } else { if (*limit <= 0 || *limit >= 100) { LM_ERR("invalid limit for FEEDBACK algorithm " "(must be between 0 and 100)\n"); lock_release(rl_lock); goto end; } *rl_feedback_limit = *limit; pid_setpoint_limit(*limit); } lock_release(rl_lock); } hash_idx = RL_GET_INDEX(*name); RL_GET_LOCK(hash_idx); /* try to get the value */ pipe = RL_GET_PIPE(hash_idx, *name); if (!pipe) { LM_ERR("cannot get the index\n"); goto release; } if (!*pipe) { /* allocate new pipe */ if (!(*pipe = rl_create_pipe(*limit, algo))) goto release; LM_DBG("Pipe %.*s doesn't exist, but was created %p\n", name->len, name->s, *pipe); if ((*pipe)->algo == PIPE_ALGO_NETWORK) should_update = 1; } else { LM_DBG("Pipe %.*s found: %p - last used %lu\n", name->len, name->s, *pipe, (*pipe)->last_used); if (algo != PIPE_ALGO_NOP && (*pipe)->algo != algo) { LM_WARN("algorithm %d different from the initial one %d for pipe " "%.*s", algo, (*pipe)->algo, name->len, name->s); } /* update the limit */ (*pipe)->limit = *limit; } /* set the last used time */ (*pipe)->last_used = time(0); if (RL_USE_CDB(*pipe)) { /* release the counter for a while */ if (rl_change_counter(name, *pipe, 1) < 0) { LM_ERR("cannot increase counter\n"); goto release; } } else { (*pipe)->counter++; } ret = rl_pipe_check(*pipe); LM_DBG("Pipe %.*s counter:%d load:%d limit:%d should %sbe blocked (%p)\n", name->len, name->s, (*pipe)->counter, (*pipe)->load, (*pipe)->limit, ret == 1 ? "NOT " : "", *pipe); release: RL_RELEASE_LOCK(hash_idx); if (should_update) { lock_get(rl_lock); (*rl_network_count)++; lock_release(rl_lock); } end: return ret; }