diff --git a/src/core/config.h b/src/core/config.h
index bdc76573653..a891328eb37 100644
--- a/src/core/config.h
+++ b/src/core/config.h
@@ -166,7 +166,7 @@
#define MAX_PRINT_TEXT 256 /*!< max length of the text of fifo 'print' command */
-#define MAX_REDIRECTION_LEN 512 /*!< maximum length of Contact header field in redirection replies */
+#define MAX_REDIRECTION_LEN 4096 /*!< maximum length of Contact header field in redirection replies */
/*! \brief used by FIFO statistics in module to terminate line;
extra whitespaces are used to overwrite remainders of
diff --git a/src/core/dset.c b/src/core/dset.c
index a534366bf6e..1803155206c 100644
--- a/src/core/dset.c
+++ b/src/core/dset.c
@@ -39,6 +39,7 @@
#include "dset.h"
#include "mem/mem.h"
#include "ip_addr.h"
+#include "strutils.h"
#define CONTACT "Contact: "
#define CONTACT_LEN (sizeof(CONTACT) - 1)
@@ -46,9 +47,14 @@
#define CONTACT_DELIM ", "
#define CONTACT_DELIM_LEN (sizeof(CONTACT_DELIM) - 1)
-#define Q_PARAM ">;q="
+#define Q_PARAM ";q="
#define Q_PARAM_LEN (sizeof(Q_PARAM) - 1)
+#define ROUTE_PARAM "?Route="
+#define ROUTE_PARAM_LEN (sizeof(ROUTE_PARAM) - 1)
+
+#define FLAGS_PARAM ";flags="
+#define FLAGS_PARAM_LEN (sizeof(FLAGS_PARAM) - 1)
/*
* Where we store URIs of additional transaction branches
@@ -466,108 +472,144 @@ int append_branch(struct sip_msg* msg, str* uri, str* dst_uri, str* path,
}
-/*
- * Create a Contact header field from the dset
- * array
+/*! \brief
+ * Combines the given elements into a Contact header field
+ * dest = target buffer, will be updated to new position after the printed contact
+ * uri, q = contact elements
+ * end = end of target buffer
+ * Returns 0 on success or -1 on error (buffer is too short)
*/
-char* print_dset(struct sip_msg* msg, int* len)
+static int print_contact_str(char **dest, str *uri, qvalue_t q, str *path, unsigned int flags, char *end, int options)
{
- int cnt, i;
- unsigned int qlen;
- qvalue_t q;
- str uri;
- char* p, *qbuf;
- int crt_branch;
- static char dset[MAX_REDIRECTION_LEN];
+ char *p = *dest;
+ str buf;
- if (msg->new_uri.s) {
- cnt = 1;
- *len = msg->new_uri.len + 1 /*'<'*/;
- if (ruri_q != Q_UNSPECIFIED) {
- *len += Q_PARAM_LEN + len_q(ruri_q);
- } else {
- *len += 1 /*'>'*/;
+ /* uri */
+ if (p + uri->len + 2 > end) {
+ return -1;
+ }
+ *p++ = '<';
+ memcpy(p, uri->s, uri->len);
+ p += uri->len;
+
+ /* uri parameters */
+ /* path vector as route header parameter */
+ if ((options & DS_PATH) && path->len > 0) {
+ if (p + ROUTE_PARAM_LEN + path->len > end) {
+ return -1;
}
- } else {
- cnt = 0;
- *len = 0;
+ memcpy(p, ROUTE_PARAM, ROUTE_PARAM_LEN);
+ p += ROUTE_PARAM_LEN;
+ /* copy escaped path into dest */
+ buf.s = p;
+ buf.len = end - p;
+ if (escape_param(path, &buf) < 0) {
+ return -1;
+ }
+ p += buf.len;
}
- /* backup current branch index to restore it later */
- crt_branch = get_branch_iterator();
+ /* end of uri parameters */
+ *p++ = '>';
- init_branch_iterator();
- while ((uri.s = next_branch(&uri.len, &q, 0, 0, 0, 0, 0, 0, 0))) {
- cnt++;
- *len += uri.len + 1 /*'<'*/;
- if (q != Q_UNSPECIFIED) {
- *len += Q_PARAM_LEN + len_q(q);
- } else {
- *len += 1 /*'>'*/;
+ /* header parameters */
+ /* q value */
+ if (q != Q_UNSPECIFIED) {
+ buf.s = q2str(q, (unsigned int*)&buf.len);
+ if (p + Q_PARAM_LEN + buf.len > end) {
+ return -1;
}
+ memcpy(p, Q_PARAM, Q_PARAM_LEN);
+ p += Q_PARAM_LEN;
+ memcpy(p, buf.s, buf.len);
+ p += buf.len;
}
- if (cnt == 0) return 0;
+ /* branch flags (not SIP standard conformant) */
+ if (options & DS_FLAGS) {
+ buf.s = int2str(flags, &buf.len);
+ if (p + FLAGS_PARAM_LEN + buf.len > end) {
+ return -1;
+ }
+ memcpy(p, FLAGS_PARAM, FLAGS_PARAM_LEN);
+ p += FLAGS_PARAM_LEN;
+ memcpy(p, buf.s, buf.len);
+ p += buf.len;
+ }
- *len += CONTACT_LEN + CRLF_LEN + (cnt - 1) * CONTACT_DELIM_LEN;
+ *dest = p;
+ return 0;
+}
- if (*len + 1 > MAX_REDIRECTION_LEN) {
- LM_ERR("redirection buffer length exceed\n");
- goto error;
- }
- memcpy(dset, CONTACT, CONTACT_LEN);
- p = dset + CONTACT_LEN;
- if (msg->new_uri.s) {
- *p++ = '<';
+/*
+ * Create a Contact header field from the dset
+ * array
+ */
+char* print_dset(struct sip_msg* msg, int* len, int options)
+{
+ int cnt = 0;
+ qvalue_t q;
+ str uri, path;
+ unsigned int flags;
+ char *p;
+ int crt_branch;
+ static char dset[MAX_REDIRECTION_LEN];
+ char *end = dset + MAX_REDIRECTION_LEN;
- memcpy(p, msg->new_uri.s, msg->new_uri.len);
- p += msg->new_uri.len;
+ /* backup current branch index to restore it later */
+ crt_branch = get_branch_iterator();
- if (ruri_q != Q_UNSPECIFIED) {
- memcpy(p, Q_PARAM, Q_PARAM_LEN);
- p += Q_PARAM_LEN;
+ /* contact header name */
+ if (CONTACT_LEN + CRLF_LEN + 1 > MAX_REDIRECTION_LEN) {
+ goto memfail;
+ }
+ memcpy(dset, CONTACT, CONTACT_LEN);
+ p = dset + CONTACT_LEN;
- qbuf = q2str(ruri_q, &qlen);
- memcpy(p, qbuf, qlen);
- p += qlen;
- } else {
- *p++ = '>';
+ /* current uri */
+ if (msg->new_uri.s) {
+ if (print_contact_str(&p, &msg->new_uri, ruri_q, &msg->path_vec, ruri_bflags, end, options) < 0) {
+ goto memfail;
}
- i = 1;
- } else {
- i = 0;
+ cnt++;
}
+ /* branches */
init_branch_iterator();
- while ((uri.s = next_branch(&uri.len, &q, 0, 0, 0, 0, 0, 0, 0))) {
- if (i) {
+ while ((uri.s = next_branch(&uri.len, &q, 0, &path, &flags, 0, 0, 0, 0))) {
+ if (cnt > 0) {
+ if (p + CONTACT_DELIM_LEN > end) {
+ goto memfail;
+ }
memcpy(p, CONTACT_DELIM, CONTACT_DELIM_LEN);
p += CONTACT_DELIM_LEN;
}
- *p++ = '<';
+ if (print_contact_str(&p, &uri, q, &path, flags, end, options) < 0) {
+ goto memfail;
+ }
- memcpy(p, uri.s, uri.len);
- p += uri.len;
- if (q != Q_UNSPECIFIED) {
- memcpy(p, Q_PARAM, Q_PARAM_LEN);
- p += Q_PARAM_LEN;
+ cnt++;
+ }
- qbuf = q2str(q, &qlen);
- memcpy(p, qbuf, qlen);
- p += qlen;
- } else {
- *p++ = '>';
- }
- i++;
+ if (cnt == 0) {
+ LM_WARN("no r-uri or branches\n");
+ goto error;
}
+ if (p + CRLF_LEN + 1 > end) {
+ goto memfail;
+ }
memcpy(p, CRLF " ", CRLF_LEN + 1);
+ *len = p - dset + CRLF_LEN;
set_branch_iterator(crt_branch);
return dset;
+memfail:
+ LM_ERR("redirection buffer length exceed\n");
error:
+ *len = 0;
set_branch_iterator(crt_branch);
return 0;
}
diff --git a/src/core/dset.h b/src/core/dset.h
index 603b2023d19..65b54c31049 100644
--- a/src/core/dset.h
+++ b/src/core/dset.h
@@ -37,6 +37,9 @@
extern unsigned int nr_branches;
extern int ruri_is_new;
+#define DS_FLAGS 1
+#define DS_PATH 2
+
/*! \brief
* Structure for storing branch attributes
*/
@@ -158,7 +161,7 @@ void clear_branches(void);
* Create a Contact header field from the
* list of current branches
*/
-char* print_dset(struct sip_msg* msg, int* len);
+char* print_dset(struct sip_msg* msg, int* len, int options);
/*! \brief
diff --git a/src/core/parser/contact/contact.c b/src/core/parser/contact/contact.c
index 06b85dd5dde..61a40e3bd80 100644
--- a/src/core/parser/contact/contact.c
+++ b/src/core/parser/contact/contact.c
@@ -244,6 +244,7 @@ int parse_contacts(str* _s, contact_t** _c)
c->methods = hooks.contact.methods;
c->instance = hooks.contact.instance;
c->reg_id = hooks.contact.reg_id;
+ c->flags = hooks.contact.flags;
if (_s->len == 0) goto ok;
}
@@ -314,6 +315,7 @@ void print_contacts(FILE* _o, contact_t* _c)
fprintf(_o, "methods : %p\n", ptr->methods);
fprintf(_o, "instance: %p\n", ptr->instance);
fprintf(_o, "reg-id : %p\n", ptr->reg_id);
+ fprintf(_o, "flags : %p\n", ptr->flags);
fprintf(_o, "len : %d\n", ptr->len);
if (ptr->params) {
print_params(_o, ptr->params);
diff --git a/src/core/parser/contact/contact.h b/src/core/parser/contact/contact.h
index c2d63aef71b..b72f9e59d9c 100644
--- a/src/core/parser/contact/contact.h
+++ b/src/core/parser/contact/contact.h
@@ -50,6 +50,7 @@ typedef struct contact {
param_t* received; /* received parameter hook */
param_t* instance; /* sip.instance parameter hook */
param_t* reg_id; /* reg-id parameter hook */
+ param_t* flags; /* flags parameter hook */
param_t* params; /* List of all parameters */
int len; /* Total length of the element */
struct contact* next; /* Next contact in the list */
diff --git a/src/core/parser/parse_param.c b/src/core/parser/parse_param.c
index 5af3993cb94..b80ffbdcc02 100644
--- a/src/core/parser/parse_param.c
+++ b/src/core/parser/parse_param.c
@@ -173,6 +173,14 @@ static inline void parse_contact_class(param_hooks_t *_h, param_t *_p)
_h->contact.ob = _p;
}
break;
+ case 'f':
+ case 'F':
+ if ((_p->name.len == 5) &&
+ (!strncasecmp(_p->name.s + 1, "lags", 4))) {
+ _p->type = P_FLAGS;
+ _h->contact.flags = _p;
+ }
+ break;
}
}
@@ -673,6 +681,9 @@ static inline void print_param(FILE *_o, param_t *_p)
case P_METHODS:
type = "P_METHODS";
break;
+ case P_FLAGS:
+ type = "P_FLAGS";
+ break;
case P_TRANSPORT:
type = "P_TRANSPORT";
break;
diff --git a/src/core/parser/parse_param.h b/src/core/parser/parse_param.h
index 1007358125a..ebb3ac56d6e 100644
--- a/src/core/parser/parse_param.h
+++ b/src/core/parser/parse_param.h
@@ -44,6 +44,7 @@ typedef enum ptype {
P_EXPIRES, /*!< Contact: expires parameter */
P_METHODS, /*!< Contact: methods parameter */
P_RECEIVED, /*!< Contact: received parameter */
+ P_FLAGS, /*!< Contact: flags parameter */
P_TRANSPORT, /*!< URI: transport parameter */
P_LR, /*!< URI: lr parameter */
P_R2, /*!< URI: r2 parameter (ser specific) */
@@ -98,6 +99,7 @@ struct contact_hooks {
struct param* instance; /*!< sip.instance parameter */
struct param* reg_id; /*!< reg-id parameter */
struct param* ob; /*!< ob parameter */
+ struct param* flags; /*!< flags parameter */
};
diff --git a/src/modules/pv/pv_core.c b/src/modules/pv/pv_core.c
index 0419641efdc..ac119ef3d34 100644
--- a/src/modules/pv/pv_core.c
+++ b/src/modules/pv/pv_core.c
@@ -1335,7 +1335,7 @@ int pv_get_dset(struct sip_msg *msg, pv_param_t *param,
if(msg==NULL)
return -1;
- s.s = print_dset(msg, &s.len);
+ s.s = print_dset(msg, &s.len, 0);
if (s.s == NULL)
return pv_get_null(msg, param, res);
s.len -= CRLF_LEN;
diff --git a/src/modules/sl/doc/sl_params.xml b/src/modules/sl/doc/sl_params.xml
index f6ee54ba3de..79db29ab88c 100644
--- a/src/modules/sl/doc/sl_params.xml
+++ b/src/modules/sl/doc/sl_params.xml
@@ -61,4 +61,34 @@ modparam("sl", "bind_tm", 0) # feature disabled
+
+ rich_redirect (int)
+
+ When sending a 3xx class reply, include additional branch info
+ to the contacts such as path vector and branch flags.
+
+
+
+ 0 - no extra info is added (default)
+
+
+ 1 - include branch flags as contact header parameter
+
+
+ 2 - include path as contact uri Route header
+
+
+
+ Values may be combined (added).
+
+
+ rich_redirect example
+
+...
+modparam("sl", "rich_redirect", 3)
+...
+
+
+
+
diff --git a/src/modules/sl/sl.c b/src/modules/sl/sl.c
index 36c8a8eec7d..10361b12e1c 100644
--- a/src/modules/sl/sl.c
+++ b/src/modules/sl/sl.c
@@ -116,6 +116,7 @@ static param_export_t params[] = {
{"default_code", PARAM_INT, &default_code},
{"default_reason", PARAM_STR, &default_reason},
{"bind_tm", PARAM_INT, &sl_bind_tm},
+ {"rich_redirect", PARAM_INT, &sl_rich_redirect},
{0, 0, 0}
};
diff --git a/src/modules/sl/sl_funcs.c b/src/modules/sl/sl_funcs.c
index 1e408e653f1..7cdce0cda29 100644
--- a/src/modules/sl/sl_funcs.c
+++ b/src/modules/sl/sl_funcs.c
@@ -55,6 +55,9 @@ static int _sl_filtered_ack_route = -1; /* default disabled */
static int _sl_evrt_local_response = -1; /* default disabled */
+/* send path and flags in 3xx class reply */
+int sl_rich_redirect = 0;
+
/*!
* lookup sl event routes
*/
@@ -150,7 +153,7 @@ int sl_reply_helper(struct sip_msg *msg, int code, char *reason, str *tag)
/* if that is a redirection message, dump current message set to it */
if (code>=300 && code<400) {
- dset.s=print_dset(msg, &dset.len);
+ dset.s=print_dset(msg, &dset.len, sl_rich_redirect);
if (dset.s) {
add_lump_rpl(msg, dset.s, dset.len, LUMP_RPL_HDR);
}
diff --git a/src/modules/sl/sl_funcs.h b/src/modules/sl/sl_funcs.h
index 659061f366f..53711efd374 100644
--- a/src/modules/sl/sl_funcs.h
+++ b/src/modules/sl/sl_funcs.h
@@ -30,6 +30,8 @@
#define SL_TOTAG_SEPARATOR '.'
+extern int sl_rich_redirect;
+
int sl_startup();
int sl_shutdown();
diff --git a/src/modules/tm/doc/params.xml b/src/modules/tm/doc/params.xml
index 3692dab0d48..75b60d9b0a7 100644
--- a/src/modules/tm/doc/params.xml
+++ b/src/modules/tm/doc/params.xml
@@ -1485,4 +1485,34 @@ modparam("tm", "relay_100", 1)
+
+ rich_redirect (int)
+
+ When sending a 3xx class reply, include additional branch info
+ to the contacts such as path vector and branch flags.
+
+
+
+ 0 - no extra info is added (default)
+
+
+ 1 - include branch flags as contact header parameter
+
+
+ 2 - include path as contact uri Route header
+
+
+
+ Values may be combined (added).
+
+
+ rich_redirect example
+
+...
+modparam("tm", "rich_redirect", 3)
+....
+
+
+
+
diff --git a/src/modules/tm/t_reply.c b/src/modules/tm/t_reply.c
index 81f041fc60e..e1e8051cf14 100644
--- a/src/modules/tm/t_reply.c
+++ b/src/modules/tm/t_reply.c
@@ -102,6 +102,8 @@ int goto_on_sl_reply=0;
/* remap 503 response code to 500 */
extern int tm_remap_503_500;
+/* send path and flags in 3xx class reply */
+int tm_rich_redirect = 0;
/* how to deal with winning branch reply selection in failure_route
* can be overwritten per transaction with t_drop_replies(...)
@@ -640,7 +642,7 @@ static int _reply( struct cell *trans, struct sip_msg* p_msg,
/* if that is a redirection message, dump current message set to it */
if (code>=300 && code<400) {
- dset=print_dset(p_msg, &dset_len);
+ dset=print_dset(p_msg, &dset_len, tm_rich_redirect);
if (dset) {
add_lump_rpl(p_msg, dset, dset_len, LUMP_RPL_HDR);
}
diff --git a/src/modules/tm/tm.c b/src/modules/tm/tm.c
index c8afee9c4cd..c4a277d8241 100644
--- a/src/modules/tm/tm.c
+++ b/src/modules/tm/tm.c
@@ -475,6 +475,7 @@ static param_export_t params[]={
{"xavp_contact", PARAM_STR, &ulattrs_xavp_name },
{"event_callback", PARAM_STR, &tm_event_callback },
{"relay_100", PARAM_INT, &default_tm_cfg.relay_100 },
+ {"rich_redirect" , PARAM_INT, &tm_rich_redirect },
{0,0,0}
};
diff --git a/src/modules/uac_redirect/doc/uac_redirect_admin.xml b/src/modules/uac_redirect/doc/uac_redirect_admin.xml
index 2c7fc0e883f..b044d38c250 100644
--- a/src/modules/uac_redirect/doc/uac_redirect_admin.xml
+++ b/src/modules/uac_redirect/doc/uac_redirect_admin.xml
@@ -302,8 +302,46 @@ branch_route[1] {
+
+ flags_hdr_mode (int)
+
+ Specifies if and how a Contact's flags header parameter
+ must be used. If set, and a flags header parameter is set,
+ its value will be set as branch flags for that contact.
+
+
+ Its values may be:
+
+
+
+ 0 - ignore flags header parameter,
+ just use bflags module parameter
+
+
+ 1 - use flags header parameter if
+ present, ignore bflags module parameter
+
+
+ 2 - use flags header parameter if
+ present and merge (binary or) it with the bflags module
+ parameter
+
+
+
+
+ The default value is 0
.
+
+
+
+ Set flags_hdr_mode parameter
+
+...
+modparam("uac_redirect","flags_hdr_mode",2)
+...
+
+
+
-
Functions
diff --git a/src/modules/uac_redirect/rd_funcs.c b/src/modules/uac_redirect/rd_funcs.c
index fdd885b1791..3dcf8077b69 100644
--- a/src/modules/uac_redirect/rd_funcs.c
+++ b/src/modules/uac_redirect/rd_funcs.c
@@ -199,6 +199,7 @@ static int shmcontact2dset(struct sip_msg *req, struct sip_msg *sh_rpl,
int added;
int dup;
int ret;
+ unsigned int flags;
/* dup can be:
* 0 - sh reply but nothing duplicated
@@ -294,8 +295,14 @@ static int shmcontact2dset(struct sip_msg *req, struct sip_msg *sh_rpl,
LM_DBG("adding contact <%.*s>\n", scontacts[i]->uri.len,
scontacts[i]->uri.s);
if(sruid_next(&_redirect_sruid)==0) {
+ if (flags_hdr_mode && scontacts[i]->flags && str2int(&(scontacts[i]->flags->body), &flags) == 0) {
+ if (flags_hdr_mode == 2)
+ flags |= bflags;
+ } else {
+ flags = bflags;
+ }
if(append_branch( 0, &scontacts[i]->uri, 0, 0, sqvalues[i],
- bflags, 0, &_redirect_sruid.uid, 0,
+ flags, 0, &_redirect_sruid.uid, 0,
&_redirect_sruid.uid, &_redirect_sruid.uid)<0) {
LM_ERR("failed to add contact to dset\n");
} else {
diff --git a/src/modules/uac_redirect/rd_funcs.h b/src/modules/uac_redirect/rd_funcs.h
index a5304c19dc0..f686615969e 100644
--- a/src/modules/uac_redirect/rd_funcs.h
+++ b/src/modules/uac_redirect/rd_funcs.h
@@ -36,6 +36,8 @@ extern cmd_function rd_acc_fct;
extern char *acc_db_table;
+extern int flags_hdr_mode;
+
int get_redirect( struct sip_msg *msg , int maxt, int maxb,
struct acc_param *reason, unsigned int bflags);
diff --git a/src/modules/uac_redirect/uac_redirect.c b/src/modules/uac_redirect/uac_redirect.c
index e1f7d640db7..6ade1719c6b 100644
--- a/src/modules/uac_redirect/uac_redirect.c
+++ b/src/modules/uac_redirect/uac_redirect.c
@@ -48,6 +48,7 @@ char *accept_filter_s = 0;
char *def_filter_s = 0;
unsigned int bflags = 0;
+int flags_hdr_mode = 0;
#define ACCEPT_RULE_STR "accept"
#define DENY_RULE_STR "deny"
@@ -86,6 +87,7 @@ static param_export_t params[] = {
{"acc_function", PARAM_STRING, &acc_fct_s },
{"acc_db_table", PARAM_STRING, &acc_db_table },
{"bflags", INT_PARAM, &bflags },
+ {"flags_hdr_mode", INT_PARAM, &flags_hdr_mode },
{0, 0, 0}
};
diff --git a/src/modules/xprint/xp_lib.c b/src/modules/xprint/xp_lib.c
index 068608a3049..bbe2ceaafed 100644
--- a/src/modules/xprint/xp_lib.c
+++ b/src/modules/xprint/xp_lib.c
@@ -559,7 +559,7 @@ static int xl_get_dset(struct sip_msg *msg, str *res, str *hp, int hi, int hf)
if(msg==NULL || res==NULL)
return -1;
- res->s = print_dset(msg, &res->len);
+ res->s = print_dset(msg, &res->len, 0);
if ((res->s) == NULL) return xl_get_null(msg, res, hp, hi, hf);