Merge remote branch 'origin/daniel/xavp'
authorAndrei Pelinescu-Onciul <andrei@iptel.org>
Mon, 15 Feb 2010 14:47:37 +0000 (15:47 +0100)
committerAndrei Pelinescu-Onciul <andrei@iptel.org>
Mon, 15 Feb 2010 14:47:37 +0000 (15:47 +0100)
* origin/daniel/xavp:
  pv: export new PV class $xavp(name)
  core: introducing xavp (eXtended AVP)
  tm: set/reset head of xavps on TM events
  pv: new pv class $xavp(...)
  core: destroy xavp list once sip msg processing is done

Conflicts:
modules/tm/h_table.c
modules/tm/t_reply.c
modules/tm/uac.c
modules_k/pv/pv.c

modules/tm/h_table.c
modules/tm/h_table.h
modules/tm/t_hooks.c
modules/tm/t_reply.c
modules/tm/uac.c
modules_k/pv/pv.c
modules_k/pv/pv_xavp.c [new file with mode: 0644]
modules_k/pv/pv_xavp.h [new file with mode: 0644]
receive.c
xavp.c [new file with mode: 0644]
xavp.h [new file with mode: 0644]

index c860005..1e61ea6 100644 (file)
@@ -212,6 +212,10 @@ void free_cell( struct cell* dead_cell )
                destroy_avp_list_unsafe( &dead_cell->uri_avps_from );
        if (dead_cell->uri_avps_to)
                destroy_avp_list_unsafe( &dead_cell->uri_avps_to );
+#ifdef WITH_XAVP
+       if (dead_cell->xavps_list)
+               xavp_destroy_list_unsafe( &dead_cell->xavps_list );
+#endif
 
        /* the cell's body */
        shm_free_unsafe( dead_cell );
@@ -278,6 +282,9 @@ struct cell*  build_cell( struct sip_msg* p_msg )
        int          sip_msg_len;
        avp_list_t* old;
        struct tm_callback *cbs, *cbs_tmp;
+#ifdef WITH_XAVP
+       sr_xavp_t** xold;
+#endif
 
        /* allocs a new cell */
        /* if syn_branch==0 add space for md5 (MD5_LEN -sizeof(struct cell.md5)) */
@@ -317,6 +324,12 @@ struct cell*  build_cell( struct sip_msg* p_msg )
        new_cell->user_avps_to = *old;
        *old = 0;
 
+#ifdef WITH_XAVP
+       xold = xavp_set_list(&new_cell->xavps_list );
+       new_cell->xavps_list = *xold;
+       *xold = 0;
+#endif
+
             /* We can just store pointer to domain avps in the transaction context,
              * because they are read-only
              */
@@ -380,9 +393,15 @@ error:
        destroy_avp_list(&new_cell->user_avps_to);
        destroy_avp_list(&new_cell->uri_avps_from);
        destroy_avp_list(&new_cell->uri_avps_to);
+#ifdef WITH_XAVP
+       xavp_destroy_list(&new_cell->xavps_list);
+#endif
        shm_free(new_cell);
        /* unlink transaction AVP list and link back the global AVP list (bogdan)*/
        reset_avps();
+#ifdef WITH_XAVP
+       xavp_reset_list();
+#endif
        return NULL;
 }
 
index 5588fff..1c1cd2d 100644 (file)
@@ -71,6 +71,9 @@
 #include "../../types.h"
 #include "../../md5utils.h"
 #include "../../usr_avp.h"
+#ifdef WITH_XAVP
+#include "../../xavp.h"
+#endif
 #include "../../timer.h"
 #include "../../flags.h"
 #include "../../atomic_ops.h"
@@ -362,7 +365,10 @@ typedef struct cell
        struct usr_avp *user_avps_to;
        struct usr_avp *domain_avps_from;
        struct usr_avp *domain_avps_to;
-       
+#ifdef WITH_XAVP
+       sr_xavp_t *xavps_list;
+#endif
+
        /* protection against concurrent reply processing */
        ser_lock_t   reply_mutex;
        
index 3d64bae..8dc77b1 100644 (file)
@@ -259,6 +259,9 @@ void run_trans_callbacks_internal(struct tmcb_head_list* cb_lst, int type,
 {
        struct tm_callback    *cbp;
        avp_list_t* backup_from, *backup_to, *backup_dom_from, *backup_dom_to, *backup_uri_from, *backup_uri_to;
+#ifdef WITH_XAVP
+       sr_xavp_t **backup_xavps;
+#endif
 
        backup_uri_from = set_avp_list(AVP_CLASS_URI | AVP_TRACK_FROM,
                        &trans->uri_avps_from );
@@ -272,6 +275,10 @@ void run_trans_callbacks_internal(struct tmcb_head_list* cb_lst, int type,
                        &trans->domain_avps_from);
        backup_dom_to = set_avp_list(AVP_CLASS_DOMAIN | AVP_TRACK_TO, 
                        &trans->domain_avps_to);
+#ifdef WITH_XAVP
+       backup_xavps = xavp_set_list(&trans->xavps_list);
+#endif
+
        cbp=(struct tm_callback*)cb_lst->first;
        while(cbp){
                membar_depends(); /* make sure the cache has the correct cbp 
@@ -290,6 +297,9 @@ void run_trans_callbacks_internal(struct tmcb_head_list* cb_lst, int type,
        set_avp_list(AVP_CLASS_USER | AVP_TRACK_FROM, backup_from );
        set_avp_list(AVP_CLASS_URI | AVP_TRACK_TO, backup_uri_to );
        set_avp_list(AVP_CLASS_URI | AVP_TRACK_FROM, backup_uri_from );
+#ifdef WITH_XAVP
+       xavp_set_list(backup_xavps);
+#endif
 }
 
 
index 0301ad8..2ef60df 100644 (file)
 #include "../../data_lump.h"
 #include "../../data_lump_rpl.h"
 #include "../../usr_avp.h"
+#ifdef WITH_XAVP
+#include "../../usr_avp.h"
+#endif
 #include "../../atomic_ops.h" /* membar_write() */
 #include "../../compiler_opt.h"
 #ifdef USE_DST_BLACKLIST
@@ -692,6 +695,9 @@ void faked_env( struct cell *t, struct sip_msg *msg)
        static avp_list_t* backup_user_from, *backup_user_to;
        static avp_list_t* backup_domain_from, *backup_domain_to;
        static avp_list_t* backup_uri_from, *backup_uri_to;
+#ifdef WITH_XAVP
+       static sr_xavp_t **backup_xavps;
+#endif
        static struct socket_info* backup_si;
 
        if (msg) {
@@ -722,6 +728,9 @@ void faked_env( struct cell *t, struct sip_msg *msg)
                backup_user_to = set_avp_list(AVP_TRACK_TO | AVP_CLASS_USER, &t->user_avps_to );
                backup_domain_from = set_avp_list(AVP_TRACK_FROM | AVP_CLASS_DOMAIN, &t->domain_avps_from );
                backup_domain_to = set_avp_list(AVP_TRACK_TO | AVP_CLASS_DOMAIN, &t->domain_avps_to );
+#ifdef WITH_XAVP
+               backup_xavps = xavp_set_list(&t->xavps_list);
+#endif
                /* set default send address to the saved value */
                backup_si=bind_address;
                bind_address=t->uac[0].request.dst.send_sock;
@@ -737,6 +746,9 @@ void faked_env( struct cell *t, struct sip_msg *msg)
                set_avp_list(AVP_TRACK_TO | AVP_CLASS_DOMAIN, backup_domain_to );
                set_avp_list(AVP_TRACK_FROM | AVP_CLASS_URI, backup_uri_from );
                set_avp_list(AVP_TRACK_TO | AVP_CLASS_URI, backup_uri_to );
+#ifdef WITH_XAVP
+               xavp_set_list(backup_xavps);
+#endif
                bind_address=backup_si;
        }
 }
@@ -1857,6 +1869,9 @@ int reply_received( struct sip_msg  *p_msg )
        avp_list_t* backup_user_from, *backup_user_to;
        avp_list_t* backup_domain_from, *backup_domain_to;
        avp_list_t* backup_uri_from, *backup_uri_to;
+#ifdef WITH_XAVP
+       sr_xavp_t **backup_xavps;
+#endif
        int replies_locked;
 #ifdef USE_DNS_FAILOVER
        int branch_ret;
@@ -2006,6 +2021,9 @@ int reply_received( struct sip_msg  *p_msg )
                backup_user_to = set_avp_list(AVP_TRACK_TO | AVP_CLASS_USER, &t->user_avps_to );
                backup_domain_from = set_avp_list(AVP_TRACK_FROM | AVP_CLASS_DOMAIN, &t->domain_avps_from );
                backup_domain_to = set_avp_list(AVP_TRACK_TO | AVP_CLASS_DOMAIN, &t->domain_avps_to );
+#ifdef WITH_XAVP
+               backup_xavps = xavp_set_list(&t->xavps_list);
+#endif
                setbflagsval(0, uac->branch_flags);
                /* Pre- and post-script callbacks have already
                 * been executed by the core. (Miklos)
@@ -2032,6 +2050,9 @@ int reply_received( struct sip_msg  *p_msg )
                set_avp_list( AVP_TRACK_TO | AVP_CLASS_USER, backup_user_to );
                set_avp_list( AVP_TRACK_FROM | AVP_CLASS_DOMAIN, backup_domain_from );
                set_avp_list( AVP_TRACK_TO | AVP_CLASS_DOMAIN, backup_domain_to );
+#ifdef WITH_XAVP
+               xavp_set_list(backup_xavps);
+#endif
        }
 #ifdef USE_DST_BLACKLIST
                /* add temporary to the blacklist the source of a 503 reply */
index 7565763..d311cc9 100644 (file)
@@ -409,6 +409,9 @@ static inline int t_uac_prepare(uac_req_t *uac_r,
        /* better reset avp list now - anyhow, it's useless from
         * this point (bogdan) */
        reset_avps();
+#ifdef WITH_XAVP
+       xavp_reset_list();
+#endif
 
        new_cell->method.s = buf;
        new_cell->method.len = uac_r->method->len;
index 11a6c9d..5475271 100644 (file)
@@ -36,7 +36,9 @@
 #include "pv_time.h"
 #include "pv_trans.h"
 #include "pv_select.h"
-
+#ifdef WITH_XAVP
+#include "pv_xavp.h"
+#endif
 
 MODULE_VERSION
 
@@ -70,6 +72,11 @@ static pv_export_t mod_pvs[] = {
                pv_parse_select_name, 0, 0, 0 },
        {{"snd", (sizeof("snd")-1)}, PVT_OTHER, pv_get_snd, 0,
                pv_parse_snd_name, 0, 0, 0},
+#ifdef WITH_XAVP
+       { {"xavp", sizeof("xavp")-1}, /* xavp */
+               PVT_OTHER, pv_get_xavp, pv_set_xavp,
+               pv_parse_xavp_name, 0, 0, 0 },
+#endif
 
        {{"avp", (sizeof("avp")-1)}, PVT_AVP, pv_get_avp, pv_set_avp,
                pv_parse_avp_name, pv_parse_index, 0, 0},
@@ -397,6 +404,10 @@ static cmd_export_t cmds[]={
                ANY_ROUTE },
        {"pv_unset",  (cmd_function)pv_unset,  1, fixup_pvar_null, 0, 
                ANY_ROUTE },
+#ifdef WITH_XAVP
+       {"pv_xavp_print",  (cmd_function)pv_xavp_print,  0, 0, 0, 
+               ANY_ROUTE },
+#endif
        {0,0,0,0,0,0}
 };
 
diff --git a/modules_k/pv/pv_xavp.c b/modules_k/pv/pv_xavp.c
new file mode 100644 (file)
index 0000000..34dd91b
--- /dev/null
@@ -0,0 +1,518 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2009 Daniel-Constantin Mierla (asipto.com) 
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifdef WITH_XAVP
+
+#include <stdio.h>
+
+#include "../../dprint.h"
+#include "../../xavp.h"
+
+#include "pv_xavp.h"
+
+int pv_xavp_get_value(struct sip_msg *msg, pv_param_t *param,
+               pv_value_t *res, sr_xavp_t *avp)
+{
+       static char _pv_xavp_buf[128];
+       str s;
+
+       switch(avp->val.type) {
+               case SR_XTYPE_NULL:
+                       return pv_get_null(msg, param, res);
+               break;
+               case SR_XTYPE_INT:
+                       return pv_get_sintval(msg, param, res, avp->val.v.i);
+               break;
+               case SR_XTYPE_STR:
+                       return pv_get_strval(msg, param, res, &avp->val.v.s);
+               break;
+               case SR_XTYPE_TIME:
+                       if(snprintf(_pv_xavp_buf, 128, "%lu", avp->val.v.t)<0)
+                               return pv_get_null(msg, param, res);
+               break;
+               case SR_XTYPE_LONG:
+                       if(snprintf(_pv_xavp_buf, 128, "%ld", avp->val.v.l)<0)
+                               return pv_get_null(msg, param, res);
+               break;
+               case SR_XTYPE_LLONG:
+                       if(snprintf(_pv_xavp_buf, 128, "%lld", avp->val.v.ll)<0)
+                               return pv_get_null(msg, param, res);
+               break;
+               case SR_XTYPE_XAVP:
+                       if(snprintf(_pv_xavp_buf, 128, "<<xavp:%p>>", avp->val.v.xavp)<0)
+                               return pv_get_null(msg, param, res);
+               break;
+               case SR_XTYPE_DATA:
+                       if(snprintf(_pv_xavp_buf, 128, "<<data:%p>>", avp->val.v.data)<0)
+                               return pv_get_null(msg, param, res);
+               break;
+               default:
+                       return pv_get_null(msg, param, res);
+       }
+       s.s = _pv_xavp_buf;
+       s.len = strlen(_pv_xavp_buf);
+       return pv_get_strval(msg, param, res, &s);
+}
+
+
+int pv_get_xavp(struct sip_msg *msg, pv_param_t *param,
+               pv_value_t *res)
+{
+       pv_xavp_name_t *xname=NULL;
+       sr_xavp_t *avp=NULL;
+       int idxf = 0;
+       int idx = 0;
+       int count;
+
+       if(param==NULL)
+       {
+               LM_ERR("bad parameters\n");
+               return -1;
+       }
+       xname = (pv_xavp_name_t*)param->pvn.u.dname;
+
+       if(xname->index.type==PVT_EXTRA)
+       {
+               /* get the index */
+               if(pv_get_spec_index(msg, &xname->index.pvp, &idx, &idxf)!=0)
+               {
+                       LM_ERR("invalid index\n");
+                       return -1;
+               }
+       }
+       /* fix the index */
+       if(idx<0)
+       {
+               count = xavp_count(&xname->name, NULL);
+               idx = count + idx + 1;
+       }
+       avp = xavp_get_by_index(&xname->name, idx, NULL);
+       if(avp==NULL)
+               return pv_get_null(msg, param, res);
+       if(xname->next==NULL)
+               return pv_xavp_get_value(msg, param, res, avp);
+
+       if(xname->next->index.type==PVT_EXTRA)
+       {
+               /* get the index */
+               if(pv_get_spec_index(msg, &xname->next->index.pvp, &idx, &idxf)!=0)
+               {
+                       LM_ERR("invalid index\n");
+                       return -1;
+               }
+       }
+       /* fix the index */
+       if(idx<0)
+       {
+               count = xavp_count(&xname->next->name, &avp->val.v.xavp);
+               idx = count + idx + 1;
+       }
+       avp = xavp_get_by_index(&xname->next->name, idx, &avp->val.v.xavp);
+       if(avp==NULL)
+               return pv_get_null(msg, param, res);
+       return pv_xavp_get_value(msg, param, res, avp);
+}
+
+/**
+ * $xavp(name1[idx1]=>name2[idx2])
+ */
+int pv_set_xavp(struct sip_msg* msg, pv_param_t *param,
+               int op, pv_value_t *val)
+{
+       pv_xavp_name_t *xname=NULL;
+       sr_xavp_t *avp=NULL;
+       sr_xavp_t *list=NULL;
+       sr_xval_t xval;
+       int idxf = 0;
+       int idx = 0;
+       int idxf1 = 0;
+       int idx1 = 0;
+       int count;
+
+       if(param==NULL)
+       {
+               LM_ERR("bad parameters\n");
+               return -1;
+       }
+       xname = (pv_xavp_name_t*)param->pvn.u.dname;
+
+       if(xname->index.type==PVT_EXTRA)
+       {
+               /* get the index */
+               if(pv_get_spec_index(msg, &xname->index.pvp, &idx, &idxf)!=0)
+               {
+                       LM_ERR("invalid index\n");
+                       return -1;
+               }
+       }
+
+       if((val==NULL) || (val->flags&PV_VAL_NULL))
+       {
+               if(xname->next==NULL)
+               {
+                       if(xname->index.type==PVT_EXTRA) {
+                               if(idxf==PV_IDX_ALL) {
+                                       xavp_rm_by_name(&xname->name, 1, NULL);
+                                       return 0;
+                               }
+                       }
+                       if(idx==0) {
+                               xavp_rm_by_name(&xname->name, 0, NULL);
+                               return 0;
+                       }
+                       /* fix the index */
+                       if(idx<0)
+                       {
+                               count = xavp_count(&xname->name, NULL);
+                               idx = count + idx + 1;
+                       }
+                       xavp_rm_by_index(&xname->name, idx, NULL);
+                       return 0;
+               }
+               
+               if(xname->next->index.type==PVT_EXTRA)
+               {
+                       /* get the index */
+                       if(pv_get_spec_index(msg,&xname->next->index.pvp,&idx1,&idxf1)!=0)
+                       {
+                               LM_ERR("invalid index!\n");
+                               return -1;
+                       }
+               }
+
+               if(idxf==PV_IDX_ALL) {
+                       /* iterate */
+                       avp = xavp_get(&xname->name, NULL);
+                       while(avp) {
+                               if(avp->val.type==SR_XTYPE_XAVP) {
+                                       if(xname->next->index.type==PVT_EXTRA) {
+                                               if(idxf1==PV_IDX_ALL) {
+                                                       xavp_rm_by_name(&xname->next->name, 1,
+                                                                       &avp->val.v.xavp);
+                                               } else {
+                                                       /* fix the index */
+                                                       idx = idx1;
+                                                       if(idx<0)
+                                                       {
+                                                               count = xavp_count(&xname->next->name,
+                                                                               &avp->val.v.xavp);
+                                                               idx = count + idx1 + 1;
+                                                       }
+                                                       xavp_rm_by_index(&xname->next->name, idx,
+                                                                       &avp->val.v.xavp);
+                                               }
+                                       } else {
+                                               xavp_rm_by_name(&xname->next->name, 0,
+                                                               &avp->val.v.xavp);
+                                       }
+                               }
+                               avp = xavp_get_next(avp);
+                       }
+                       return 0;
+               }
+
+               if(idx==0) {
+                       avp = xavp_get(&xname->name, NULL);
+               } else {
+                       /* fix the index */
+                       if(idx<0)
+                       {
+                               count = xavp_count(&xname->name, NULL);
+                               idx = count + idx + 1;
+                       }
+                       avp = xavp_get_by_index(&xname->name, idx, NULL);
+               }
+               if(avp) {
+                       if(avp->val.type==SR_XTYPE_XAVP) {
+                               if(xname->next->index.type==PVT_EXTRA) {
+                                       if(idxf1==PV_IDX_ALL) {
+                                               xavp_rm_by_name(&xname->next->name, 1,
+                                                               &avp->val.v.xavp);
+                                       } else {
+                                               /* fix the index */
+                                               idx = idx1;
+                                               if(idx<0)
+                                               {
+                                                       count = xavp_count(&xname->next->name,
+                                                                       &avp->val.v.xavp);
+                                                       idx = count + idx1 + 1;
+                                               }
+                                               xavp_rm_by_index(&xname->next->name, idx,
+                                                               &avp->val.v.xavp);
+                                       }
+                               } else {
+                                       xavp_rm_by_name(&xname->next->name, 0,
+                                                       &avp->val.v.xavp);
+                               }
+                       }
+               }
+               return 0;
+       } /* NULL assignment */
+
+       /* build xavp value */
+       memset(&xval, 0, sizeof(sr_xval_t));
+
+       if(val->flags&PV_TYPE_INT)
+       {
+               xval.type = SR_XTYPE_INT;
+               xval.v.i = val->ri;
+       } else {
+               xval.type = SR_XTYPE_STR;
+               xval.v.s = val->rs;
+       }
+
+       /* where to add */
+       if(xname->next==NULL)
+       {
+               /* xavp with single value */
+               if(xname->index.type==PVT_EXTRA) {
+                       if(idxf==PV_IDX_ALL) {
+                               /* ignore: should iterate and set same value to all xavps
+                                * with same name?!?! */
+                               return -1;
+                       }
+                       /* fix the index */
+                       if(idx<0)
+                       {
+                               count = xavp_count(&xname->name, NULL);
+                               idx = count + idx + 1;
+                       }
+                       /* set the value */
+                       if(xavp_set_value(&xname->name, idx, &xval, NULL)==NULL)
+                               return -1;
+                       return 0;
+               }
+               /* add new value */
+               if(xavp_add_value(&xname->name, &xval, NULL)==NULL)
+                       return -1;
+               return 0;
+       }
+               
+       /* xavp with xavp list value */
+       if(xname->next->index.type==PVT_EXTRA)
+       {
+               /* get the index */
+               if(pv_get_spec_index(msg,&xname->next->index.pvp,&idx1,&idxf1)!=0)
+               {
+                       LM_ERR("invalid index!\n");
+                       return -1;
+               }
+       }
+
+       if(xname->index.type==PVT_EXTRA)
+       {
+               /* set the value */
+               if(idxf==PV_IDX_ALL) {
+                       /* ignore: should iterate and set same value to all xavps
+                        * with same name?!?! */
+                       return 0;
+               }
+
+               if(idx==0) {
+                       avp = xavp_get(&xname->name, NULL);
+               } else {
+                       /* fix the index */
+                       if(idx<0)
+                       {
+                               count = xavp_count(&xname->name, NULL);
+                               idx = count + idx + 1;
+                       }
+                       avp = xavp_get_by_index(&xname->name, idx, NULL);
+               }
+               if(avp==NULL)
+                       return 0;
+
+               if(avp->val.type!=SR_XTYPE_XAVP)
+                       return -1;
+                       
+               if(xname->next->index.type==PVT_EXTRA) {
+                       if(idxf1==PV_IDX_ALL) {
+                               /* ignore: should iterate and set same value to all xavps
+                                * with same name?!?! */
+                               return 0;
+                       }
+                       /* fix the index */
+                       idx = idx1;
+                       if(idx<0)
+                       {
+                               count = xavp_count(&xname->next->name,
+                                               &avp->val.v.xavp);
+                               idx = count + idx1 + 1;
+                       }
+                       /* set value */
+                       xavp_set_value(&xname->next->name, idx, &xval, &avp->val.v.xavp);
+                       return 0;
+               }
+               /* add new value in sublist */
+               if(xavp_add_value(&xname->next->name, &xval, &avp->val.v.xavp)==NULL)
+                       return -1;
+               return 0;
+       }
+       /* add new xavp with xavp list */
+       if(xavp_add_value(&xname->next->name, &xval, &list)==NULL)
+               return -1;
+       
+       /* build xavp value */
+       memset(&xval, 0, sizeof(sr_xval_t));
+       xval.type = SR_XTYPE_XAVP;
+       xval.v.xavp = list;
+       xavp_add_value(&xname->name, &xval, NULL);
+
+       return 0;
+}
+
+char* pv_xavp_fill_ni(str *in, pv_xavp_name_t *xname)
+{
+       char *p;
+       str idx;
+       int n;
+
+       if(in->s==NULL || in->len<=0 || xname==NULL)
+               return NULL;
+       p = in->s;
+
+       /* eat ws */
+       while(p<in->s+in->len && (*p==' ' || *p=='\t' || *p=='\n' || *p=='\r'))
+               p++;
+       if(p>in->s+in->len || *p=='\0')
+               goto error;
+       xname->name.s = p;
+       while(p < in->s + in->len)
+       {
+               if(*p=='=' || *p==' ' || *p=='\t' || *p=='\n' || *p=='\r' || *p=='[')
+                       break;
+               p++;
+       }
+       xname->name.len = p - xname->name.s;
+       if(p>in->s+in->len || *p=='\0')
+               return p;
+       /* eat ws */
+       while(p<in->s+in->len && (*p==' ' || *p=='\t' || *p=='\n' || *p=='\r'))
+               p++;
+       if(p>in->s+in->len || *p=='\0')
+               return p;
+
+       if(*p!='[')
+               return p;
+       /* there is index */
+       p++;
+       idx.s = p;
+       n = 0;
+       while(p<in->s+in->len && *p!='\0')
+       {
+               if(*p==']')
+               {
+                       if(n==0)
+                               break;
+                       n--;
+               }
+               if(*p == '[')
+                       n++;
+               p++;
+       }
+       if(p>in->s+in->len || *p=='\0')
+               goto error;
+
+       if(p==idx.s)
+       {
+               LM_ERR("xavp [\"%.*s\"] does not get empty index param\n",
+                               in->len, in->s);
+               goto error;
+       }
+       idx.len = p - idx.s;
+       if(pv_parse_index(&xname->index, &idx)!=0)
+       {
+               LM_ERR("idx \"%.*s\" has an invalid index param [%.*s]\n",
+                                       in->len, in->s, idx.len, idx.s);
+               goto error;
+       }
+       xname->index.type = PVT_EXTRA;
+       p++;
+       return p;
+error:
+       return NULL;
+}
+
+void pv_xavp_name_destroy(pv_xavp_name_t *xname)
+{
+       return;
+}
+
+int pv_parse_xavp_name(pv_spec_p sp, str *in)
+{
+       pv_xavp_name_t *xname=NULL;
+       char *p;
+       str s;
+
+       if(in->s==NULL || in->len<=0)
+               return -1;
+
+       xname = (pv_xavp_name_t*)pkg_malloc(sizeof(pv_xavp_name_t));
+       if(xname==NULL)
+               return -1;
+
+       memset(xname, 0, sizeof(pv_xavp_name_t));
+
+       s = *in;
+
+       p = pv_xavp_fill_ni(&s, xname);
+       if(p==NULL)
+               goto error;
+
+       if(*p!='=')
+               goto done;
+       p++;
+       if(*p!='>')
+               goto error;
+       p++;
+
+       s.len = in->len - (int)(p - in->s);
+       s.s = p;
+       LM_DBG("xavp sublist [%.*s] - key [%.*s]\n", xname->name.len,
+                       xname->name.s, s.len, s.s);
+
+       xname->next = (pv_xavp_name_t*)pkg_malloc(sizeof(pv_xavp_name_t));
+       if(xname->next==NULL)
+               goto error;
+
+       memset(xname->next, 0, sizeof(pv_xavp_name_t));
+
+       p = pv_xavp_fill_ni(&s, xname->next);
+       if(p==NULL)
+               goto error;
+
+done:
+       sp->pvp.pvn.u.dname = (void*)xname;
+       sp->pvp.pvn.type = PV_NAME_PVAR;
+       return 0;
+
+error:
+       if(xname!=NULL) {
+               pv_xavp_name_destroy(xname);
+               pkg_free(xname);
+       }
+       return -1;
+}
+
+int pv_xavp_print(struct sip_msg* msg, char* s1, char *s2)
+{
+       xavp_print_list(NULL);
+       return 1;
+}
+
+#endif
diff --git a/modules_k/pv/pv_xavp.h b/modules_k/pv/pv_xavp.h
new file mode 100644 (file)
index 0000000..2e12870
--- /dev/null
@@ -0,0 +1,41 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2009 Daniel-Constantin Mierla (asipto.com) 
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef _PV_XAVP_H_
+#define _PV_XAVP_H_
+
+#ifdef WITH_XAVP
+
+#include "../../pvar.h"
+
+typedef struct _pv_xavp_name {
+       str name;
+       pv_spec_t index;
+       struct _pv_xavp_name *next;
+} pv_xavp_name_t;
+
+int pv_get_xavp(struct sip_msg *msg, pv_param_t *param,
+               pv_value_t *res);
+int pv_set_xavp(struct sip_msg* msg, pv_param_t *param,
+               int op, pv_value_t *val);
+int pv_parse_xavp_name(pv_spec_p sp, str *in);
+
+int pv_xavp_print(struct sip_msg* msg, char* s1, char *s2);
+
+#endif
+#endif
index 2a26b62..a045e3a 100644 (file)
--- a/receive.c
+++ b/receive.c
@@ -66,6 +66,9 @@
 #include "nonsip_hooks.h"
 #include "dset.h"
 #include "usr_avp.h"
+#ifdef WITH_XAVP
+#include "xavp.h"
+#endif
 #include "select_buf.h"
 
 #include "tcp_server.h" /* for tcpconn_add_alias */
@@ -279,6 +282,9 @@ end:
 #endif
        /* free possible loaded avps -bogdan */
        reset_avps();
+#ifdef WITH_XAVP
+       xavp_reset_list();
+#endif
        DBG("receive_msg: cleaning up\n");
        free_sip_msg(msg);
        pkg_free(msg);
@@ -291,6 +297,9 @@ error_rpl:
        /* execute post reply-script callbacks */
        exec_post_script_cb(msg, ONREPLY_CB_TYPE);
        reset_avps();
+#ifdef WITH_XAVP
+       xavp_reset_list();
+#endif
        goto error02;
 #endif /* NO_ONREPLY_ROUTE_ERROR */
 error_req:
@@ -300,6 +309,9 @@ error_req:
 error03:
        /* free possible loaded avps -bogdan */
        reset_avps();
+#ifdef WITH_XAVP
+       xavp_reset_list();
+#endif
 error02:
        free_sip_msg(msg);
        pkg_free(msg);
diff --git a/xavp.c b/xavp.c
new file mode 100644 (file)
index 0000000..6b19d40
--- /dev/null
+++ b/xavp.c
@@ -0,0 +1,508 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2009 Daniel-Constantin Mierla (asipto.com) 
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ * History:
+ * --------
+ *  2009-05-20  created by daniel
+ */
+
+
+#ifdef WITH_XAVP
+
+#include <stdio.h>
+#include <string.h>
+
+#include "mem/shm_mem.h"
+#include "dprint.h"
+#include "hashes.h"
+#include "xavp.h"
+
+/*! XAVP list head */
+static sr_xavp_t *_xavp_list_head = 0;
+/*! Pointer to XAVP current list */
+static sr_xavp_t **_xavp_list_crt = &_xavp_list_head;
+
+void xavp_shm_free(void *p)
+{
+       shm_free(p);
+}
+
+void xavp_shm_free_unsafe(void *p)
+{
+       shm_free_unsafe(p);
+}
+
+
+void xavp_free(sr_xavp_t *xa)
+{
+       if(xa->val.type == SR_XTYPE_DATA) {
+               if(xa->val.v.data!=NULL && xa->val.v.data->pfree!=NULL) {
+                       xa->val.v.data->pfree(xa->val.v.data->p, xavp_shm_free);
+                       shm_free(xa->val.v.data);
+               }
+       } else if(xa->val.type == SR_XTYPE_XAVP) {
+               xavp_destroy_list(&xa->val.v.xavp);
+       }
+       shm_free(xa);
+}
+
+void xavp_free_unsafe(sr_xavp_t *xa)
+{
+       if(xa->val.type == SR_XTYPE_DATA) {
+               if(xa->val.v.data!=NULL && xa->val.v.data->pfree!=NULL) {
+                       xa->val.v.data->pfree(xa->val.v.data->p, xavp_shm_free_unsafe);
+                       shm_free_unsafe(xa->val.v.data);
+               }
+       } else if(xa->val.type == SR_XTYPE_XAVP) {
+               xavp_destroy_list_unsafe(&xa->val.v.xavp);
+       }
+       shm_free_unsafe(xa);
+}
+
+sr_xavp_t *xavp_add_value(str *name, sr_xval_t *val, sr_xavp_t **list)
+{
+       sr_xavp_t *avp=0;
+       int size;
+
+       if(name==NULL || name->s==NULL || val==NULL)
+               return NULL;
+
+       size = sizeof(sr_xavp_t) + name->len + 1;
+       if(val->type == SR_XTYPE_STR)
+               size += val->v.s.len + 1;
+       avp = (sr_xavp_t*)shm_malloc(size);
+       if(avp==NULL)
+               return NULL;
+       memset(avp, 0, size);
+       avp->id = get_hash1_raw(name->s, name->len);
+       avp->name.s = (char*)avp + sizeof(sr_xavp_t);
+       memcpy(avp->name.s, name->s, name->len);
+       avp->name.s[name->len] = '\0';
+       avp->name.len = name->len;
+       memcpy(&avp->val, val, sizeof(sr_xval_t));
+       if(val->type == SR_XTYPE_STR)
+       {
+               avp->val.v.s.s = avp->name.s + avp->name.len + 1;
+               memcpy(avp->val.v.s.s, val->v.s.s, val->v.s.len);
+               avp->val.v.s.s[val->v.s.len] = '\0';
+               avp->val.v.s.len = val->v.s.len;
+       }
+       if(list) {
+               avp->next = *list;
+               *list = avp;
+       } else {
+               avp->next = *_xavp_list_crt;
+               *_xavp_list_crt = avp;
+       }
+
+       return avp;
+}
+
+sr_xavp_t *xavp_set_value(str *name, int idx, sr_xval_t *val, sr_xavp_t **list)
+{
+       sr_xavp_t *avp=0;
+       sr_xavp_t *prv=0;
+       sr_xavp_t *tmp=0;
+       unsigned int id;
+       int size;
+       int n=0;
+
+       if(name==NULL || name->s==NULL || val==NULL)
+               return NULL;
+
+       id = get_hash1_raw(name->s, name->len);
+       if(list)
+               avp = *list;
+       else
+               avp=*_xavp_list_crt;
+       while(avp)
+       {
+               if(avp->id==id && avp->name.len==name->len
+                               && strncmp(avp->name.s, name->s, name->len)==0)
+               {
+                       if(idx==n)
+                               return avp;
+                       n++;
+               }
+               prv = avp;
+               avp=avp->next;
+       }
+       if(avp==NULL)
+               return NULL;
+       tmp = avp;
+
+       size = sizeof(sr_xavp_t) + name->len + 1;
+       if(val->type == SR_XTYPE_STR)
+               size += val->v.s.len + 1;
+       avp = (sr_xavp_t*)shm_malloc(size);
+       if(avp==NULL)
+               return NULL;
+       memset(avp, 0, size);
+       avp->id = get_hash1_raw(name->s, name->len);
+       avp->name.s = (char*)avp + sizeof(sr_xavp_t);
+       memcpy(avp->name.s, name->s, name->len);
+       avp->name.s[name->len] = '\0';
+       avp->name.len = name->len;
+       memcpy(&avp->val, val, sizeof(sr_xval_t));
+       if(val->type == SR_XTYPE_STR)
+       {
+               avp->val.v.s.s = avp->name.s + avp->name.len + 1;
+               memcpy(avp->val.v.s.s, val->v.s.s, val->v.s.len);
+               avp->val.v.s.s[val->v.s.len] = '\0';
+               avp->val.v.s.len = val->v.s.len;
+       }
+       if(prv)
+       {
+                       avp->next = prv->next;
+                       prv->next = avp;
+       } else {
+               if(list) {
+                       avp->next = *list;
+                       *list = avp;
+               } else {
+                       avp->next = *_xavp_list_crt;
+                       *_xavp_list_crt = avp;
+               }
+       }
+       xavp_free(tmp);
+
+       return avp;
+}
+
+sr_xavp_t *xavp_get(str *name, sr_xavp_t *start)
+{
+       sr_xavp_t *avp=0;
+       unsigned int id;
+
+       if(name==NULL || name->s==NULL)
+               return NULL;
+       id = get_hash1_raw(name->s, name->len);
+       
+       if(start)
+               avp = start;
+       else
+               avp=*_xavp_list_crt;
+       while(avp)
+       {
+               if(avp->id==id && avp->name.len==name->len
+                               && strncmp(avp->name.s, name->s, name->len)==0)
+                       return avp;
+               avp=avp->next;
+       }
+
+       return NULL;
+}
+
+sr_xavp_t *xavp_get_by_index(str *name, int idx, sr_xavp_t **start)
+{
+       sr_xavp_t *avp=0;
+       unsigned int id;
+       int n = 0;
+
+       if(name==NULL || name->s==NULL)
+               return NULL;
+       id = get_hash1_raw(name->s, name->len);
+       
+       if(start)
+               avp = *start;
+       else
+               avp=*_xavp_list_crt;
+       while(avp)
+       {
+               if(avp->id==id && avp->name.len==name->len
+                               && strncmp(avp->name.s, name->s, name->len)==0)
+               {
+                       if(idx==n)
+                               return avp;
+                       n++;
+               }
+               avp=avp->next;
+       }
+
+       return NULL;
+}
+
+
+sr_xavp_t *xavp_get_next(sr_xavp_t *start)
+{
+       sr_xavp_t *avp=0;
+
+       if(start==NULL)
+               return NULL;
+       
+       avp = start->next;
+       while(avp)
+       {
+               if(avp->id==start->id && avp->name.len==start->name.len
+                               && strncmp(avp->name.s, start->name.s, start->name.len)==0)
+                       return avp;
+               avp=avp->next;
+       }
+
+       return NULL;
+}
+
+
+int xavp_rm(sr_xavp_t *xa, sr_xavp_t **head)
+{
+       sr_xavp_t *avp=0;
+       sr_xavp_t *prv=0;
+
+       if(head!=NULL)
+               avp = *head;
+       else
+               avp=*_xavp_list_crt;
+
+       while(avp)
+       {
+               if(avp==xa)
+               {
+                       if(prv)
+                               prv->next=avp->next;
+                       else
+                               if(head!=NULL)
+                                       *head = avp->next;
+                               else
+                                       *_xavp_list_crt = avp->next;
+                       xavp_free(avp);
+                       return 1;
+               }
+               prv=avp; avp=avp->next;
+       }
+       return 0;
+}
+
+
+int xavp_rm_by_name(str *name, int all, sr_xavp_t **head)
+{
+       sr_xavp_t *avp=0;
+       sr_xavp_t *foo=0;
+       sr_xavp_t *prv=0;
+       unsigned int id = 0;
+       int n=0;
+
+       if(name==NULL || name->s==NULL)
+               return 0;
+
+       id = get_hash1_raw(name->s, name->len);
+       if(head!=NULL)
+               avp = *head;
+       else
+               avp=*_xavp_list_crt;
+       while(avp)
+       {
+               foo = avp;
+               avp=avp->next;
+               if(foo->id==id && foo->name.len==name->len
+                               && strncmp(foo->name.s, name->s, name->len)==0)
+               {
+                       if(prv!=NULL)
+                               prv->next=foo->next;
+                       else
+                               if(head!=NULL)
+                                       *head = foo->next;
+                               else
+                                       *_xavp_list_crt = foo->next;
+                       xavp_free(foo);
+                       n++;
+                       if(all==0)
+                               return n;
+               } else {
+                       prv = foo;
+               }
+       }
+       return n;
+}
+
+int xavp_rm_by_index(str *name, int idx, sr_xavp_t **head)
+{
+       sr_xavp_t *avp=0;
+       sr_xavp_t *foo=0;
+       sr_xavp_t *prv=0;
+       unsigned int id = 0;
+       int n=0;
+
+       if(name==NULL || name->s==NULL)
+               return 0;
+       if(idx<0)
+               return 0;
+
+       id = get_hash1_raw(name->s, name->len);
+       if(head!=NULL)
+               avp = *head;
+       else
+               avp=*_xavp_list_crt;
+       while(avp)
+       {
+               foo = avp;
+               avp=avp->next;
+               if(foo->id==id && foo->name.len==name->len
+                               && strncmp(foo->name.s, name->s, name->len)==0)
+               {
+                       if(idx==n)
+                       {
+                               if(prv!=NULL)
+                                       prv->next=foo->next;
+                               else
+                                       if(head!=NULL)
+                                               *head = foo->next;
+                                       else
+                                               *_xavp_list_crt = foo->next;
+                               xavp_free(foo);
+                               return 1;
+                       }
+                       n++;
+               }
+               prv = foo;
+       }
+       return 0;
+}
+
+
+int xavp_count(str *name, sr_xavp_t **start)
+{
+       sr_xavp_t *avp=0;
+       unsigned int id;
+       int n = 0;
+
+       if(name==NULL || name->s==NULL)
+               return -1;
+       id = get_hash1_raw(name->s, name->len);
+       
+       if(start)
+               avp = *start;
+       else
+               avp=*_xavp_list_crt;
+       while(avp)
+       {
+               if(avp->id==id && avp->name.len==name->len
+                               && strncmp(avp->name.s, name->s, name->len)==0)
+               {
+                       n++;
+               }
+               avp=avp->next;
+       }
+
+       return n;
+}
+
+void xavp_destroy_list_unsafe(sr_xavp_t **head)
+{
+       sr_xavp_t *avp, *foo;
+
+       avp = *head;
+       while(avp)
+       {
+               foo = avp;
+               avp = avp->next;
+               xavp_free_unsafe(foo);
+       }
+       *head = 0;
+}
+
+
+void xavp_destroy_list(sr_xavp_t **head)
+{
+       sr_xavp_t *avp, *foo;
+
+       LM_DBG("destroying xavp list %p\n", *head);
+       avp = *head;
+       while(avp)
+       {
+               foo = avp;
+               avp = avp->next;
+               xavp_free(foo);
+       }
+       *head = 0;
+}
+
+
+void xavp_reset_list(void)
+{
+       assert(_xavp_list_crt!=0 );
+       
+       if (_xavp_list_crt!=&_xavp_list_head)
+               _xavp_list_crt=&_xavp_list_head;
+       xavp_destroy_list(_xavp_list_crt);
+}
+
+
+sr_xavp_t **xavp_set_list(sr_xavp_t **head)
+{
+       sr_xavp_t **avp;
+       
+       assert(_xavp_list_crt!=0);
+
+       avp = _xavp_list_crt;
+       _xavp_list_crt = head;
+       return avp;
+}
+
+sr_xavp_t **xavp_get_crt_list(void)
+{
+       assert(_xavp_list_crt!=0);
+       return _xavp_list_crt;
+}
+
+void xavp_print_list(sr_xavp_t **head)
+{
+       sr_xavp_t *avp=0;
+
+       if(head!=NULL)
+               avp = *head;
+       else
+               avp=*_xavp_list_crt;
+       LM_DBG("+++++ XAVP list: %p\n", avp);
+       while(avp)
+       {
+               LM_DBG("     *** XAVP name: %s\n", avp->name.s);
+               LM_DBG("     XAVP id: %u\n", avp->id);
+               LM_DBG("     XAVP value type: %d\n", avp->val.type);
+               switch(avp->val.type) {
+                       case SR_XTYPE_NULL:
+                               LM_DBG("     XAVP value: <null>\n");
+                       break;
+                       case SR_XTYPE_INT:
+                               LM_DBG("     XAVP value: %d\n", avp->val.v.i);
+                       break;
+                       case SR_XTYPE_STR:
+                               LM_DBG("     XAVP value: %s\n", avp->val.v.s.s);
+                       break;
+                       case SR_XTYPE_TIME:
+                               LM_DBG("     XAVP value: %lu\n", avp->val.v.t);
+                       break;
+                       case SR_XTYPE_LONG:
+                               LM_DBG("     XAVP value: %ld\n", avp->val.v.l);
+                       break;
+                       case SR_XTYPE_LLONG:
+                               LM_DBG("     XAVP value: %lld\n", avp->val.v.ll);
+                       break;
+                       case SR_XTYPE_XAVP:
+                               LM_DBG("     XAVP value: <xavp:%p>\n", avp->val.v.xavp);
+                               xavp_print_list(&avp->val.v.xavp);
+                       break;
+                       case SR_XTYPE_DATA:
+                               LM_DBG("     XAVP value: <data:%p>\n", avp->val.v.data);
+                       break;
+               }
+               avp = avp->next;
+       }
+       LM_DBG("----- XAVP list\n");
+}
+
+#endif
diff --git a/xavp.h b/xavp.h
new file mode 100644 (file)
index 0000000..9a31a0e
--- /dev/null
+++ b/xavp.h
@@ -0,0 +1,95 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2009 Daniel-Constantin Mierla (asipto.com) 
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ * History:
+ * --------
+ *  2009-05-20  created by daniel
+ */
+
+
+#ifndef _SR_XAVP_H_
+#define _SR_XAVP_H_
+
+#ifdef WITH_XAVP
+
+#include <time.h>
+#include "str.h"
+
+struct _sr_xavp;
+
+typedef enum {
+       SR_XTYPE_NULL=0,
+       SR_XTYPE_INT,
+       SR_XTYPE_STR,
+       SR_XTYPE_TIME,
+       SR_XTYPE_LONG,
+       SR_XTYPE_LLONG,
+       SR_XTYPE_XAVP,
+       SR_XTYPE_DATA
+} sr_xtype_t;
+
+typedef void (*sr_xavp_sfree_f)(void *d);
+typedef void (*sr_data_free_f)(void *d, sr_xavp_sfree_f sfree);
+
+typedef struct _sr_data {
+       void *p;
+       sr_data_free_f pfree;
+} sr_data_t;
+
+typedef struct _sr_xval {
+       sr_xtype_t type;
+       union {
+               int i;
+               str s;                 /* replicated */
+               time_t t;
+               long l;
+               long long ll;
+               struct _sr_xavp *xavp; /* must be given in shm */
+               sr_data_t *data;       /* must be given in shm */
+       } v;
+} sr_xval_t;
+
+typedef struct _sr_xavp {
+       unsigned int id;
+       str name;
+       sr_xval_t val;
+       struct _sr_xavp *next;
+} sr_xavp_t;
+
+int xavp_init_head(void);
+void avpx_free(sr_xavp_t *xa);
+
+sr_xavp_t *xavp_add_value(str *name, sr_xval_t *val, sr_xavp_t **list);
+sr_xavp_t *xavp_set_value(str *name, int idx, sr_xval_t *val, sr_xavp_t **list);
+sr_xavp_t *xavp_get(str *name, sr_xavp_t *start);
+sr_xavp_t *xavp_get_by_index(str *name, int idx, sr_xavp_t **start);
+sr_xavp_t *xavp_get_next(sr_xavp_t *start);
+int xavp_rm_by_name(str *name, int all, sr_xavp_t **head);
+int xavp_rm_by_index(str *name, int idx, sr_xavp_t **head);
+int xavp_rm(sr_xavp_t *xa, sr_xavp_t **head);
+int xavp_count(str *name, sr_xavp_t **start);
+void xavp_destroy_list_unsafe(sr_xavp_t **head);
+void xavp_destroy_list(sr_xavp_t **head);
+void xavp_reset_list(void);
+sr_xavp_t **xavp_set_list(sr_xavp_t **head);
+sr_xavp_t **xavp_get_crt_list(void);
+
+void xavp_print_list(sr_xavp_t **head);
+#endif
+
+#endif