MT#58547 lcr_rate: use gw_id field from gw_uri_avp for load_peers()

* merge lcr_rate patches
* format code with kamailio clang definitions

Change-Id: Ic20e9e535ca0f904b5f497468ddcf26abcb9fa2a
mr13.0
Victor Seva 9 months ago
parent 7508181031
commit 8be5217b1f

@ -11,7 +11,6 @@ sipwise/parallel_build.patch
## New Modules
sipwise/add_pcem_module.patch
sipwise/add_lcr_rate_module.patch
sipwise/fix_lcr_rate_wrong_id.patch
sipwise/add_tcap_module.patch
sipwise/add_presence_dfks_module.patch
sipwise/presence_dfks_null_ptr_fixes.patch

@ -7,8 +7,8 @@ Subject: add_lcr_rate_module
src/core/mod_fix.c | 3 +
src/core/mod_fix.h | 2 +
src/modules/lcr_rate/Makefile | 9 +
src/modules/lcr_rate/lcr_rate_mod.c | 473 ++++++++++++++++++++++++++++++++++++
5 files changed, 494 insertions(+), 2 deletions(-)
src/modules/lcr_rate/lcr_rate_mod.c | 517 ++++++++++++++++++++++++++++++++++++
5 files changed, 538 insertions(+), 2 deletions(-)
create mode 100644 src/modules/lcr_rate/Makefile
create mode 100644 src/modules/lcr_rate/lcr_rate_mod.c
@ -97,10 +97,10 @@ index 0000000..9a3cee1
+include ../../Makefile.modules
diff --git a/src/modules/lcr_rate/lcr_rate_mod.c b/src/modules/lcr_rate/lcr_rate_mod.c
new file mode 100644
index 0000000..f3a9ab2
index 0000000..5670871
--- /dev/null
+++ b/src/modules/lcr_rate/lcr_rate_mod.c
@@ -0,0 +1,473 @@
@@ -0,0 +1,517 @@
+/*
+ * call rating for least cost routing module
+ *
@ -138,7 +138,8 @@ index 0000000..f3a9ab2
+
+MODULE_VERSION
+
+struct peer {
+struct peer
+{
+ int valid;
+ unsigned int id;
+ double cost;
@ -151,10 +152,25 @@ index 0000000..f3a9ab2
+static int child_init(int rank);
+
+static int lcr_rate(sip_msg_t *msg, char *su, char *sq);
+static int lcr_get_prepaid_from_uuid(sip_msg_t *msg, char *uuid, char *avp, char *avp2);
+static int lcr_get_prepaid_from_uuid(
+ sip_msg_t *msg, char *uuid, char *avp, char *avp2);
+static int lcr_get_prepaid_from_uuid2(sip_msg_t *msg, char *uuid, char *avp);
+static int lcr_get_profile_id_from_uuid(sip_msg_t *msg, char *uuid, char *avp);
+
+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 int swrate_done;
+static SWRATE *swrate_ptr;
+
+/* clang-format off */
+static cmd_export_t cmds[] = {
+ {"lcr_rate", lcr_rate, 2, fixup_spve_spve, 0,
+ REQUEST_ROUTE | FAILURE_ROUTE},
@ -167,16 +183,6 @@ index 0000000..f3a9ab2
+ {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},
@ -187,9 +193,6 @@ index 0000000..f3a9ab2
+ {0,},
+};
+
+static int swrate_done;
+static SWRATE *swrate_ptr;
+
+struct module_exports exports = {
+ "lcr_rate", /* module name */
+ DEFAULT_DLFLAGS, /* dlopen flags */
@ -202,13 +205,15 @@ index 0000000..f3a9ab2
+ child_init, /* per-child init function */
+ mod_destroy /* module destroy function */
+};
+/* clang-format on */
+
+static int mod_init() {
+static int mod_init()
+{
+ pv_spec_t avp_spec;
+ str s;
+ unsigned short avp_flags;
+
+ if (!gw_uri_avp_param || !*gw_uri_avp_param) {
+ if(!gw_uri_avp_param || !*gw_uri_avp_param) {
+ LM_ERR("gw_uri_avp not set\n");
+ return -1;
+ }
@ -216,12 +221,12 @@ index 0000000..f3a9ab2
+ s.s = gw_uri_avp_param;
+ s.len = strlen(s.s);
+
+ if (!pv_parse_spec(&s, &avp_spec) || avp_spec.type != PVT_AVP) {
+ 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)) {
+ 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;
+ }
@ -230,21 +235,25 @@ index 0000000..f3a9ab2
+ return 0;
+}
+
+static int child_init(int rank) {
+static int child_init(int rank)
+{
+ return 0;
+}
+
+static void mod_destroy() {
+ ;
+static void mod_destroy()
+{
+ return;
+}
+
+static int check_swrate_init() {
+ if (swrate_done)
+static int check_swrate_init()
+{
+ if(swrate_done)
+ return 0;
+ swrate_ptr = swrate_new(db_host, db_port, db_db, db_user, db_pass, NULL, 0, 1, 0);
+ if (!swrate_ptr || !swrate_new_ok(swrate_ptr)) {
+ swrate_ptr = swrate_new(
+ db_host, db_port, db_db, db_user, db_pass, NULL, 0, 1, 0);
+ if(!swrate_ptr || !swrate_new_ok(swrate_ptr)) {
+ LM_ERR("failed to initialized libswrate\n");
+ if (swrate_ptr)
+ if(swrate_ptr)
+ swrate_free(swrate_ptr);
+ return -1;
+ }
@ -252,37 +261,39 @@ index 0000000..f3a9ab2
+ return 0;
+}
+
+static struct peer *load_peers(int *num, char *src_user, char *src_domain, char *dst_user, char *dst_domain) {
+static struct peer *load_peers(int *num, char *src_user, char *src_domain,
+ char *dst_user, char *dst_domain)
+{
+ struct usr_avp *avp;
+ int_str val;
+ struct peer *ret, *j;
+ int len, i;
+ int len, i, k;
+ char *c;
+ str s;
+ swr_rate_t rate;
+ time_t now;
+
+ LM_DBG("loading peers for user <%s>@<%s> -> <%s>@<%s> from avp\n",
+ src_user, src_domain, dst_user, dst_domain);
+ LM_DBG("loading peers for user <%s>@<%s> -> <%s>@<%s> from avp\n", src_user,
+ src_domain, dst_user, dst_domain);
+
+ len = 4;
+ ret = pkg_malloc(len * sizeof(*ret));
+ if (!ret) {
+ if(!ret) {
+ LM_ERR("out of pkg memory\n");
+ return NULL;
+ }
+ i = 0;
+ time(&now);
+
+ while (1) {
+ while(1) {
+ avp = search_first_avp(gw_uri_avp_type, gw_uri_avp, &val, 0);
+ if (!avp)
+ if(!avp)
+ break;
+
+ if (i == len) {
+ if(i == len) {
+ len <<= 1;
+ j = pkg_realloc(ret, len * sizeof(*ret));
+ if (!j) {
+ if(!j) {
+ pkg_free(ret);
+ LM_ERR("out of pkg memory\n");
+ return NULL;
@ -295,22 +306,47 @@ index 0000000..f3a9ab2
+
+ j->s.len = val.s.len;
+ j->s.s = pkg_malloc(val.s.len);
+ if (!j->s.s) {
+ if(!j->s.s) {
+ pkg_free(ret);
+ LM_ERR("out of pkg memory\n");
+ return NULL;
+ }
+ memcpy(j->s.s, val.s.s, val.s.len);
+ c = memrchr(j->s.s, '|', val.s.len);
+ if (!c) {
+ LM_ERR("separator not found in string <%.*s>\n", val.s.len, j->s.s);
+ goto next;
+
+ /* lcr gw fields:
+ * 0: gw index
+ * 1: scheme
+ * 2: strip
+ * 3: prefix
+ * 4: tag
+ * 5: ip adr
+ * 6: hostname
+ * 7: port
+ * 8: params
+ * 9: transport
+ * 10: flags
+ * 11: rule id
+ * 12: gw id
+ */
+ c = j->s.s;
+ for(k = 0; k < 12; k++) {
+ c = memchr(c, '|', val.s.len - (c - j->s.s));
+ if(!c) {
+ LM_ERR("separator not found in string <%.*s> (field #%i)\n",
+ val.s.len, j->s.s, k);
+ goto next;
+ }
+ c++;
+ }
+
+ c++;
+ s.s = c;
+ s.len = val.s.len - (c - j->s.s);
+ if (str2int(&s, &j->id)) {
+
+ /* find terminator */
+ c = memchr(c, '|', val.s.len - (c - j->s.s));
+ if(!c)
+ c = j->s.s + val.s.len;
+ s.len = c - s.s;
+ if(str2int(&s, &j->id)) {
+ LM_ERR("could not convert string <%.*s> to int\n", s.len, s.s);
+ goto next;
+ }
@ -318,17 +354,18 @@ index 0000000..f3a9ab2
+ LM_DBG("finding rate for peer %u\n", j->id);
+ j->weight = i;
+
+ if (swrate_get_peer_ab_rate(&rate, swrate_ptr, j->id, src_user,
+ src_domain, dst_user, dst_domain, now)) {
+ LM_ERR("failed to get rate for call, peer id %u, user <%s>@<%s> -> <%s>@<%s>\n",
+ j->id, src_user, src_domain, dst_user, dst_domain);
+ if(swrate_get_peer_ab_rate(&rate, swrate_ptr, j->id, src_user,
+ src_domain, dst_user, dst_domain, now)) {
+ LM_ERR("failed to get rate for call, peer id %u, user <%s>@<%s> -> "
+ "<%s>@<%s>\n",
+ j->id, src_user, src_domain, dst_user, dst_domain);
+ goto next;
+ }
+ j->cost = rate.init_rate;
+ j->valid = 1;
+ LM_DBG("cost is %f\n", j->cost);
+
+next:
+ next:
+ destroy_avp(avp);
+ i++;
+ }
@ -337,37 +374,39 @@ index 0000000..f3a9ab2
+ return ret;
+}
+
+static int peers_cmp(const void *aa, const void *bb) {
+static int peers_cmp(const void *aa, const void *bb)
+{
+ const struct peer *a = aa, *b = bb;
+
+ if (a->valid && !b->valid)
+ if(a->valid && !b->valid)
+ return 1;
+ if (!a->valid && b->valid)
+ if(!a->valid && b->valid)
+ return -1;
+ if (!a->valid && !b->valid)
+ if(!a->valid && !b->valid)
+ return 0;
+
+ if (a->cost < b->cost)
+ if(a->cost < b->cost)
+ return 1;
+ if (a->cost > b->cost)
+ if(a->cost > b->cost)
+ return -1;
+
+ if (a->weight < b->weight)
+ if(a->weight < b->weight)
+ return 1;
+ if (a->weight > b->weight)
+ if(a->weight > b->weight)
+ return -1;
+
+ return 0;
+}
+
+static int save_peers(struct peer *peers, int num) {
+static int save_peers(struct peer *peers, int num)
+{
+ int i;
+ int_str val;
+
+ for (i = 0; i < num; i++) {
+ for(i = 0; i < num; i++) {
+ LM_DBG("adding back peer %u\n", peers[i].id);
+ val.s = peers[i].s;
+ if (add_avp(gw_uri_avp_type|AVP_VAL_STR, gw_uri_avp, val))
+ if(add_avp(gw_uri_avp_type | AVP_VAL_STR, gw_uri_avp, val))
+ LM_ERR("add_avp failed\n");
+ pkg_free(val.s.s);
+ }
@ -376,35 +415,37 @@ index 0000000..f3a9ab2
+ return 0;
+}
+
+static void extract_ud(str *s, char **user, char **at, char **domain) {
+static void extract_ud(str *s, char **user, char **at, char **domain)
+{
+ *user = *at = *domain = NULL;
+ if (!s || !s->s || !*s->s)
+ if(!s || !s->s || !*s->s)
+ return;
+ *user = s->s;
+ *at = strchr(*user, '@');
+ if (!*at)
+ if(!*at)
+ return;
+ **at = '\0';
+ *domain = *at + 1;
+ if (!**domain)
+ if(!**domain)
+ *domain = NULL;
+}
+
+static int lcr_rate(sip_msg_t *msg, char *su, char *sq) {
+static int lcr_rate(sip_msg_t *msg, char *su, char *sq)
+{
+ struct peer *peers;
+ int num_peers, ret;
+ str src, dst;
+ char *src_user, *src_at, *src_domain;
+ char *dst_user, *dst_at, *dst_domain;
+
+ if (check_swrate_init())
+ if(check_swrate_init())
+ return -1;
+
+ if (fixup_get_svalue(msg, (gparam_t *) su, &src)) {
+ if(fixup_get_svalue(msg, (gparam_t *)su, &src)) {
+ LM_ERR("failed to get user parameter\n");
+ return -1;
+ }
+ if (fixup_get_svalue(msg, (gparam_t *) sq, &dst)) {
+ if(fixup_get_svalue(msg, (gparam_t *)sq, &dst)) {
+ LM_ERR("failed to get domain parameter\n");
+ return -1;
+ }
@ -414,17 +455,17 @@ index 0000000..f3a9ab2
+
+ peers = load_peers(&num_peers, src_user, src_domain, dst_user, dst_domain);
+
+ if (*src_at)
+ if(*src_at)
+ *src_at = '@';
+ if (*dst_at)
+ if(*dst_at)
+ *dst_at = '@';
+
+ if (!peers)
+ if(!peers)
+ return -1;
+ qsort(peers, num_peers, sizeof(*peers), peers_cmp);
+
+ ret = 1;
+ if (!num_peers || (!peers[0].valid && !peers[num_peers - 1].valid)) {
+ if(!num_peers || (!peers[0].valid && !peers[num_peers - 1].valid)) {
+ LM_ERR("no peers with valid ratings found\n");
+ ret = -1;
+ }
@ -434,26 +475,24 @@ index 0000000..f3a9ab2
+ return ret;
+}
+
+static int get_avp(unsigned short *avp_type, int_str *avp_name, char *avp_s) {
+static int get_avp(unsigned short *avp_type, int_str *avp_name, char *avp_s)
+{
+ pv_spec_t *avp_spec = NULL;
+ str *avp;
+
+ avp = (str *) avp_s;
+ avp = (str *)avp_s;
+
+ if (pv_locate_name(avp) != avp->len)
+ {
+ if(pv_locate_name(avp) != avp->len) {
+ LM_ERR("invalid AVP parameter\n");
+ return -1;
+ }
+
+ if (((avp_spec = pv_cache_get(avp)) == NULL)
+ || avp_spec->type!=PVT_AVP) {
+ if(((avp_spec = pv_cache_get(avp)) == NULL) || avp_spec->type != PVT_AVP) {
+ LM_ERR("malformed or non AVP %s AVP definition\n", avp->s);
+ return -1;
+ }
+
+ if(pv_get_avp_name(0, &avp_spec->pvp, avp_name, avp_type)!=0)
+ {
+ if(pv_get_avp_name(0, &avp_spec->pvp, avp_name, avp_type) != 0) {
+ LM_ERR("[%s]- invalid AVP definition\n", avp->s);
+ return -1;
+ }
@ -461,21 +500,23 @@ index 0000000..f3a9ab2
+ return 0;
+}
+
+static int get_profile_from_uuid(swr_profile_t *prof, sip_msg_t *msg, char *uuid_s) {
+static int get_profile_from_uuid(
+ swr_profile_t *prof, sip_msg_t *msg, char *uuid_s)
+{
+ char *pc, *ip;
+ str uuid;
+
+ if (check_swrate_init())
+ if(check_swrate_init())
+ return -1;
+
+ // validate parameters
+
+ if (get_str_fparam(&uuid, msg, (fparam_t *) uuid_s)) {
+ if(get_str_fparam(&uuid, msg, (fparam_t *)uuid_s)) {
+ LM_ERR("unable to extract uuid parameter\n");
+ return -1;
+ }
+
+ if (!uuid.s || !*uuid.s) {
+ if(!uuid.s || !*uuid.s) {
+ LM_ERR("empty uuid parameter\n");
+ return -1;
+ }
@ -483,14 +524,15 @@ index 0000000..f3a9ab2
+ // split up "uuid;ip"
+
+ pc = strchr(uuid.s, ';');
+ if (!pc)
+ if(!pc)
+ ip = NULL;
+ else {
+ *pc = 0;
+ ip = pc+1;
+ ip = pc + 1;
+ }
+
+ if (swrate_get_subscriber_billing_profile(prof, swrate_ptr, time(NULL), uuid.s, ip)) {
+ if(swrate_get_subscriber_billing_profile(
+ prof, swrate_ptr, time(NULL), uuid.s, ip)) {
+ LM_ERR("swrate call returned error\n");
+ return -1;
+ }
@ -498,11 +540,14 @@ index 0000000..f3a9ab2
+ return 0;
+}
+
+static int lcr_get_prepaid_from_uuid2(sip_msg_t *msg, char *uuid_s, char *avp_s) {
+static int lcr_get_prepaid_from_uuid2(sip_msg_t *msg, char *uuid_s, char *avp_s)
+{
+ return lcr_get_prepaid_from_uuid(msg, uuid_s, avp_s, NULL);
+}
+
+static int lcr_get_prepaid_from_uuid(sip_msg_t *msg, char *uuid_s, char *avp_s, char *avp2_s) {
+static int lcr_get_prepaid_from_uuid(
+ sip_msg_t *msg, char *uuid_s, char *avp_s, char *avp2_s)
+{
+ swr_profile_t *prof;
+ unsigned short avp_type = 0;
+ int_str avp_val;
@ -512,33 +557,31 @@ index 0000000..f3a9ab2
+ int_str avp2_name;
+
+ prof = swrate_profile_new();
+ if (!prof)
+ if(!prof)
+ return -1;
+
+ if (get_profile_from_uuid(prof, msg, uuid_s))
+ if(get_profile_from_uuid(prof, msg, uuid_s))
+ goto err;
+ if (get_avp(&avp_type, &avp_name, avp_s))
+ if(get_avp(&avp_type, &avp_name, avp_s))
+ goto err;
+ if (avp2_s) {
+ if (get_avp(&avp2_type, &avp2_name, avp2_s))
+ if(avp2_s) {
+ if(get_avp(&avp2_type, &avp2_name, avp2_s))
+ goto err;
+ }
+
+ avp_val.s.s = prof->prepaid ? "1" : "0";
+ avp_val.s.len = 1;
+
+ if (add_avp(AVP_VAL_STR | avp_type, avp_name, avp_val) != 0)
+ {
+ if(add_avp(AVP_VAL_STR | avp_type, avp_name, avp_val) != 0) {
+ LM_ERR("Failed to add result avp");
+ goto err;
+ }
+
+ if (avp2_s) {
+ if(avp2_s) {
+ avp2_val.s.s = prof->prepaid_library;
+ avp2_val.s.len = strlen(prof->prepaid_library);
+
+ if (add_avp(AVP_VAL_STR | avp2_type, avp2_name, avp2_val) != 0)
+ {
+ if(add_avp(AVP_VAL_STR | avp2_type, avp2_name, avp2_val) != 0) {
+ LM_ERR("Failed to add result avp");
+ goto err;
+ }
@ -553,21 +596,22 @@ index 0000000..f3a9ab2
+ return -1;
+}
+
+static int lcr_get_profile_id_from_uuid(sip_msg_t *msg, char *uuid_s, char *avp_s) {
+static int lcr_get_profile_id_from_uuid(
+ sip_msg_t *msg, char *uuid_s, char *avp_s)
+{
+ swr_profile_t prof;
+ unsigned short avp_type = 0;
+ int_str avp_val;
+ int_str avp_name;
+
+ if (get_profile_from_uuid(&prof, msg, uuid_s))
+ if(get_profile_from_uuid(&prof, msg, uuid_s))
+ return -1;
+ if (get_avp(&avp_type, &avp_name, avp_s))
+ if(get_avp(&avp_type, &avp_name, avp_s))
+ return -1;
+
+ avp_val.s.s = int2str(prof.profile_id, &avp_val.s.len);
+
+ if (add_avp(AVP_VAL_STR | avp_type, avp_name, avp_val) != 0)
+ {
+ if(add_avp(AVP_VAL_STR | avp_type, avp_name, avp_val) != 0) {
+ LM_ERR("Failed to add result avp");
+ return -1;
+ }

@ -1,67 +0,0 @@
From: Sipwise Development Team <support@sipwise.com>
Date: Thu, 26 Mar 2020 10:06:46 +0100
Subject: fix_lcr_rate_wrong_id
---
src/modules/lcr_rate/lcr_rate_mod.c | 38 ++++++++++++++++++++++++++++++-------
1 file changed, 31 insertions(+), 7 deletions(-)
diff --git a/src/modules/lcr_rate/lcr_rate_mod.c b/src/modules/lcr_rate/lcr_rate_mod.c
index f3a9ab2..f35e577 100644
--- a/src/modules/lcr_rate/lcr_rate_mod.c
+++ b/src/modules/lcr_rate/lcr_rate_mod.c
@@ -153,7 +153,7 @@ static struct peer *load_peers(int *num, char *src_user, char *src_domain, char
struct usr_avp *avp;
int_str val;
struct peer *ret, *j;
- int len, i;
+ int len, i, k;
char *c;
str s;
swr_rate_t rate;
@@ -198,15 +198,39 @@ static struct peer *load_peers(int *num, char *src_user, char *src_domain, char
return NULL;
}
memcpy(j->s.s, val.s.s, val.s.len);
- c = memrchr(j->s.s, '|', val.s.len);
- if (!c) {
- LM_ERR("separator not found in string <%.*s>\n", val.s.len, j->s.s);
- goto next;
+
+ /* lcr gw fields:
+ * 0: gw index
+ * 1: scheme
+ * 2: strip
+ * 3: prefix
+ * 4: tag
+ * 5: ip adr
+ * 6: hostname
+ * 7: port
+ * 8: params
+ * 9: transport
+ * 10: flags
+ * 11: rule id
+ */
+ c = j->s.s;
+ for (k = 0; k < 10; k++) {
+ c = memchr(c, '|', val.s.len - (c - j->s.s));
+ if (!c) {
+ LM_ERR("separator not found in string <%.*s> (field #%i)\n",
+ val.s.len, j->s.s, k);
+ goto next;
+ }
+ c++;
}
- c++;
s.s = c;
- s.len = val.s.len - (c - j->s.s);
+
+ /* find terminator */
+ c = memchr(c, '|', val.s.len - (c - j->s.s));
+ if (!c)
+ c = j->s.s + val.s.len;
+ s.len = c - s.s;
if (str2int(&s, &j->id)) {
LM_ERR("could not convert string <%.*s> to int\n", s.len, s.s);
goto next;
Loading…
Cancel
Save