瀏覽代碼

Merge pull request #163 from kamailio/seudin_erlang_fixes

erlang: fixes and new PV
Seudin Kasumovic 10 年之前
父節點
當前提交
6d32e8df95

+ 37 - 20
modules/erlang/README

@@ -40,7 +40,8 @@ Seudin Kasumovic
               4.3. $atom(name)
               4.4. $list(name)
               4.5. $tuple(name)
-              4.6. $xbuff(name)
+              4.6. $pid(name)
+              4.7. $xbuff(name)
 
         5. Functions
 
@@ -81,12 +82,13 @@ Seudin Kasumovic
    1.9. Example set and print to log atom
    1.10. Example of using lists
    1.11. Example of using tuple
-   1.12. Example of using xbuff
-   1.13. Example of using erl_rpc
-   1.14. Example of using erl_reg_send
-   1.15. Example of registered process
-   1.16. Example of registered process
-   1.17. Example of using default event route
+   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 use erl_reply
+   1.17. Example of registered process
+   1.18. 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
@@ -120,7 +122,8 @@ Chapter 1. Admin Guide
         4.3. $atom(name)
         4.4. $list(name)
         4.5. $tuple(name)
-        4.6. $xbuff(name)
+        4.6. $pid(name)
+        4.7. $xbuff(name)
 
    5. Functions
 
@@ -271,7 +274,8 @@ modparam("erlang", "trace_level", 5)
    4.3. $atom(name)
    4.4. $list(name)
    4.5. $tuple(name)
-   4.6. $xbuff(name)
+   4.6. $pid(name)
+   4.7. $xbuff(name)
 
 4.1. Overview
 
@@ -290,8 +294,8 @@ modparam("erlang", "trace_level", 5)
    by self determine variable type, but we need to know what type on some
    position is.
      * type
-       get variable type. Possible types are: atom, integer, list, string
-       and tuple.
+       get variable type. Possible types are: atom, integer, list, string,
+       tuple and pid.
      * length
        get length of list or tuple.
      * format
@@ -410,7 +414,20 @@ xlogl("L_DEBUG","length(T): $tuple(T=>length), format(T): $tuple(T=>format)\n");
 DEBUG: <script>: 153:length(T): 2, format(T): {line, [{id, 23}, {owner, "Bob"}]}
 ...
 
-4.6. $xbuff(name)
+4.6. $pid(name)
+
+   pid holds Eralng process identifier. Provides access to pid value and
+   could be used in send message.
+
+   Example 1.12. Example of using pid
+...
+if ($xbuff(msg[0]=>type) == "pid") {
+        $pid(pid) = $xbuff(msg[0]);
+        xlogl("L_INFO","Received PID: $pid(pid=>format)\n");
+}
+...
+
+4.7. $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
@@ -418,7 +435,7 @@ DEBUG: <script>: 153:length(T): 2, format(T): {line, [{id, 23}, {owner, "Bob"}]}
    initialization. Module functions expect this PV as return value, and PV
    for incoming erlang message.
 
-   Example 1.12. Example of using xbuff
+   Example 1.13. Example of using xbuff
 ...
 # tuple T from previous example
 
@@ -457,7 +474,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.13. Example of using erl_rpc
+   Example 1.14. Example of using erl_rpc
 ...
 # example of call erlang:list_to_tuple(["one","two"])
 # on remote node
@@ -487,7 +504,7 @@ DEBUG: <script>: 386:type(repl): tuple, format(repl): {"one", "two"}
 
    The argument msg is containing the message to be sent.
 
-   Example 1.14. Example of using erl_reg_send
+   Example 1.15. Example of using erl_reg_send
 ...
 # example of send message to registered process
 # {notifier,'[email protected]'} ! {example,message}
@@ -506,7 +523,7 @@ erl_reg_send("notifier","$tuple(M)");
    Function to send message from event route (pseudo process). Function
    sends reply message msg to the sender process.
 
-   Example 1.15. Example of registered process
+   Example 1.16. Example of use erl_reply
 ...
 # event route acts as registered process
 event_route[erlang:greetings] {
@@ -543,8 +560,8 @@ INFO: <script>: 951:Received message: {"hello", "Kamailio"}
    we can use event routes. Event routes executed when asynchronous
    message received from erlang node.
 
-   Event route receive message in $xbuff(msg). Reply variable is optional
-   and can be sent with erl_reply.
+   Event route receives message in $xbuff(msg) and sender process in
+   $xbuff(pid). Reply message is optional and can be sent with erl_reply.
 
 6.1. Registered pseudo process
 
@@ -552,7 +569,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.16. Example of registered process
+   Example 1.17. Example of registered process
 ...
 # event route acts as registered process
 event_route[erlang:handler] {
@@ -576,7 +593,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.17. Example of using default event route
+   Example 1.18. Example of using default event route
 ...
 # default event route from erlang
 event_route[erlang:self] {

+ 23 - 4
modules/erlang/doc/erlang_admin.xml

@@ -241,7 +241,7 @@ modparam("erlang", "trace_level", 5)
 					<varname>type</varname>
 					<para>
 						get variable type. Possible types are: <emphasis>atom, integer,
-						list, string</emphasis> and <emphasis>tuple</emphasis>.
+						list, string</emphasis>, <emphasis>tuple</emphasis> and <emphasis>pid</emphasis>.
 					</para>
 				</listitem>
 				<listitem>
@@ -390,6 +390,24 @@ xlogl("L_DEBUG","length(T): $tuple(T=>length), format(T): $tuple(T=>format)\n");
 &gt; log output is:
 ...
 DEBUG: &lt;script&gt;: 153:length(T): 2, format(T): {line, [{id, 23}, {owner, "Bob"}]}
+...
+				</programlisting>
+			</example>
+		</section>
+		<section id="erlang.v.pid">
+			<title><varname>$pid(name)</varname></title>
+			<para>
+				<emphasis>pid</emphasis> holds Eralng process identifier. Provides
+				access to pid value and could be used in send message.
+			</para>
+			<example>
+				<title>Example of using pid</title>
+				<programlisting format="linespecific">
+...
+if ($xbuff(msg[0]=>type) == "pid") {
+	$pid(pid) = $xbuff(msg[0]);
+	xlogl("L_INFO","Received PID: $pid(pid=>format)\n");
+}
 ...
 				</programlisting>
 			</example>
@@ -512,7 +530,7 @@ erl_reg_send("notifier","$tuple(M)");
 				Function sends reply message <emphasis>msg</emphasis> to the sender process.
 			</para>
 			<example>
-				<title>Example of registered process</title>
+				<title>Example of use <emphasis>erl_reply</emphasis></title>
 				<programlisting format="linespecific">
 ...
 # event route acts as registered process
@@ -553,8 +571,9 @@ INFO: &lt;script&gt;: 951:Received message: {"hello", "Kamailio"}
 			from erlang node.
 		</para>
 		<para>
-			Event route receive message in <varname>$xbuff(msg)</varname>. Reply
-			variable is optional and can be sent with <emphasis>erl_reply</emphasis>.
+			Event route receives message in <varname>$xbuff(msg)</varname> and sender
+			process in <varname>$xbuff(pid)</varname>. Reply message is optional
+			and can be sent with <emphasis>erl_reply</emphasis>.
 		</para>
 		<section>
 			<title>Registered pseudo process</title>

+ 45 - 1
modules/erlang/handle_emsg.c

@@ -55,7 +55,11 @@ int handle_reg_send(cnode_handler_t *phandler, erlang_msg * msg)
 	size_t sz;
 	ei_x_buff *request = &phandler->request;
 	sr_xavp_t *xreq = NULL;
+	sr_xavp_t *xpid = NULL;
 	str msg_name = str_init("msg");
+	str pid_name = str_init("pid");
+	sr_xval_t val;
+	sr_data_t *data = NULL;
 
 	sz = sizeof("erlang")+strlen(msg->toname)+2;
 	route = (char*)pkg_malloc(sz);
@@ -81,7 +85,7 @@ int handle_reg_send(cnode_handler_t *phandler, erlang_msg * msg)
 	fmsg = &tmsg;
 
 	if ((xreq = pv_xbuff_get_xbuff(&msg_name))) {
-		LM_DBG("free previous value\n");
+		LM_DBG("free previous $xbuff(msg) value\n");
 		xavp_destroy_list(&xreq->val.v.xavp);
 	} else {
 		xreq = xbuff_new(&msg_name);
@@ -101,6 +105,42 @@ int handle_reg_send(cnode_handler_t *phandler, erlang_msg * msg)
 		goto err;
 	}
 
+	if ((xpid = pv_xbuff_get_xbuff(&pid_name))) {
+		LM_DBG("free previous $xbuff(pid) value\n");
+		xavp_destroy_list(&xpid->val.v.xavp);
+	} else {
+		xpid = xbuff_new(&pid_name);
+	}
+
+	if (!xpid) {
+		LM_ERR("failed to create $xbuff(pid) variable\n");
+		goto err;
+	}
+
+	/* put erl_pid into $xbuff(pid) */
+	data = (sr_data_t*)shm_malloc(sizeof(sr_data_t)+sizeof(erlang_pid));
+	if (!data) {
+		LM_ERR("not enough shared memory\n");
+		goto err;
+	}
+
+	memset((void*)data,0,sizeof(sr_data_t)+sizeof(erlang_pid));
+
+	data->p = (void*)data+sizeof(sr_data_t);
+	data->pfree = xbuff_data_free;
+
+	memcpy(data->p,(void*)&msg->from,sizeof(erlang_pid));
+
+	val.type = SR_XTYPE_DATA;
+	val.v.data = data;
+
+	xpid->val.v.xavp = xavp_new_value(&pid_name,&val);
+	if (!xpid->val.v.xavp) {
+		LM_ERR("failed to create xavp!\n");
+		goto err;
+	}
+	xpid->val.type = SR_XTYPE_XAVP;
+
 	backup_rt = get_route_type();
 	set_route_type(EVENT_ROUTE);
 	init_run_actions_ctx(&ctx);
@@ -113,12 +153,16 @@ int handle_reg_send(cnode_handler_t *phandler, erlang_msg * msg)
 	return 0;
 
 err:
+	shm_free(data);
 	pkg_free(route);
 	free_xbuff_fmt_buff();
 	xavp_destroy_list(xavp_get_crt_list());
 	return -1;
 }
 
+/*
+ * handle ERL_SEND
+ */
 int handle_send(cnode_handler_t *phandler, erlang_msg * msg)
 {
 	int rt, backup_rt;

+ 11 - 0
modules/erlang/mod_erlang.c

@@ -49,6 +49,7 @@
 #include "pv_tuple.h"
 #include "pv_atom.h"
 #include "pv_list.h"
+#include "pv_pid.h"
 
 MODULE_VERSION
 
@@ -127,6 +128,16 @@ static pv_export_t pvs[] = {
 				0,
 				0
 		},
+		{
+				{ "pid", (sizeof("pid")-1) },
+				PVT_OTHER,
+				pv_pid_get,
+				pv_pid_set,
+				pv_pid_parse_name,
+				0,
+				0,
+				0
+		},
 		{{0,0}, 0, 0, 0, 0, 0, 0, 0}
 };
 

+ 1 - 59
modules/erlang/pv_atom.c

@@ -146,65 +146,6 @@ sr_xavp_t *xavp_get_atoms()
 	return list;
 }
 
-int pv_atom_new_xavp(sr_xval_t *xval, pv_value_t *pval, int *counter)
-{
-	char s[32];
-	str name;
-	sr_xavp_t *xavp = NULL;
-	sr_xval_t nval;
-	xbuff_type_t type;
-
-	if (!xval) return -1;
-
-	memset((void*)xval,0,sizeof(sr_xval_t));
-
-	if (pval->flags&PV_VAL_NULL) {
-		nval.type = SR_XTYPE_NULL;
-	} else if (pval->flags&PV_VAL_INT) {
-		LM_ERR("can't convert integer to atom\n");
-		return -1;
-	} else if (pval->flags&PV_VAL_STR) {
-		/* check what it is */
-		if (xbuff_match_type_re(&pval->rs,&type,&xavp)) {
-			nval.type = SR_XTYPE_STR;
-			nval.v.s = pval->rs;
-		} else {
-			switch (type) {
-			case XBUFF_TYPE_ATOM:
-			case XBUFF_TYPE_STR:
-				break;
-			case XBUFF_TYPE_TUPLE:
-			case XBUFF_TYPE_LIST:
-			case XBUFF_TYPE_INT:
-				LM_ERR("can't convert integer, tuple or list into atom\n");
-				return -1;
-				break;
-			default:
-				LM_ERR("BUG: unexpected XBUFF type!\n");
-				return -1;
-			}
-
-			/* copy tree */
-			nval.type = SR_XTYPE_STR;
-			nval.v.s = xavp->val.v.s;
-		}
-	}
-
-	name.s = s;
-	name.len = snprintf(s,31,"a%d",(*counter)++) + 1;
-
-	xavp = xavp_new_value(&name,&nval);
-
-	if (!xavp) {
-		return -1;
-	}
-
-	xval->type = SR_XTYPE_XAVP;
-	xval->v.xavp = xavp;
-
-	return 0;
-}
-
 int pv_atom_set(struct sip_msg* msg,  pv_param_t* param, int op, pv_value_t* val)
 {
 	str name;
@@ -275,6 +216,7 @@ err:
 
 	return -1;
 }
+
 int pv_atom_get_value(struct sip_msg *msg, pv_param_t *param,
 		pv_value_t *res, sr_xavp_t *avp)
 {

+ 4 - 1
modules/erlang/pv_list.c

@@ -242,7 +242,10 @@ int pv_list_get_value(struct sip_msg *msg, pv_param_t *param,
 		}
 		break;
 	case SR_XTYPE_DATA:
-		if(snprintf(_pv_xavp_buf, 128, "<<binary:%p>>", avp->val.v.data)<0)
+		if (avp->name.s[0] == 'p') {
+			if(snprintf(_pv_xavp_buf, 128, "<<pid:%p>>", avp->val.v.data)<0)
+				return pv_get_null(msg, param, res);
+		} else if(snprintf(_pv_xavp_buf, 128, "<<binary:%p>>", avp->val.v.data)<0)
 			return pv_get_null(msg, param, res);
 		break;
 	default:

+ 333 - 0
modules/erlang/pv_pid.c

@@ -0,0 +1,333 @@
+/**
+ * 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_pid.h"
+#include "pv_xbuff.h"
+
+static str pid_list=str_init("[pids]");
+static char *pid_fmt_buff = NULL;
+static int counter;
+
+int pv_pid_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_pids()
+{
+	sr_xavp_t *list;
+	list = xavp_get(&pid_list,NULL);
+
+	if(!list) counter = 0;
+
+	return list;
+}
+
+int pv_pid_set(struct sip_msg* msg,  pv_param_t* param, int op, pv_value_t* val)
+{
+	str name;
+	sr_xavp_t *pid_root;
+	sr_xavp_t *pid;
+	sr_xavp_t *new,*old=NULL;
+	sr_xavp_t *pid_xavp;
+	sr_xval_t pid_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(&pid_xavp,val,&counter,'p')) {
+		LM_ERR("failed to create new value\n");
+		return -1;
+	}
+
+	/* pid var name */
+	name = param->pvn.u.isname.name.s;
+
+	memset((void*)&pid_val,0,sizeof(sr_xval_t));
+
+	pid_root = xavp_get_pids();
+
+	if(!pid_root) {
+
+		pid_val.type = SR_XTYPE_XAVP;
+		pid_val.v.xavp = pid_xavp;
+		pid = xavp_add_xavp_value(&pid_list,&name,&pid_val,xavp_get_crt_list());
+
+		if (!pid)
+			goto err;
+
+		return 0;
+	}
+
+	pid = xavp_get_child(&pid_list, &name);
+
+	if (!pid) {
+
+		pid_val.type = SR_XTYPE_XAVP;
+		pid_val.v.xavp = pid_xavp;
+
+		new = xavp_add_value(&name,&pid_val,&pid_root->val.v.xavp);
+
+		if (!new)
+			goto err;
+
+		return 0;
+	}
+
+	old = pid->val.v.xavp;
+	new = pid_xavp;
+
+	if (old) {
+		xavp_destroy_list(&old);
+	}
+
+	pid->val.v.xavp = new;
+
+	return 0;
+
+err:
+	LM_ERR("failed to set pid value\n");
+	xavp_destroy_list(&pid_xavp);
+
+	return -1;
+}
+
+int pv_pid_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, "<<pid:%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 pid 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_pid_get(struct sip_msg* msg,  pv_param_t* param, pv_value_t* res)
+{
+	str name;
+	sr_xavp_t *pids_root;
+	sr_xavp_t *pid;
+	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;
+
+	/* pid name */
+	name = param->pvn.u.isname.name.s;
+	/* attributes */
+	attr = xbuff_get_attr_flags(param->pvi.type);
+
+	pids_root = xavp_get_pids();
+	if(!pids_root) {
+		return pv_get_null(msg,param,res);
+	}
+
+	pid = xavp_get(&name,pids_root->val.v.xavp);
+	if (!pid) {
+		return pv_get_null(msg,param,res);
+	}
+
+	xavp = pid->val.v.xavp;
+
+	switch (xbuff_is_attr_set(attr)) {
+	case XBUFF_ATTR_TYPE:
+		return pv_get_strval(msg,param,res,&xbuff_types[XBUFF_TYPE_PID]);
+		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(&pid_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,pid_fmt_buff);
+		ei_x_free(&xbuff);
+		return i;
+	}
+
+	if (!xavp) {
+		return pv_get_null(msg,param,res);
+	}
+
+	return pv_pid_get_value(msg,param,res,xavp);
+}
+
+/*
+ * free format buffer for tuple
+ */
+void free_pid_fmt_buff() {
+	if (pid_fmt_buff) {
+		free(pid_fmt_buff);
+	}
+	pid_fmt_buff = 0;
+}

+ 35 - 0
modules/erlang/pv_pid.h

@@ -0,0 +1,35 @@
+/**
+ * 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_PID_H_
+#define PV_PID_H_
+
+#include "../../pvar.h"
+
+int pv_pid_parse_name(pv_spec_t *sp, str *in);
+int pv_pid_set(struct sip_msg* msg,  pv_param_t* param, int op, pv_value_t* val);
+int pv_pid_get(struct sip_msg*, pv_param_t*, pv_value_t*);
+
+void free_pid_fmt_buff();
+
+#endif /* PV_PID_H_ */

+ 4 - 2
modules/erlang/pv_tuple.c

@@ -97,7 +97,6 @@ int pv_tuple_set(struct sip_msg* msg,  pv_param_t* param, int op, pv_value_t* va
 
 	if (!tuple) {
 
-
 		if(pv_xbuff_new_xavp(&tuple_xavp,&empty,&counter,'t')) {
 			LM_ERR("failed to create new value\n");
 			return -1;
@@ -245,7 +244,10 @@ int pv_tuple_get_value(struct sip_msg *msg, pv_param_t *param,
 		}
 		break;
 	case SR_XTYPE_DATA:
-		if(snprintf(_pv_xavp_buf, 128, "<<binary:%p>>", avp->val.v.data)<0)
+		if (avp->name.s[0] == 'p') {
+			if(snprintf(_pv_xavp_buf, 128, "<<pid:%p>>", avp->val.v.data)<0)
+				return pv_get_null(msg, param, res);
+		} else if(snprintf(_pv_xavp_buf, 128, "<<binary:%p>>", avp->val.v.data)<0)
 			return pv_get_null(msg, param, res);
 		break;
 	default:

+ 81 - 28
modules/erlang/pv_xbuff.c

@@ -41,6 +41,7 @@ str xbuff_types[] = {
 		STR_STATIC_INIT("string"),
 		STR_STATIC_INIT("tuple"),
 		STR_STATIC_INIT("list"),
+		STR_STATIC_INIT("pid"),
 		STR_NULL
 };
 
@@ -54,6 +55,8 @@ static str xbuff_list=str_init("[xbuffs]");
 static int counter;
 static char *xbuff_fmt_buff = NULL;
 
+void xbuff_data_free(void *p, sr_xavp_sfree_f sfree);
+
 sr_xavp_t *xavp_get_xbuffs()
 {
 	sr_xavp_t *list;
@@ -103,7 +106,7 @@ sr_xavp_t *xbuff_new(str *name)
  */
 int compile_xbuff_re()
 {
-	char *pattern = "^<<\\(tuple\\|list\\|atom\\):\\(0x[[:xdigit:]]\\+\\)>>$";
+	char *pattern = "^<<\\(tuple\\|list\\|atom\\|pid\\):\\(0x[[:xdigit:]]\\+\\)>>$";
 	size_t bfsz = 128;
 	char errbuff[128];
 	int e;
@@ -147,6 +150,8 @@ int xbuff_match_type_re(str *s, xbuff_type_t *type, sr_xavp_t **addr)
 			t = XBUFF_TYPE_LIST;
 		} else if (STR_EQ(tname,xbuff_types[XBUFF_TYPE_TUPLE])) {
 			t = XBUFF_TYPE_TUPLE;
+		} else if (STR_EQ(tname,xbuff_types[XBUFF_TYPE_PID])) {
+			t = XBUFF_TYPE_PID;
 		} else {
 			LM_ERR("BUG: unknown xbuff type");
 			return -1;
@@ -320,17 +325,13 @@ int pv_xbuff_new_xavp(sr_xavp_t **new, pv_value_t *pval, int *counter, char pref
 				if (!cxavp)
 					return -1;
 
-				if (type == XBUFF_TYPE_ATOM) {
-					nval.type = SR_XTYPE_XAVP;
-					nval.v.xavp = cxavp;
-				} else {
-					nval = cxavp->val;
+				nval = cxavp->val;
+
+				/* free overhead */
+				cxavp->next = NULL;
+				cxavp->val.v.xavp = NULL;
+				xavp_destroy_list(&cxavp);
 
-					/* free overhead */
-					cxavp->next = NULL;
-					cxavp->val.v.xavp = NULL;
-					xavp_destroy_list(&cxavp);
-				}
 				break;
 			case XBUFF_TYPE_TUPLE:
 				s[0] = 't';
@@ -341,17 +342,22 @@ int pv_xbuff_new_xavp(sr_xavp_t **new, pv_value_t *pval, int *counter, char pref
 				if (!cxavp)
 					return -1;
 
-				if (type == XBUFF_TYPE_ATOM) {
-					nval.type = SR_XTYPE_XAVP;
-					nval.v.xavp = cxavp;
-				} else {
-					nval = cxavp->val;
+				nval = cxavp->val;
 
-					/* free overhead */
-					cxavp->next = NULL;
-					cxavp->val.v.xavp = NULL;
-					xavp_destroy_list(&cxavp);
+				/* free overhead */
+				cxavp->next = NULL;
+				cxavp->val.v.xavp = NULL;
+				xavp_destroy_list(&cxavp);
+				break;
+			case XBUFF_TYPE_PID:
+				s[0] = 'p';
+				nval.type = SR_XTYPE_DATA;
+				nval.v.data = (sr_data_t*)shm_malloc(sizeof(sr_data_t)+sizeof(erlang_pid));
+				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_pid));
 				break;
 			case XBUFF_TYPE_INT:
 			case XBUFF_TYPE_STR:
@@ -400,6 +406,9 @@ int pv_xbuff_get_type(struct sip_msg *msg, pv_param_t *param,
 	case 't':
 		return pv_get_strval(msg, param, res, &xbuff_types[XBUFF_TYPE_TUPLE]);
 		break;
+	case 'p':
+		return pv_get_strval(msg, param, res, &xbuff_types[XBUFF_TYPE_PID]);
+		break;
 	}
 
 	return pv_get_null(msg, param, res);
@@ -584,6 +593,17 @@ int pv_xbuff_get_value(struct sip_msg *msg, pv_param_t *param,
 		if(snprintf(_pv_xavp_buf, 128, "%lld", avp->val.v.ll)<0)
 			return pv_get_null(msg, param, res);
 		break;
+	case SR_XTYPE_DATA:
+		switch (avp->name.s[0]) {
+		case 'p':
+			if(snprintf(_pv_xavp_buf, 128, "<<pid:%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);
+		}
+		break;
 	case SR_XTYPE_XAVP:
 		switch(avp->name.s[0]) {
 		case 't':
@@ -600,10 +620,6 @@ int pv_xbuff_get_value(struct sip_msg *msg, pv_param_t *param,
 //			return pv_get_null(msg, param, res);
 		}
 		break;
-	case SR_XTYPE_DATA:
-		if(snprintf(_pv_xavp_buf, 128, "<<binary:%p>>", avp->val.v.data)<0)
-			return pv_get_null(msg, param, res);
-		break;
 	default:
 		return pv_get_null(msg, param, res);
 	}
@@ -883,6 +899,9 @@ int xavp_encode(ei_x_buff *xbuff, sr_xavp_t *xavp,int level)
 			if (xavp_encode(xbuff, xavp->val.v.xavp, level + 1)) return -1;
 			ei_x_encode_empty_list(xbuff);
 			break;
+		case 'p':
+			ei_x_encode_pid(xbuff,xavp->val.v.data->p);
+			break;
 		case 'n':
 			ei_x_encode_atom(xbuff,"undefined");
 			break;
@@ -911,11 +930,12 @@ int xavp_decode(ei_x_buff *xbuff, int *index, sr_xavp_t **xavp,int level)
 	sr_xavp_t **tail;
 	sr_xavp_t *new;
 	char *pbuf=0;
-	erlang_pid pid;
+	erlang_pid *pid;
 	erlang_ref ref;
 	erlang_fun fun;
 	double d;
 	char *p = NULL;
+	sr_data_t *data;
 
 	name.s = _s;
 
@@ -1068,16 +1088,45 @@ int xavp_decode(ei_x_buff *xbuff, int *index, sr_xavp_t **xavp,int level)
 		break;
 
 	case ERL_PID_EXT:
+		name.len = snprintf(_s,sizeof(_s),"p%d",counter++);
+
+		data = (sr_data_t*)shm_malloc(sizeof(sr_data_t)+sizeof(erlang_pid));
+		if (!data) {
+			LM_ERR("not enough shared memory\n");
+			goto err;
+		}
+
+		memset((void*)data,0,sizeof(sr_data_t)+sizeof(erlang_pid));
+
+		data->p = pid = (void*)data+sizeof(sr_data_t);
+		data->pfree = xbuff_data_free;
+
+		if (ei_decode_pid(xbuff->buff,index,pid)<0) {
+			LM_ERR("failed to decode pid\n");
+			shm_free(data);
+			goto err;
+		}
+
+		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_REFERENCE_EXT:
 	case ERL_NEW_REFERENCE_EXT:
 		name.len = snprintf(_s,sizeof(_s),"s%d",counter++);
 		i = *index;
 
-		if (type==ERL_PID_EXT) ei_decode_pid(xbuff->buff,index,&pid);
-		else ei_decode_ref(xbuff->buff,index,&ref);
+		ei_decode_ref(xbuff->buff,index,&ref);
 
 		if (ei_s_print_term(&p,xbuff->buff,&i)<0) {
-			LM_ERR("failed to decode %s\n",type==ERL_PID_EXT?"pid":"reference");
+			LM_ERR("failed to decode reference\n");
 			goto err;
 		}
 		val.type = SR_XTYPE_STR;
@@ -1151,3 +1200,7 @@ void xbuff_destroy_all()
 	list = xavp_get_xbuffs();
 	if (list) xavp_destroy_list(&list);
 }
+
+/* does nothing but must be executed in xavp_free[_unsafe] */
+void xbuff_data_free(void *p, sr_xavp_sfree_f sfree) {
+}

+ 3 - 1
modules/erlang/pv_xbuff.h

@@ -43,6 +43,7 @@ typedef enum {
 	XBUFF_TYPE_STR,
 	XBUFF_TYPE_TUPLE,
 	XBUFF_TYPE_LIST,
+	XBUFF_TYPE_PID,
 	XBUFF_TYPE_COUNT
 } xbuff_type_t;
 
@@ -83,7 +84,7 @@ void free_xbuff_fmt_buff();
 void xbuff_destroy_all();
 
 /**
- * atom,tuple,xbuff and list
+ * atom,tuple,xbuf,pid and list
  */
 extern regex_t xbuff_type_re;
 
@@ -96,5 +97,6 @@ sr_xavp_t *xavp_get_nth(sr_xavp_t **list, int idx, sr_xavp_t **prv);
 int xavp_get_count(sr_xavp_t *list);
 int xavp_encode(ei_x_buff *xbuff, sr_xavp_t *xavp,int level);
 
+void xbuff_data_free(void *p, sr_xavp_sfree_f sfree);
 
 #endif /* PV_XBUFF_H_ */