Procházet zdrojové kódy

erlang: New pseudo variable for Erlang reference

- introduce new pseudo variable for Erlang reference.
- document $ref variable
Seudin Kasumovic před 10 roky
rodič
revize
922f4b0b38

+ 36 - 19
modules/erlang/README

@@ -41,7 +41,8 @@ Seudin Kasumovic
               4.4. $list(name)
               4.4. $list(name)
               4.5. $tuple(name)
               4.5. $tuple(name)
               4.6. $pid(name)
               4.6. $pid(name)
-              4.7. $xbuff(name)
+              4.7. $ref(name)
+              4.8. $xbuff(name)
 
 
         5. Functions
         5. Functions
 
 
@@ -85,13 +86,14 @@ Seudin Kasumovic
    1.10. Example of using lists
    1.10. Example of using lists
    1.11. Example of using tuple
    1.11. Example of using tuple
    1.12. Example of using pid
    1.12. Example of using pid
-   1.13. Example of using xbuff
-   1.14. Example of using erl_rpc
-   1.15. Example of using erl_reg_send
-   1.16. Example of using erl_send
-   1.17. Example of use erl_reply
-   1.18. Example of registered process
-   1.19. Example of using default event route
+   1.13. Example of using ref
+   1.14. Example of using xbuff
+   1.15. Example of using erl_rpc
+   1.16. Example of using erl_reg_send
+   1.17. Example of using erl_send
+   1.18. Example of use erl_reply
+   1.19. Example of registered process
+   1.20. Example of using default event route
    2.1. Example of RPC call from erlang shell with no response
    2.1. Example of RPC call from erlang shell with no response
    2.2. Example, check is line registered
    2.2. Example, check is line registered
    2.3. Example get config variable
    2.3. Example get config variable
@@ -126,7 +128,8 @@ Chapter 1. Admin Guide
         4.4. $list(name)
         4.4. $list(name)
         4.5. $tuple(name)
         4.5. $tuple(name)
         4.6. $pid(name)
         4.6. $pid(name)
-        4.7. $xbuff(name)
+        4.7. $ref(name)
+        4.8. $xbuff(name)
 
 
    5. Functions
    5. Functions
 
 
@@ -279,7 +282,8 @@ modparam("erlang", "trace_level", 5)
    4.4. $list(name)
    4.4. $list(name)
    4.5. $tuple(name)
    4.5. $tuple(name)
    4.6. $pid(name)
    4.6. $pid(name)
-   4.7. $xbuff(name)
+   4.7. $ref(name)
+   4.8. $xbuff(name)
 
 
 4.1. Overview
 4.1. Overview
 
 
@@ -299,7 +303,7 @@ modparam("erlang", "trace_level", 5)
    position is.
    position is.
      * type
      * type
        get variable type. Possible types are: atom, integer, list, string,
        get variable type. Possible types are: atom, integer, list, string,
-       tuple and pid.
+       tuple, pid and ref.
      * length
      * length
        get length of list or tuple.
        get length of list or tuple.
      * format
      * format
@@ -431,7 +435,20 @@ if ($xbuff(msg[0]=>type) == "pid") {
 }
 }
 ...
 ...
 
 
-4.7. $xbuff(name)
+4.7. $ref(name)
+
+   ref holds Erlang reference. Provides access to reference value and
+   could be used in send message.
+
+   Example 1.13. Example of using ref
+...
+if ($xbuff(msg[0]=>type) == "ref") {
+        $ref(ref) = $xbuff(msg[0]);
+        xlogl("L_INFO","Reference: $ref(ref=>format)\n");
+}
+...
+
+4.8. $xbuff(name)
 
 
    xbuff is created as generic pseudo variable to acts as other pseudo
    xbuff is created as generic pseudo variable to acts as other pseudo
    variables exported from module. It's useful when in advance we don't
    variables exported from module. It's useful when in advance we don't
@@ -439,7 +456,7 @@ if ($xbuff(msg[0]=>type) == "pid") {
    initialization. Module functions expect this PV as return value, and PV
    initialization. Module functions expect this PV as return value, and PV
    for incoming erlang message.
    for incoming erlang message.
 
 
-   Example 1.13. Example of using xbuff
+   Example 1.14. Example of using xbuff
 ...
 ...
 # tuple T from previous example
 # tuple T from previous example
 
 
@@ -479,7 +496,7 @@ DEBUG: <script>: 410:typeof(X): tuple, length(X): 2, format(X): {line, [{id, 23}
    function. If executing remote function caused error function still
    function. If executing remote function caused error function still
    returns true but error is encoded into repl parameter.
    returns true but error is encoded into repl parameter.
 
 
-   Example 1.14. Example of using erl_rpc
+   Example 1.15. Example of using erl_rpc
 ...
 ...
 # example of call erlang:list_to_tuple(["one","two"])
 # example of call erlang:list_to_tuple(["one","two"])
 # on remote node
 # on remote node
@@ -509,7 +526,7 @@ DEBUG: <script>: 386:type(repl): tuple, format(repl): {"one", "two"}
 
 
    The argument msg is containing the message to be sent.
    The argument msg is containing the message to be sent.
 
 
-   Example 1.15. Example of using erl_reg_send
+   Example 1.16. Example of using erl_reg_send
 ...
 ...
 # example of send message to registered process
 # example of send message to registered process
 # {notifier,'[email protected]'} ! {example,message}
 # {notifier,'[email protected]'} ! {example,message}
@@ -530,7 +547,7 @@ erl_reg_send("notifier","$tuple(M)");
    intended recipient process on remote node. The argument msg is
    intended recipient process on remote node. The argument msg is
    containing the message to be sent.
    containing the message to be sent.
 
 
-   Example 1.16. Example of using erl_send
+   Example 1.17. Example of using erl_send
 ...
 ...
 # example of send message to process
 # example of send message to process
 # Pid ! {example,message}
 # Pid ! {example,message}
@@ -554,7 +571,7 @@ erl_send("$xbuff(pid)","$tuple(M)");
    Function to send message from event route (pseudo process). Function
    Function to send message from event route (pseudo process). Function
    sends reply message msg to the sender process.
    sends reply message msg to the sender process.
 
 
-   Example 1.17. Example of use erl_reply
+   Example 1.18. Example of use erl_reply
 ...
 ...
 # event route acts as registered process
 # event route acts as registered process
 event_route[erlang:greetings] {
 event_route[erlang:greetings] {
@@ -600,7 +617,7 @@ INFO: <script>: 951:Received message: {"hello", "Kamailio"}
    event route in form of event_route[erlang:<my_process_name>]. Where
    event route in form of event_route[erlang:<my_process_name>]. Where
    <my_process_name> is the name of pseudo process.
    <my_process_name> is the name of pseudo process.
 
 
-   Example 1.18. Example of registered process
+   Example 1.19. Example of registered process
 ...
 ...
 # event route acts as registered process
 # event route acts as registered process
 event_route[erlang:handler] {
 event_route[erlang:handler] {
@@ -624,7 +641,7 @@ INFO: <script>: 951:Received message: {"hello", "Kamailio"}
    The reserved pseudo process name to receive messages sent to Kamailio C
    The reserved pseudo process name to receive messages sent to Kamailio C
    node. The message are sent to non registered process.
    node. The message are sent to non registered process.
 
 
-   Example 1.19. Example of using default event route
+   Example 1.20. Example of using default event route
 ...
 ...
 # default event route from erlang
 # default event route from erlang
 event_route[erlang:self] {
 event_route[erlang:self] {

+ 20 - 1
modules/erlang/doc/erlang_admin.xml

@@ -241,7 +241,8 @@ modparam("erlang", "trace_level", 5)
 					<varname>type</varname>
 					<varname>type</varname>
 					<para>
 					<para>
 						get variable type. Possible types are: <emphasis>atom, integer,
 						get variable type. Possible types are: <emphasis>atom, integer,
-						list, string</emphasis>, <emphasis>tuple</emphasis> and <emphasis>pid</emphasis>.
+						list, string</emphasis>, <emphasis>tuple</emphasis>,
+						<emphasis>pid</emphasis> and <emphasis>ref</emphasis>.
 					</para>
 					</para>
 				</listitem>
 				</listitem>
 				<listitem>
 				<listitem>
@@ -408,6 +409,24 @@ if ($xbuff(msg[0]=>type) == "pid") {
 	$pid(pid) = $xbuff(msg[0]);
 	$pid(pid) = $xbuff(msg[0]);
 	xlogl("L_INFO","Received PID: $pid(pid=>format)\n");
 	xlogl("L_INFO","Received PID: $pid(pid=>format)\n");
 }
 }
+...
+				</programlisting>
+			</example>
+		</section>
+		<section id="erlang.v.ref">
+			<title><varname>$ref(name)</varname></title>
+			<para>
+				<emphasis>ref</emphasis> holds Erlang reference. Provides
+				access to reference value and could be used in send message.
+			</para>
+			<example>
+				<title>Example of using ref</title>
+				<programlisting format="linespecific">
+...
+if ($xbuff(msg[0]=>type) == "ref") {
+	$ref(ref) = $xbuff(msg[0]);
+	xlogl("L_INFO","Reference: $ref(ref=>format)\n");
+}
 ...
 ...
 				</programlisting>
 				</programlisting>
 			</example>
 			</example>

+ 13 - 0
modules/erlang/mod_erlang.c

@@ -50,6 +50,7 @@
 #include "pv_atom.h"
 #include "pv_atom.h"
 #include "pv_list.h"
 #include "pv_list.h"
 #include "pv_pid.h"
 #include "pv_pid.h"
+#include "pv_ref.h"
 
 
 MODULE_VERSION
 MODULE_VERSION
 
 
@@ -140,6 +141,16 @@ static pv_export_t pvs[] = {
 				0,
 				0,
 				0
 				0
 		},
 		},
+		{
+				{ "ref", (sizeof("ref")-1) },
+				PVT_OTHER,
+				pv_ref_get,
+				pv_ref_set,
+				pv_ref_parse_name,
+				0,
+				0,
+				0
+		},
 		{{0,0}, 0, 0, 0, 0, 0, 0, 0}
 		{{0,0}, 0, 0, 0, 0, 0, 0, 0}
 };
 };
 
 
@@ -393,6 +404,7 @@ static void mod_destroy(void)
 		free_list_fmt_buff();
 		free_list_fmt_buff();
 		free_xbuff_fmt_buff();
 		free_xbuff_fmt_buff();
 		free_pid_fmt_buff();
 		free_pid_fmt_buff();
+		free_ref_fmt_buff();
 }
 }
 
 
 static int postprocess_request(struct sip_msg *msg, unsigned int flags, void *_param)
 static int postprocess_request(struct sip_msg *msg, unsigned int flags, void *_param)
@@ -402,6 +414,7 @@ static int postprocess_request(struct sip_msg *msg, unsigned int flags, void *_p
 	free_list_fmt_buff();
 	free_list_fmt_buff();
 	free_xbuff_fmt_buff();
 	free_xbuff_fmt_buff();
 	free_pid_fmt_buff();
 	free_pid_fmt_buff();
+	free_ref_fmt_buff();
 	return 0;
 	return 0;
 }
 }
 
 

+ 338 - 0
modules/erlang/pv_ref.c

@@ -0,0 +1,338 @@
+/**
+ * Copyright (C) 2015 Bicom Systems Ltd, (bicomsystems.com)
+ *
+ * Author: Seudin Kasumovic ([email protected])
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <stdlib.h>
+
+#include "../../str.h"
+#include "../../xavp.h"
+#include "../../pvapi.h"
+
+#include "pv_ref.h"
+#include "pv_xbuff.h"
+
+static str ref_list=str_init("[refs]");
+static char *ref_fmt_buff = NULL;
+static int counter;
+
+sr_xavp_t *pv_ref_get_ref(str *name)
+{
+	return xavp_get_child(&ref_list,name);
+}
+
+int pv_ref_parse_name(pv_spec_t *sp, str *in)
+{
+	char *p;
+	str idx;
+	str name;
+	str attr;
+
+	if (in->s == NULL || in->len <= 0)
+		return -1;
+
+	p = in->s;
+
+	name.s = p;
+
+	while (is_in_str(p, in)) {
+		if (*p == '[' || *p== '=')
+			break;
+		if (!is_pv_xbuff_valid_char(*p)) {
+			LM_ERR("invalid character in var name %.*s at %d\n",STR_FMT(in),p-in->s);
+			goto error;
+		}
+		p++;
+	}
+
+	/* from in->s to p */
+	name.len = p - in->s;
+
+	if (pv_parse_avp_name(sp,&name))
+		goto error;
+
+	if (is_in_str(p,in) && *p =='[')
+	{
+		idx.s=++p;
+
+		while (is_in_str(p,in)) {
+			if (*p == ']' || *p == '=')
+				break;
+			p++;
+		}
+
+		if (is_in_str(p,in) && *p==']') {
+			idx.len = p - idx.s;
+
+			LM_ERR("index isn't allowed for this variable\n");
+			goto error;
+		}
+		p++;
+	} else {
+		xbuff_set_attr_flag(sp->pvp.pvi.type,XBUFF_NO_IDX);
+	}
+
+	if (is_in_str(p,in) && *p =='=')
+	{
+		p++;
+
+		if (!is_in_str(p,in) || *p!='>') {
+			LM_ERR("invalid operator (expected =>) for accessing attribute in token %.*s at position %d\n",STR_FMT(in),p-in->s);
+			goto error;
+		}
+
+		attr.s = ++p;
+
+		while (is_in_str(p,in)) {
+			if (!is_pv_xbuff_valid_char(*p)) {
+				LM_ERR("invalid character in attribute name in token %.*s at %d\n",STR_FMT(in),p-in->s);
+				goto error;
+			}
+			p++;
+		}
+
+		attr.len = p - attr.s;
+
+		if (attr.len > 0 ) {
+
+			if (STR_EQ(attr,xbuff_attr_name(XBUFF_ATTR_TYPE))) {
+				xbuff_set_attr_flag(sp->pvp.pvi.type,XBUFF_ATTR_TYPE);
+			} else if (STR_EQ(attr,xbuff_attr_name(XBUFF_ATTR_FORMAT))) {
+				xbuff_set_attr_flag(sp->pvp.pvi.type,XBUFF_ATTR_FORMAT);
+			} else if (STR_EQ(attr,xbuff_attr_name(XBUFF_ATTR_LENGTH))) {
+				LM_ERR("attribute isn't supported for this variable\n");
+				goto error;
+			} else {
+				LM_ERR("unknown attribute %.*s\n",STR_FMT(&attr));
+				goto error;
+			}
+		}
+	}
+
+	if (p < in->s + in->len) {
+		LM_ERR("unexpected token in %.*s at %d\n",STR_FMT(in),p-in->s);
+		goto error;
+	}
+
+	return 0;
+
+error:
+
+	return -1;
+}
+
+sr_xavp_t *xavp_get_refs()
+{
+	sr_xavp_t *list;
+	list = xavp_get(&ref_list,NULL);
+
+	if(!list) counter = 0;
+
+	return list;
+}
+
+int pv_ref_set(struct sip_msg* msg,  pv_param_t* param, int op, pv_value_t* val)
+{
+	str name;
+	sr_xavp_t *ref_root;
+	sr_xavp_t *ref;
+	sr_xavp_t *new,*old=NULL;
+	sr_xavp_t *ref_xavp;
+	sr_xval_t ref_val;
+
+	if (param->pvn.type != PV_NAME_INTSTR || !(param->pvn.u.isname.type & AVP_NAME_STR)) {
+		LM_ERR("invalid variable name type\n");
+		return -1;
+	}
+
+	if(pv_xbuff_new_xavp(&ref_xavp,val,&counter,'r')) {
+		LM_ERR("failed to create new value\n");
+		return -1;
+	}
+
+	/* ref var name */
+	name = param->pvn.u.isname.name.s;
+
+	memset((void*)&ref_val,0,sizeof(sr_xval_t));
+
+	ref_root = xavp_get_refs();
+
+	if(!ref_root) {
+
+		ref_val.type = SR_XTYPE_XAVP;
+		ref_val.v.xavp = ref_xavp;
+		ref = xavp_add_xavp_value(&ref_list,&name,&ref_val,xavp_get_crt_list());
+
+		if (!ref)
+			goto err;
+
+		return 0;
+	}
+
+	ref = xavp_get_child(&ref_list, &name);
+
+	if (!ref) {
+
+		ref_val.type = SR_XTYPE_XAVP;
+		ref_val.v.xavp = ref_xavp;
+
+		new = xavp_add_value(&name,&ref_val,&ref_root->val.v.xavp);
+
+		if (!new)
+			goto err;
+
+		return 0;
+	}
+
+	old = ref->val.v.xavp;
+	new = ref_xavp;
+
+	if (old) {
+		xavp_destroy_list(&old);
+	}
+
+	ref->val.v.xavp = new;
+
+	return 0;
+
+err:
+	LM_ERR("failed to set ref value\n");
+	xavp_destroy_list(&ref_xavp);
+
+	return -1;
+}
+
+int pv_ref_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;
+
+	if (!avp) return pv_get_null(msg,param,res);
+
+	switch(avp->val.type) {
+	case SR_XTYPE_NULL:
+		return pv_get_null(msg, param, res);
+		break;
+	case SR_XTYPE_DATA:
+		if(snprintf(_pv_xavp_buf, 128, "<<ref:%p>>", avp->val.v.data)<0)
+			return pv_get_null(msg, param, res);
+		break;
+	case SR_XTYPE_XAVP:
+	case SR_XTYPE_STR:
+	case SR_XTYPE_INT:
+	case SR_XTYPE_TIME:
+	case SR_XTYPE_LONG:
+	case SR_XTYPE_LLONG:
+		LM_ERR("BUG: unexpected ref value\n");
+		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_ref_get(struct sip_msg* msg,  pv_param_t* param, pv_value_t* res)
+{
+	str name;
+	sr_xavp_t *refs_root;
+	sr_xavp_t *ref;
+	sr_xavp_t *xavp;
+	int attr;
+	int i;
+
+	ei_x_buff xbuff;
+
+	if(param==NULL)
+	{
+		LM_ERR("bad parameters\n");
+		return -1;
+	}
+
+	if (param->pvn.type != PV_NAME_INTSTR || !(param->pvn.u.isname.type & AVP_NAME_STR))
+				return -1;
+
+	/* ref name */
+	name = param->pvn.u.isname.name.s;
+	/* attributes */
+	attr = xbuff_get_attr_flags(param->pvi.type);
+
+	refs_root = xavp_get_refs();
+	if(!refs_root) {
+		return pv_get_null(msg,param,res);
+	}
+
+	ref = xavp_get(&name,refs_root->val.v.xavp);
+	if (!ref) {
+		return pv_get_null(msg,param,res);
+	}
+
+	xavp = ref->val.v.xavp;
+
+	switch (xbuff_is_attr_set(attr)) {
+	case XBUFF_ATTR_TYPE:
+		return pv_get_strval(msg,param,res,&xbuff_types[XBUFF_TYPE_REF]);
+		break;
+	case XBUFF_ATTR_LENGTH: /* always 1 */
+		return pv_get_uintval(msg,param,res,1);
+		break;
+	case XBUFF_ATTR_FORMAT:
+		/*
+		 * Prints a term, in clear text, to the PV value pointed to by res.
+		 * It tries to resemble the term printing in the erlang shell.
+		 */
+		ei_x_new_with_version(&xbuff);
+		if (xavp && xavp_encode(&xbuff,xavp,1)) {
+			ei_x_free(&xbuff);
+			return -1;
+		} else {
+			ei_x_encode_atom(&xbuff,"undefined");
+		}
+		i = 1;
+		if (ei_s_print_term(&ref_fmt_buff,xbuff.buff,&i)<0) {
+			LM_ERR("BUG: xbuff[index] doesn't contain a valid term!\n");
+			ei_x_free(&xbuff);
+			return -1;
+		}
+		i = pv_get_strzval(msg,param,res,ref_fmt_buff);
+		ei_x_free(&xbuff);
+		return i;
+	}
+
+	if (!xavp) {
+		return pv_get_null(msg,param,res);
+	}
+
+	return pv_ref_get_value(msg,param,res,xavp);
+}
+
+/*
+ * free format buffer for tuple
+ */
+void free_ref_fmt_buff() {
+	if (ref_fmt_buff) {
+		free(ref_fmt_buff);
+	}
+	ref_fmt_buff = 0;
+}

+ 37 - 0
modules/erlang/pv_ref.h

@@ -0,0 +1,37 @@
+/**
+ * Copyright (C) 2015 Bicom Systems Ltd, (bicomsystems.com)
+ *
+ * Author: Seudin Kasumovic ([email protected])
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef PV_REF_H_
+#define PV_REF_H_
+
+#include "../../pvar.h"
+
+int pv_ref_parse_name(pv_spec_t *sp, str *in);
+int pv_ref_set(struct sip_msg* msg,  pv_param_t* param, int op, pv_value_t* val);
+int pv_ref_get(struct sip_msg*, pv_param_t*, pv_value_t*);
+
+sr_xavp_t *pv_ref_get_ref(str *name);
+
+void free_ref_fmt_buff();
+
+#endif /* PV_PID_H_ */

+ 44 - 10
modules/erlang/pv_xbuff.c

@@ -42,6 +42,7 @@ str xbuff_types[] = {
 		STR_STATIC_INIT("tuple"),
 		STR_STATIC_INIT("tuple"),
 		STR_STATIC_INIT("list"),
 		STR_STATIC_INIT("list"),
 		STR_STATIC_INIT("pid"),
 		STR_STATIC_INIT("pid"),
+		STR_STATIC_INIT("ref"),
 		STR_NULL
 		STR_NULL
 };
 };
 
 
@@ -106,7 +107,7 @@ sr_xavp_t *xbuff_new(str *name)
  */
  */
 int compile_xbuff_re()
 int compile_xbuff_re()
 {
 {
-	char *pattern = "^<<\\(tuple\\|list\\|atom\\|pid\\):\\(0x[[:xdigit:]]\\+\\)>>$";
+	char *pattern = "^<<\\(tuple\\|list\\|atom\\|pid\\|ref\\):\\(0x[[:xdigit:]]\\+\\)>>$";
 	size_t bfsz = 128;
 	size_t bfsz = 128;
 	char errbuff[128];
 	char errbuff[128];
 	int e;
 	int e;
@@ -152,6 +153,8 @@ int xbuff_match_type_re(str *s, xbuff_type_t *type, sr_xavp_t **addr)
 			t = XBUFF_TYPE_TUPLE;
 			t = XBUFF_TYPE_TUPLE;
 		} else if (STR_EQ(tname,xbuff_types[XBUFF_TYPE_PID])) {
 		} else if (STR_EQ(tname,xbuff_types[XBUFF_TYPE_PID])) {
 			t = XBUFF_TYPE_PID;
 			t = XBUFF_TYPE_PID;
+		} else if (STR_EQ(tname,xbuff_types[XBUFF_TYPE_REF])) {
+			t = XBUFF_TYPE_REF;
 		} else {
 		} else {
 			LM_ERR("BUG: unknown xbuff type");
 			LM_ERR("BUG: unknown xbuff type");
 			return -1;
 			return -1;
@@ -359,6 +362,16 @@ int pv_xbuff_new_xavp(sr_xavp_t **new, pv_value_t *pval, int *counter, char pref
 				}
 				}
 				memcpy((void*)nval.v.data,(void*)xavp,sizeof(sr_data_t)+sizeof(erlang_pid));
 				memcpy((void*)nval.v.data,(void*)xavp,sizeof(sr_data_t)+sizeof(erlang_pid));
 				break;
 				break;
+			case XBUFF_TYPE_REF:
+				s[0] = 'r';
+				nval.type = SR_XTYPE_DATA;
+				nval.v.data = (sr_data_t*)shm_malloc(sizeof(sr_data_t)+sizeof(erlang_ref));
+				if (!nval.v.data) {
+					LM_ERR("not enough shared memory\n");
+					return -1;
+				}
+				memcpy((void*)nval.v.data,(void*)xavp,sizeof(sr_data_t)+sizeof(erlang_ref));
+				break;
 			case XBUFF_TYPE_INT:
 			case XBUFF_TYPE_INT:
 			case XBUFF_TYPE_STR:
 			case XBUFF_TYPE_STR:
 			default:
 			default:
@@ -409,6 +422,9 @@ int pv_xbuff_get_type(struct sip_msg *msg, pv_param_t *param,
 	case 'p':
 	case 'p':
 		return pv_get_strval(msg, param, res, &xbuff_types[XBUFF_TYPE_PID]);
 		return pv_get_strval(msg, param, res, &xbuff_types[XBUFF_TYPE_PID]);
 		break;
 		break;
+	case 'r':
+		return pv_get_strval(msg, param, res, &xbuff_types[XBUFF_TYPE_REF]);
+		break;
 	}
 	}
 
 
 	return pv_get_null(msg, param, res);
 	return pv_get_null(msg, param, res);
@@ -599,6 +615,10 @@ int pv_xbuff_get_value(struct sip_msg *msg, pv_param_t *param,
 			if(snprintf(_pv_xavp_buf, 128, "<<pid:%p>>", avp->val.v.data)<0)
 			if(snprintf(_pv_xavp_buf, 128, "<<pid:%p>>", avp->val.v.data)<0)
 				return pv_get_null(msg, param, res);
 				return pv_get_null(msg, param, res);
 			break;
 			break;
+		case 'r':
+			if(snprintf(_pv_xavp_buf, 128, "<<ref:%p>>", avp->val.v.data)<0)
+				return pv_get_null(msg, param, res);
+			break;
 		default:
 		default:
 			if(snprintf(_pv_xavp_buf, 128, "<<binary:%p>>", avp->val.v.data)<0)
 			if(snprintf(_pv_xavp_buf, 128, "<<binary:%p>>", avp->val.v.data)<0)
 				return pv_get_null(msg, param, res);
 				return pv_get_null(msg, param, res);
@@ -902,6 +922,9 @@ int xavp_encode(ei_x_buff *xbuff, sr_xavp_t *xavp,int level)
 		case 'p':
 		case 'p':
 			ei_x_encode_pid(xbuff,xavp->val.v.data->p);
 			ei_x_encode_pid(xbuff,xavp->val.v.data->p);
 			break;
 			break;
+		case 'r':
+			ei_x_encode_ref(xbuff,xavp->val.v.data->p);
+			break;
 		case 'n':
 		case 'n':
 			ei_x_encode_atom(xbuff,"undefined");
 			ei_x_encode_atom(xbuff,"undefined");
 			break;
 			break;
@@ -931,7 +954,7 @@ int xavp_decode(ei_x_buff *xbuff, int *index, sr_xavp_t **xavp,int level)
 	sr_xavp_t *new;
 	sr_xavp_t *new;
 	char *pbuf=0;
 	char *pbuf=0;
 	erlang_pid *pid;
 	erlang_pid *pid;
-	erlang_ref ref;
+	erlang_ref *ref;
 	erlang_fun fun;
 	erlang_fun fun;
 	double d;
 	double d;
 	char *p = NULL;
 	char *p = NULL;
@@ -1120,24 +1143,35 @@ int xavp_decode(ei_x_buff *xbuff, int *index, sr_xavp_t **xavp,int level)
 		break;
 		break;
 	case ERL_REFERENCE_EXT:
 	case ERL_REFERENCE_EXT:
 	case ERL_NEW_REFERENCE_EXT:
 	case ERL_NEW_REFERENCE_EXT:
-		name.len = snprintf(_s,sizeof(_s),"s%d",counter++);
-		i = *index;
+		name.len = snprintf(_s,sizeof(_s),"r%d",counter++);
+
+		data = (sr_data_t*)shm_malloc(sizeof(sr_data_t)+sizeof(erlang_ref));
+		if (!data) {
+			LM_ERR("not enough shared memory\n");
+			goto err;
+		}
 
 
-		ei_decode_ref(xbuff->buff,index,&ref);
+		memset((void*)data,0,sizeof(sr_data_t)+sizeof(erlang_ref));
 
 
-		if (ei_s_print_term(&p,xbuff->buff,&i)<0) {
-			LM_ERR("failed to decode reference\n");
+		data->p = ref = (void*)data+sizeof(sr_data_t);
+		data->pfree = xbuff_data_free;
+
+		if (ei_decode_ref(xbuff->buff,index,ref)<0) {
+			LM_ERR("failed to decode pid\n");
+			shm_free(data);
 			goto err;
 			goto err;
 		}
 		}
-		val.type = SR_XTYPE_STR;
-		val.v.s.s = p;
-		val.v.s.len = strlen(p);
+
+		val.type = SR_XTYPE_DATA;
+		val.v.data = data;
 
 
 		*xavp = xavp_new_value(&name,&val);
 		*xavp = xavp_new_value(&name,&val);
 		if (!*xavp) {
 		if (!*xavp) {
 			LM_ERR("failed to create new xavp!\n");
 			LM_ERR("failed to create new xavp!\n");
+			shm_free(data);
 			goto err;
 			goto err;
 		}
 		}
+
 		break;
 		break;
 	case ERL_FUN_EXT:
 	case ERL_FUN_EXT:
 		name.len = snprintf(_s,sizeof(_s),"s%d",counter++);
 		name.len = snprintf(_s,sizeof(_s),"s%d",counter++);

+ 1 - 0
modules/erlang/pv_xbuff.h

@@ -44,6 +44,7 @@ typedef enum {
 	XBUFF_TYPE_TUPLE,
 	XBUFF_TYPE_TUPLE,
 	XBUFF_TYPE_LIST,
 	XBUFF_TYPE_LIST,
 	XBUFF_TYPE_PID,
 	XBUFF_TYPE_PID,
+	XBUFF_TYPE_REF,
 	XBUFF_TYPE_COUNT
 	XBUFF_TYPE_COUNT
 } xbuff_type_t;
 } xbuff_type_t;