Module: sip-router Branch: alexh/master Commit: 0ef0618e2273dfd717014d4caa484f7f20f0a2c1 URL: http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=0ef0618e...
Author: Alex Hermann alex@speakup.nl Committer: Alex Hermann alex@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; }