Module: sip-router Branch: master Commit: 48ebf54389b103904c3f6f46cd2d652d3d632588 URL: http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=48ebf543...
Author: Tristan Bruns bruns@decoit.de Committer: Daniel-Constantin Mierla miconda@gmail.com Date: Fri Aug 5 09:24:14 2011 +0200
modules_k/siptrace: Add "x-headers" feature
The "x-headers" feature stores the fromip, toip, method and direction in the message body (using X-* headers). This allows to transmit them using duplicate_uri from one kamailio to an other.
Signed-off-by: Tristan Bruns bruns@decoit.de Signed-off-by: Daniel-Constantin Mierla miconda@gmail.com
---
modules_k/siptrace/doc/siptrace_admin.xml | 60 ++++++++++ modules_k/siptrace/siptrace.c | 175 ++++++++++++++++++++++++++++- 2 files changed, 234 insertions(+), 1 deletions(-)
diff --git a/modules_k/siptrace/doc/siptrace_admin.xml b/modules_k/siptrace/doc/siptrace_admin.xml index cbca2e6..3924f1e 100644 --- a/modules_k/siptrace/doc/siptrace_admin.xml +++ b/modules_k/siptrace/doc/siptrace_admin.xml @@ -305,6 +305,66 @@ modparam("siptrace", "trace_sl_acks", 0) </programlisting> </example> </section> + <section> + <title><varname>xheaders_write</varname> (integer)</title> + <para> + Parameter to enable/disable writing of x-headers. + </para> + <para> + Stores fromip, toip, method and direction in X-Siptrace-* headers. + This allows to transmit them to a second kamailio server + using the duplicate_uri feature. + Because the headers are added after the data is written to the database, + the headers only show up in the packets sent by duplicate_uri. + </para> + <para> + See <varname>xheaders_read</varname>, it should be used on the receiving + side. + </para> + <para> + Note: The headers are first read, then written. This allows to relay + the information over more then two kamailio servers by setting both + <varname>xheaders_write</varname> and <varname>xheaders_read</varname> + to "1" on the servers in the middle. + </para> + <para> + <emphasis> + Default value is "0". + </emphasis> + </para> + <example> + <title>Set <varname>xheaders_write</varname> parameter</title> + <programlisting format="linespecific"> +... +modparam("siptrace", "xheaders_write", 0) +... +</programlisting> + </example> + </section> + <section> + <title><varname>xheaders_read</varname> (integer)</title> + <para> + Parameter to enable/disable reading of x-headers. + </para> + <para> + Reads and removes the X-Siptrace-* headers. Packets not containing the + headers are neither stored to the database nor relayed (duplicate_uri). + See <varname>xheaders_write</varname> for further information. + </para> + <para> + <emphasis> + Default value is "0". + </emphasis> + </para> + <example> + <title>Set <varname>xheaders_read</varname> parameter</title> + <programlisting format="linespecific"> +... +modparam("siptrace", "xheaders_read", 0) +... +</programlisting> + </example> + </section> </section> <section> diff --git a/modules_k/siptrace/siptrace.c b/modules_k/siptrace/siptrace.c index c970002..939f290 100644 --- a/modules_k/siptrace/siptrace.c +++ b/modules_k/siptrace/siptrace.c @@ -113,18 +113,26 @@ static str direction_column = str_init("direction"); /* 09 */
#define NR_KEYS 10
+#define XHEADERS_BUFSIZE 512 + int trace_flag = -1; int trace_on = 0; int trace_sl_acks = 1;
int trace_to_database = 1;
+int xheaders_write = 0; +int xheaders_read = 0; + str dup_uri_str = {0, 0}; struct sip_uri *dup_uri = 0;
int *trace_on_flag = NULL; int *trace_to_database_flag = NULL;
+int *xheaders_write_flag = NULL; +int *xheaders_read_flag = NULL; + static unsigned short traced_user_avp_type = 0; static int_str traced_user_avp; static str traced_user_avp_str = {NULL, 0}; @@ -172,6 +180,8 @@ static param_export_t params[] = { {"trace_to_database", INT_PARAM, &trace_to_database }, {"trace_local_ip", STR_PARAM, &trace_local_ip.s }, {"trace_sl_acks", INT_PARAM, &trace_sl_acks }, + {"xheaders_write", INT_PARAM, &xheaders_write }, + {"xheaders_read", INT_PARAM, &xheaders_read }, {0, 0, 0} };
@@ -294,6 +304,15 @@ static int mod_init(void) *trace_to_database_flag = trace_to_database; + xheaders_write_flag = (int*)shm_malloc(sizeof(int)); + xheaders_read_flag = (int*)shm_malloc(sizeof(int)); + if (!(xheaders_write_flag && xheaders_read_flag)) { + LM_ERR("no more shm memory left\n"); + return -1; + } + *xheaders_write_flag = xheaders_write; + *xheaders_read_flag = xheaders_read; + /* register callbacks to TM */ if (load_tm_api(&tmb)!=0) { @@ -474,6 +493,153 @@ error: return -1; }
+// Appends x-headers to the message in sto->body containing data from sto +static int sip_trace_xheaders_write(struct _siptrace_data *sto) +{ + if(xheaders_write_flag==NULL || *xheaders_write_flag==0) + return 0; + + // Memory for the message with some additional headers. + // It gets free()ed in sip_trace_xheaders_free(). + char* buf = malloc(sto->body.len + XHEADERS_BUFSIZE); + if (buf == NULL) { + LM_ERR("sip_trace_xheaders_write: out of memory\n"); + return -1; + } + + // Copy the whole message to buf first; it must be \0-terminated for + // strstr() to work. Then search for the end-of-header sequence. + memcpy(buf, sto->body.s, sto->body.len); + buf[sto->body.len] = '\0'; + char* eoh = strstr(buf, "\r\n\r\n"); + if (eoh == NULL) { + LM_ERR("sip_trace_xheaders_write: malformed message\n"); + return -1; + } + eoh += 2; // the first \r\n belongs to the last header => skip it + + // Write the new headers a the end-of-header position. This overwrites + // the \r\n terminating the old headers and the beginning of the message + // body. Both will be recovered later. + int bytes_written = snprintf(eoh, XHEADERS_BUFSIZE, + "X-Siptrace-Fromip: %.*s\r\n" + "X-Siptrace-Toip: %.*s\r\n" + "X-Siptrace-Method: %.*s\r\n" + "X-Siptrace-Dir: %s\r\n", + sto->fromip.len, sto->fromip.s, + sto->toip.len, sto->toip.s, + sto->method.len, sto->method.s, + sto->dir); + if (bytes_written >= XHEADERS_BUFSIZE) { + LM_ERR("sip_trace_xheaders_write: string too long\n"); + return -1; + } + + // Copy the \r\n terminating the old headers and the message body from the + // old buffer in sto->body.s to the new end-of-header in buf. + int eoh_offset = eoh - buf; + char* new_eoh = eoh + bytes_written; + memcpy(new_eoh, sto->body.s + eoh_offset, sto->body.len - eoh_offset); + + // Change sto to point to the new buffer. + sto->body.s = buf; + sto->body.len += bytes_written; + return 0; +} + +// Parses x-headers, saves the data back to sto, and removes the x-headers +// from the message in sto->buf +static int sip_trace_xheaders_read(struct _siptrace_data *sto) +{ + if(xheaders_read_flag==NULL || *xheaders_read_flag==0) + return 0; + + // Find the end-of-header marker \r\n\r\n + char* searchend = sto->body.s + sto->body.len - 3; + char* eoh = memchr(sto->body.s, '\r', searchend - eoh); + while (eoh != NULL && eoh < searchend) { + if (memcmp(eoh, "\r\n\r\n", 4) == 0) + break; + eoh = memchr(eoh + 1, '\r', searchend - eoh); + } + if (eoh == NULL) { + LM_ERR("sip_trace_xheaders_read: malformed message\n"); + return -1; + } + + // Find x-headers: eoh will be overwritten by \0 to allow the use of + // strstr(). The byte at eoh will later be recovered, when the + // message body is shifted towards the beginning of the message + // to remove the x-headers. + *eoh = '\0'; + char* xheaders = strstr(sto->body.s, "\r\nX-Siptrace-Fromip: "); + if (xheaders == NULL) { + LM_ERR("sip_trace_xheaders_read: message without x-headers " + "from %.*s, callid %.*s\n", + sto->fromip.len, sto->fromip.s, sto->callid.len, sto->callid.s); + return -1; + } + + // Allocate memory for new strings in sto + // (gets free()ed in sip_trace_xheaders_free() ) + sto->fromip.s = malloc(51); + sto->toip.s = malloc(51); + sto->method.s = malloc(51); + sto->dir = malloc(4); + if (!(sto->fromip.s && sto->toip.s && sto->method.s && sto->dir)) { + LM_ERR("sip_trace_xheaders_read: out of memory\n"); + goto erroraftermalloc; + } + + // Parse the x-headers: scanf() + if (sscanf(xheaders, "\r\n" + "X-Siptrace-Fromip: %50s\r\n" + "X-Siptrace-Toip: %50s\r\n" + "X-Siptrace-Method: %50s\r\n" + "X-Siptrace-Dir: %3s", + sto->fromip.s, sto->toip.s, + sto->method.s, + sto->dir) == EOF) { + LM_ERR("sip_trace_xheaders_read: malformed x-headers\n"); + goto erroraftermalloc; + } + sto->fromip.len = strlen(sto->fromip.s); + sto->toip.len = strlen(sto->toip.s); + sto->method.len = strlen(sto->method.s); + + // Remove the x-headers: the message body is shifted towards the beginning + // of the message, overwriting the x-headers. Before that, the byte at eoh + // is recovered. + *eoh = '\r'; + memmove(xheaders, eoh, sto->body.len - (eoh - sto->body.s)); + sto->body.len -= eoh - xheaders; + + return 0; + +erroraftermalloc: + if (sto->fromip.s) free(sto->fromip.s); + if (sto->toip.s) free(sto->toip.s); + if (sto->method.s) free(sto->method.s); + if (sto->dir) free(sto->dir); + return -1; +} + +// Frees the memory allocated by sip_trace_xheaders_{write,read} +static int sip_trace_xheaders_free(struct _siptrace_data *sto) +{ + if (xheaders_write_flag != NULL && *xheaders_write_flag != 0) { + free(sto->body.s); + } + + if (xheaders_read_flag != NULL && *xheaders_read_flag != 0) { + free(sto->fromip.s); + free(sto->toip.s); + free(sto->dir); + } + + return 0; +} + static int sip_trace_store(struct _siptrace_data *sto) { if(sto==NULL) @@ -482,8 +648,15 @@ static int sip_trace_store(struct _siptrace_data *sto) return -1; } + if (sip_trace_xheaders_read(sto) != 0) return -1; + int ret = sip_trace_store_db(sto); + + if (sip_trace_xheaders_write(sto) != 0) return -1; trace_send_duplicate(sto->body.s, sto->body.len); - return sip_trace_store_db(sto); + + if (sip_trace_xheaders_free(sto) != 0) return -1; + + return ret; }
static int sip_trace_store_db(struct _siptrace_data *sto)