소스 검색

erlang: New pseudo variable for Erlang reference

- introduce new pseudo variable for Erlang reference.
- document $ref variable
Seudin Kasumovic 10 년 전
부모
커밋
922f4b0b38
7개의 변경된 파일489개의 추가작업 그리고 30개의 파일을 삭제
  1. 36 19
      modules/erlang/README
  2. 20 1
      modules/erlang/doc/erlang_admin.xml
  3. 13 0
      modules/erlang/mod_erlang.c
  4. 338 0
      modules/erlang/pv_ref.c
  5. 37 0
      modules/erlang/pv_ref.h
  6. 44 10
      modules/erlang/pv_xbuff.c
  7. 1 0
      modules/erlang/pv_xbuff.h

+ 36 - 19
modules/erlang/README

@@ -41,7 +41,8 @@ Seudin Kasumovic
               4.4. $list(name)
               4.5. $tuple(name)
               4.6. $pid(name)
-              4.7. $xbuff(name)
+              4.7. $ref(name)
+              4.8. $xbuff(name)
 
         5. Functions
 
@@ -85,13 +86,14 @@ Seudin Kasumovic
    1.10. Example of using lists
    1.11. Example of using tuple
    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.2. Example, check is line registered
    2.3. Example get config variable
@@ -126,7 +128,8 @@ Chapter 1. Admin Guide
         4.4. $list(name)
         4.5. $tuple(name)
         4.6. $pid(name)
-        4.7. $xbuff(name)
+        4.7. $ref(name)
+        4.8. $xbuff(name)
 
    5. Functions
 
@@ -279,7 +282,8 @@ modparam("erlang", "trace_level", 5)
    4.4. $list(name)
    4.5. $tuple(name)
    4.6. $pid(name)
-   4.7. $xbuff(name)
+   4.7. $ref(name)
+   4.8. $xbuff(name)
 
 4.1. Overview
 
@@ -299,7 +303,7 @@ modparam("erlang", "trace_level", 5)
    position is.
      * type
        get variable type. Possible types are: atom, integer, list, string,
-       tuple and pid.
+       tuple, pid and ref.
      * length
        get length of list or tuple.
      * 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
    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
    for incoming erlang message.
 
-   Example 1.13. Example of using xbuff
+   Example 1.14. Example of using xbuff
 ...
 # 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
    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"])
 # 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.
 
-   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
 # {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
    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
 # Pid ! {example,message}
@@ -554,7 +571,7 @@ erl_send("$xbuff(pid)","$tuple(M)");
    Function to send message from event route (pseudo process). Function
    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[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
    <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[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
    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
 event_route[erlang:self] {

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

@@ -241,7 +241,8 @@ modparam("erlang", "trace_level", 5)
 					<varname>type</varname>
 					<para>
 						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>
 				</listitem>
 				<listitem>
@@ -408,6 +409,24 @@ if ($xbuff(msg[0]=>type) == "pid") {
 	$pid(pid) = $xbuff(msg[0]);
 	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>
 			</example>

+ 13 - 0
modules/erlang/mod_erlang.c

@@ -50,6 +50,7 @@
 #include "pv_atom.h"
 #include "pv_list.h"
 #include "pv_pid.h"
+#include "pv_ref.h"
 
 MODULE_VERSION
 
@@ -140,6 +141,16 @@ static pv_export_t pvs[] = {
 				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}
 };
 
@@ -393,6 +404,7 @@ static void mod_destroy(void)
 		free_list_fmt_buff();
 		free_xbuff_fmt_buff();
 		free_pid_fmt_buff();
+		free_ref_fmt_buff();
 }
 
 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_xbuff_fmt_buff();
 	free_pid_fmt_buff();
+	free_ref_fmt_buff();
 	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("list"),
 		STR_STATIC_INIT("pid"),
+		STR_STATIC_INIT("ref"),
 		STR_NULL
 };
 
@@ -106,7 +107,7 @@ sr_xavp_t *xbuff_new(str *name)
  */
 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;
 	char errbuff[128];
 	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;
 		} else if (STR_EQ(tname,xbuff_types[XBUFF_TYPE_PID])) {
 			t = XBUFF_TYPE_PID;
+		} else if (STR_EQ(tname,xbuff_types[XBUFF_TYPE_REF])) {
+			t = XBUFF_TYPE_REF;
 		} else {
 			LM_ERR("BUG: unknown xbuff type");
 			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));
 				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_STR:
 			default:
@@ -409,6 +422,9 @@ int pv_xbuff_get_type(struct sip_msg *msg, pv_param_t *param,
 	case 'p':
 		return pv_get_strval(msg, param, res, &xbuff_types[XBUFF_TYPE_PID]);
 		break;
+	case 'r':
+		return pv_get_strval(msg, param, res, &xbuff_types[XBUFF_TYPE_REF]);
+		break;
 	}
 
 	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)
 				return pv_get_null(msg, param, res);
 			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:
 			if(snprintf(_pv_xavp_buf, 128, "<<binary:%p>>", avp->val.v.data)<0)
 				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':
 			ei_x_encode_pid(xbuff,xavp->val.v.data->p);
 			break;
+		case 'r':
+			ei_x_encode_ref(xbuff,xavp->val.v.data->p);
+			break;
 		case 'n':
 			ei_x_encode_atom(xbuff,"undefined");
 			break;
@@ -931,7 +954,7 @@ int xavp_decode(ei_x_buff *xbuff, int *index, sr_xavp_t **xavp,int level)
 	sr_xavp_t *new;
 	char *pbuf=0;
 	erlang_pid *pid;
-	erlang_ref ref;
+	erlang_ref *ref;
 	erlang_fun fun;
 	double d;
 	char *p = NULL;
@@ -1120,24 +1143,35 @@ int xavp_decode(ei_x_buff *xbuff, int *index, sr_xavp_t **xavp,int level)
 		break;
 	case ERL_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;
 		}
-		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);
 		if (!*xavp) {
 			LM_ERR("failed to create new xavp!\n");
+			shm_free(data);
 			goto err;
 		}
+
 		break;
 	case ERL_FUN_EXT:
 		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_LIST,
 	XBUFF_TYPE_PID,
+	XBUFF_TYPE_REF,
 	XBUFF_TYPE_COUNT
 } xbuff_type_t;