Browse Source

tsilo: initial commit

Federico Cabiddu 11 years ago
parent
commit
84be6b8e4d

+ 18 - 0
modules/tsilo/Makefile

@@ -0,0 +1,18 @@
+# $Id$
+#
+# example module makefile
+#
+#
+# WARNING: do not run this directly, it should be run by the master Makefile
+
+include ../../Makefile.defs
+auto_gen=
+NAME=tsilo.so
+LIBS=
+DEFS+= -DSER_MOD_INTERFACE
+
+ifeq ($(INSTALL_FLAVOUR),kamailio)
+DEFS+= -DWITH_EVENT_LOCAL_REQUEST
+endif # INSTALL_FLAVOUR
+
+include ../../Makefile.modules

+ 162 - 0
modules/tsilo/README

@@ -0,0 +1,162 @@
+TSILO Module
+
+Federico Cabiddu
+
+   <[email protected]>
+
+Edited by
+
+Federico Cabiddu
+
+   <[email protected]>
+
+   Copyright © 2014 Federico Cabiddu
+     __________________________________________________________________
+
+   Table of Contents
+
+   1. Admin Guide
+
+        1. Overview
+        2. Dependencies
+
+              2.1. Kamailio modules
+              2.2. External libraries or applications
+
+        3. Parameters
+        4. Functions
+
+              4.1. tstore()
+              4.2. t_append(domain, ruri)
+              4.3. t_append_to(tindex, tlabel, domain)
+
+        5. Statistics
+
+   List of Examples
+
+   1.1. tstore usage
+   1.2. t_append usage
+   1.3. t_append_to usage
+
+Chapter 1. Admin Guide
+
+   Table of Contents
+
+   1. Overview
+   2. Dependencies
+
+        2.1. Kamailio modules
+        2.2. External libraries or applications
+
+   3. Parameters
+   4. Functions
+
+        4.1. tstore()
+        4.2. t_append(domain, ruri)
+        4.3. t_append_to(tindex, tlabel, domain)
+
+   5. Statistics
+
+1. Overview
+
+   This modules provides transaction storage for the Kamailio SIP Server
+   Platform. It stores in an internal table transactions for an user and
+   add branches to them if new contacts are added.
+
+   For each message, the modules stores “Request-URI” (“R-URI”), URI and
+   the internal transaction index and label.
+
+   When the transaction is destroyed (by the TM module, the transaction is
+   removed from the module table.
+
+2. Dependencies
+
+   2.1. Kamailio modules
+   2.2. External libraries or applications
+
+2.1. Kamailio modules
+
+   The following modules must be loaded before this module:
+     * REGISTRAR--registrar module-- used to lookup for new contacts and
+       update the dset for the r-uri.
+     * TM--transaction module-- used to send SIP requests.
+
+2.2. External libraries or applications
+
+   The following libraries or applications must be installed before
+   running Kamailio with this module:
+     * none.
+
+3. Parameters
+
+4. Functions
+
+   4.1. tstore()
+   4.2. t_append(domain, ruri)
+   4.3. t_append_to(tindex, tlabel, domain)
+
+4.1. tstore()
+
+   The method stores r-uri, tindex and tlabel of the current transaction.
+
+   This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
+
+   Example 1.1. tstore usage
+...
+if (is_method("INVITE")) {
+        if (t_newtran()) {
+                tstore();
+        }
+}
+...
+
+4.2. t_append(domain, ruri)
+
+   The method add branches to all the stored transactions for the SIP ruri
+   passed as parameter, performing a contact lookup on the table specified
+   by the domain parameter. The method should be called when a REGISTER
+   request is received.
+
+   Meaning of the parameters is as follows:
+     * domain - Name of table that should be used for looking up new
+       contacts for r-uri.
+     * ruri - The r-uri for which we want to check existing transactions
+       and add them new branches. Can be a static string value or a
+       dynamic string with pseudo-variables.
+
+   This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
+
+   Example 1.2. t_append usage
+...
+if (is_method("REGISTER")) {
+        t_append("location", "$tu");
+}
+...
+
+4.3. t_append_to(tindex, tlabel, domain)
+
+   The method add branches to the transaction identified by tindex and
+   tlabel, performing a contacts lookup on the table specified by the
+   domain parameter. The method should be called when a REGISTER request
+   is received.
+
+   Meaning of the parameters is as follows:
+     * tindex - internal index of transaction. Can be an integer or a
+       pseudo-variable.
+     * tlabel - internal label of transaction. Can be an integer or a
+       pseudo-variable.
+     * domain - Name of table that should be used for looking up new
+       contacts for r-uri.
+
+   This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
+
+   Example 1.3. t_append_to usage
+...
+if (is_method("REGISTER")) {
+        $var(tindex) = ...
+        $var(tlabel) = ...
+        t_append_to("$var(tindex)", "$var(tlabel", "location");
+}
+...
+
+5. Statistics

+ 4 - 0
modules/tsilo/doc/Makefile

@@ -0,0 +1,4 @@
+docs = tsilo.xml
+
+docbook_dir = ../../../docbook
+include $(docbook_dir)/Makefile.module

+ 37 - 0
modules/tsilo/doc/tsilo.xml

@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+
+]>
+
+<book xmlns:xi="http://www.w3.org/2001/XInclude">
+    <bookinfo>
+	<title>TSILO Module</title>
+	<productname class="trade">&kamailioname;</productname>
+	<authorgroup>
+	    <author>
+		<firstname>Federico</firstname>
+		<surname>Cabiddu</surname>
+		<email>[email protected]</email>
+	    </author>
+	    <editor>
+		<firstname>Federico</firstname>
+		<surname>Cabiddu</surname>
+		<email>[email protected]</email>
+	    </editor>
+	</authorgroup>
+	<copyright>
+	    <year>2014</year>
+	    <holder>Federico Cabiddu</holder>
+	</copyright>
+    </bookinfo>
+    <toc></toc>
+
+    <xi:include href="tsilo_admin.xml"/>
+
+
+</book>

+ 206 - 0
modules/tsilo/doc/tsilo_admin.xml

@@ -0,0 +1,206 @@
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+
+]>
+<!-- Module User's Guide -->
+
+<chapter xmlns:xi="http://www.w3.org/2001/XInclude">
+
+	<title>&adminguide;</title>
+
+	<section>
+	<title>Overview</title>
+	<para>
+		This modules provides transaction storage for the &kamailioname;. It
+		stores in an internal table transactions for an user and add branches
+		to them if new contacts are added.
+	</para>
+	<para>
+		For each message, the modules stores <quote>Request-URI</quote>
+		(<quote>R-URI</quote>), &uri; and the internal transaction index
+		and label.
+	</para>
+	<para>
+		When the transaction is destroyed (by the <emphasis>TM</emphasis> module,
+		the transaction is removed from the module table.
+	</para>
+	</section>
+	<section>
+	<title>Dependencies</title>
+	<section>
+		<title>&kamailio; modules</title>
+		<para>
+		The following modules must be loaded before this module:
+			<itemizedlist>
+			<listitem>
+			<para>
+				<emphasis>REGISTRAR</emphasis>--registrar module-- used to lookup
+				for new contacts and update the dset for the r-uri.
+			</para>
+			</listitem>
+			<listitem>
+			<para>
+				<emphasis>TM</emphasis>--transaction module-- used to
+				send &sip; requests.
+			</para>
+			</listitem>
+			</itemizedlist>
+		</para>
+	</section>
+	<section>
+		<title>External libraries or applications</title>
+		<para>
+		The following libraries or applications must be installed before
+		running &kamailio; with this module:
+			<itemizedlist>
+			<listitem>
+			<para>
+				<emphasis>none</emphasis>.
+			</para>
+			</listitem>
+			</itemizedlist>
+		</para>
+	</section>
+	</section>
+	<section>
+	<title>Parameters</title>
+	<section>
+		<title><varname>hash_size</varname> (integer)</title>
+		<para>
+		The size of the hash table internally used to keep the transaction. A
+		larger table is much faster but consumes more memory. The hash size
+		must be a power of two, otherwise it will be rounded down to the nearest
+		power of two.
+		</para>
+		<para>
+		<emphasis>
+			Default value is <quote>2048</quote>.
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>hash_size</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("tsilo", "hash_size", 1024)
+...
+</programlisting>
+		</example>
+	</section>
+	</section>
+
+	<section>
+	<title>Functions</title>
+	<section>
+		<title><function moreinfo="none">tstore()</function></title>
+		<para>
+		The method stores r-uri, tindex and tlabel of the current transaction.
+		</para>
+		<para>
+		This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
+		</para>
+		<example>
+		<title><function>tstore</function> usage</title>
+		<programlisting format="linespecific">
+...
+if (is_method("INVITE")) {
+	if (t_newtran()) {
+		tstore();
+	}
+}
+...
+</programlisting>
+		</example>
+	</section>
+	<section>
+		<title><function moreinfo="none">t_append(domain, ruri)</function></title>
+		<para>
+		The method add branches to all the stored transactions for the &sip;
+		ruri passed as parameter, performing a contact lookup on the table specified by
+		the domain parameter. The method should be called when a REGISTER
+		request is received.
+		</para>
+		<para>Meaning of the parameters is as follows:</para>
+		<itemizedlist>
+		<listitem>
+			<para>
+			<emphasis>domain</emphasis> - Name of table that should be used for looking
+			up new contacts for r-uri.
+			</para>
+		</listitem>
+		<listitem>
+			<para>
+			<emphasis>ruri</emphasis> - The r-uri for which we want to check existing
+			transactions and add them new branches. Can be a static string value or a
+			dynamic string with pseudo-variables.
+			</para>
+		</listitem>
+		</itemizedlist>
+		<para>
+		This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
+		</para>
+		<example>
+		<title><function>t_append</function> usage</title>
+		<programlisting format="linespecific">
+...
+if (is_method("REGISTER")) {
+	t_append("location", "$tu");
+}
+...
+</programlisting>
+		</example>
+	</section>
+	<section>
+		<title><function moreinfo="none">t_append_to(tindex, tlabel, domain)</function></title>
+		<para>
+		The method add branches to the transaction identified by tindex and tlabel,
+		performing a contacts lookup on the table specified by the domain parameter.
+		The method should be called when a REGISTER request is received.
+		</para>
+		<para>Meaning of the parameters is as follows:</para>
+		<itemizedlist>
+		<listitem>
+			<para>
+                        <emphasis>tindex</emphasis> - internal index of transaction.
+                        Can be an integer or a pseudo-variable.
+                        </para>
+		</listitem>
+                <listitem>
+			<para>
+                        <emphasis>tlabel</emphasis> - internal label of transaction.
+                        Can be an integer or a pseudo-variable.
+                        </para>
+		</listitem>
+		<listitem>
+			<para>
+			<emphasis>domain</emphasis> - Name of table that should be used for looking
+			up new contacts for r-uri.
+			</para>
+		</listitem>
+		</itemizedlist>
+		<para>
+		This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
+		</para>
+		<example>
+		<title><function>t_append_to</function> usage</title>
+		<programlisting format="linespecific">
+...
+if (is_method("REGISTER")) {
+	$var(tindex) = ...
+	$var(tlabel) = ...
+	t_append_to("$var(tindex)", "$var(tlabel", "location");
+}
+...
+</programlisting>
+		</example>
+	</section>
+	</section>
+
+	<section>
+	<title>Statistics</title>
+	</section>
+</chapter>

+ 88 - 0
modules/tsilo/t_append.c

@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2014 Federico Cabiddu ([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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "../../sr_module.h"
+#include "../../dprint.h"
+#include "../../mod_fix.h"
+#include "../../route.h"
+#include "../../data_lump.h"
+#include "../../lib/kcore/kstats_wrapper.h"
+#include "../../dset.h"
+#include "../../script_cb.h"
+#include "../../parser/msg_parser.h"
+#include "../../parser/contact/parse_contact.h"
+#include "tsilo.h"
+#include "ts_hash.h"
+#include "t_append.h"
+
+int t_append(struct sip_msg* msg, str *ruri, char *table) {
+	ts_urecord_t* _r;
+	ts_transaction_t* ptr;
+
+	int res;
+
+	lock_entry_by_ruri(ruri);
+
+	res = get_ts_urecord(ruri, &_r);
+
+	if (res != 0) {
+		LM_ERR("failed to retrieve record for %.*s\n", ruri->len, ruri->s);
+		 unlock_entry_by_ruri(ruri);
+		 return -1;
+        }
+
+	ptr = _r->transactions;
+
+	while(ptr) {
+		LM_DBG("transaction %u:%u found for %.*s, going to append branches\n",ptr->tindex, ptr->tlabel, ruri->len, ruri->s);
+		t_append_to(msg, ptr->tindex, ptr->tlabel, table);
+		ptr = ptr->next;
+	}
+
+	unlock_entry_by_ruri(ruri);
+
+	return 1;
+}
+
+int t_append_to(struct sip_msg* msg, int tindex, int tlabel, char *table) {
+	struct cell     *t;
+	struct sip_msg *orig_msg;
+
+	if(_tmb.t_lookup_ident(&t, tindex, tlabel) < 0)
+	{
+		LM_ERR("transaction [%u:%u] not found\n",
+				tindex, tlabel);
+		return -1;
+	}
+
+	orig_msg = t->uas.request;
+
+	if (_regapi.lookup_to_dset(orig_msg, table, NULL) != 1) {
+		LM_DBG("transaction %u:%u: error updating dset\n", tindex, tlabel);
+		return -1;
+	}
+
+	return _tmb.t_append_branches();
+}

+ 28 - 0
modules/tsilo/t_append.h

@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2014 Federico Cabiddu ([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 _T_APPEND_H
+#define _T_APPEND_H
+
+int t_append(struct sip_msg* msg, str *ruri, char *table);
+int t_append_to(struct sip_msg* msg, int tindex, int tlabel, char *table);
+
+#endif

+ 75 - 0
modules/tsilo/t_store.c

@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2014 Federico Cabiddu ([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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "../../sr_module.h"
+#include "../../dprint.h"
+#include "../../mod_fix.h"
+#include "../../route.h"
+#include "../../data_lump.h"
+#include "../../lib/kcore/kstats_wrapper.h"
+#include "../../dset.h"
+#include "../../script_cb.h"
+#include "../../parser/msg_parser.h"
+#include "../../parser/contact/parse_contact.h"
+#include "tsilo.h"
+#include "ts_hash.h"
+#include "t_store.h"
+
+int t_store(struct sip_msg* msg) {
+	struct cell     *t;
+	str ruri;
+	ts_urecord_t* r;
+	int res;
+
+	t = _tmb.t_gett();
+	ruri = msg->first_line.u.request.uri;
+
+	LM_DBG("storing transaction %u:%u for r-uri: %.*s\n", t->hash_index, t->label, ruri.len, ruri.s);
+
+	lock_entry_by_ruri(&ruri);
+
+	res = get_ts_urecord(&ruri, &r);
+
+	if (res < 0) {
+		LM_ERR("failed to retrieve record for %.*s\n", ruri.len, ruri.s);
+		unlock_entry_by_ruri(&ruri);
+		return -1;
+	}
+
+	if (res != 0) { /* entry not found for the ruri */
+		if (insert_ts_urecord(&ruri, &r) < 0) {
+			LM_ERR("failed to insert new record structure\n");
+			unlock_entry_by_ruri(&ruri);
+			return -1;
+		}
+	}
+
+	insert_ts_transaction(t, msg, r);
+	unlock_entry_by_ruri(&ruri);
+
+	LM_DBG("transaction %u:%u (ruri: %.*s) inserted\n", t->hash_index, t->label, ruri.len, ruri.s);
+
+	return 1;
+}

+ 27 - 0
modules/tsilo/t_store.h

@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2014 Federico Cabiddu ([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 _T_STORE_H
+#define _T_STORE_H
+
+int t_store(struct sip_msg* msg);
+
+#endif

+ 99 - 0
modules/tsilo/ts_handlers.c

@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2014 Federico Cabiddu ([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 <string.h>
+
+#include "ts_hash.h"
+#include "ts_handlers.h"
+
+extern struct tm_binds _tmb;
+
+/*!
+ * \brief add transaction structure to tm callbacks
+ * \param t current transaction
+ * \param req current sip request
+ * \param tma_t current transaction
+ * \return 0 on success, -1 on failure
+ */
+int ts_set_tm_callbacks(struct cell *t, sip_msg_t *req, ts_transaction_t *ts)
+{
+	ts_transaction_t* ts_clone;
+
+	if(t==NULL)
+		return -1;
+
+	if ( (ts_clone=clone_ts_transaction(ts)) < 0 ) {
+		LM_ERR("failed to clone transaction\n");
+		return -1;
+	}
+
+	if (ts_clone == NULL) {
+		LM_ERR("transaction clone null\n");
+	}
+	if ( _tmb.register_tmcb( req, t,TMCB_DESTROY,
+			ts_onreply, (void*)ts_clone, free_ts_transaction)<0 ) {
+		LM_ERR("failed to register TMCB for transaction %d:%d\n", t->hash_index, t->label);
+		return -1;
+	}
+	LM_DBG("registered TMCB for transaction %d:%d\n", ts_clone->tindex, ts_clone->tlabel);
+
+	return 0;
+}
+
+void ts_onreply(struct cell* t, int type, struct tmcb_params *param)
+{
+	ts_urecord_t* _r;
+	ts_entry_t* _e;
+	ts_transaction_t *cb_ptr, *ptr;
+
+	cb_ptr = (ts_transaction_t*)(*param->param);
+	if (cb_ptr == NULL) {
+		LM_DBG("NULL param for type %d\n", type);
+		return;
+	}
+
+	if (type &(TMCB_DESTROY)) {
+		LM_DBG("TMCB_DESTROY called for transaction %u:%u\n", cb_ptr->tindex, cb_ptr->tlabel);
+		_r = cb_ptr->urecord;
+		_e = _r->entry;
+		lock_entry(_e);
+		ptr = _r->transactions;
+		while(ptr) {
+			if ((ptr->tindex == cb_ptr->tindex) && (ptr->tlabel == cb_ptr->tlabel)) {
+				remove_ts_transaction(ptr);
+
+				if (_r->transactions == NULL) {
+					LM_DBG("last transaction for %.*s, removing urecord\n", _r->ruri.len, _r->ruri.s);
+					remove_ts_urecord(_r);
+				}
+				unlock_entry(_e);
+				return;
+			}
+			ptr = ptr->next;
+		}
+		LM_DBG("transaction %u:%u not found\n",ptr->tindex, ptr->tlabel);
+		unlock_entry(_e);
+	} else {
+		LM_DBG("called with uknown type %d\n", type);
+	}
+
+	return;
+}

+ 41 - 0
modules/tsilo/ts_handlers.h

@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2014 Federico Cabiddu ([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 _T_TS_HANDLERS_H
+#define _T_TS_HANDLERS_H
+
+#include "../../modules/tm/t_hooks.h"
+
+/*!
+ * \brief add transaction structure to tm callbacks
+ * \param t current transaction
+ * \param req current sip request
+ * \param tma_t current transaction
+ * \return 0 on success, -1 on failure
+ */
+int ts_set_tm_callbacks(struct cell *t, sip_msg_t *req, ts_transaction_t *ts);
+
+/*
+ *
+ */
+void ts_onreply(struct cell* t, int type, struct tmcb_params *param);
+
+#endif

+ 416 - 0
modules/tsilo/ts_hash.c

@@ -0,0 +1,416 @@
+/*
+ * Copyright (C) 2014 Federico Cabiddu ([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
+ *
+ */
+
+
+/*!
+ * \file
+ * \brief Functions and definitions related to per user transaction indexing and searching
+ * \ingroup tsilo
+ * Module: \ref tsilo
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "../../dprint.h"
+#include "../../ut.h"
+#include "../../hashes.h"
+#include "../../lib/kmi/mi.h"
+#include "ts_hash.h"
+#include "ts_handlers.h"
+
+/*! global transaction table */
+struct ts_table *t_table = 0;
+
+/*!
+ * \brief Destroy a urecord and free memory
+ * \param tma destroyed urecord
+ */
+inline void free_ts_urecord(struct ts_urecord *urecord)
+{
+	LM_DBG("destroying urecord %p\n", urecord);
+	ts_transaction_t* ptr;
+
+	while(urecord->transactions) {
+		ptr = urecord->transactions;
+		urecord->transactions = urecord->transactions->next;
+		free_ts_transaction(ptr);
+	}
+
+	if (urecord->ruri.s) shm_free(urecord->ruri.s);
+
+	shm_free(urecord);
+
+	urecord = 0;
+}
+
+/*!
+ * \brief Initialize the per user transactions table
+ * \param size size of the table
+ * \return 0 on success, -1 on failure
+ */
+int init_ts_table(unsigned int size)
+{
+	unsigned int n;
+	unsigned int i;
+
+	t_table = (struct ts_table*)shm_malloc( sizeof(struct ts_table));
+	if (t_table==0) {
+		LM_ERR("no more shm mem (1)\n");
+		return -1;
+	}
+
+	memset( t_table, 0, sizeof(struct ts_table) );
+
+	t_table->size = size;
+
+	n = (size<MAX_TS_LOCKS)?size:MAX_TS_LOCKS;
+	for(  ; n>=MIN_TS_LOCKS ; n-- ) {
+		t_table->locks = lock_set_alloc(n);
+		if (t_table->locks==0)
+			continue;
+		if (lock_set_init(t_table->locks)==0) {
+			lock_set_dealloc(t_table->locks);
+			t_table->locks = 0;
+			continue;
+		}
+		t_table->locks_no = n;
+		break;
+	}
+
+	if (t_table->locks==0) {
+		LM_ERR("unable to allocted at least %d locks for the hash table\n",
+			MIN_TS_LOCKS);
+		goto error;
+	}
+
+	t_table->entries = (ts_entry_t*)shm_malloc(sizeof(ts_entry_t) * size);
+	if (!t_table->entries) {
+		LM_ERR("no more shm mem (2)\n");
+		goto error;
+	}
+
+	for( i=0 ; i<size; i++ ) {
+		memset( &(t_table->entries[i]), 0, sizeof(struct ts_entry) );
+		t_table->entries[i].next_id = rand() % (3*size);
+		t_table->entries[i].lock_idx = i % t_table->locks_no;
+	}
+
+	return 0;
+error:
+	shm_free( t_table );
+	t_table = NULL;
+	return -1;
+}
+
+/*!
+ * \brief Destroy the per user transaction table
+ */
+void destroy_ts_table(void)
+{
+	struct ts_urecord *ts_u, *l_ts_u;
+	unsigned int i;
+
+	if (t_table==0)
+		return;
+
+	if (t_table->locks) {
+		lock_set_destroy(t_table->locks);
+		lock_set_dealloc(t_table->locks);
+	}
+
+	for( i=0 ; i<t_table->size; i++ ) {
+		ts_u = t_table->entries[i].first;
+		while (ts_u) {
+			l_ts_u = ts_u;
+			ts_u = ts_u->next;
+			free_ts_urecord(l_ts_u);
+		}
+	}
+
+	shm_free(t_table);
+	t_table = 0;
+
+	return;
+}
+
+void lock_entry(ts_entry_t *entry) {
+	ts_lock(t_table, entry);
+}
+
+void unlock_entry(ts_entry_t *entry) {
+	ts_unlock(t_table, entry);
+}
+
+void lock_entry_by_ruri(str* ruri)
+{
+        unsigned int sl;
+
+	sl = core_hash(ruri, 0, 0) & (t_table->size-1);
+	ts_lock(t_table, &t_table->entries[sl]);
+}
+
+void unlock_entry_by_ruri(str* ruri)
+{
+	unsigned int sl;
+
+	sl = core_hash(ruri, 0, 0) & (t_table->size-1);
+	ts_unlock(t_table, &t_table->entries[sl]);
+}
+
+/*
+ * Obtain a urecord pointer if the urecord exists in the table
+ */
+int get_ts_urecord(str* ruri, struct ts_urecord** _r)
+{
+	int sl, i, rurihash;
+	ts_urecord_t* r;
+
+	rurihash = core_hash(ruri, 0, 0);
+	sl = rurihash&(t_table->size-1);
+	r = t_table->entries[sl].first;
+
+	for(i = 0; r!=NULL && i < t_table->entries[sl].n; i++) {
+		if((r->rurihash==rurihash) && (r->ruri.len==ruri->len)
+				&& !memcmp(r->ruri.s,ruri->s,ruri->len)){
+			*_r = r;
+			return 0;
+		}
+		r = r->next;
+	}
+
+	return 1;   /* Nothing found */
+}
+
+/*!
+ * \brief Create and initialize new record structure
+ * \param ruri request uri
+ * \param _r pointer to the new record
+ * \return 0 on success, negative on failure
+ */
+int new_ts_urecord(str* ruri, ts_urecord_t** _r)
+{
+	*_r = (ts_urecord_t*)shm_malloc(sizeof(ts_urecord_t));
+	if (*_r == 0) {
+		LM_ERR("no more share memory\n");
+		return -1;
+	}
+	memset(*_r, 0, sizeof(ts_urecord_t));
+
+	(*_r)->ruri.s = (char*)shm_malloc(ruri->len);
+	if ((*_r)->ruri.s == 0) {
+		LM_ERR("no more share memory\n");
+		shm_free(*_r);
+		*_r = 0;
+		return -2;
+	}
+	memcpy((*_r)->ruri.s, ruri->s, ruri->len);
+	(*_r)->ruri.len = ruri->len;
+	(*_r)->rurihash = core_hash(ruri, 0, 0);
+	return 0;
+}
+
+/*!
+ * \brief Insert a new record into transactions table
+ * \param ruri request uri
+ * \return 0 on success, -1 on failure
+ */
+int insert_ts_urecord(str* ruri, ts_urecord_t** _r)
+{
+	ts_entry_t* entry;
+
+	int sl;
+
+	if (new_ts_urecord(ruri, _r) < 0) {
+		LM_ERR("creating urecord failed\n");
+		return -1;
+	}
+
+	sl = ((*_r)->rurihash)&(t_table->size-1);
+	entry = &t_table->entries[sl];
+
+	if (entry->n == 0) {
+		entry->first = entry->last = *_r;
+	} else {
+		(*_r)->prev = entry->last;
+		entry->last->next = *_r;
+		entry->last = *_r;
+	}
+	entry->n++;
+	(*_r)->entry = entry;
+	LM_DBG("urecord entry %p",entry);
+	return 0;
+}
+
+/*!
+ * \brief remove a urecord from table and free the memory
+ * \param urecord t
+ * \return 0 on success, -1 on failure
+ */
+void remove_ts_urecord(ts_urecord_t* _r)
+{
+	ts_entry_t* entry;
+
+	entry = _r->entry;
+
+	if (_r->prev)
+		_r->prev->next = _r->next;
+	if (_r->next)
+		_r->next->prev = _r->prev;
+
+	/* it was the last urecord */
+	if (entry->n == 1) {
+                entry->first = entry->last = NULL;
+	}
+
+	entry->n--;
+	free_ts_urecord(_r);
+
+        return;
+}
+
+/*!
+ * \brief Insert a new transaction structure into urecord
+ * \param _r urecord
+ * \param tindex transaction index in tm table
+ * \param tlabel transaction label in tm table
+ * \return 0 on success, -1 otherwise
+ */
+int insert_ts_transaction(struct cell* t, struct sip_msg* msg, struct ts_urecord* _r)
+{
+	ts_transaction_t *ptr, *prev;
+        ts_transaction_t* ts;
+
+	unsigned int tindex;
+	unsigned int tlabel;
+
+	tindex = t->hash_index;
+	tlabel = t->label;
+
+	ptr = prev = 0;
+	ptr = _r->transactions;
+
+	while(ptr) {
+		if ((ptr->tindex == tindex) && (ptr->tlabel == tlabel)) {
+			LM_DBG("transaction already inserted\n");
+			return -1;
+		}
+		prev = ptr;
+		ptr = ptr->next;
+	}
+
+	if ( (ts=new_ts_transaction(tindex, tlabel) ) == 0) {
+		LM_ERR("failed to create new contact\n");
+		return -1;
+	}
+
+	ts->urecord = _r;
+	/* add the new transaction at the end of the list */
+
+	if (prev) {
+		prev->next = ts;
+		ts->prev = prev;
+	} else {
+		_r->transactions = ts;
+	}
+
+	if (ts_set_tm_callbacks(t, msg, ts) < 0) {
+		LM_ERR("failed to set transaction %d:%d callbacks\n", tindex, tlabel);
+	}
+	return 0;
+}
+/*!
+ * \brief Create a new transaction structure
+ * \param tindex transaction index in tm table
+ * \param tlabel transaction label in tm table
+ * \return created transaction structure on success, NULL otherwise
+ */
+ts_transaction_t* new_ts_transaction(int tindex, int tlabel)
+{
+	ts_transaction_t *ts;
+	int len;
+
+	len = sizeof(ts_transaction_t);
+	ts = (ts_transaction_t*)shm_malloc(len);
+	if (ts==0) {
+		LM_ERR("no more shm mem (%d)\n",len);
+		return 0;
+	}
+
+	memset(ts, 0, len);
+	ts->tindex = tindex;
+	ts->tlabel = tlabel;
+	return ts;
+}
+
+/*!
+ * \brief Clone a transaction structure
+ * \param ts transaction to be cloned
+ * \return cloned transaction structure on success, NULL otherwise
+ */
+ts_transaction_t* clone_ts_transaction(ts_transaction_t* ts)
+{
+	ts_transaction_t *ts_clone;
+	int len;
+
+	if (ts == NULL)
+		return NULL;
+
+	len = sizeof(ts_transaction_t);
+	ts_clone = (ts_transaction_t*)shm_malloc(len);
+	if (ts_clone==NULL) {
+		LM_ERR("no more shm mem (%d)\n",len);
+		return NULL;
+	}
+
+	memcpy(ts_clone, ts, len);
+	return ts_clone;
+}
+
+/*!
+ * \brief remove a transaction from the urecord transactions list
+ * \param tma unlinked transaction
+ */
+inline void remove_ts_transaction(ts_transaction_t* ts_t)
+{
+	if (ts_t->next)
+		ts_t->next->prev = ts_t->prev;
+	if (ts_t->prev)
+		ts_t->prev->next = ts_t->next;
+
+	if ((ts_t->prev == NULL) && (ts_t->next == NULL))
+		ts_t->urecord->transactions = NULL;
+
+	free_ts_transaction((void*)ts_t);
+
+	return;
+}
+
+
+/*!
+ * \brief Destroy a transaction and free memory
+ * \param tma destroyed transaction
+ */
+inline void free_ts_transaction(void *ts_t)
+{
+	shm_free((struct ts_transaction*)ts_t);
+	ts_t = 0;
+}

+ 179 - 0
modules/tsilo/ts_hash.h

@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2014 Federico Cabiddu, [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
+ *
+ */
+
+/*!
+ * \file
+ * \brief Functions and definitions related to per user transaction indexing and searching
+ * \ingroup tsilo
+ * Module: \ref tsilo
+ */
+
+#ifndef _DIALOG_TS_HASH_H_
+#define _DIALOG_TS_HASH_H_
+
+#include "../../locking.h"
+#include "../../lib/kmi/mi.h"
+#include "../../modules/tm/tm_load.h"
+
+#define MAX_TS_LOCKS  2048
+#define MIN_TS_LOCKS  2
+
+typedef struct ts_transaction
+{
+	unsigned int		tindex;		/*!< transaction index */
+	unsigned int		tlabel;		/*!< transaction label */
+
+	struct ts_urecord	*urecord;	/*!< > urecord entry the transaction belongs to */
+
+	struct ts_transaction	*next;		/*!< next entry in the list */
+	struct ts_transaction	*prev;		/*!< previous entry in the list */
+} ts_transaction_t;
+
+/*! entries in the transaction list */
+typedef struct ts_urecord
+{
+	str		     ruri;		/*!< request uri of the transaction */
+	unsigned int	     rurihash;		/*!< hash request uri of the transaction */
+
+	struct ts_entry     *entry;		/*!< Collision slot in the hash table */
+	ts_transaction_t    *transactions;	/*!< One or more transactions */
+
+	struct ts_urecord   *next;		/*!< next entry in the list */
+	struct ts_urecord   *prev;		/*!< previous entry in the list */
+} ts_urecord_t;
+
+
+/*! entries in the main transaction table */
+typedef struct ts_entry
+{
+	int n;                  	/*!< Number of elements in the collision slot */
+	struct ts_urecord    *first;	/*!< urecord list */
+	struct ts_urecord    *last;	/*!< optimisation, end of the urecord list */
+	unsigned int       next_id;	/*!< next id */
+	unsigned int       lock_idx;	/*!< lock index */
+} ts_entry_t;
+
+
+/*! main transaction table */
+typedef struct ts_table
+{
+	unsigned int       size;	/*!< size of the dialog table */
+	struct ts_entry    *entries;	/*!< urecord hash table */
+	unsigned int       locks_no;	/*!< number of locks */
+	gen_lock_set_t     *locks;	/*!< lock table */
+} ts_table_t;
+
+/*! global dialog table */
+extern ts_table_t *t_table;
+
+/*!
+ * \brief Set a transaction lock
+ * \param _table transaction table
+ * \param _entry locked entry
+ */
+#define ts_lock(_table, _entry) \
+		lock_set_get( (_table)->locks, (_entry)->lock_idx);
+
+/*!
+ * \brief Release a transaction lock
+ * \param _table transaction table
+ * \param _entry locked entry
+ */
+#define ts_unlock(_table, _entry) \
+		lock_set_release( (_table)->locks, (_entry)->lock_idx);
+
+void lock_entry(ts_entry_t *entry);
+void unlock_entry(ts_entry_t *entry);
+
+void lock_entry_by_ruri(str* ruri);
+void unlock_entry_by_ruri(str* ruri);
+
+/*!
+ * \brief Initialize the per user transactions table
+ * \param size size of the table
+ * \return 0 on success, -1 on failure
+ */
+int init_ts_table(unsigned int size);
+
+/*!
+ * \brief Destroy the per user transaction table
+ */
+void destroy_ts_table(void);
+
+/*
+ * Obtain a urecord pointer if the urecord exists in the table
+ */
+int get_ts_urecord(str* ruri, struct ts_urecord** _r);
+
+/*!
+ * \brief Create and initialize new record structure
+ * \param ruri request uri
+ * \param _r pointer to the new record
+ * \return 0 on success, negative on failure
+ */
+int new_ts_urecord(str* ruri, ts_urecord_t** _r);
+
+/*!
+ * \brief Insert a new record into transactions table
+ * \param ruri request uri
+ * \return 0 on success, -1 on failure
+ */
+int insert_ts_urecord(str* ruri, ts_urecord_t** _r);
+
+/*!
+ * \brief remove a urecord from table and free the memory
+ * \param urecord t
+ * \return 0 on success, -1 on failure
+ */
+void remove_ts_urecord(ts_urecord_t* _r);
+
+/*!
+ * \brief Insert a new transaction structure into urecord
+ * \param _r urecord
+ * \param tindex transaction index in tm table
+ * \param tlabel transaction label in tm table
+ * \return 0 on success, -1 otherwise
+ */
+int insert_ts_transaction(struct cell* t, sip_msg_t* msg, struct ts_urecord* _r);
+
+/*!
+ * \brief Create a new transaction structure
+ * \param tindex transaction index in tm table
+ * \param tlabel transaction label in tm table
+ * \return created transaction structure on success, NULL otherwise
+ */
+ts_transaction_t* new_ts_transaction(int tindex, int tlabel);
+
+/*!
+ * \brief Clone a transaction structure
+ * \param tma transaction to be cloned
+ * \return cloned transaction structure on success, NULL otherwise
+ */
+ts_transaction_t* clone_ts_transaction(ts_transaction_t* ts);
+
+/*!
+ * \brief remove a transaction from the urecord transactions list
+ * \param tma unlinked transaction
+ */
+inline void remove_ts_transaction(ts_transaction_t* ts_t);
+
+inline void free_ts_transaction(void *ts_t);
+#endif

+ 226 - 0
modules/tsilo/tsilo.c

@@ -0,0 +1,226 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2014 Federico Cabiddu ([email protected])
+ *
+ * This file is part of SIP-Router.org, a free SIP server.
+ *
+ * SIP-Router 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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "../../sr_module.h"
+#include "../../dprint.h"
+#include "../../mod_fix.h"
+#include "../../route.h"
+#include "../../script_cb.h"
+#include "../../modules/tm/tm_load.h"
+#include "../../modules/registrar/api.h"
+#include "../../dset.h"
+
+#include "ts_hash.h"
+#include "ts_handlers.h"
+#include "t_append.h"
+#include "t_store.h"
+
+MODULE_VERSION
+
+
+/** TM bind **/
+struct tm_binds _tmb;
+/** REGISTRAR bind **/
+registrar_api_t _regapi;
+
+/** parameters */
+static int hash_size = 2048;
+
+/** module functions */
+static int mod_init(void);
+static void destroy(void);
+
+static int w_t_append_to(struct sip_msg* msg, char *idx, char *lbl, char *d);
+static int fixup_t_append_to(void** param, int param_no);
+static int w_t_append(struct sip_msg* _msg, char *_table, char *_ruri);
+static int fixup_t_append(void** param, int param_no);
+
+static int w_t_store(struct sip_msg* msg);
+
+
+static cmd_export_t cmds[]={
+	{"t_append_to", (cmd_function)w_t_append_to,  3,
+		fixup_t_append_to, REQUEST_ROUTE | FAILURE_ROUTE },
+	{"t_append", (cmd_function)w_t_append,  2,
+		fixup_t_append, REQUEST_ROUTE | FAILURE_ROUTE },
+	{"t_store", (cmd_function)w_t_store,  0,
+		0 , REQUEST_ROUTE | FAILURE_ROUTE },
+	{0,0,0,0,0}
+};
+
+static param_export_t params[]={
+	{"hash_size",	INT_PARAM,	&hash_size},
+	{0,0,0}
+};
+
+
+/** module exports */
+struct module_exports exports= {
+	"tsilo",
+	cmds,
+	0, /* RPC methods */
+	params,
+	mod_init,   /* module initialization function */
+	0,
+	(destroy_function) destroy,  /* destroy function */
+	0,
+	0
+};
+
+/**
+ * init module function
+ */
+static int mod_init(void)
+{
+	unsigned int n;
+
+	/* load the TM API */
+	if (load_tm_api(&_tmb)!=0) {
+		LM_ERR("can't load TM API\n");
+		return -1;
+	}
+
+	/* load the REGISTRAR API */
+	if (registrar_load_api(&_regapi) != 0) {
+		LM_ERR("cannot load REGISTRAR API\n");
+		return -1;
+	}
+	/* sanitize hash_size */
+    if (hash_size < 1){
+        LM_WARN("hash_size is smaller "
+				"than 1  -> rounding from %d to 1\n",
+                hash_size);
+        hash_size = 1;
+    }
+
+    /* initialize the hash table */
+    for( n=0 ; n<(8*sizeof(n)) ; n++) {
+        if (hash_size==(1<<n))
+            break;
+        if (n && hash_size<(1<<n)) {
+            LM_WARN("hash_size is not a power "
+                "of 2 as it should be -> rounding from %d to %d (n=%d)\n",
+                hash_size, 1<<(n-1), n);
+            hash_size = 1<<(n-1);
+			break;
+        }
+    }
+
+	LM_DBG("creating table with size %d", hash_size);
+	if ( init_ts_table(hash_size)<0 ) {
+		LM_ERR("failed to create hash table\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+/**
+ * destroy function
+ */
+static void destroy(void)
+{
+	destroy_ts_table();
+	return;
+}
+
+/**
+ *
+ */
+
+static int fixup_t_append_to(void** param, int param_no)
+{
+	if (param_no==1 || param_no==2) {
+		return fixup_igp_null(param, 1);
+	}
+
+	if (param_no==3) {
+		if(strlen((char*)*param)<=1 && (*(char*)(*param)==0 || *(char*)(*param)=='0')) {
+			*param = (void*)0;
+			LM_ERR("empty table name\n");
+			return -1;
+		}
+	}
+	return 0;
+}
+
+static int fixup_t_append(void** param, int param_no)
+{
+	if (param_no==1) {
+		if(strlen((char*)*param)<=1 && (*(char*)(*param)==0 || *(char*)(*param)=='0')) {
+			*param = (void*)0;
+			LM_ERR("empty table name\n");
+			return -1;
+		}
+	}
+
+	if (param_no==2 || param_no==3) {
+		return fixup_spve_null(param, 1);
+	}
+
+	return 0;
+}
+/**
+ *
+ */
+static int w_t_append(struct sip_msg* _msg, char *_table, char *_ruri)
+{
+	str ruri = {0};
+
+	if(_ruri==NULL || (fixup_get_svalue(_msg, (gparam_p)_ruri, &ruri)!=0 || ruri.len<=0)) {
+		LM_ERR("invalid ruri parameter\n");
+		return -1;
+	}
+	return t_append(_msg, &ruri, _table);
+}
+/**
+ *
+ */
+static int w_t_append_to(struct sip_msg* msg, char *idx, char *lbl, char *table)
+{
+	unsigned int tindex;
+	unsigned int tlabel;
+
+	if(fixup_get_ivalue(msg, (gparam_p)idx, (int*)&tindex)<0) {
+		LM_ERR("cannot get transaction index\n");
+		return -1;
+	}
+
+	if(fixup_get_ivalue(msg, (gparam_p)lbl, (int*)&tlabel)<0) {
+		LM_ERR("cannot get transaction label\n");
+		return -1;
+	}
+
+	return t_append_to(msg, tindex, tlabel, table);
+}
+
+/**
+ *
+ */
+static int w_t_store(struct sip_msg* msg)
+{
+	return t_store(msg);
+}

+ 34 - 0
modules/tsilo/tsilo.h

@@ -0,0 +1,34 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2014 Federico Cabiddu ([email protected])
+ *
+ * This file is part of SIP-Router.org, a free SIP server.
+ *
+ * SIP-Router 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 _TM_APPEND_MOD_H_
+#define _TM_APPEND_MOD_H_
+
+#include "../../modules/tm/tm_load.h"
+#include "../../modules/registrar/api.h"
+
+/** TM bind */
+extern struct tm_binds _tmb;
+/** REGISTRAR bind */
+extern registrar_api_t _regapi;
+
+#endif