main/kamailio: add srv_query function to ipops module

This commit is contained in:
Leonardo Arena 2015-02-24 14:19:05 +00:00
parent e211cfc6cb
commit 2bf3eba2ae
2 changed files with 664 additions and 1 deletions

View File

@ -13,7 +13,7 @@ _gittag=HEAD
pkgver=4.2.3
pkgrel=0
pkgrel=1
[ -z "${_gitcommit}" ] && _suffix="_src" || _suffix="-${_gitcommit}"
pkgdesc="Open Source SIP Server"
@ -225,6 +225,8 @@ done
source="http://www.kamailio.org/pub/kamailio/$pkgver/src/kamailio-${pkgver}${_suffix}.tar.gz
kamailio-4.2-backslash.patch
0001-musl-fixes.patch
kamailio-4.2-ipops-srv-query.patch
kamailio.cfg
kamailio.initd
"
@ -489,15 +491,18 @@ redis() {
md5sums="f94eb1db3820dba22bd3fdae464e93b3 kamailio-4.2.3_src.tar.gz
bad1ac2d4c95043df271d2ea6d37627a kamailio-4.2-backslash.patch
4685288dc54680597b00f956dc95d4d6 0001-musl-fixes.patch
5b7ecf5c4ae06420c028e03721cb9e89 kamailio-4.2-ipops-srv-query.patch
a3c959ec568c43a905710e7d25cd8c25 kamailio.cfg
0e0a271fd3ddb7e87c01c26c7d041d59 kamailio.initd"
sha256sums="7dbbca4a515778d3e903380adcc49f727ddc4853238cb905e14c811a5671ed80 kamailio-4.2.3_src.tar.gz
d7e59be721ed0ad4621d404493b9a519708d801e9d4914b0164b819fa1abcd13 kamailio-4.2-backslash.patch
b98555ff304b51b82c6cf7e01d757b15ea4f05bd2e603c84d4384df6a6be62b6 0001-musl-fixes.patch
cfe645fc80eaed8a9e4bd56047f75555b2a9e3edcb3e2b6c6cece1547ab0a574 kamailio-4.2-ipops-srv-query.patch
8024266849033a917147827c3579a382f10f3796989bebc6de3d7c80c965fb72 kamailio.cfg
a90d3ab09a3ed58892e94710a1f80492a61ffad1ccf7ccb5b851bb8f538d32c4 kamailio.initd"
sha512sums="2f42499fe84eefac236fe3d4aa3c7bc424944236f00b95a7071feaa816b3df5764f84076d57b2137908dab7ff06a2440cc7a53a799216befd9511f8718a2eee5 kamailio-4.2.3_src.tar.gz
a9bb1e8f9f373264b8351ddae099a36a46ddd46fdec09e468d297ba4f64bb4896e7d6e599da70a424e8a28695ab3f3b4ac940afab534593a6b9d08ae462f001a kamailio-4.2-backslash.patch
dea7ef2ccf01357576045ba375d41301e2447b4454324007c7ca1862322835c57045852017192ca5434b32dd1b7a2e9669209b7111889dab335b74f042d0f11f 0001-musl-fixes.patch
3a9bb5d05b4628f6146b824b8916db259f1da51415398ba420900311d73986d21cab653079080c0e8c55ef512909f542279ca7da944b5ef14520331584ca958f kamailio-4.2-ipops-srv-query.patch
0b666bfa10fd0af97b62749f8691cb3f76d9b40d1abe0a33e810e367bd733d2e8189c89f7f23010ec591116aada6e1a8a403b17449fe775038917617f281ad4d kamailio.cfg
5ddaa059cdef10462c904f061f7bb085e62ad7501e2ed41f797d9e68822bce4e0e5ca09c1586c3901c920f8ce563c8c3ede860752c2b9bdb8f09908388ef337f kamailio.initd"

View File

@ -0,0 +1,658 @@
--- a/modules/ipops/ipops_mod.c
+++ b/modules/ipops/ipops_mod.c
@@ -21,6 +21,7 @@
*
* History:
* -------
+ * 2015-02-04: Added srv_query function (rboisvert)
* 2011-07-29: Added a function to detect RFC1918 private IPv4 addresses (ibc)
* 2011-04-27: Initial version (ibc)
*/
@@ -92,10 +93,13 @@
static int w_dns_int_match_ip(sip_msg_t*, char*, char*);
static int w_dns_query(struct sip_msg* msg, char* str1, char* str2);
+static int w_srv_query(struct sip_msg* msg, char* str1, char* str2);
static pv_export_t mod_pvs[] = {
{ {"dns", sizeof("dns")-1}, PVT_OTHER, pv_get_dns, 0,
pv_parse_dns_name, 0, 0, 0 },
+ { {"srvquery", sizeof("srvquery")-1}, PVT_OTHER, pv_get_srv, 0,
+ pv_parse_srv_name, 0, 0, 0 },
{ {"HN", sizeof("HN")-1}, PVT_OTHER, pv_get_hn, 0,
pv_parse_hn_name, 0, 0, 0 },
{ {0, 0}, 0, 0, 0, 0, 0, 0, 0 }
@@ -132,6 +136,8 @@
ANY_ROUTE },
{ "dns_query", (cmd_function)w_dns_query, 2, fixup_spve_spve, 0,
ANY_ROUTE },
+ { "srv_query", (cmd_function)w_srv_query, 2, fixup_spve_spve, 0,
+ ANY_ROUTE },
{ "bind_ipops", (cmd_function)bind_ipops, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0 }
};
@@ -772,4 +778,32 @@
}
return dns_update_pv(&hostname, &name);
+}
+
+/**
+ *
+ */
+static int w_srv_query(struct sip_msg* msg, char* str1, char* str2)
+{
+ str srvcname;
+ str name;
+
+ if(msg==NULL)
+ {
+ LM_ERR("received null msg\n");
+ return -1;
+ }
+
+ if(fixup_get_svalue(msg, (gparam_t*)str1, &srvcname)<0)
+ {
+ LM_ERR("cannot get the srvcname\n");
+ return -1;
+ }
+ if(fixup_get_svalue(msg, (gparam_t*)str2, &name)<0)
+ {
+ LM_ERR("cannot get the pvid name\n");
+ return -1;
+ }
+
+ return srv_update_pv(&srvcname, &name);
}
--- a/modules/ipops/ipops_pv.c
+++ b/modules/ipops/ipops_pv.c
@@ -32,6 +32,7 @@
#include <netinet/in.h>
#include "../../dprint.h"
+#include "../../rand/fastrand.h"
#include "../../hashes.h"
#include "../../resolve.h"
#include "../../pvar.h"
@@ -66,7 +67,6 @@
int nidx;
} dns_pv_t;
-
static sr_dns_item_t *_sr_dns_list = NULL;
/**
@@ -132,7 +132,6 @@
return it;
}
-
/**
*
*/
@@ -431,7 +430,6 @@
return 1;
}
-
struct _hn_pv_data {
str data;
str fullname;
@@ -594,4 +592,545 @@
return pv_get_null(msg, param, res);;
return pv_get_strval(msg, param, res, &_hn_data->hostname);
}
+}
+
+/**********
+* srvquery PV
+**********/
+
+static char *srvqrylst []
+ = {"count", "port", "priority", "target", "weight", NULL};
+
+#define PV_SRV_MAXSTR 64
+#define PV_SRV_MAXRECS 32
+
+typedef struct _sr_srv_record {
+ unsigned short priority;
+ unsigned short weight;
+ unsigned short port;
+ char target [PV_SRV_MAXSTR + 1];
+} sr_srv_record_t;
+
+typedef struct _sr_srv_item {
+ str pvid;
+ unsigned int hashid;
+ int count;
+ sr_srv_record_t rr [PV_SRV_MAXRECS];
+ struct _sr_srv_item *next;
+} sr_srv_item_t;
+
+typedef struct _srv_pv {
+ sr_srv_item_t *item;
+ int type;
+ int flags;
+ pv_spec_t *pidx;
+ int nidx;
+} srv_pv_t;
+
+static sr_srv_item_t *_sr_srv_list = NULL;
+
+/**********
+* Add srvquery Item
+*
+* INPUT:
+* Arg (1) = pvid string pointer
+* Arg (2) = find flag; <>0=search only
+* OUTPUT: srv record pointer; NULL=not found
+**********/
+
+sr_srv_item_t *sr_srv_add_item (str *pvid, int findflg)
+
+{
+sr_srv_item_t *pitem;
+unsigned int hashid;
+
+/**********
+* o get hash
+* o already exists?
+**********/
+
+hashid = get_hash1_raw (pvid->s, pvid->len);
+for (pitem = _sr_srv_list; pitem; pitem = pitem->next) {
+ if (pitem->hashid == hashid
+ && pitem->pvid.len == pvid->len
+ && !strncmp (pitem->pvid.s, pvid->s, pvid->len))
+ return pitem;
+}
+if (findflg)
+ return NULL;
+
+/**********
+* o alloc/init item structure
+* o link in new item
+**********/
+
+pitem = (sr_srv_item_t *) pkg_malloc (sizeof (sr_srv_item_t));
+if (!pitem) {
+ LM_ERR ("No more pkg memory!\n");
+ return NULL;
+}
+memset (pitem, 0, sizeof (sr_srv_item_t));
+pitem->pvid.s = (char *) pkg_malloc (pvid->len + 1);
+if (!pitem->pvid.s) {
+ LM_ERR ("No more pkg memory!\n");
+ pkg_free (pitem);
+ return NULL;
+}
+memcpy (pitem->pvid.s, pvid->s, pvid->len);
+pitem->pvid.len = pvid->len;
+pitem->hashid = hashid;
+pitem->next = _sr_srv_list;
+_sr_srv_list = pitem;
+return pitem;
+}
+
+/**********
+* Skip Over
+*
+* INPUT:
+* Arg (1) = string pointer
+* Arg (2) = starting position
+* Arg (3) = whitespace flag
+* OUTPUT: position past skipped
+**********/
+
+int skip_over (str *pstr, int pos, int bWS)
+
+{
+char *pchar;
+
+/**********
+* o string exists?
+* o skip over
+**********/
+
+if (pos >= pstr->len)
+ return pstr->len;
+for (pchar = &pstr->s [pos]; pos < pstr->len; pchar++, pos++) {
+ if (*pchar == ' ' || *pchar == '\t' || *pchar == '\n' || *pchar == '\r') {
+ if (bWS)
+ continue;
+ }
+ if ((*pchar>='A' && *pchar<='Z') || (*pchar>='a' && *pchar<='z')
+ || (*pchar>='0' && *pchar<='9')) {
+ if (!bWS)
+ continue;
+ }
+ break;
+}
+return pos;
+}
+
+/**********
+* Sort SRV Records by Weight (RFC 2782)
+*
+* INPUT:
+* Arg (1) = pointer to array of SRV records
+* Arg (2) = first record in range
+* Arg (3) = last record in range
+* OUTPUT: position past skipped
+**********/
+
+void sort_weights (struct srv_rdata **plist, int pos1, int pos2)
+
+{
+int idx1, idx2, idx3, lastfound;
+struct srv_rdata *wlist [PV_SRV_MAXRECS];
+unsigned int rand, sum, sums [PV_SRV_MAXRECS];
+
+/**********
+* place zero weights in the unordered list and then non-zero
+**********/
+
+idx2 = 0;
+for (idx1 = pos1; idx1 <= pos2; idx1++) {
+ if (!plist [idx1]->weight) {
+ wlist [idx2++] = plist [idx1];
+ }
+}
+for (idx1 = pos1; idx1 <= pos2; idx1++) {
+ if (plist [idx1]->weight) {
+ wlist [idx2++] = plist [idx1];
+ }
+}
+
+/**********
+* generate running sum list
+**********/
+
+sum = 0;
+for (idx1 = pos1; idx1 <= pos2; idx1++) {
+ sum += wlist [idx1]->weight;
+ sums [pos1 - idx1] = sum;
+}
+
+/**********
+* resort randomly
+**********/
+
+idx3 = pos1;
+lastfound = 0;
+for (idx1 = pos2 - pos1; idx1; --idx1) {
+ /**********
+ * o calculate a random number in range
+ * o find first unsorted
+ **********/
+
+ rand = fastrand_max (sum);
+ for (idx2 = 0; idx2 < pos2 - pos1; idx2++) {
+ if (!wlist [idx2]) {
+ continue;
+ }
+ if (sums [idx2] >= rand) {
+ plist [idx3++] = wlist [idx2];
+ wlist [idx2] = 0;
+ break;
+ }
+ lastfound = idx2;
+ }
+ if (idx2 == pos2 - pos1) {
+ plist [idx3++] = wlist [lastfound];
+ wlist [lastfound] = 0;
+ }
+}
+return;
+}
+
+/**********
+* Sort SRV Records by Priority/Weight
+*
+* INPUT:
+* Arg (1) = pointer to array of SRV records
+* Arg (2) = record count
+* OUTPUT: position past skipped
+**********/
+
+void sort_srv (struct srv_rdata **plist, int rcount)
+
+{
+int idx1, idx2;
+struct srv_rdata *pswap;
+
+/**********
+* sort by priority
+**********/
+
+for (idx1 = 1; idx1 < rcount; idx1++) {
+ pswap = plist [idx1];
+ for (idx2 = idx1;
+ idx2 && (plist [idx2 - 1]->priority > pswap->priority); --idx2) {
+ plist [idx2] = plist [idx2 - 1];
+ }
+ plist [idx2] = pswap;
+}
+
+/**********
+* check for multiple priority
+**********/
+
+idx2 = 0;
+pswap = plist [0];
+for (idx1 = 1; idx1 <= rcount; idx1++) {
+ if ((idx1 == rcount) || (pswap->priority != plist [idx1]->priority)) {
+ /**********
+ * o range has more than one element?
+ * o restart range
+ **********/
+
+ if (idx1 - idx2 - 1) {
+ sort_weights (plist, idx2, idx1 - 1);
+ }
+ idx2 = idx1;
+ pswap = plist [idx2];
+ }
+}
+return;
+}
+
+/**********
+* Parse srvquery Name
+*
+* INPUT:
+* Arg (1) = pv spec pointer
+* Arg (2) = input string pointer
+* OUTPUT: 0=success
+**********/
+
+int pv_parse_srv_name (pv_spec_t *sp, str *in)
+
+{
+char *pstr;
+int i, pos, sign;
+srv_pv_t *dpv;
+str pvi, pvk, pvn;
+
+/**********
+* o alloc/init pvid structure
+* o extract pvid name
+* o check separator
+**********/
+
+if (!sp || !in || in->len<=0)
+ return -1;
+dpv = (srv_pv_t *) pkg_malloc (sizeof (srv_pv_t));
+if (!dpv) {
+ LM_ERR ("No more pkg memory!\n");
+ return -1;
+}
+memset (dpv, 0, sizeof (srv_pv_t));
+pos = skip_over (in, 0, 1);
+if (pos == in->len)
+ goto error;
+pvn.s = &in->s [pos];
+pvn.len = pos;
+pos = skip_over (in, pos, 0);
+pvn.len = pos - pvn.len;
+if (!pvn.len)
+ goto error;
+pos = skip_over (in, pos, 1);
+if ((pos + 2) > in->len)
+ goto error;
+if (strncmp (&in->s [pos], "=>", 2))
+ goto error;
+
+/**********
+* o extract key name
+* o check key name
+* o count?
+**********/
+
+pos = skip_over (in, pos + 2, 1);
+pvk.s = &in->s [pos];
+pvk.len = pos;
+pos = skip_over (in, pos, 0);
+pvk.len = pos - pvk.len;
+if (!pvk.len)
+ goto error;
+for (i = 0; srvqrylst [i]; i++) {
+ if (strlen (srvqrylst [i]) != pvk.len)
+ continue;
+ if (!strncmp (pvk.s, srvqrylst [i], pvk.len)) {
+ dpv->type = i;
+ break;
+ }
+}
+if (!srvqrylst [i])
+ goto error;
+if (!i)
+ goto noindex;
+
+/**********
+* o check for array
+* o extract array index and check
+**********/
+
+pos = skip_over (in, pos, 1);
+if ((pos + 3) > in->len)
+ goto error;
+if (in->s [pos] != '[')
+ goto error;
+pos = skip_over (in, pos + 1, 1);
+if ((pos + 2) > in->len)
+ goto error;
+pvi.s = &in->s [pos];
+pvi.len = pos;
+if (in->s [pos] == PV_MARKER) {
+ /**********
+ * o search from the end back to array close
+ * o get PV value
+ **********/
+
+ for (i = in->len - 1; i != pos; --i) {
+ if (in->s [i] == ']')
+ break;
+ }
+ if (i == pos)
+ goto error;
+ pvi.len = i - pvi.len;
+ pos = i + 1;
+ dpv->pidx = pv_cache_get (&pvi);
+ if (!dpv->pidx)
+ goto error;
+ dpv->flags |= SR_DNS_PVIDX;
+} else {
+ /**********
+ * o get index value
+ * o check for reverse index
+ * o convert string to number
+ **********/
+
+ pos = skip_over (in, pos, 0);
+ pvi.len = pos - pvi.len;
+ sign = 1;
+ i = 0;
+ pstr = pvi.s;
+ if (*pstr == '-') {
+ sign = -1;
+ i++;
+ pstr++;
+ }
+ for (dpv->nidx = 0; i < pvi.len; i++) {
+ if (*pstr >= '0' && *pstr <= '9')
+ dpv->nidx = (dpv->nidx * 10) + *pstr++ - '0';
+ }
+ if (i != pvi.len)
+ goto error;
+ dpv->nidx *= sign;
+ pos = skip_over (in, pos, 1);
+ if (pos == in->len)
+ goto error;
+ if (in->s [pos++] != ']')
+ goto error;
+}
+
+/**********
+* o check for trailing whitespace
+* o add data to PV
+**********/
+
+noindex:
+if (skip_over (in, pos, 1) != in->len)
+ goto error;
+LM_DBG ("srvquery (%.*s => %.*s [%.*s])\n",
+ pvn.len, pvn.s, pvk.len, pvk.s, pvi.len, pvi.s);
+dpv->item = sr_srv_add_item (&pvn, 0);
+if (!dpv->item)
+ goto error;
+sp->pvp.pvn.u.dname = (void *)dpv;
+sp->pvp.pvn.type = PV_NAME_OTHER;
+return 0;
+
+error:
+LM_ERR ("error at PV srvquery: %.*s@%d\n", in->len, in->s, pos);
+pkg_free (dpv);
+return -1;
+}
+
+int srv_update_pv (str *srvcname, str *pvid)
+
+{
+int idx1, idx2, rcount;
+struct rdata *phead, *psrv;
+struct srv_rdata *plist [PV_SRV_MAXRECS];
+sr_srv_item_t *pitem;
+sr_srv_record_t *prec;
+
+/**********
+* o service name missing?
+* o find pvid
+**********/
+
+if (!srvcname->len) {
+ LM_DBG ("service name missing: %.*s\n", srvcname->len, srvcname->s);
+ return -2;
+}
+pitem = sr_srv_add_item (pvid, 1);
+if (!pitem) {
+ LM_DBG ("pvid not found: %.*s\n", pvid->len, pvid->s);
+ return -3;
+}
+
+/**********
+* o get records
+* o sort by priority/weight
+* o save to PV
+**********/
+
+LM_DBG ("attempting to query: %.*s\n", srvcname->len, srvcname->s);
+phead = get_record (srvcname->s, T_SRV, RES_ONLY_TYPE);
+rcount = 0;
+for (psrv = phead; psrv; psrv = psrv->next) {
+ if (rcount < PV_SRV_MAXRECS) {
+ plist [rcount++] = (struct srv_rdata *) psrv->rdata;
+ } else {
+ LM_WARN ("truncating srv_query list to %d records!", PV_SRV_MAXRECS);
+ break;
+ }
+}
+pitem->count = rcount;
+if (rcount)
+ sort_srv (plist, rcount);
+for (idx1 = 0; idx1 < rcount; idx1++) {
+ prec = &pitem->rr [idx1];
+ prec->priority = plist [idx1]->priority;
+ prec->weight = plist [idx1]->weight;
+ prec->port = plist [idx1]->port;
+ idx2 = plist [idx1]->name_len;
+ if (idx2 > PV_SRV_MAXSTR) {
+ LM_WARN ("truncating srv_query target (%.*s)!", idx2, plist [idx1]->name);
+ idx2 = PV_SRV_MAXSTR;
+ }
+ strncpy (prec->target, plist [idx1]->name, idx2);
+ prec->target [idx2] = '\0';
+}
+if (phead)
+ free_rdata_list (phead);
+LM_DBG ("srvquery PV updated for: %.*s (%d)\n",
+ srvcname->len, srvcname->s, rcount);
+return 1;
+}
+
+/**********
+* Get srvquery Values
+*
+* INPUT:
+* Arg (1) = SIP message pointer
+* Arg (2) = parameter pointer
+* Arg (3) = PV value pointer
+* OUTPUT: 0=success
+**********/
+
+int pv_get_srv (sip_msg_t *pmsg, pv_param_t *param, pv_value_t *res)
+
+{
+pv_value_t val;
+srv_pv_t *dpv;
+
+/**********
+* o sipmsg and param exist?
+* o PV name exists?
+* o count?
+**********/
+
+if(!pmsg || !param)
+ return -1;
+dpv = (srv_pv_t *) param->pvn.u.dname;
+if(!dpv || !dpv->item)
+ return -1;
+if (!dpv->type)
+ return pv_get_sintval (pmsg, param, res, dpv->item->count);
+
+/**********
+* o get index value
+* o reverse index?
+* o extract data
+**********/
+
+if (!dpv->pidx) {
+ val.ri = dpv->nidx;
+} else {
+ if (pv_get_spec_value (pmsg, dpv->pidx, &val) < 0
+ || !(val.flags & PV_VAL_INT)) {
+ LM_ERR ("failed to evaluate index variable!\n");
+ return pv_get_null (pmsg, param, res);
+ }
+}
+if (val.ri < 0) {
+ if ((dpv->item->count + val.ri) < 0)
+ return pv_get_null (pmsg, param, res);
+ val.ri = dpv->item->count + val.ri;
+}
+if (val.ri >= dpv->item->count)
+ return pv_get_null(pmsg, param, res);
+switch (dpv->type) {
+ case 1: /* port */
+ return pv_get_sintval (pmsg, param, res, dpv->item->rr [val.ri].port);
+ case 2: /* priority */
+ return pv_get_sintval (pmsg, param, res, dpv->item->rr [val.ri].priority);
+ case 3: /* target */
+ return pv_get_strzval (pmsg, param, res, dpv->item->rr [val.ri].target);
+ case 4: /* weight */
+ return pv_get_sintval (pmsg, param, res, dpv->item->rr [val.ri].weight);
+}
+return pv_get_null (pmsg, param, res);
}
--- a/modules/ipops/ipops_pv.h
+++ b/modules/ipops/ipops_pv.h
@@ -39,5 +39,9 @@
int pv_get_hn(struct sip_msg *msg, pv_param_t *param,
pv_value_t *res);
+int pv_parse_srv_name(pv_spec_t *, str *);
+int pv_get_srv(sip_msg_t *, pv_param_t *, pv_value_t *);
+int srv_update_pv(str *, str *);
+
#endif