From 8ea5426e1308620ef6c1b6742824cf92d4aedecd Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Mon, 3 Dec 2012 17:47:33 +0000 Subject: [PATCH] implement lcr resorting. almost certainly doesnt work and completely lacks error checking. WIP --- modules/lcr_rate/Makefile | 4 +- modules/lcr_rate/lcr_rate_mod.c | 167 +++++++++++++++++++++++++++++++- 2 files changed, 168 insertions(+), 3 deletions(-) diff --git a/modules/lcr_rate/Makefile b/modules/lcr_rate/Makefile index 5a4b5051a..86ad93629 100644 --- a/modules/lcr_rate/Makefile +++ b/modules/lcr_rate/Makefile @@ -2,6 +2,8 @@ include ../../Makefile.defs auto_gen= NAME=lcr_rate.so -DEFS+=-DKAMAILIO_MOD_INTERFACE +DEFS+=-DKAMAILIO_MOD_INTERFACE -D_GNU_SOURCE +DEFS+=$(shell mysql_config --cflags) +LIBS+=-lswrate include ../../Makefile.modules diff --git a/modules/lcr_rate/lcr_rate_mod.c b/modules/lcr_rate/lcr_rate_mod.c index a59b10cd9..1a708bf1e 100644 --- a/modules/lcr_rate/lcr_rate_mod.c +++ b/modules/lcr_rate/lcr_rate_mod.c @@ -1,11 +1,24 @@ #include #include #include +#include +#include +#include #include "../../sr_module.h" #include "../../mod_fix.h" +#include "../../pvar.h" +#include "../../mem/mem.h" +#include "../../mem/shm_mem.h" MODULE_VERSION +struct peer { + unsigned int id; + double cost; + unsigned int weight; + str s; +}; + static void mod_destroy(); static int mod_init(); static int child_init(int rank); @@ -13,16 +26,39 @@ static int child_init(int rank); static int lcr_rate(sip_msg_t *msg, char *su, char *sq); static cmd_export_t cmds[] = { - {"lcr_rate", (cmd_function)lcr_rate, 1, 0, 0, + {"lcr_rate", (cmd_function)lcr_rate, 2, fixup_spve_spve, 0, REQUEST_ROUTE | FAILURE_ROUTE}, {0,} }; +static char *gw_uri_avp_param; +static int gw_uri_avp_type; +static int_str gw_uri_avp; + +static char *db_host; +static unsigned int db_port; +static char *db_user; +static char *db_pass; +static char *db_db; + +static param_export_t params[] = { + {"gw_uri_avp", STR_PARAM, &gw_uri_avp_param}, + {"db_host", STR_PARAM, &db_host}, + {"db_port", INT_PARAM, &db_port}, + {"db_user", STR_PARAM, &db_user}, + {"db_pass", STR_PARAM, &db_pass}, + {"db_db", STR_PARAM, &db_db}, + {0,}, +}; + +static int swrate_done; +static SWRATE swrate_handle; + struct module_exports exports = { "lcr_rate", DEFAULT_DLFLAGS, cmds, - 0, + params, 0, 0, 0, @@ -34,6 +70,29 @@ struct module_exports exports = { }; static int mod_init() { + pv_spec_t avp_spec; + str s; + unsigned short avp_flags; + + if (!gw_uri_avp_param || !*gw_uri_avp_param) { + LM_ERR("gw_uri_avp not set\n"); + return -1; + } + + s.s = gw_uri_avp_param; + s.len = strlen(s.s); + + if (!pv_parse_spec(&s, &avp_spec) || avp_spec.type != PVT_AVP) { + LM_ERR("malformed or non AVP definition <%s>\n", gw_uri_avp_param); + return -1; + } + + if (pv_get_avp_name(0, &(avp_spec.pvp), &gw_uri_avp, &avp_flags)) { + LM_ERR("invalid AVP definition <%s>\n", gw_uri_avp_param); + return -1; + } + gw_uri_avp_type = avp_flags; + return 0; } @@ -45,6 +104,110 @@ static void mod_destroy() { ; } +static int check_swrate_init() { + if (swrate_done) + return 0; + if (swrate_init(&swrate_handle, db_host, db_port, db_db, db_user, db_pass, NULL, 0, 1, 0)) + return -1; + return 0; +} + +struct peer *load_peers(int *num, str *user, str *domain) { + struct usr_avp *avp; + int_str val; + struct peer *ret, *j; + int len, i; + char *c; + str s; + swr_rate_t rate; + time_t now; + + len = 4; + ret = pkg_malloc(len * sizeof(*ret)); + if (!ret) + return NULL; + i = 0; + time(&now); + + while (1) { + avp = search_first_avp(gw_uri_avp_type, gw_uri_avp, &val, 0); + if (!avp) + break; + + if (i == len) { + len <<= 1; + ret = pkg_realloc(ret, len * sizeof(*ret)); + if (!ret) + return NULL; + } + + j = &ret[i]; + + j->s.len = val.s.len; + j->s.s = pkg_malloc(val.s.len); + memcpy(j->s.s, val.s.s, val.s.len); + c = memrchr(j->s.s, '|', val.s.len); + if (!c) + return NULL; + + c++; + s.s = c; + s.len = val.s.len - (c - j->s.s); + str2int(&s, &j->id); + + j->weight = i; + + swrate_get_peer_rate(&rate, &swrate_handle, j->id, user->s, domain->s, now); + j->cost = rate.init_rate; + + destroy_avp(avp); + i++; + } + + *num = i; + return ret; +} + +static int peers_cmp(const void *aa, const void *bb) { + const struct peer *a = aa, *b = bb; + + if (a->cost < b->cost) + return -1; + if (a->cost > b->cost) + return 1; + if (a->weight < b->cost) + return -1; + return 1; +} + +static int save_peers(struct peer *peers, int num) { + int i; + int_str val; + + for (i = 0; i < num; i++) { + val.s = peers[i].s; + add_avp(gw_uri_avp_type|AVP_VAL_STR, gw_uri_avp, val); + pkg_free(val.s.s); + } + + pkg_free(peers); + return 0; +} + static int lcr_rate(sip_msg_t *msg, char *su, char *sq) { + struct peer *peers; + int num_peers; + str user, domain; + + if (check_swrate_init()) + return -1; + + fixup_get_svalue(msg, (gparam_t *) su, &user); + fixup_get_svalue(msg, (gparam_t *) sq, &domain); + + peers = load_peers(&num_peers, &user, &domain); + qsort(peers, num_peers, sizeof(*peers), peers_cmp); + save_peers(peers, num_peers); + return 0; }