Hi

the inline patch adds a new module called 'histinfo'. it implements
a subset of the History-Info header as defined in RFC 4244. the main
purpose of the module was to implement the extension of RFC 4244,
defined in draft-rosenberg-sip-target-uri-delivery-00


we would like to commit the module to CVS, but would really like
some input from the SER community first. the module also requires
some changes in the `tm' module which must be reviewed carefully.


summary of changes:

- new module 'histinfo'
- tm module: save current processed branch, export t_get_branch()


I also envision that we can implement full support for RFC 4244
in this module, adding new script functions. This will keep all
history-info related code in one place.


it would be nice if you all could review the script functions:

    histinfo_add_target()  - Append H-I to a SIP request
    histinfo_copy()        - Copy H-I from SIP request to response
    histinfo_add_reply()   - Prepend H-I to a SIP response


comments are welcome!


/alfred

---
--- sip_router-orig/modules/histinfo/histinfo.c 1970-01-01 01:00:00.000000000 
+0100
+++ sip_router/modules/histinfo/histinfo.c      2008-12-08 14:06:04.000000000 
+0100
@@ -0,0 +1,599 @@
+/*
+ * History-Info Module
+ *
+ * Copyright (C) 2008 Alfred E. Heggestad
+ * Copyright (C) 2008 Telio Telecom
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser 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
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [EMAIL PROTECTED]
+ *
+ * ser 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 <stdio.h>
+#include <stdlib.h>
+#include "../../sr_module.h"
+#include "../../mem/mem.h"
+#include "../../data_lump.h"
+#include "../../data_lump_rpl.h"
+#include "../../parser/parse_uri.h"
+#include "../../parser/msg_parser.h"
+#include "../tm/tm_load.h"
+#include "../tm/t_lookup.h"
+
+
+MODULE_VERSION
+#define DBG_PRFX "histinfo: "
+
+/*
+ * Implements an extension to History-Info (RFC 4244)
+ * draft-rosenberg-sip-target-uri-delivery-00
+ *
+ * TODO: implement the complete RFC 4244
+ */
+
+
+#ifndef STR_STATIC_INIT
+#define STR_STATIC_INIT(v) {(v), sizeof((v)) - 1}
+#endif
+
+#ifndef STR_FMT
+#define STR_FMT(_pstr_) \
+       (((_pstr_) != (str *)0) ? (_pstr_)->len : 0),        \
+       (((_pstr_) != (str *)0) ? (_pstr_)->s : "")
+#endif
+
+
+static struct tm_binds tmb;
+static const str str_histinfo = STR_STATIC_INIT("History-Info");
+
+
+/*
+ * Utility functions
+ */
+
+
+/**
+ * Compare two `str' strings and return 1 if match
+ */
+static inline int str_casecmp(const str *a, const str *b)
+{
+       if (!a || !b)
+               return 0;
+
+       if (a->len != b->len)
+               return 0;
+
+       return 0 == strncasecmp(a->s, b->s, a->len);
+}
+
+
+/**
+ * Duplicate a `str' string to a char string, return NULL if fail
+ *
+ * NOTE: returned string is NOT null-terminated!
+ */
+static char *str_dup(const str *str)
+{
+       char *s;
+
+       if (!str)
+               return NULL;
+
+       s = pkg_malloc(str->len);
+       if (!s)
+               return NULL;
+
+       memcpy(s, str->s, str->len);
+       return s;
+}
+
+
+/**
+ * Append a header to the SIP message
+ */
+static int append_hf(struct sip_msg *msg, const str *str1)
+{
+       struct lump *anchor;
+       char *s;
+
+       if (!msg || !str1)
+               return -1;
+
+       if (parse_headers(msg, HDR_EOH_F, 0) == -1) {
+               LOG(L_ERR, "append_hf(): Error while parsing message\n");
+               return -1;
+       }
+
+       anchor = anchor_lump(msg, msg->unparsed - msg->buf, 0, 0);
+       if (anchor == 0) {
+               LOG(L_ERR, "append_hf(): Can't get anchor\n");
+               return -1;
+       }
+
+       s = str_dup(str1);
+       if (!s) {
+               LOG(L_ERR, "append_hf(): No memory left\n");
+               return -1;
+       }
+
+       if (insert_new_lump_before(anchor, s, str1->len, 0) == 0) {
+               LOG(L_ERR, "append_hf(): Can't insert lump\n");
+               pkg_free(s);
+               return -1;
+       }
+       return 1;
+}
+
+
+/**
+ * Prepend a header to a SIP message
+ */
+static int prepend_hf(struct sip_msg *msg, const str *hname, const str *str1)
+{
+       const struct hdr_field *hf;
+       struct lump *l;
+       char *s = NULL;
+
+       if (!msg || !hname || !str1)
+               return -1;
+
+       if (parse_headers(msg, HDR_EOH_F, 0) < 0) {
+               LOG(L_ERR, "prepend_hf(): parse headers EOH failed\n");
+               return -1;
+       }
+
+       /* Find first header */
+       for (hf = msg->headers; hf; hf = hf->next) {
+               if (str_casecmp(&hf->name, hname))
+                       break;
+       }
+
+       if (hf) {
+               /* header found, add ours in front of that */
+               l = anchor_lump(msg, hf->name.s - msg->buf, 0, 0);
+       }
+       else {
+               /* no header found, append to message */
+               l = anchor_lump(msg, msg->unparsed - msg->buf, 0, 0);
+       }
+
+       if (!l) {
+               LOG(L_ERR, "prepend_hf(): no anchor found\n");
+               goto err;
+       }
+
+       s = str_dup(str1);
+       if (!s) {
+               LOG(L_ERR, "prepend_hf(): No memory left\n");
+               goto err;
+       }
+
+       if (insert_new_lump_before(l, s, str1->len, 0) == 0) {
+               LOG(L_ERR, "prepend_hf(): Can't insert lump\n");
+               goto err;
+       }
+
+       return 1;
+
+ err:
+       if (s)
+               pkg_free(s);
+
+       return -1;
+}
+
+
+/**
+ * Check if the header-field exist in a SIP message
+ */
+static int hf_exist(struct sip_msg *msg, const str *str_hf)
+{
+       struct hdr_field *hf;
+
+       if (!msg || !str_hf)
+               return 0;
+
+       /* we need to be sure we have seen all HFs */
+       parse_headers(msg, HDR_EOH_F, 0);
+
+       for (hf=msg->headers; hf; hf=hf->next) {
+
+               if (str_casecmp(&hf->name, str_hf))
+                       return 1;
+       }
+
+       return 0;
+}
+
+
+/**
+ * Copy all `hdr' headers from SIP Message src to dst
+ */
+static void cpy_hfs(struct sip_msg *dst, struct sip_msg *src, const str *hdr)
+{
+       const struct hdr_field *hf;
+       str tmp_str;
+
+       if (!dst || !src)
+               return;
+
+       if (parse_headers(src, HDR_EOH_F, 0) < 0) {
+               LOG(L_ERR, DBG_PRFX "parse_headers() failed\n");
+               return;
+       }
+
+       /* Copy all History-Info headers from request to response */
+       for (hf=src->headers; hf; hf=hf->next) {
+
+               if (!str_casecmp(&hf->name, hdr))
+                       continue;
+
+               tmp_str.s   = hf->name.s;
+               tmp_str.len = hf->len;
+
+               /* FIXME this is inefficient */
+               if (append_hf(dst, &tmp_str) < 0) {
+                       LOG(L_ERR, DBG_PRFX "append_hf() failed\n");
+               }
+       }
+}
+
+
+/**
+ * Make a History-Info header, return length or <0 if fail
+ */
+static int hi_mk(char *buf, int sz, const str *ouri,
+                const struct sip_uri *iuri, int branch)
+{
+       int l;
+
+       if (!buf || !sz || !ouri || !iuri || branch < 0)
+               return -1;
+
+       l = snprintf(buf, sz, "%.*s: <sip:[EMAIL PROTECTED]>;target;index=1,"
+                    " <%.*s>;target;index=1.%d\r\n", STR_FMT(&str_histinfo),
+                    STR_FMT(&iuri->user), STR_FMT(&iuri->host),
+                    STR_FMT(ouri), branch+1);
+       if (l < 0) {
+               LOG(L_ERR, DBG_PRFX "hi_mk: snprintf() failed %d\n", l);
+               return -1;
+       }
+       buf[sz-1] = '\0';
+
+       return l;
+}
+
+
+/**
+ * Append a History-Info header to a SIP message
+ */
+static int hi_append(struct sip_msg *msg, const str *ouri,
+                    const struct sip_uri *iuri, int branch)
+{
+       char s[512];
+       str h = {s, 0};
+
+       h.len = hi_mk(s, sizeof(s), ouri, iuri, branch);
+       if (h.len < 0) {
+               LOG(L_ERR, DBG_PRFX "hi_append: hi_mk() failed\n");
+               return -1;
+       }
+
+       if (append_hf(msg, &h) < 0) {
+               LOG(L_ERR, DBG_PRFX "hi_append: append_hf() failed\n");
+               return -1;
+       }
+
+       return 1;
+}
+
+
+/**
+ * Prepend a History-Info header to a SIP message
+ */
+static int hi_prepend(struct sip_msg *msg, const str *ouri,
+                    const struct sip_uri *iuri, int branch)
+{
+       char s[512];
+       str h = {s, 0};
+
+       h.len = hi_mk(s, sizeof(s), ouri, iuri, branch);
+       if (h.len < 0) {
+               LOG(L_ERR, DBG_PRFX "hi_append: hi_mk() failed\n");
+               return -1;
+       }
+
+       if (prepend_hf(msg, &str_histinfo, &h) < 0) {
+               LOG(L_ERR, DBG_PRFX "hi_prepend: append_hf() failed\n");
+               return -1;
+       }
+
+       return 1;
+}
+
+
+/**
+ * Find the outgoing request for the corresponding transaction/branch
+ *
+ * NOTE: request is allocated and must be free'd
+ */
+static struct sip_msg *find_uac_request(const struct cell *t, int branch)
+{
+       const struct retr_buf *rbuf;
+       struct sip_msg *req = NULL;
+
+       rbuf = &t->uac[branch].request;
+
+       req = pkg_malloc(sizeof(*req));
+       if (!req)
+               return NULL;
+
+       memset(req, 0, sizeof(*req));
+       req->buf = rbuf->buffer;
+       req->len = rbuf->buffer_len;
+
+       if (parse_msg(rbuf->buffer, rbuf->buffer_len, req) != 0){
+               LOG(L_ERR, DBG_PRFX "find_request: parse_msg() failed\n");
+               goto err;
+       }
+
+       return req;
+
+ err:
+       if (req) {
+               free_sip_msg(req);
+               pkg_free(req);
+       }
+       return NULL;
+}
+
+
+#if 0
+static void print_uris(const char *prfx, struct sip_msg *msg)
+{
+       const struct sip_uri *iuri;
+       const str *ouri;
+
+       /* Get the outgoing-ruri */
+       ouri = GET_RURI(msg);
+
+       if (parse_orig_ruri(msg) < 0)
+               return;
+
+       /* Get the incoming-ruri */
+       iuri = &msg->parsed_orig_ruri;
+
+       printf(" %s: iuri=<[EMAIL PROTECTED]>\n", prfx,
+              STR_FMT(&iuri->user), STR_FMT(&iuri->host));
+
+       printf(" %s: ouri=<%.*s>\n", prfx, STR_FMT(ouri));
+
+       if (SIP_REQUEST == msg->first_line.type) {
+               printf(" %s: request_uri=<%.*s>\n", prfx,
+                      STR_FMT(&msg->first_line.u.request.uri));
+       }
+}
+#endif
+
+
+/*
+ * Module functions
+ */
+
+
+static int mod_init(void)
+{
+       load_tm_f load_tm;
+
+       /* import the TM auto-loading function */
+       load_tm = (load_tm_f)find_export("load_tm", NO_SCRIPT, 0);
+       if (!load_tm) {
+               LOG(L_ERR, DBG_PRFX "ERROR: mod_init: can't import load_tm\n");
+               return -1;
+       }
+       /* let the auto-loading function load all TM stuff */
+       if (load_tm(&tmb) == -1)
+               return -1;
+
+       return 0;
+}
+
+
+static void mod_destroy(void)
+{
+}
+
+
+/**
+ * Append History-Info headers with target info to SIP Request
+ *
+ * Both forms are valid:
+ *
+ *    History-Info: <sip:incoming-ruri>;target;index=1,
+ *                  <sip:outgoing-ruri>;target;index=1.1
+ *
+ *    History-Info: <sip:incoming-ruri>;target;index=1
+ *    History-Info: <sip:outgoing-ruri>;target;index=1.1
+ */
+static int hi_add_trg(struct sip_msg *req, char *p1, char *p2)
+{
+       const str *ouri;
+       const struct sip_uri *iuri;
+       int branch;
+
+       /* Get branch */
+       branch = tmb.t_get_branch();
+       if (branch < 0) {
+               LOG(L_ERR, DBG_PRFX "hi_add_trg: invalid branch %d\n", branch);
+               return -1;
+       }
+
+       /* Get the outgoing-ruri */
+       ouri = GET_RURI(req);
+
+       /* We need to find the original Request URI */
+       if (parse_orig_ruri(req) < 0) {
+               LOG(L_ERR, DBG_PRFX "parse_orig_ruri() failed\n");
+               return -1;
+       }
+
+       /* Get the incoming-ruri */
+       iuri = &req->parsed_orig_ruri;
+
+       LOG(L_INFO, DBG_PRFX "Request: iuri=<[EMAIL PROTECTED]> ouri=<%.*s>\n",
+           STR_FMT(&iuri->user), STR_FMT(&iuri->host), STR_FMT(ouri));
+
+       if (hi_append(req, ouri, iuri, branch) < 0) {
+               LOG(L_ERR, DBG_PRFX "hi_append() failed\n");
+               return -1;
+       }
+
+       /* returns >0 if ok , <0 on error, 0 to stop processing (==DROP) */
+       return 1;
+}
+
+
+/**
+ * Copy History-Info from SIP Request to SIP Response, if not present
+ * in the SIP Response.
+ */
+static int hi_copy_trg(struct sip_msg *resp, char *p1, char *p2)
+{
+       struct cell *t;
+       struct sip_msg *req = NULL;
+       int branch;
+
+       /* Skip if already present in SIP Response */
+       if (hf_exist(resp, &str_histinfo))
+               return 1;
+
+       /* Get transaction */
+       t = tmb.t_gett();
+       if (!t)
+               goto out;
+
+       /* Get branch */
+       branch = tmb.t_get_branch();
+       if (branch < 0) {
+               LOG(L_ERR, DBG_PRFX "hi_copy_trg: invalid branch %d\n",
+                   branch);
+               goto out;
+       }
+
+       LOG(L_INFO, DBG_PRFX "Response: %u branch %d\n",
+           resp->first_line.u.reply.statuscode, branch);
+
+       req = find_uac_request(t, branch);
+       if (!req)
+               goto out;
+
+       cpy_hfs(resp, req, &str_histinfo);
+
+ out:
+       if (req) {
+               free_sip_msg(req);
+               pkg_free(req);
+       }
+
+       return 1;
+}
+
+
+/**
+ * Add History-Info header to a final SIP Response
+ */
+static int hi_add_reply(struct sip_msg *resp, char *p1, char *p2)
+{
+       struct cell *t;
+       struct sip_msg *req_uac = NULL, *req_uas = NULL;
+       const struct sip_uri *iuri;
+       const str *ouri;
+       int branch;
+
+       /* Get transaction */
+       t = tmb.t_gett();
+       if (!t) {
+               LOG(L_ERR, DBG_PRFX "add_reply: could not get transaction\n");
+               goto out;
+       }
+
+       /* Get branch */
+       branch = tmb.t_get_branch();
+       if (branch < 0) {
+               LOG(L_ERR, DBG_PRFX "add_reply: invalid branch %d\n", branch);
+               goto out;
+       }
+
+       /* Get the incoming-ruri from the UAS Request */
+       req_uas = t->uas.request;
+       if (parse_orig_ruri(req_uas) < 0) {
+               LOG(L_ERR, DBG_PRFX "add_reply: parse_orig_ruri() failed\n");
+               goto out;
+       }
+       iuri = &req_uas->parsed_orig_ruri;
+
+       /* Find corresponding outgoing UAC request */
+       req_uac = find_uac_request(t, branch);
+       if (!req_uac) {
+               LOG(L_ERR, DBG_PRFX "add_reply: could not find uac request\n");
+       }
+       ouri = GET_RURI(req_uac);
+
+       /* Prepend History-Info header to 200 OK response */
+
+       LOG(L_INFO, DBG_PRFX "add_reply: branch %d: iuri=<[EMAIL PROTECTED]>"
+           " ouri=<%.*s>\n", branch, STR_FMT(&iuri->user),
+           STR_FMT(&iuri->host), STR_FMT(ouri));
+
+       if (hi_prepend(resp, ouri, iuri, branch) < 0) {
+               LOG(L_ERR, DBG_PRFX "add_reply: hi_append() failed\n");
+               goto out;
+       }
+
+ out:
+       if (req_uac) {
+               free_sip_msg(req_uac);
+               pkg_free(req_uac);
+       }
+
+       /* returns >0 if ok , <0 on error, 0 to stop processing (==DROP) */
+       return 1;
+}
+
+
+static cmd_export_t cmds[] = {
+       {"histinfo_add_target", hi_add_trg,   0, 0, REQUEST_ROUTE},
+       {"histinfo_copy",       hi_copy_trg,  0, 0, ONREPLY_ROUTE},
+       {"histinfo_add_reply",  hi_add_reply, 0, 0, ONREPLY_ROUTE},
+       {}
+};
+
+struct module_exports exports = {
+       "histinfo",
+       cmds,
+       NULL,
+       NULL,
+       mod_init,
+       0,
+       mod_destroy,
+       0,
+       0
+};
diff -Naur --exclude ip_set_rpc.c --exclude lex.yy.c --exclude ser-oob.cfg -X /home/alfredh/svn/.priv/exclude sip_router-orig/modules/histinfo/Makefile sip_router/modules/histinfo/Makefile
--- sip_router-orig/modules/histinfo/Makefile   1970-01-01 01:00:00.000000000 
+0100
+++ sip_router/modules/histinfo/Makefile        2008-12-08 13:35:17.000000000 
+0100
@@ -0,0 +1,7 @@
+include ../../Makefile.defs
+
+auto_gen=
+NAME=histinfo.so
+LIBS=
+
+include ../../Makefile.modules
diff -Naur --exclude ip_set_rpc.c --exclude lex.yy.c --exclude ser-oob.cfg -X /home/alfredh/svn/.priv/exclude sip_router-orig/modules/histinfo/README sip_router/modules/histinfo/README
--- sip_router-orig/modules/histinfo/README     1970-01-01 01:00:00.000000000 
+0100
+++ sip_router/modules/histinfo/README  2008-12-08 13:56:26.000000000 +0100
@@ -0,0 +1,63 @@
+histinfo module
+---------------
+
+        *** NOTE NOTE NOTE! This module is in development ***
+
+
+This module implements an extension of History-Info as defined in RFC 4244.
+It also implements an extension called `target' which is currently
+loosely defined here:
+
+    draft-rosenberg-sip-target-uri-delivery-00
+
+
+The module can be used to add information in the signalling path about
+which final target, in call scenarios like call forwarding and other
+retargetting services.
+
+
+The format of the History-Info header is as follows:
+
+    History-Info: <sip:incoming-ruri>;target;index=1,
+                  <sip:outgoing-ruri>;target;index=1.1
+
+If the function histinfo_add_reply() is invoked from the onreply_route[]
+it will prepend this header to the response. The incoming-uri means the
+original request-uri coming in to the proxy, and the outgoing-uri means
+the outgoing request-uri after the messages has been proxied.
+
+
+------------------------------------------------------------------------------
+Example ser.cfg:
+
+
+route {
+
+       # Call forwarding from B -> C
+       if (uri =~ "sip:b") {
+
+               # Must be called to set onreply_route   
+               t_on_reply("1");
+
+               # Set RETARGET flag
+               setflag(7);
+
+               rewriteuri("sip:[EMAIL PROTECTED]");
+
+               route(1);
+               break;
+       }
+}
+
+
+onreply_route[1]
+{
+       if (status =~ "2[0-9][0-9]") {
+
+               # Prepend History-Info header to response
+               if (isflagset(7)) {
+                       histinfo_add_reply();
+               }
+       }
+}
+------------------------------------------------------------------------------
diff -Naur --exclude ip_set_rpc.c --exclude lex.yy.c --exclude ser-oob.cfg -X /home/alfredh/svn/.priv/exclude sip_router-orig/modules/histinfo/ser.cfg sip_router/modules/histinfo/ser.cfg
--- sip_router-orig/modules/histinfo/ser.cfg    1970-01-01 01:00:00.000000000 
+0100
+++ sip_router/modules/histinfo/ser.cfg 2008-12-08 13:35:17.000000000 +0100
@@ -0,0 +1,218 @@
+#
+# $Id: ser.cfg,v 1.1.1.1 2005/09/08 08:25:03 janakj Exp $
+#
+# simple quick-start config script
+#
+
+# ----------- global configuration parameters ------------------------
+
+listen=127.0.0.1
+#debug=3         # debug level (cmd line: -dddddddddd)
+#fork=yes
+#log_stderror=no       # (cmd line: -E)
+
+/* Uncomment these lines to enter debugging mode
+fork=no
+log_stderror=yes
+*/
+
+check_via=no   # (cmd. line: -v)
+dns=no           # (cmd. line: -r)
+rev_dns=no      # (cmd. line: -R)
+#port=5060
+#children=4
+fifo="/tmp/ser_fifo"
+
+# ------------------ module loading ----------------------------------
+
+# Uncomment this if you want to use SQL database
+#loadmodule "/usr/local/lib/ser/modules/mysql.so"
+
+loadmodule "/usr/lib/ser/modules/sl.so"
+loadmodule "/usr/lib/ser/modules/tm.so"
+loadmodule "/usr/lib/ser/modules/rr.so"
+loadmodule "/usr/lib/ser/modules/maxfwd.so"
+loadmodule "/usr/lib/ser/modules/usrloc.so"
+loadmodule "/usr/lib/ser/modules/registrar.so"
+loadmodule "/usr/lib/ser/modules/textops.so"
+loadmodule "/usr/lib/ser/modules/xlog.so"
+loadmodule "/usr/lib/ser/modules/histinfo.so"
+
+# Uncomment this if you want digest authentication
+# mysql.so must be loaded !
+#loadmodule "/usr/local/lib/ser/modules/auth.so"
+#loadmodule "/usr/local/lib/ser/modules/auth_db.so"
+
+# ----------------- setting module-specific parameters ---------------
+
+# -- usrloc params --
+
+modparam("usrloc", "db_mode",   0)
+
+# Uncomment this if you want to use SQL database
+# for persistent storage and comment the previous line
+#modparam("usrloc", "db_mode", 2)
+
+# -- auth params --
+# Uncomment if you are using auth module
+#
+#modparam("auth_db", "calculate_ha1", yes)
+#
+# If you set "calculate_ha1" parameter to yes (which true in this config),
+# uncomment also the following parameter)
+#
+#modparam("auth_db", "password_column", "password")
+
+# -- rr params --
+# add value to ;lr param to make some broken UAs happy
+modparam("rr", "enable_full_lr", 1)
+
+# -------------------------  request routing logic -------------------
+
+# main routing logic
+
+route{
+
+       # initial sanity checks -- messages with
+       # max_forwards==0, or excessively long requests
+       if (!mf_process_maxfwd_header("10")) {
+               sl_send_reply("483","Too Many Hops");
+               break;
+       };
+       if (msg:len >=  2048 ) {
+               sl_send_reply("513", "Message too big");
+               break;
+       };
+
+       #
+       # XXX: This section is only for testing of histinfo module
+       #
+       if (method == "INVITE") {
+
+               # Must be called to set onreply_route   
+               t_on_reply("1");
+
+               #
+               # Fork X to E and F
+               #
+               if (uri =~ "sip:x") {
+                       xlog("L_NOTICE", "redirect X -> E and F\n");
+
+                       # Set RETARGET flag
+                       setflag(7);
+
+                       rewriteuri("sip:[EMAIL PROTECTED]");
+                       append_branch();
+
+                       rewriteuri("sip:[EMAIL PROTECTED]");
+                       append_branch();
+
+                       route(1);
+                       break;
+               }
+
+               #
+               # Test one level of retargetting
+               #
+               if (uri =~ "sip:c") {
+                       xlog("L_NOTICE", "redirect C -> B\n");
+
+                       # Set RETARGET flag
+                       setflag(7);
+
+                       rewriteuri("sip:[EMAIL PROTECTED]");
+
+                       route(1);
+                       break;
+               }
+
+               #
+               # Test two levels of nested retargetting (D -> C -> B)
+               #
+               if (uri =~ "sip:d") {
+                       xlog("L_NOTICE", "redirect D -> C\n");
+
+                       # Set RETARGET flag
+                       setflag(7);
+
+                       rewriteuri("sip:[EMAIL PROTECTED]");
+
+                       route(1);
+                       break;
+               }
+       }
+
+       # we record-route all messages -- to make sure that
+       # subsequent messages will go through our proxy; that's
+       # particularly good if upstream and downstream entities
+       # use different transport protocol
+       if (!method=="REGISTER") record_route();      
+
+       # subsequent messages withing a dialog should take the
+       # path determined by record-routing
+       if (loose_route()) {
+               # mark routing logic in request
+               append_hf("P-hint: rr-enforced\r\n");
+               route(1);
+               break;
+       };
+
+       if (!uri==myself) {
+               # mark routing logic in request
+               append_hf("P-hint: outbound\r\n");
+               route(1);
+               break;
+       };
+
+       # if the request is for other domain use UsrLoc
+       # (in case, it does not work, use the following command
+       # with proper names and addresses in it)
+       if (uri==myself) {
+
+               if (method=="REGISTER") {
+
+# Uncomment this if you want to use digest authentication
+#                      if (!www_authorize("iptel.org", "subscriber")) {
+#                              www_challenge("iptel.org", "0");
+#                              break;
+#                      };
+
+                       save("location");
+                       break;
+               };
+
+               lookup("aliases");
+               if (!uri==myself) {
+                       append_hf("P-hint: outbound alias\r\n");
+                       route(1);
+                       break;
+               };
+
+               # native SIP destinations are handled using our USRLOC DB
+               if (!lookup("location")) {
+                       sl_send_reply("404", "Not Found");
+                       break;
+               };
+       };
+       append_hf("P-hint: usrloc applied\r\n");
+       route(1);
+}
+
+route[1]
+{
+       # send it out now; use stateful forwarding as it works reliably
+       # even for UDP2TCP
+       if (!t_relay()) {
+               sl_reply_error();
+       };
+}
+
+onreply_route[1]
+{
+       if (status =~ "2[0-9][0-9]") {
+
+               if (isflagset(7)) {
+                       histinfo_add_reply();
+               }
+       }
+}
diff -Naur --exclude ip_set_rpc.c --exclude lex.yy.c --exclude ser-oob.cfg -X /home/alfredh/svn/.priv/exclude sip_router-orig/modules/tm/t_lookup.c sip_router/modules/tm/t_lookup.c
--- sip_router-orig/modules/tm/t_lookup.c       2008-03-31 18:26:08.000000000 
+0200
+++ sip_router/modules/tm/t_lookup.c    2008-12-08 13:35:17.000000000 +0100
@@ -173,7 +173,10 @@
 */
 unsigned int     global_msg_id;

-
+/* For reply processing, we may need the branch as well and thus store
+ * it in a global variable, too.
+ */
+static int global_branch;

 struct cell *get_t() { return T; }
 void set_t(struct cell *t) { T=t; }
@@ -1026,7 +1029,6 @@
  */
 int t_check( struct sip_msg* p_msg , int *param_branch )
 {
-       int local_branch;
        int canceled;

        /* is T still up-to-date ? */
@@ -1089,8 +1091,7 @@
                                        }
                        }

-                       t_reply_matching( p_msg ,
-                               param_branch!=0?param_branch:&local_branch );
+           t_reply_matching (p_msg, &global_branch);

                }
 #ifdef EXTRA_DEBUG
@@ -1109,7 +1110,18 @@
                        DBG("DEBUG: t_check: T previously sought and not 
found\n");
        }

-       return T ? (T==T_UNDEFINED ? -1 : 1 ) : 0;
+       if (T == NULL) {
+               return 0;
+       }
+       else if (T == T_UNDEFINED) {
+               return -1;
+       }
+       else {
+               if (param_branch != NULL) {
+                       *param_branch = global_branch;
+               }
+               return 1;
+       }
 }

 int init_rb( struct retr_buf *rb, struct sip_msg *msg)
@@ -1262,6 +1274,7 @@
 #endif
        insert_into_hash_table_unsafe( new_cell, p_msg->hash_index );
        set_t(new_cell);
+       global_branch = -1;
 #ifndef TM_DEL_UNREF
        INIT_REF_UNSAFE(T);
 #endif
@@ -1789,3 +1802,8 @@
        return 1;
 }

+
+int t_get_branch(void)
+{
+       return global_branch;
+}
diff -Naur --exclude ip_set_rpc.c --exclude lex.yy.c --exclude ser-oob.cfg -X /home/alfredh/svn/.priv/exclude sip_router-orig/modules/tm/t_lookup.h sip_router/modules/tm/t_lookup.h
--- sip_router-orig/modules/tm/t_lookup.h       2008-03-31 20:19:50.000000000 
+0200
+++ sip_router/modules/tm/t_lookup.h    2008-12-08 13:35:17.000000000 +0100
@@ -118,4 +118,7 @@
                unsigned int *hash_index, unsigned int *label);
 #endif /* WITH_AS_SUPPORT */

+typedef int (*t_get_branch_f)(void);
+int t_get_branch(void);
+
 #endif
diff -Naur --exclude ip_set_rpc.c --exclude lex.yy.c --exclude ser-oob.cfg -X 
/home/alfredh/svn/.priv/exclude sip_router-orig/modules/tm/tm.c 
sip_router/modules/tm/tm.c
--- sip_router-orig/modules/tm/tm.c     2008-11-10 13:47:02.000000000 +0100
+++ sip_router/modules/tm/tm.c  2008-12-08 13:35:17.000000000 +0100
@@ -402,6 +402,7 @@
 #endif
        {"t_suspend",          (cmd_function)t_suspend,         NO_SCRIPT,   0, 
0},
        {"t_continue",         (cmd_function)t_continue,        NO_SCRIPT,   0, 
0},
+       {"t_get_branch",       (cmd_function)t_get_branch,      NO_SCRIPT,   0, 
0},
        {0,0,0,0,0}
 };

diff -Naur --exclude ip_set_rpc.c --exclude lex.yy.c --exclude ser-oob.cfg -X /home/alfredh/svn/.priv/exclude sip_router-orig/modules/tm/tm_load.c sip_router/modules/tm/tm_load.c
--- sip_router-orig/modules/tm/tm_load.c        2008-11-10 13:47:02.000000000 
+0100
+++ sip_router/modules/tm/tm_load.c     2008-12-08 13:35:17.000000000 +0100
@@ -226,5 +226,10 @@
                LOG( L_ERR, LOAD_ERROR "'t_continue' not found\n");
                return -1;
        }
+       if (! (tmb->t_get_branch=(t_get_branch_f)find_export("t_get_branch",
+                                                            NO_SCRIPT,0))) {
+               LOG( L_ERR, LOAD_ERROR "'t_get_branch' not found\n");
+               return -1;
+       }
        return 1;
 }
diff -Naur --exclude ip_set_rpc.c --exclude lex.yy.c --exclude ser-oob.cfg -X /home/alfredh/svn/.priv/exclude sip_router-orig/modules/tm/tm_load.h sip_router/modules/tm/tm_load.h
--- sip_router-orig/modules/tm/tm_load.h        2008-11-10 13:47:02.000000000 
+0100
+++ sip_router/modules/tm/tm_load.h     2008-12-08 13:35:17.000000000 +0100
@@ -132,6 +132,7 @@
 #endif
        t_suspend_f     t_suspend;
        t_continue_f    t_continue;
+       t_get_branch_f  t_get_branch;
 };

 extern int tm_init;
_______________________________________________
Serdev mailing list
[email protected]
http://lists.iptel.org/mailman/listinfo/serdev

Reply via email to