Explorar o código

Merge pull request #163 from kamailio/seudin_erlang_fixes

erlang: fixes and new PV
Seudin Kasumovic %!s(int64=10) %!d(string=hai) anos
pai
achega
6d32e8df95

+ 37 - 20
modules/erlang/README

@@ -40,7 +40,8 @@ Seudin Kasumovic
               4.3. $atom(name)
               4.3. $atom(name)
               4.4. $list(name)
               4.4. $list(name)
               4.5. $tuple(name)
               4.5. $tuple(name)
-              4.6. $xbuff(name)
+              4.6. $pid(name)
+              4.7. $xbuff(name)
 
 
         5. Functions
         5. Functions
 
 
@@ -81,12 +82,13 @@ Seudin Kasumovic
    1.9. Example set and print to log atom
    1.9. Example set and print to log atom
    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 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.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
@@ -120,7 +122,8 @@ Chapter 1. Admin Guide
         4.3. $atom(name)
         4.3. $atom(name)
         4.4. $list(name)
         4.4. $list(name)
         4.5. $tuple(name)
         4.5. $tuple(name)
-        4.6. $xbuff(name)
+        4.6. $pid(name)
+        4.7. $xbuff(name)
 
 
    5. Functions
    5. Functions
 
 
@@ -271,7 +274,8 @@ modparam("erlang", "trace_level", 5)
    4.3. $atom(name)
    4.3. $atom(name)
    4.4. $list(name)
    4.4. $list(name)
    4.5. $tuple(name)
    4.5. $tuple(name)
-   4.6. $xbuff(name)
+   4.6. $pid(name)
+   4.7. $xbuff(name)
 
 
 4.1. Overview
 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
    by self determine variable type, but we need to know what type on some
    position is.
    position is.
      * type
      * 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
      * length
        get length of list or tuple.
        get length of list or tuple.
      * format
      * 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"}]}
 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
    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
@@ -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
    initialization. Module functions expect this PV as return value, and PV
    for incoming erlang message.
    for incoming erlang message.
 
 
-   Example 1.12. Example of using xbuff
+   Example 1.13. Example of using xbuff
 ...
 ...
 # tuple T from previous example
 # 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
    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.13. Example of using erl_rpc
+   Example 1.14. 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
@@ -487,7 +504,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.14. Example of using erl_reg_send
+   Example 1.15. 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}
@@ -506,7 +523,7 @@ erl_reg_send("notifier","$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.15. Example of registered process
+   Example 1.16. 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] {
@@ -543,8 +560,8 @@ INFO: <script>: 951:Received message: {"hello", "Kamailio"}
    we can use event routes. Event routes executed when asynchronous
    we can use event routes. Event routes executed when asynchronous
    message received from erlang node.
    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
 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
    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.16. Example of registered process
+   Example 1.17. Example of registered process
 ...
 ...
 # event route acts as registered process
 # event route acts as registered process
 event_route[erlang:handler] {
 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
    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.17. Example of using default event route
+   Example 1.18. Example of using default event route
 ...
 ...
 # default event route from erlang
 # default event route from erlang
 event_route[erlang:self] {
 event_route[erlang:self] {

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

@@ -241,7 +241,7 @@ 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> and <emphasis>tuple</emphasis>.
+						list, string</emphasis>, <emphasis>tuple</emphasis> and <emphasis>pid</emphasis>.
 					</para>
 					</para>
 				</listitem>
 				</listitem>
 				<listitem>
 				<listitem>
@@ -390,6 +390,24 @@ xlogl("L_DEBUG","length(T): $tuple(T=>length), format(T): $tuple(T=>format)\n");
 &gt; log output is:
 &gt; log output is:
 ...
 ...
 DEBUG: &lt;script&gt;: 153:length(T): 2, format(T): {line, [{id, 23}, {owner, "Bob"}]}
 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>
 				</programlisting>
 			</example>
 			</example>
@@ -512,7 +530,7 @@ erl_reg_send("notifier","$tuple(M)");
 				Function sends reply message <emphasis>msg</emphasis> to the sender process.
 				Function sends reply message <emphasis>msg</emphasis> to the sender process.
 			</para>
 			</para>
 			<example>
 			<example>
-				<title>Example of registered process</title>
+				<title>Example of use <emphasis>erl_reply</emphasis></title>
 				<programlisting format="linespecific">
 				<programlisting format="linespecific">
 ...
 ...
 # event route acts as registered process
 # event route acts as registered process
@@ -553,8 +571,9 @@ INFO: &lt;script&gt;: 951:Received message: {"hello", "Kamailio"}
 			from erlang node.
 			from erlang node.
 		</para>
 		</para>
 		<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>
 		</para>
 		<section>
 		<section>
 			<title>Registered pseudo process</title>
 			<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;
 	size_t sz;
 	ei_x_buff *request = &phandler->request;
 	ei_x_buff *request = &phandler->request;
 	sr_xavp_t *xreq = NULL;
 	sr_xavp_t *xreq = NULL;
+	sr_xavp_t *xpid = NULL;
 	str msg_name = str_init("msg");
 	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;
 	sz = sizeof("erlang")+strlen(msg->toname)+2;
 	route = (char*)pkg_malloc(sz);
 	route = (char*)pkg_malloc(sz);
@@ -81,7 +85,7 @@ int handle_reg_send(cnode_handler_t *phandler, erlang_msg * msg)
 	fmsg = &tmsg;
 	fmsg = &tmsg;
 
 
 	if ((xreq = pv_xbuff_get_xbuff(&msg_name))) {
 	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);
 		xavp_destroy_list(&xreq->val.v.xavp);
 	} else {
 	} else {
 		xreq = xbuff_new(&msg_name);
 		xreq = xbuff_new(&msg_name);
@@ -101,6 +105,42 @@ int handle_reg_send(cnode_handler_t *phandler, erlang_msg * msg)
 		goto err;
 		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();
 	backup_rt = get_route_type();
 	set_route_type(EVENT_ROUTE);
 	set_route_type(EVENT_ROUTE);
 	init_run_actions_ctx(&ctx);
 	init_run_actions_ctx(&ctx);
@@ -113,12 +153,16 @@ int handle_reg_send(cnode_handler_t *phandler, erlang_msg * msg)
 	return 0;
 	return 0;
 
 
 err:
 err:
+	shm_free(data);
 	pkg_free(route);
 	pkg_free(route);
 	free_xbuff_fmt_buff();
 	free_xbuff_fmt_buff();
 	xavp_destroy_list(xavp_get_crt_list());
 	xavp_destroy_list(xavp_get_crt_list());
 	return -1;
 	return -1;
 }
 }
 
 
+/*
+ * handle ERL_SEND
+ */
 int handle_send(cnode_handler_t *phandler, erlang_msg * msg)
 int handle_send(cnode_handler_t *phandler, erlang_msg * msg)
 {
 {
 	int rt, backup_rt;
 	int rt, backup_rt;

+ 11 - 0
modules/erlang/mod_erlang.c

@@ -49,6 +49,7 @@
 #include "pv_tuple.h"
 #include "pv_tuple.h"
 #include "pv_atom.h"
 #include "pv_atom.h"
 #include "pv_list.h"
 #include "pv_list.h"
+#include "pv_pid.h"
 
 
 MODULE_VERSION
 MODULE_VERSION
 
 
@@ -127,6 +128,16 @@ static pv_export_t pvs[] = {
 				0,
 				0,
 				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}
 		{{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;
 	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)
 int pv_atom_set(struct sip_msg* msg,  pv_param_t* param, int op, pv_value_t* val)
 {
 {
 	str name;
 	str name;
@@ -275,6 +216,7 @@ err:
 
 
 	return -1;
 	return -1;
 }
 }
+
 int pv_atom_get_value(struct sip_msg *msg, pv_param_t *param,
 int pv_atom_get_value(struct sip_msg *msg, pv_param_t *param,
 		pv_value_t *res, sr_xavp_t *avp)
 		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;
 		break;
 	case SR_XTYPE_DATA:
 	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);
 			return pv_get_null(msg, param, res);
 		break;
 		break;
 	default:
 	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 (!tuple) {
 
 
-
 		if(pv_xbuff_new_xavp(&tuple_xavp,&empty,&counter,'t')) {
 		if(pv_xbuff_new_xavp(&tuple_xavp,&empty,&counter,'t')) {
 			LM_ERR("failed to create new value\n");
 			LM_ERR("failed to create new value\n");
 			return -1;
 			return -1;
@@ -245,7 +244,10 @@ int pv_tuple_get_value(struct sip_msg *msg, pv_param_t *param,
 		}
 		}
 		break;
 		break;
 	case SR_XTYPE_DATA:
 	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);
 			return pv_get_null(msg, param, res);
 		break;
 		break;
 	default:
 	default:

+ 81 - 28
modules/erlang/pv_xbuff.c

@@ -41,6 +41,7 @@ str xbuff_types[] = {
 		STR_STATIC_INIT("string"),
 		STR_STATIC_INIT("string"),
 		STR_STATIC_INIT("tuple"),
 		STR_STATIC_INIT("tuple"),
 		STR_STATIC_INIT("list"),
 		STR_STATIC_INIT("list"),
+		STR_STATIC_INIT("pid"),
 		STR_NULL
 		STR_NULL
 };
 };
 
 
@@ -54,6 +55,8 @@ static str xbuff_list=str_init("[xbuffs]");
 static int counter;
 static int counter;
 static char *xbuff_fmt_buff = NULL;
 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 *xavp_get_xbuffs()
 {
 {
 	sr_xavp_t *list;
 	sr_xavp_t *list;
@@ -103,7 +106,7 @@ sr_xavp_t *xbuff_new(str *name)
  */
  */
 int compile_xbuff_re()
 int compile_xbuff_re()
 {
 {
-	char *pattern = "^<<\\(tuple\\|list\\|atom\\):\\(0x[[:xdigit:]]\\+\\)>>$";
+	char *pattern = "^<<\\(tuple\\|list\\|atom\\|pid\\):\\(0x[[:xdigit:]]\\+\\)>>$";
 	size_t bfsz = 128;
 	size_t bfsz = 128;
 	char errbuff[128];
 	char errbuff[128];
 	int e;
 	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;
 			t = XBUFF_TYPE_LIST;
 		} else if (STR_EQ(tname,xbuff_types[XBUFF_TYPE_TUPLE])) {
 		} else if (STR_EQ(tname,xbuff_types[XBUFF_TYPE_TUPLE])) {
 			t = XBUFF_TYPE_TUPLE;
 			t = XBUFF_TYPE_TUPLE;
+		} else if (STR_EQ(tname,xbuff_types[XBUFF_TYPE_PID])) {
+			t = XBUFF_TYPE_PID;
 		} else {
 		} else {
 			LM_ERR("BUG: unknown xbuff type");
 			LM_ERR("BUG: unknown xbuff type");
 			return -1;
 			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)
 				if (!cxavp)
 					return -1;
 					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;
 				break;
 			case XBUFF_TYPE_TUPLE:
 			case XBUFF_TYPE_TUPLE:
 				s[0] = 't';
 				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)
 				if (!cxavp)
 					return -1;
 					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;
 				break;
 			case XBUFF_TYPE_INT:
 			case XBUFF_TYPE_INT:
 			case XBUFF_TYPE_STR:
 			case XBUFF_TYPE_STR:
@@ -400,6 +406,9 @@ int pv_xbuff_get_type(struct sip_msg *msg, pv_param_t *param,
 	case 't':
 	case 't':
 		return pv_get_strval(msg, param, res, &xbuff_types[XBUFF_TYPE_TUPLE]);
 		return pv_get_strval(msg, param, res, &xbuff_types[XBUFF_TYPE_TUPLE]);
 		break;
 		break;
+	case 'p':
+		return pv_get_strval(msg, param, res, &xbuff_types[XBUFF_TYPE_PID]);
+		break;
 	}
 	}
 
 
 	return pv_get_null(msg, param, res);
 	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)
 		if(snprintf(_pv_xavp_buf, 128, "%lld", avp->val.v.ll)<0)
 			return pv_get_null(msg, param, res);
 			return pv_get_null(msg, param, res);
 		break;
 		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:
 	case SR_XTYPE_XAVP:
 		switch(avp->name.s[0]) {
 		switch(avp->name.s[0]) {
 		case 't':
 		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);
 //			return pv_get_null(msg, param, res);
 		}
 		}
 		break;
 		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:
 	default:
 		return pv_get_null(msg, param, res);
 		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;
 			if (xavp_encode(xbuff, xavp->val.v.xavp, level + 1)) return -1;
 			ei_x_encode_empty_list(xbuff);
 			ei_x_encode_empty_list(xbuff);
 			break;
 			break;
+		case 'p':
+			ei_x_encode_pid(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;
@@ -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 **tail;
 	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;
+	sr_data_t *data;
 
 
 	name.s = _s;
 	name.s = _s;
 
 
@@ -1068,16 +1088,45 @@ int xavp_decode(ei_x_buff *xbuff, int *index, sr_xavp_t **xavp,int level)
 		break;
 		break;
 
 
 	case ERL_PID_EXT:
 	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_REFERENCE_EXT:
 	case ERL_NEW_REFERENCE_EXT:
 	case ERL_NEW_REFERENCE_EXT:
 		name.len = snprintf(_s,sizeof(_s),"s%d",counter++);
 		name.len = snprintf(_s,sizeof(_s),"s%d",counter++);
 		i = *index;
 		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) {
 		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;
 			goto err;
 		}
 		}
 		val.type = SR_XTYPE_STR;
 		val.type = SR_XTYPE_STR;
@@ -1151,3 +1200,7 @@ void xbuff_destroy_all()
 	list = xavp_get_xbuffs();
 	list = xavp_get_xbuffs();
 	if (list) xavp_destroy_list(&list);
 	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_STR,
 	XBUFF_TYPE_TUPLE,
 	XBUFF_TYPE_TUPLE,
 	XBUFF_TYPE_LIST,
 	XBUFF_TYPE_LIST,
+	XBUFF_TYPE_PID,
 	XBUFF_TYPE_COUNT
 	XBUFF_TYPE_COUNT
 } xbuff_type_t;
 } xbuff_type_t;
 
 
@@ -83,7 +84,7 @@ void free_xbuff_fmt_buff();
 void xbuff_destroy_all();
 void xbuff_destroy_all();
 
 
 /**
 /**
- * atom,tuple,xbuff and list
+ * atom,tuple,xbuf,pid and list
  */
  */
 extern regex_t xbuff_type_re;
 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_get_count(sr_xavp_t *list);
 int xavp_encode(ei_x_buff *xbuff, sr_xavp_t *xavp,int level);
 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_ */
 #endif /* PV_XBUFF_H_ */