瀏覽代碼

msrp: added internal map table to track msrp connections

- initial version
- the table can be enabled via config parameters
Daniel-Constantin Mierla 12 年之前
父節點
當前提交
ea3cacb10d

+ 3 - 0
modules/msrp/Makefile

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

+ 131 - 24
modules/msrp/README

@@ -16,7 +16,7 @@ Alex Balashov
 
 
    <[email protected]>
    <[email protected]>
 
 
-   Copyright © 2012 asipto.com
+   Copyright © 2012 asipto.com
      __________________________________________________________________
      __________________________________________________________________
 
 
    Table of Contents
    Table of Contents
@@ -32,6 +32,10 @@ Alex Balashov
         3. Parameters
         3. Parameters
 
 
               3.1. sipmsg (int)
               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
         4. Functions
 
 
@@ -42,6 +46,8 @@ Alex Balashov
               4.5. msrp_set_dst(addr, sock)
               4.5. msrp_set_dst(addr, sock)
               4.6. msrp_relay_flags(flags)
               4.6. msrp_relay_flags(flags)
               4.7. msrp_reply_flags(flags)
               4.7. msrp_reply_flags(flags)
+              4.8. msrp_cmap_save()
+              4.9. msrp_cmap_lookup()
 
 
         5. Pseudo Variables
         5. Pseudo Variables
         6. Event Routes
         6. Event Routes
@@ -50,14 +56,20 @@ Alex Balashov
    List of Examples
    List of Examples
 
 
    1.1. Set sipmsg parameter
    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
 Chapter 1. Admin Guide
 
 
@@ -72,6 +84,10 @@ Chapter 1. Admin Guide
    3. Parameters
    3. Parameters
 
 
         3.1. sipmsg (int)
         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
    4. Functions
 
 
@@ -82,6 +98,8 @@ Chapter 1. Admin Guide
         4.5. msrp_set_dst(addr, sock)
         4.5. msrp_set_dst(addr, sock)
         4.6. msrp_relay_flags(flags)
         4.6. msrp_relay_flags(flags)
         4.7. msrp_reply_flags(flags)
         4.7. msrp_reply_flags(flags)
+        4.8. msrp_cmap_save()
+        4.9. msrp_cmap_lookup()
 
 
    5. Pseudo Variables
    5. Pseudo Variables
    6. Event Routes
    6. Event Routes
@@ -137,6 +155,10 @@ Chapter 1. Admin Guide
 3. Parameters
 3. Parameters
 
 
    3.1. sipmsg (int)
    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)
 3.1. sipmsg (int)
 
 
@@ -152,6 +174,52 @@ Chapter 1. Admin Guide
 modparam("msrp", "sipmsg", 1)
 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. Functions
 
 
    4.1. msrp_relay()
    4.1. msrp_relay()
@@ -161,8 +229,10 @@ modparam("msrp", "sipmsg", 1)
    4.5. msrp_set_dst(addr, sock)
    4.5. msrp_set_dst(addr, sock)
    4.6. msrp_relay_flags(flags)
    4.6. msrp_relay_flags(flags)
    4.7. msrp_reply_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
    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
    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.
    This function can be used in ANY_ROUTE.
 
 
-   Example 1.2. msrp usage
+   Example 1.6. msrp usage
 ...
 ...
 event_route[msrp:frame-in] {
 event_route[msrp:frame-in] {
     msrp_relay();
     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.
    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.
    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] {
 event_route[msrp:frame-in] {
     msrp_reply("403", "Not allowed");
     msrp_reply("403", "Not allowed");
 }
 }
 ...
 ...
 
 
-4.3.  msrp_is_request()
+4.3. msrp_is_request()
 
 
    Return true if the MSRP frame is a request.
    Return true if the MSRP frame is a request.
 
 
    This function can be used in ANY_ROUTE.
    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] {
 event_route[msrp:frame-in] {
     if(msrp_is_request())
     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.
    Return true if the MSRP frame is a reply.
 
 
    This function can be used in ANY_ROUTE.
    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] {
 event_route[msrp:frame-in] {
     if(msrp_is_reply())
     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 -
    Set destination attributes: addr - target address as MSRP URI; sock -
    local socket to be used (format 'proto:ip:port').
    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.
    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] {
 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;
    Set transport layer sending flags for forwarding current MSRP frame;
    flags - a bitmask of flags - 1 (don't create a new connection), 2
    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.
    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] {
 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
    Set transport layer sending flags for replies to the current MSRP
    frame; flags - a bitmask of flags - 1 (don't create a new connection),
    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.
    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] {
 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
 5. Pseudo Variables
 
 
    The module exports a pseudo-variable class, $msrp(key), to access the
    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
    Next is an example of configuration file with the routing block for
    MSRP frames. In this config, the SIP traffic is rejected.
    MSRP frames. In this config, the SIP traffic is rejected.
 
 
-   Example 1.9. Event Route
+   Example 1.15. Event Route
 ...
 ...
 
 
 #!KAMAILIO
 #!KAMAILIO

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

@@ -102,6 +102,84 @@
 ...
 ...
 modparam("msrp", "sipmsg", 1)
 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>
 </programlisting>
 		</example>
 		</example>
 	</section>
 	</section>
@@ -299,6 +377,61 @@ event_route[msrp:frame-in] {
 	    </example>
 	    </example>
 	</section>
 	</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>
 
 
 	<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_
 #ifndef _MSRP_ENV_H_
 #define _MSRP_ENV_H_
 #define _MSRP_ENV_H_
 
 
+#include "../../parser/msg_parser.h"
 #include "msrp_parser.h"
 #include "msrp_parser.h"
 
 
 #define MSRP_ENV_SRCINFO	(1<<0)
 #define MSRP_ENV_SRCINFO	(1<<0)

+ 94 - 10
modules/msrp/msrp_mod.c

@@ -36,11 +36,13 @@
 #include "../../events.h"
 #include "../../events.h"
 #include "../../tcp_conn.h"
 #include "../../tcp_conn.h"
 #include "../../pvar.h"
 #include "../../pvar.h"
+#include "../../timer_proc.h" /* register_sync_timer */
 
 
 #include "msrp_parser.h"
 #include "msrp_parser.h"
 #include "msrp_netio.h"
 #include "msrp_netio.h"
 #include "msrp_vars.h"
 #include "msrp_vars.h"
 #include "msrp_env.h"
 #include "msrp_env.h"
+#include "msrp_cmap.h"
 
 
 MODULE_VERSION
 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_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_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_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_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);
 static int msrp_frame_received(void *data);
 sip_msg_t *msrp_fake_sipmsg(msrp_frame_t *mf);
 sip_msg_t *msrp_fake_sipmsg(msrp_frame_t *mf);
@@ -83,21 +93,29 @@ static cmd_export_t cmds[]={
 		0, ANY_ROUTE},
 		0, ANY_ROUTE},
 	{"msrp_reply", (cmd_function)w_msrp_reply3, 3, fixup_spve_all,
 	{"msrp_reply", (cmd_function)w_msrp_reply3, 3, fixup_spve_all,
 		0, ANY_ROUTE},
 		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},
 		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},
 		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},
 		0, ANY_ROUTE},
 	{"msrp_relay_flags", (cmd_function)w_msrp_relay_flags, 1, fixup_igp_null,
 	{"msrp_relay_flags", (cmd_function)w_msrp_relay_flags, 1, fixup_igp_null,
 		0, ANY_ROUTE},
 		0, ANY_ROUTE},
 	{"msrp_reply_flags", (cmd_function)w_msrp_reply_flags, 1, fixup_igp_null,
 	{"msrp_reply_flags", (cmd_function)w_msrp_reply_flags, 1, fixup_igp_null,
 		0, ANY_ROUTE},
 		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}
 	{0, 0, 0, 0, 0, 0}
 };
 };
 
 
 static param_export_t params[]={
 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}
 	{0, 0, 0}
 };
 };
 
 
@@ -123,6 +141,22 @@ struct module_exports exports = {
  */
  */
 static int mod_init(void)
 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);
 	sr_event_register_cb(SREV_TCP_MSRP_FRAME, msrp_frame_received);
 	return 0;
 	return 0;
 }
 }
@@ -132,8 +166,20 @@ static int mod_init(void)
  */
  */
 static int child_init(int rank)
 static int child_init(int rank)
 {
 {
+	if(msrp_sruid_init()<0) {
+		LM_ERR("cannot init msrp uid\n");
+		return -1;
+	}
+
 	if (rank!=PROC_MAIN)
 	if (rank!=PROC_MAIN)
 		return 0;
 		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;
 	return 0;
 }
 }
@@ -333,6 +379,42 @@ static int w_msrp_reply_flags(sip_msg_t* msg, char *tflags, char* str2)
 	return ret;
 	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;
 	tcp_event_info_t *tev;
 	static msrp_frame_t mf;
 	static msrp_frame_t mf;
-	msrp_uri_t uri;
 	sip_msg_t *fmsg;
 	sip_msg_t *fmsg;
 	struct run_act_ctx ctx;
 	struct run_act_ctx ctx;
 	int rtb, rt;
 	int rtb, rt;
@@ -385,10 +466,13 @@ static int msrp_frame_received(void *data)
 	}
 	}
 	msrp_reset_env();
 	msrp_reset_env();
 	msrp_destroy_frame(&mf);
 	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;
 	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("Authorization"),        MSRP_HDR_AUTH },
 	{ str_init("WWW-Authenticate"),     MSRP_HDR_WWWAUTH },
 	{ str_init("WWW-Authenticate"),     MSRP_HDR_WWWAUTH },
 	{ str_init("Authentication-Info"),  MSRP_HDR_AUTHINFO },
 	{ str_init("Authentication-Info"),  MSRP_HDR_AUTHINFO },
+	{ str_init("Expires"),              MSRP_HDR_EXPIRES },
 	{ {0, 0}, 0}
 	{ {0, 0}, 0}
 };
 };
 
 
@@ -698,3 +699,94 @@ int msrp_parse_hdr_to_path(msrp_frame_t *mf)
 	return msrp_parse_hdr_uri_list(hdr);
 	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_AUTH			9
 #define MSRP_HDR_WWWAUTH		10
 #define MSRP_HDR_WWWAUTH		10
 #define MSRP_HDR_AUTHINFO		11
 #define MSRP_HDR_AUTHINFO		11
+#define MSRP_HDR_EXPIRES		12
 
 
 #define MSRP_DATA_SET	1
 #define MSRP_DATA_SET	1
 
 
@@ -136,4 +137,7 @@ typedef struct str_array {
 	str *list;
 	str *list;
 } str_array_t;
 } 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
 #endif