Module: sip-router
Branch: alexh/master
Commit: 0ef0618e2273dfd717014d4caa484f7f20f0a2c1
URL:
http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=0ef0618…
Author: Alex Hermann <alex(a)speakup.nl>
Committer: Alex Hermann <alex(a)speakup.nl>
Date: Tue Jul 26 10:23:36 2011 +0200
core/dset: Create contacts with path vector as Route header
---
config.h | 2 +-
dset.c | 197 ++++++++++++++++++++++++++++++++++++++++++--------------------
2 files changed, 134 insertions(+), 65 deletions(-)
diff --git a/config.h b/config.h
index 57c40b2..70791a1 100644
--- a/config.h
+++ b/config.h
@@ -170,7 +170,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 1024 /*!< 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/dset.c b/dset.c
index f8bb337..2a42d43 100644
--- a/dset.c
+++ b/dset.c
@@ -54,6 +54,8 @@
#define Q_PARAM ">;q="
#define Q_PARAM_LEN (sizeof(Q_PARAM) - 1)
+#define PATH_PARAM "?Route="
+#define PATH_PARAM_LEN (sizeof(PATH_PARAM) - 1)
/*
* Where we store URIs of additional transaction branches
@@ -355,97 +357,164 @@ int append_branch(struct sip_msg* msg, str* uri, str* dst_uri, str*
path,
}
-/*
- * Create a Contact header field from the dset
- * array
+/*! \brief
+ * Escape all printable characters that are not valid in
+ * a param part of request uri: = | ; | , | | " | ? | &
*/
-char* print_dset(struct sip_msg* msg, int* len)
+static int escape_param(str *sin, str *sout)
{
- int cnt, i;
- unsigned int qlen;
- qvalue_t q;
- str uri;
- char* p, *qbuf;
- static char dset[MAX_REDIRECTION_LEN];
+ char *at, *p;
+ unsigned char x;
+
+ if (sin==NULL || sout==NULL || sin->s==NULL || sout->s==NULL ||
+ sin->len<0 || sout->len < 3*sin->len+1)
+ return -1;
+
+ at = sout->s;
+ p = sin->s;
+ while (p < sin->s+sin->len) {
+ if (*p < 32 || *p > 126) {
+ LM_ERR("invalid escaped character <%u>\n", (unsigned
int)*p);
+ return -1;
+ }
+ switch (*p) {
+ case ' ':
+ case '?':
+ case '&':
+ case '=':
+ case ',':
+ case ';':
+ case '"':
+ case '+':
+ *at++ = '%';
+ x = (*p) >> 4;
+ if (x < 10)
+ {
+ *at++ = x + '0';
+ } else {
+ *at++ = x - 10 + 'a';
+ }
+ x = (*p) & 0x0f;
+ if (x < 10) {
+ *at = x + '0';
+ } else {
+ *at = x - 10 + 'a';
+ }
+ break;
+ default:
+ *at = *p;
+ }
+ at++;
+ p++;
+ }
+ *at = 0;
+ sout->len = at - sout->s;
+ LM_DBG("escaped string is <%s>\n", sout->s);
+
+ return 0;
+}
- if (msg->new_uri.s) {
- cnt = 1;
- *len = msg->new_uri.len;
- if (ruri_q != Q_UNSPECIFIED) {
- *len += 1 + Q_PARAM_LEN + len_q(ruri_q);
- }
- } else {
- cnt = 0;
- *len = 0;
+
+/*! \brief
+ * Combines the given elements into a Contact header field
+ * p = target buffer
+ * uri, q, path = contact elements
+ * end = end of target buffer
+ * Returns pointer to final position in target buffer or 0 on failure
+ */
+char* print_contact_str(char *p, str uri, qvalue_t q, str path, char *end)
+{
+ str buf;
+
+ if (q != Q_UNSPECIFIED) {
+ if (p + 1 > end) return 0;
+ *p++ = '<';
}
- init_branch_iterator();
- while ((uri.s = next_branch(&uri.len, &q, 0, 0, 0, 0))) {
- cnt++;
- *len += uri.len;
- if (q != Q_UNSPECIFIED) {
- *len += 1 + Q_PARAM_LEN + len_q(q);
- }
+ /* uri */
+ if (p + uri.len > end) return 0;
+ memcpy(p, uri.s, uri.len);
+ p += uri.len;
+
+ /* path vector in Route header (uri parameter)*/
+ if (path.len > 0) {
+ if (p + PATH_PARAM_LEN + path.len*3 > end) return 0;
+ memcpy(p, PATH_PARAM, PATH_PARAM_LEN);
+ p += PATH_PARAM_LEN;
+ /* strip <> from path and escape */
+ path.s += 1;
+ path.len -= 2;
+ buf.s = p;
+ buf.len = end - p;
+ if (escape_param(&path, &buf) < 0) return 0;
+ p += buf.len;
}
- if (cnt == 0) return 0;
+ /* q value (header parameter) */
+ if (q != Q_UNSPECIFIED) {
+ buf.s = q2str(q, (unsigned int*)&buf.len);
+ if (p + Q_PARAM_LEN + buf.len > end) return 0;
+ memcpy(p, Q_PARAM, Q_PARAM_LEN);
+ p += Q_PARAM_LEN;
+ memcpy(p, buf.s, buf.len);
+ p += buf.len;
+ }
- *len += CONTACT_LEN + CRLF_LEN + (cnt - 1) * CONTACT_DELIM_LEN;
+ return p;
+}
- if (*len + 1 > MAX_REDIRECTION_LEN) {
- LOG(L_ERR, "ERROR: redirection buffer length exceed\n");
- return 0;
- }
+/*
+ * Create a Contact header field from the dset array
+ */
+char* print_dset(struct sip_msg* msg, int* len)
+{
+ int i;
+ qvalue_t q;
+ str uri, path;
+ char *p;
+ static char dset[MAX_REDIRECTION_LEN];
+ char *end = dset + MAX_REDIRECTION_LEN;
+
+ if (CONTACT_LEN + CRLF_LEN > MAX_REDIRECTION_LEN) goto memfail;
memcpy(dset, CONTACT, CONTACT_LEN);
p = dset + CONTACT_LEN;
if (msg->new_uri.s) {
- if (ruri_q != Q_UNSPECIFIED) {
- *p++ = '<';
- }
-
- memcpy(p, msg->new_uri.s, msg->new_uri.len);
- p += msg->new_uri.len;
-
- if (ruri_q != Q_UNSPECIFIED) {
- memcpy(p, Q_PARAM, Q_PARAM_LEN);
- p += Q_PARAM_LEN;
-
- qbuf = q2str(ruri_q, &qlen);
- memcpy(p, qbuf, qlen);
- p += qlen;
- }
+ p = print_contact_str(p, msg->new_uri, ruri_q, msg->path_vec, end);
+ if (!p)
+ goto memfail;
i = 1;
} else {
i = 0;
}
init_branch_iterator();
- while ((uri.s = next_branch(&uri.len, &q, 0, 0, 0, 0))) {
+ while ((uri.s = next_branch(&uri.len, &q, 0, &path, 0, 0))) {
if (i) {
+ if (p + CONTACT_DELIM_LEN > end) goto memfail;
memcpy(p, CONTACT_DELIM, CONTACT_DELIM_LEN);
p += CONTACT_DELIM_LEN;
}
-
- if (q != Q_UNSPECIFIED) {
- *p++ = '<';
- }
-
- memcpy(p, uri.s, uri.len);
- p += uri.len;
- if (q != Q_UNSPECIFIED) {
- memcpy(p, Q_PARAM, Q_PARAM_LEN);
- p += Q_PARAM_LEN;
-
- qbuf = q2str(q, &qlen);
- memcpy(p, qbuf, qlen);
- p += qlen;
- }
+ p = print_contact_str(p, uri, q, path, end);
+ if (!p)
+ goto memfail;
i++;
}
- memcpy(p, CRLF " ", CRLF_LEN + 1);
+ /* No contacts */
+ if (!i) {
+ goto none;
+ }
+
+ memcpy(p, CRLF, CRLF_LEN);
+ *len = p + CRLF_LEN - dset;
return dset;
+
+memfail:
+ LM_ERR("redirection buffer length exceeded\n");
+none:
+ *len = 0;
+ return 0;
}