Przeglądaj źródła

msrp: added internal map table to track msrp connections

- initial version
- the table can be enabled via config parameters
Daniel-Constantin Mierla 12 lat temu
rodzic
commit
ea3cacb10d

+ 3 - 0
modules/msrp/Makefile

@@ -9,4 +9,7 @@ LIBS=
 
 DEFS+=-DKAMAILIO_MOD_INTERFACE
 
+SERLIBPATH=../../lib
+SER_LIBS+=$(SERLIBPATH)/srutils/srutils
+
 include ../../Makefile.modules

+ 131 - 24
modules/msrp/README

@@ -16,7 +16,7 @@ Alex Balashov
 
    <[email protected]>
 
-   Copyright © 2012 asipto.com
+   Copyright © 2012 asipto.com
      __________________________________________________________________
 
    Table of Contents
@@ -32,6 +32,10 @@ Alex Balashov
         3. Parameters
 
               3.1. sipmsg (int)
+              3.2. cmap_size (int)
+              3.3. timer_interval (int)
+              3.4. auth_min_expires (int)
+              3.5. auth_max_expires (int)
 
         4. Functions
 
@@ -42,6 +46,8 @@ Alex Balashov
               4.5. msrp_set_dst(addr, sock)
               4.6. msrp_relay_flags(flags)
               4.7. msrp_reply_flags(flags)
+              4.8. msrp_cmap_save()
+              4.9. msrp_cmap_lookup()
 
         5. Pseudo Variables
         6. Event Routes
@@ -50,14 +56,20 @@ Alex Balashov
    List of Examples
 
    1.1. Set sipmsg parameter
-   1.2. msrp usage
-   1.3. msrp_reply usage
-   1.4. msrp_is_request usage
-   1.5. msrp_is_reply usage
-   1.6. msrp_set_dst usage
-   1.7. msrp_relay_flags usage
-   1.8. msrp_reply_flags usage
-   1.9. Event Route
+   1.2. Set cmap_size parameter
+   1.3. Set timer_interval parameter
+   1.4. Set auth_min_expires parameter
+   1.5. Set auth_max_expires parameter
+   1.6. msrp usage
+   1.7. msrp_reply usage
+   1.8. msrp_is_request usage
+   1.9. msrp_is_reply usage
+   1.10. msrp_set_dst usage
+   1.11. msrp_relay_flags usage
+   1.12. msrp_reply_flags usage
+   1.13. msrp_cmap_save usage
+   1.14. msrp_cmap_lookup usage
+   1.15. Event Route
 
 Chapter 1. Admin Guide
 
@@ -72,6 +84,10 @@ Chapter 1. Admin Guide
    3. Parameters
 
         3.1. sipmsg (int)
+        3.2. cmap_size (int)
+        3.3. timer_interval (int)
+        3.4. auth_min_expires (int)
+        3.5. auth_max_expires (int)
 
    4. Functions
 
@@ -82,6 +98,8 @@ Chapter 1. Admin Guide
         4.5. msrp_set_dst(addr, sock)
         4.6. msrp_relay_flags(flags)
         4.7. msrp_reply_flags(flags)
+        4.8. msrp_cmap_save()
+        4.9. msrp_cmap_lookup()
 
    5. Pseudo Variables
    6. Event Routes
@@ -137,6 +155,10 @@ Chapter 1. Admin Guide
 3. Parameters
 
    3.1. sipmsg (int)
+   3.2. cmap_size (int)
+   3.3. timer_interval (int)
+   3.4. auth_min_expires (int)
+   3.5. auth_max_expires (int)
 
 3.1. sipmsg (int)
 
@@ -152,6 +174,52 @@ Chapter 1. Admin Guide
 modparam("msrp", "sipmsg", 1)
 ...
 
+3.2. cmap_size (int)
+
+   The size of connection map table, to be computed as power of 2 (e.g.,
+   if the value is 4, then the number of slots in map table is 2^4 = 16).
+
+   Default value is '0' (no internal map table to be used).
+
+   Example 1.2. Set cmap_size parameter
+...
+modparam("msrp", "cmap_size", 8)
+...
+
+3.3. timer_interval (int)
+
+   The timer interval in seconds to run the procedure for cleaning expired
+   connections.
+
+   Default value is '60'.
+
+   Example 1.3. Set timer_interval parameter
+...
+modparam("msrp", "timer_interval", 90)
+...
+
+3.4. auth_min_expires (int)
+
+   The minimum value accepted for Expires header in AUTH requests.
+
+   Default value is '60'.
+
+   Example 1.4. Set auth_min_expires parameter
+...
+modparam("msrp", "auth_min_expiresl", 90)
+...
+
+3.5. auth_max_expires (int)
+
+   The maximum value accepted for Expires header in AUTH requests.
+
+   Default value is '3600'.
+
+   Example 1.5. Set auth_max_expires parameter
+...
+modparam("msrp", "auth_max_expiresl", 1800)
+...
+
 4. Functions
 
    4.1. msrp_relay()
@@ -161,8 +229,10 @@ modparam("msrp", "sipmsg", 1)
    4.5. msrp_set_dst(addr, sock)
    4.6. msrp_relay_flags(flags)
    4.7. msrp_reply_flags(flags)
+   4.8. msrp_cmap_save()
+   4.9. msrp_cmap_lookup()
 
-4.1.  msrp_relay()
+4.1. msrp_relay()
 
    Relay MSRP frame according to the To-Path. This function has to be
    executed for each MSRP request or reply that has to be forwarded. Note
@@ -171,14 +241,14 @@ modparam("msrp", "sipmsg", 1)
 
    This function can be used in ANY_ROUTE.
 
-   Example 1.2. msrp usage
+   Example 1.6. msrp usage
 ...
 event_route[msrp:frame-in] {
     msrp_relay();
 }
 ...
 
-4.2.  msrp_reply(code, text [, hdrs])
+4.2. msrp_reply(code, text [, hdrs])
 
    Send a reply for the current MSRP request, adding optional headers.
 
@@ -186,20 +256,20 @@ event_route[msrp:frame-in] {
 
    This function can be used in ANY_ROUTE.
 
-   Example 1.3. msrp_reply usage
+   Example 1.7. msrp_reply usage
 ...
 event_route[msrp:frame-in] {
     msrp_reply("403", "Not allowed");
 }
 ...
 
-4.3.  msrp_is_request()
+4.3. msrp_is_request()
 
    Return true if the MSRP frame is a request.
 
    This function can be used in ANY_ROUTE.
 
-   Example 1.4. msrp_is_request usage
+   Example 1.8. msrp_is_request usage
 ...
 event_route[msrp:frame-in] {
     if(msrp_is_request())
@@ -210,13 +280,13 @@ event_route[msrp:frame-in] {
 }
 ...
 
-4.4.  msrp_is_reply()
+4.4. msrp_is_reply()
 
    Return true if the MSRP frame is a reply.
 
    This function can be used in ANY_ROUTE.
 
-   Example 1.5. msrp_is_reply usage
+   Example 1.9. msrp_is_reply usage
 ...
 event_route[msrp:frame-in] {
     if(msrp_is_reply())
@@ -227,7 +297,7 @@ event_route[msrp:frame-in] {
 }
 ...
 
-4.5.  msrp_set_dst(addr, sock)
+4.5. msrp_set_dst(addr, sock)
 
    Set destination attributes: addr - target address as MSRP URI; sock -
    local socket to be used (format 'proto:ip:port').
@@ -236,7 +306,7 @@ event_route[msrp:frame-in] {
 
    This function can be used in ANY_ROUTE.
 
-   Example 1.6. msrp_set_dst usage
+   Example 1.10. msrp_set_dst usage
 ...
 event_route[msrp:frame-in] {
     ...
@@ -245,7 +315,7 @@ event_route[msrp:frame-in] {
 }
 ...
 
-4.6.  msrp_relay_flags(flags)
+4.6. msrp_relay_flags(flags)
 
    Set transport layer sending flags for forwarding current MSRP frame;
    flags - a bitmask of flags - 1 (don't create a new connection), 2
@@ -255,7 +325,7 @@ event_route[msrp:frame-in] {
 
    This function can be used in ANY_ROUTE.
 
-   Example 1.7. msrp_relay_flags usage
+   Example 1.11. msrp_relay_flags usage
 ...
 event_route[msrp:frame-in] {
     ...
@@ -264,7 +334,7 @@ event_route[msrp:frame-in] {
 }
 ...
 
-4.7.  msrp_reply_flags(flags)
+4.7. msrp_reply_flags(flags)
 
    Set transport layer sending flags for replies to the current MSRP
    frame; flags - a bitmask of flags - 1 (don't create a new connection),
@@ -274,7 +344,7 @@ event_route[msrp:frame-in] {
 
    This function can be used in ANY_ROUTE.
 
-   Example 1.8. msrp_reply_flags usage
+   Example 1.12. msrp_reply_flags usage
 ...
 event_route[msrp:frame-in] {
     ...
@@ -283,6 +353,43 @@ event_route[msrp:frame-in] {
 }
 ...
 
+4.8. msrp_cmap_save()
+
+   Save details of a MSRP connection upon AUTH request inside the internal
+   map table, indexed by session id.
+
+   This function can be used in ANY_ROUTE.
+
+   Example 1.13. msrp_cmap_save usage
+...
+event_route[msrp:frame-in] {
+    ...
+        if(metod=="AUTH") { msrp_cmap_save(); exit; }
+    ...
+}
+...
+
+4.9. msrp_cmap_lookup()
+
+   Lookup MSRP connection details for current session id.
+
+   This function can be used in ANY_ROUTE.
+
+   Example 1.14. msrp_cmap_lookup usage
+...
+event_route[msrp:frame-in] {
+    ...
+        if(metod=="SEND" and $msrp(nexthops)==1) {
+                if(msrp_cmap_lookup()) {
+                        msrp_relay();
+                } else {
+                        msrp_reply("481", "Session not found");
+                }
+        }
+    ...
+}
+...
+
 5. Pseudo Variables
 
    The module exports a pseudo-variable class, $msrp(key), to access the
@@ -362,7 +469,7 @@ Content-Type: text/plain
    Next is an example of configuration file with the routing block for
    MSRP frames. In this config, the SIP traffic is rejected.
 
-   Example 1.9. Event Route
+   Example 1.15. Event Route
 ...
 
 #!KAMAILIO

+ 133 - 0
modules/msrp/doc/msrp_admin.xml

@@ -102,6 +102,84 @@
 ...
 modparam("msrp", "sipmsg", 1)
 ...
+</programlisting>
+		</example>
+	</section>
+	<section>
+		<title><varname>cmap_size</varname> (int)</title>
+		<para>
+		The size of connection map table, to be computed as power of 2 (e.g.,
+		if the value is 4, then the number of slots in map table is 2^4 = 16).
+		</para>
+		<para>
+		<emphasis>
+			Default value is '0' (no internal map table to be used).
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>cmap_size</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("msrp", "cmap_size", 8)
+...
+</programlisting>
+		</example>
+	</section>
+	<section>
+		<title><varname>timer_interval</varname> (int)</title>
+		<para>
+		The timer interval in seconds to run the procedure for cleaning
+		expired connections.
+		</para>
+		<para>
+		<emphasis>
+			Default value is '60'.
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>timer_interval</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("msrp", "timer_interval", 90)
+...
+</programlisting>
+		</example>
+	</section>
+	<section>
+		<title><varname>auth_min_expires</varname> (int)</title>
+		<para>
+		The minimum value accepted for Expires header in AUTH requests.
+		</para>
+		<para>
+		<emphasis>
+			Default value is '60'.
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>auth_min_expires</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("msrp", "auth_min_expiresl", 90)
+...
+</programlisting>
+		</example>
+	</section>
+	<section>
+		<title><varname>auth_max_expires</varname> (int)</title>
+		<para>
+		The maximum value accepted for Expires header in AUTH requests.
+		</para>
+		<para>
+		<emphasis>
+			Default value is '3600'.
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>auth_max_expires</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("msrp", "auth_max_expiresl", 1800)
+...
 </programlisting>
 		</example>
 	</section>
@@ -299,6 +377,61 @@ event_route[msrp:frame-in] {
 	    </example>
 	</section>
 
+	<section>
+	    <title>
+		<function moreinfo="none">msrp_cmap_save()</function>
+	    </title>
+	    <para>
+		Save details of a MSRP connection upon AUTH request inside
+		the internal map table, indexed by session id.
+		</para>
+		<para>
+		This function can be used in ANY_ROUTE.
+		</para>
+		<example>
+		<title><function>msrp_cmap_save</function> usage</title>
+		<programlisting format="linespecific">
+...
+event_route[msrp:frame-in] {
+    ...
+	if(metod=="AUTH") { msrp_cmap_save(); exit; }
+    ...
+}
+...
+</programlisting>
+	    </example>
+	</section>
+
+	<section>
+	    <title>
+		<function moreinfo="none">msrp_cmap_lookup()</function>
+	    </title>
+	    <para>
+		Lookup MSRP connection details for current session id.
+		</para>
+		<para>
+		This function can be used in ANY_ROUTE.
+		</para>
+		<example>
+		<title><function>msrp_cmap_lookup</function> usage</title>
+		<programlisting format="linespecific">
+...
+event_route[msrp:frame-in] {
+    ...
+	if(metod=="SEND" and $msrp(nexthops)==1) {
+		if(msrp_cmap_lookup()) {
+			msrp_relay();
+		} else {
+			msrp_reply("481", "Session not found");
+		}
+	}
+    ...
+}
+...
+</programlisting>
+	    </example>
+	</section>
+
 	</section>
 
 	<section>

+ 405 - 0
modules/msrp/msrp_cmap.c

@@ -0,0 +1,405 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Daniel-Constantin Mierla (asipto.com)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file 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
+ *
+ *
+ * This file 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "../../mem/shm_mem.h"
+#include "../../mem/mem.h"
+#include "../../dprint.h"
+#include "../../hashes.h"
+#include "../../ut.h"
+
+#include "../../lib/srutils/sruid.h"
+
+#include "msrp_netio.h"
+#include "msrp_env.h"
+#include "msrp_cmap.h"
+
+static msrp_cmap_t *_msrp_cmap_head = NULL;
+
+static sruid_t _msrp_sruid;
+
+extern int msrp_auth_min_expires;
+extern int msrp_auth_max_expires;
+
+/**
+ *
+ */
+int msrp_sruid_init(void)
+{
+	return sruid_init(&_msrp_sruid, '-', "msrp", SRUID_INC);
+}
+
+/**
+ *
+ */
+int msrp_citem_free(msrp_citem_t *it)
+{
+	if(it==NULL)
+		return -1;
+	shm_free(it);
+	return 0;
+}
+
+/**
+ *
+ */
+int msrp_cmap_init(int msize)
+{
+	int i;
+
+	_msrp_cmap_head = (msrp_cmap_t*)shm_malloc(sizeof(msrp_cmap_t));
+	if(_msrp_cmap_head==NULL)
+	{
+		LM_ERR("no more shm\n");
+		return -1;
+	}
+	memset(_msrp_cmap_head, 0, sizeof(msrp_cmap_t));
+	_msrp_cmap_head->mapsize = msize;
+
+	_msrp_cmap_head->cslots = (msrp_centry_t*)shm_malloc(
+							_msrp_cmap_head->mapsize*sizeof(msrp_centry_t) );
+	if(_msrp_cmap_head->cslots==NULL)
+	{
+		LM_ERR("no more shm.\n");
+		shm_free(_msrp_cmap_head);
+		_msrp_cmap_head = NULL;
+		return -1;
+	}
+	memset(_msrp_cmap_head->cslots, 0,
+						_msrp_cmap_head->mapsize*sizeof(msrp_centry_t));
+
+	for(i=0; i<_msrp_cmap_head->mapsize; i++)
+	{
+		if(lock_init(&_msrp_cmap_head->cslots[i].lock)==0)
+		{
+			LM_ERR("cannot initalize lock[%d]\n", i);
+			i--;
+			while(i>=0)
+			{
+				lock_destroy(&_msrp_cmap_head->cslots[i].lock);
+				i--;
+			}
+			shm_free(_msrp_cmap_head->cslots);
+			shm_free(_msrp_cmap_head);
+			_msrp_cmap_head = NULL;
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ *
+ */
+int msrp_cmap_destroy(void)
+{
+	int i;
+	msrp_citem_t *ita, *itb;
+
+	if(_msrp_cmap_head==NULL)
+		return -1;
+
+	for(i=0; i<_msrp_cmap_head->mapsize; i++)
+	{
+		/* free entries */
+		ita = _msrp_cmap_head->cslots[i].first;
+		while(ita)
+		{
+			itb = ita;
+			ita = ita->next;
+			msrp_citem_free(itb);
+		}
+		/* free locks */
+		lock_destroy(&_msrp_cmap_head->cslots[i].lock);
+	}
+	shm_free(_msrp_cmap_head->cslots);
+	shm_free(_msrp_cmap_head);
+	_msrp_cmap_head = NULL;
+	return 0;
+}
+
+#define msrp_get_hashid(_s)        core_case_hash(_s,0,0)
+#define msrp_get_slot(_h, _size)    (_h)&((_size)-1)
+
+
+static str msrp_reply_200_code = {"200", 3};
+static str msrp_reply_200_text = {"OK", 2};
+static str msrp_reply_423_code = {"423", 3};
+static str msrp_reply_423_text = {"Interval Out Of Bounds", 22};
+
+/**
+ *
+ */
+int msrp_cmap_save(msrp_frame_t *mf)
+{
+	unsigned int idx;
+	unsigned int hid;
+	str fpeer;
+#define MSRP_SBUF_SIZE	256
+	char sbuf[MSRP_SBUF_SIZE];
+	str srcaddr;
+	str srcsock;
+	int msize;
+	int expires;
+	msrp_citem_t *it;
+	msrp_citem_t *itb;
+
+	if(_msrp_cmap_head==NULL || mf==NULL)
+		return -1;
+	if(mf->fline.rtypeid!=MSRP_REQ_AUTH)
+	{
+		LM_DBG("save can be used only for AUTH\n");
+		return -2;
+	}
+
+	if(msrp_frame_get_expires(mf, &expires)<0)
+		expires = msrp_auth_max_expires;
+	if(expires<msrp_auth_min_expires)
+	{
+		LM_DBG("expires is lower than min value\n");
+		srcaddr.len = snprintf(sbuf, MSRP_SBUF_SIZE, "Min-Expires: %d\r\n",
+				msrp_auth_min_expires);
+		msrp_reply(mf, &msrp_reply_423_code, &msrp_reply_423_text,
+				&srcaddr);
+		return -3;
+	}
+	if(expires>msrp_auth_max_expires)
+	{
+		LM_DBG("expires is greater than max value\n");
+		srcaddr.len = snprintf(sbuf, MSRP_SBUF_SIZE, "Max-Expires: %d\r\n",
+				msrp_auth_max_expires);
+		msrp_reply(mf, &msrp_reply_423_code, &msrp_reply_423_text,
+				&srcaddr);
+		return -4;
+	}
+	if(msrp_frame_get_first_from_path(mf, &fpeer)<0)
+	{
+		LM_ERR("cannot get first path uri\n");
+		return -1;
+	}
+
+	if(sruid_next(&_msrp_sruid)<0)
+	{
+		LM_ERR("cannot get next msrp uid\n");
+		return -1;
+	}
+	hid = msrp_get_hashid(&_msrp_sruid.uid);	
+	idx = msrp_get_slot(hid, _msrp_cmap_head->mapsize);
+
+	srcaddr.s = sbuf;;
+	if(mf->tcpinfo->rcv->proto==PROTO_TLS)
+	{
+		memcpy(srcaddr.s, "msrps://", 8);
+		srcaddr.s+=8;
+	} else {
+		memcpy(srcaddr.s, "msrp://", 7);
+		srcaddr.s+=7;
+	}
+	strcpy(srcaddr.s, ip_addr2a(&mf->tcpinfo->rcv->src_ip));
+	strcat(srcaddr.s, ":");
+	strcat(srcaddr.s, int2str(mf->tcpinfo->rcv->src_port, NULL));
+	srcaddr.s = sbuf;
+	srcaddr.len = strlen(srcaddr.s);
+	srcsock = mf->tcpinfo->rcv->bind_address->sock_str;
+	LM_DBG("saving connection info for [%.*s] [%.*s] (%u/%u)\n",
+			fpeer.len, fpeer.s, _msrp_sruid.uid.len, _msrp_sruid.uid.s,
+			idx, hid);
+	LM_DBG("frame received from [%.*s] via [%.*s]\n",
+			srcaddr.len, srcaddr.s, srcsock.len, srcsock.s);
+
+	msize = sizeof(msrp_citem_t) + (_msrp_sruid.uid.len
+			+ fpeer.len + srcaddr.len + srcsock.len + 4)*sizeof(char);
+
+	/* build the item */
+	it = (msrp_citem_t*)shm_malloc(msize);
+	if(it==NULL)
+	{
+		LM_ERR("no more shm\n");
+		return -1;
+	}
+	memset(it, 0, msize);
+	it->citemid = hid;
+
+	it->sessionid.s = (char*)it +  + sizeof(msrp_citem_t);
+	it->sessionid.len = _msrp_sruid.uid.len;
+	memcpy(it->sessionid.s, _msrp_sruid.uid.s, _msrp_sruid.uid.len);
+	it->sessionid.s[it->sessionid.len] = '\0';
+
+	it->peer.s = it->sessionid.s + it->sessionid.len + 1;
+	it->peer.len = fpeer.len;
+	memcpy(it->peer.s, fpeer.s, fpeer.len);
+	it->peer.s[it->peer.len] = '\0';
+
+	it->addr.s = it->peer.s + it->peer.len + 1;
+	it->addr.len = srcaddr.len;
+	memcpy(it->addr.s, srcaddr.s, srcaddr.len);
+	it->addr.s[it->addr.len] = '\0';
+
+	it->sock.s = it->addr.s + it->addr.len + 1;
+	it->sock.len = srcsock.len;
+	memcpy(it->sock.s, srcsock.s, srcsock.len);
+	it->sock.s[it->sock.len] = '\0';
+
+	it->expires = time(NULL) + expires;
+	it->conid = mf->tcpinfo->con->id;
+
+	/* insert item in cmap */
+	lock_get(&_msrp_cmap_head->cslots[idx].lock);
+	if(_msrp_cmap_head->cslots[idx].first==NULL) {
+		_msrp_cmap_head->cslots[idx].first = it;
+	} else {
+		for(itb=_msrp_cmap_head->cslots[idx].first; itb; itb=itb->next)
+		{
+			if(itb->citemid>it->citemid || itb->next==NULL) {
+				if(itb->next==NULL) {
+					itb->next=it;
+					it->prev = itb;
+				} else {
+					it->next = itb;
+					if(itb->prev==NULL) {
+						_msrp_cmap_head->cslots[idx].first = it;
+					} else {
+						itb->prev->next = it;
+					}
+					it->prev = itb->prev;
+					itb->prev = it;
+				}
+				break;
+			}
+		}
+	}
+	_msrp_cmap_head->cslots[idx].lsize++;
+	lock_release(&_msrp_cmap_head->cslots[idx].lock);
+
+	if(mf->tcpinfo->rcv->proto==PROTO_TLS)
+	{
+		srcaddr.len = snprintf(sbuf, MSRP_SBUF_SIZE,
+				"Use-Path: msrps://%.*s/%.*s;tcp\r\nExpires: %d\r\n",
+				srcsock.len-4, srcsock.s+4,
+				_msrp_sruid.uid.len, _msrp_sruid.uid.s,
+				expires);
+	} else {
+		srcaddr.len = snprintf(sbuf, MSRP_SBUF_SIZE,
+				"Use-Path: msrp://%.*s/%.*s;tcp\r\nExpires: %d\r\n",
+				srcsock.len-4, srcsock.s+4,
+				_msrp_sruid.uid.len, _msrp_sruid.uid.s,
+				expires);
+	}
+	srcaddr.s = sbuf;
+
+	if(msrp_reply(mf, &msrp_reply_200_code, &msrp_reply_200_text,
+				&srcaddr)<0)
+		return -5;
+	return 0;
+}
+
+/**
+ *
+ */
+int msrp_cmap_lookup(msrp_frame_t *mf)
+{
+	unsigned int idx;
+	unsigned int hid;
+	str sesid;
+	msrp_citem_t *itb;
+	int ret;
+
+	if(_msrp_cmap_head==NULL || mf==NULL)
+		return -1;
+	if(mf->fline.rtypeid==MSRP_REQ_AUTH)
+	{
+		LM_DBG("save cannot be used for AUTH\n");
+		return -2;
+	}
+	if(msrp_frame_get_sessionid(mf, &sesid)<0)
+	{
+		LM_ERR("cannot get session id\n");
+		return -3;
+	}
+
+	LM_DBG("searching for session [%.*s]\n", sesid.len, sesid.s);
+
+	hid = msrp_get_hashid(&sesid);	
+	idx = msrp_get_slot(hid, _msrp_cmap_head->mapsize);
+
+	ret = 0;
+	lock_get(&_msrp_cmap_head->cslots[idx].lock);
+	for(itb=_msrp_cmap_head->cslots[idx].first; itb; itb=itb->next)
+	{
+		if(itb->citemid>hid) {
+			break;
+		}
+		if(itb->citemid>hid) {
+			if(itb->sessionid.len == sesid.len
+					&& memcmp(itb->sessionid.s, sesid.s, sesid.len)==0) {
+				LM_DBG("found session [%.*s]\n", sesid.len, sesid.s);
+				ret = msrp_env_set_dstinfo(mf, &itb->addr, &itb->sock, 0);
+				break;
+			}
+		}
+	}
+	lock_release(&_msrp_cmap_head->cslots[idx].lock);
+	if(itb==NULL)
+		return -4;
+	return (ret<0)?-5:0;
+}
+
+/**
+ *
+ */
+int msrp_cmap_clean(void)
+{
+	time_t tnow;
+	msrp_citem_t *ita;
+	msrp_citem_t *itb;
+	int i;
+
+	if(_msrp_cmap_head==NULL)
+		return -1;
+	tnow = time(NULL);
+	for(i=0; i<_msrp_cmap_head->mapsize; i++)
+	{
+		lock_get(&_msrp_cmap_head->cslots[i].lock);
+		ita = _msrp_cmap_head->cslots[i].first;
+		while(ita)
+		{
+			itb = ita;
+			ita = ita->next;
+			if(itb->expires<tnow) {
+				if(itb->prev==NULL) {
+					_msrp_cmap_head->cslots[i].first = itb->next;
+				} else {
+					itb->prev->next = ita;
+				}
+				if(ita!=NULL)
+					ita->prev = itb->prev;
+				msrp_citem_free(itb);
+				_msrp_cmap_head->cslots[i].lsize--;
+			}
+		}
+		lock_release(&_msrp_cmap_head->cslots[i].lock);
+	}
+
+	return 0;
+}

+ 73 - 0
modules/msrp/msrp_cmap.h

@@ -0,0 +1,73 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Daniel-Constantin Mierla (asipto.com)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file 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
+ *
+ *
+ * This file 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef _MSRP_CMAP_H_
+#define _MSRP_CMAP_H_
+
+#include <time.h>
+
+#include "../../str.h"
+#include "../../locking.h"
+
+#include "msrp_parser.h"
+
+typedef struct _msrp_citem
+{
+    unsigned int citemid;
+	str sessionid;
+	str peer;
+	str addr;
+	str sock;
+	int conid;
+	int cflags;
+	time_t  expires;
+    struct _msrp_citem *prev;
+    struct _msrp_citem *next;
+} msrp_citem_t;
+
+typedef struct _msrp_centry
+{
+	unsigned int lsize;
+	msrp_citem_t *first;
+	gen_lock_t lock;	
+} msrp_centry_t;
+
+typedef struct _msrp_cmap
+{
+	unsigned int mapexpire;
+	unsigned int mapsize;
+	msrp_centry_t *cslots;
+	struct _msrp_cmap *next;
+} msrp_cmap_t;
+
+int msrp_cmap_init(int msize);
+int msrp_cmap_destroy(void);
+int msrp_cmap_clean(void);
+
+int msrp_cmap_save(msrp_frame_t *mf);
+int msrp_cmap_lookup(msrp_frame_t *mf);
+
+int msrp_sruid_init(void);
+
+#endif

+ 1 - 0
modules/msrp/msrp_env.h

@@ -25,6 +25,7 @@
 #ifndef _MSRP_ENV_H_
 #define _MSRP_ENV_H_
 
+#include "../../parser/msg_parser.h"
 #include "msrp_parser.h"
 
 #define MSRP_ENV_SRCINFO	(1<<0)

+ 94 - 10
modules/msrp/msrp_mod.c

@@ -36,11 +36,13 @@
 #include "../../events.h"
 #include "../../tcp_conn.h"
 #include "../../pvar.h"
+#include "../../timer_proc.h" /* register_sync_timer */
 
 #include "msrp_parser.h"
 #include "msrp_netio.h"
 #include "msrp_vars.h"
 #include "msrp_env.h"
+#include "msrp_cmap.h"
 
 MODULE_VERSION
 
@@ -56,8 +58,16 @@ static int w_msrp_is_reply(sip_msg_t* msg, char* str1, char* str2);
 static int w_msrp_set_dst(sip_msg_t* msg, char* taddr, char* fsock);
 static int w_msrp_relay_flags(sip_msg_t* msg, char *tflags, char* str2);
 static int w_msrp_reply_flags(sip_msg_t* msg, char *tflags, char* str2);
+static int w_msrp_cmap_save(sip_msg_t* msg, char* str1, char* str2);
+static int w_msrp_cmap_lookup(sip_msg_t* msg, char* str1, char* str2);
+
+static void msrp_local_timer(unsigned int ticks, void* param); /*!< Local timer handler */
 
 int msrp_param_sipmsg = 1;
+int msrp_cmap_size = 0;
+int msrp_auth_min_expires = 60;
+int msrp_auth_max_expires = 3600;
+int msrp_timer_interval = 60;
 
 static int msrp_frame_received(void *data);
 sip_msg_t *msrp_fake_sipmsg(msrp_frame_t *mf);
@@ -83,21 +93,29 @@ static cmd_export_t cmds[]={
 		0, ANY_ROUTE},
 	{"msrp_reply", (cmd_function)w_msrp_reply3, 3, fixup_spve_all,
 		0, ANY_ROUTE},
-	{"msrp_is_request", (cmd_function)w_msrp_is_request, 0, 0,
+	{"msrp_is_request",  (cmd_function)w_msrp_is_request, 0, 0,
 		0, ANY_ROUTE},
-	{"msrp_is_reply", (cmd_function)w_msrp_is_reply, 0, 0,
+	{"msrp_is_reply",    (cmd_function)w_msrp_is_reply, 0, 0,
 		0, ANY_ROUTE},
-	{"msrp_set_dst", (cmd_function)w_msrp_set_dst, 2, fixup_spve_all,
+	{"msrp_set_dst",     (cmd_function)w_msrp_set_dst, 2, fixup_spve_all,
 		0, ANY_ROUTE},
 	{"msrp_relay_flags", (cmd_function)w_msrp_relay_flags, 1, fixup_igp_null,
 		0, ANY_ROUTE},
 	{"msrp_reply_flags", (cmd_function)w_msrp_reply_flags, 1, fixup_igp_null,
 		0, ANY_ROUTE},
+	{"msrp_cmap_save",   (cmd_function)w_msrp_cmap_save, 0, 0,
+		0, ANY_ROUTE},
+	{"msrp_cmap_lookup", (cmd_function)w_msrp_cmap_lookup, 0, 0,
+		0, ANY_ROUTE},
 	{0, 0, 0, 0, 0, 0}
 };
 
 static param_export_t params[]={
-	{"sipmsg",     INT_PARAM,   &msrp_param_sipmsg},
+	{"sipmsg",            INT_PARAM,   &msrp_param_sipmsg},
+	{"cmap_size",         INT_PARAM,   &msrp_cmap_size},
+	{"auth_min_expires",  INT_PARAM,   &msrp_auth_min_expires},
+	{"auth_max_expires",  INT_PARAM,   &msrp_auth_max_expires},
+	{"timer_interval",    INT_PARAM,   &msrp_timer_interval},
 	{0, 0, 0}
 };
 
@@ -123,6 +141,22 @@ struct module_exports exports = {
  */
 static int mod_init(void)
 {
+	if(msrp_sruid_init()<0) {
+		LM_ERR("cannot init msrp uid\n");
+		return -1;
+	}
+
+	if(msrp_cmap_size>0) {
+		if(msrp_cmap_size>16)
+			msrp_cmap_size = 16;
+		if(msrp_cmap_init(1<<msrp_cmap_size)<0) {
+			LM_ERR("Cannot init internal cmap\n");
+			return -1;
+		}
+		if(msrp_timer_interval<=0)
+			msrp_timer_interval = 60;
+		register_sync_timers(1);
+	}
 	sr_event_register_cb(SREV_TCP_MSRP_FRAME, msrp_frame_received);
 	return 0;
 }
@@ -132,8 +166,20 @@ static int mod_init(void)
  */
 static int child_init(int rank)
 {
+	if(msrp_sruid_init()<0) {
+		LM_ERR("cannot init msrp uid\n");
+		return -1;
+	}
+
 	if (rank!=PROC_MAIN)
 		return 0;
+	if(msrp_cmap_size>0) {
+		if(fork_sync_timer(PROC_TIMER, "MSRP Timer", 1 /*socks flag*/,
+				msrp_local_timer, NULL, msrp_timer_interval /*sec*/)<0) {
+			LM_ERR("failed to start timer routine as process\n");
+			return -1; /* error */
+		}
+	}
 
 	return 0;
 }
@@ -333,6 +379,42 @@ static int w_msrp_reply_flags(sip_msg_t* msg, char *tflags, char* str2)
 	return ret;
 }
 
+
+/**
+ *
+ */
+static int w_msrp_cmap_save(sip_msg_t* msg, char* str1, char* str2)
+{
+	msrp_frame_t *mf;
+	int ret;
+
+	mf = msrp_get_current_frame();
+	if(mf==NULL)
+		return -1;
+
+	ret = msrp_cmap_save(mf);
+	if(ret==0) ret = 1;
+	return ret;
+}
+
+
+/**
+ *
+ */
+static int w_msrp_cmap_lookup(sip_msg_t* msg, char* str1, char* str2)
+{
+	msrp_frame_t *mf;
+	int ret;
+
+	mf = msrp_get_current_frame();
+	if(mf==NULL)
+		return -1;
+
+	ret = msrp_cmap_lookup(mf);
+	if(ret==0) ret = 1;
+	return ret;
+}
+
 /**
  *
  */
@@ -340,7 +422,6 @@ static int msrp_frame_received(void *data)
 {
 	tcp_event_info_t *tev;
 	static msrp_frame_t mf;
-	msrp_uri_t uri;
 	sip_msg_t *fmsg;
 	struct run_act_ctx ctx;
 	int rtb, rt;
@@ -385,10 +466,13 @@ static int msrp_frame_received(void *data)
 	}
 	msrp_reset_env();
 	msrp_destroy_frame(&mf);
-	msrp_parse_uri("msrps://alice.example.com:9892/98cjs;tcp",
-			sizeof("msrps://alice.example.com:9892/98cjs;tcp")-1, &uri);
-	msrp_parse_uri("msrps://[email protected]:9892/98cjs;tcp;a=123",
-			sizeof("msrps://[email protected]:9892/98cjs;tcp;a=123")-1, &uri);
-
 	return 0;
 }
+
+/**
+ *
+ */
+static void msrp_local_timer(unsigned int ticks, void* param)
+{
+	msrp_cmap_clean();
+}

+ 92 - 0
modules/msrp/msrp_parser.c

@@ -60,6 +60,7 @@ static msrp_str_id_t _msrp_htypes[] = {
 	{ str_init("Authorization"),        MSRP_HDR_AUTH },
 	{ str_init("WWW-Authenticate"),     MSRP_HDR_WWWAUTH },
 	{ str_init("Authentication-Info"),  MSRP_HDR_AUTHINFO },
+	{ str_init("Expires"),              MSRP_HDR_EXPIRES },
 	{ {0, 0}, 0}
 };
 
@@ -698,3 +699,94 @@ int msrp_parse_hdr_to_path(msrp_frame_t *mf)
 	return msrp_parse_hdr_uri_list(hdr);
 }
 
+/**
+ *
+ */
+int msrp_parse_hdr_expires(msrp_frame_t *mf)
+{
+	msrp_hdr_t *hdr;
+	str hbody;
+	int expires;
+
+	hdr = msrp_get_hdr_by_id(mf, MSRP_HDR_EXPIRES);
+	if(hdr==NULL)
+		return -1;
+	if(hdr->parsed.flags&MSRP_DATA_SET)
+		return 0;
+	hbody = hdr->body;
+	trim(&hbody);
+	if(str2sint(&hbody, &expires)<0) {
+		LM_ERR("invalid expires value\n");
+		return -1;
+	}
+	hdr->parsed.flags |= MSRP_DATA_SET;
+	hdr->parsed.free_fn = NULL;
+	hdr->parsed.data = (void*)(long)expires;
+
+	return 0;
+}
+
+/**
+ *
+ */
+int msrp_frame_get_first_from_path(msrp_frame_t *mf, str *sres)
+{
+	str s = {0};
+	msrp_hdr_t *hdr;
+	str_array_t *sar;
+
+	if(msrp_parse_hdr_from_path(mf)<0)
+		return -1;
+	hdr = msrp_get_hdr_by_id(mf, MSRP_HDR_FROM_PATH);
+	if(hdr==NULL)
+		return -1;
+	sar = (str_array_t*)hdr->parsed.data;
+	s = sar->list[sar->size-1];
+	trim(&s);
+	*sres = s;
+	return 0;
+}
+
+/**
+ *
+ */
+int msrp_frame_get_expires(msrp_frame_t *mf, int *expires)
+{
+	msrp_hdr_t *hdr;
+
+	if(msrp_parse_hdr_expires(mf)<0)
+		return -1;
+	hdr = msrp_get_hdr_by_id(mf, MSRP_HDR_AUTH);
+	if(hdr==NULL)
+		return -1;
+	*expires = (int)(long)hdr->parsed.data;
+	return 0;
+}
+
+/**
+ *
+ */
+int msrp_frame_get_sessionid(msrp_frame_t *mf, str *sres)
+{
+	str s = {0};
+	msrp_hdr_t *hdr;
+	str_array_t *sar;
+	msrp_uri_t uri;
+
+	if(msrp_parse_hdr_to_path(mf)<0)
+		return -1;
+	hdr = msrp_get_hdr_by_id(mf, MSRP_HDR_TO_PATH);
+	if(hdr==NULL)
+		return -1;
+	sar = (str_array_t*)hdr->parsed.data;
+	s = sar->list[0];
+	trim(&s);
+	if(msrp_parse_uri(s.s, s.len, &uri)<0 || uri.session.len<=0)
+		return -1;
+	s = uri.session;
+	trim(&s);
+	*sres = s;
+
+	return 0;
+}
+

+ 4 - 0
modules/msrp/msrp_parser.h

@@ -89,6 +89,7 @@ int msrp_parse_uri(char *start, int len, msrp_uri_t *uri);
 #define MSRP_HDR_AUTH			9
 #define MSRP_HDR_WWWAUTH		10
 #define MSRP_HDR_AUTHINFO		11
+#define MSRP_HDR_EXPIRES		12
 
 #define MSRP_DATA_SET	1
 
@@ -136,4 +137,7 @@ typedef struct str_array {
 	str *list;
 } str_array_t;
 
+int msrp_frame_get_sessionid(msrp_frame_t *mf, str *sres);
+int msrp_frame_get_first_from_path(msrp_frame_t *mf, str *sres);
+int msrp_frame_get_expires(msrp_frame_t *mf, int *expires);
 #endif