From ced8d46eddb2bda614eaace98437b7dab2d123e3 Mon Sep 17 00:00:00 2001 From: Xenofon Karamanos Date: Fri, 8 Dec 2023 11:01:39 +0100 Subject: [PATCH] core: parser extended to handle diversion with multiple bodies - similar to PAI and PPI --- src/core/parser/hf.c | 3 +- src/core/parser/parse_diversion.c | 195 ++++++++++++++++++++++++++---- src/core/parser/parse_diversion.h | 18 ++- 3 files changed, 188 insertions(+), 28 deletions(-) diff --git a/src/core/parser/hf.c b/src/core/parser/hf.c index d1ed5c1bb92..c71f0d89902 100644 --- a/src/core/parser/hf.c +++ b/src/core/parser/hf.c @@ -40,6 +40,7 @@ #include "parse_expires.h" #include "parse_sipifmatch.h" #include "parse_rr.h" +#include "parse_diversion.h" #include "parse_subscription_state.h" #include "contact/parse_contact.h" #include "parse_disposition.h" @@ -87,7 +88,7 @@ void clean_hdr_field(struct hdr_field *const hf) break; case HDR_DIVERSION_T: - free_to(hf->parsed); + free_diversion_body((diversion_body_t *)(hf->parsed)); break; case HDR_EVENT_T: diff --git a/src/core/parser/parse_diversion.c b/src/core/parser/parse_diversion.c index 804dfdb6b8c..539f6a7bc44 100644 --- a/src/core/parser/parse_diversion.c +++ b/src/core/parser/parse_diversion.c @@ -31,6 +31,7 @@ #include "../dprint.h" #include "../ut.h" #include "../mem/mem.h" +#include "parse_diversion.h" #include "parse_from.h" #include "parse_to.h" #include "msg_parser.h" @@ -44,49 +45,189 @@ * * limitations: it parses only the first occurrence */ -int parse_diversion_header(struct sip_msg *msg) +#define NUM_DIVERSION_BODIES 10 +int parse_diversion_body(char *buf, int len, diversion_body_t **body) { - struct to_body *diversion_b; + static to_body_t uri_b[NUM_DIVERSION_BODIES]; /* Temporary storage */ + int num_uri = 0; + int body_len = 0; + char *tmp; + int i; + to_param_t *params; - if(!msg->diversion && (parse_headers(msg, HDR_DIVERSION_F, 0) == -1)) { - goto error; + /* Reserves memory max NUM_DIVERSION_BODIES times */ + memset(uri_b, 0, NUM_DIVERSION_BODIES * sizeof(to_body_t)); + if(uri_b == NULL) { + LM_ERR("Error allocating memory for uri_b\n"); + return -1; } - if(!msg->diversion) { - /* header not found */ + tmp = parse_addr_spec(buf, buf + len, &uri_b[num_uri], 1); + if(uri_b[num_uri].error == PARSE_ERROR) { + LM_ERR("Error parsing Diversion body %u '%.*s'\n", num_uri, len, buf); + return -1; + } + + /* id.body should contain all info including uri and params */ + body_len = uri_b[num_uri].body.len; + + /* Loop over all params */ + params = uri_b[num_uri].param_lst; + while(params) { + body_len += + params->name.len + params->value.len + 2; // 2 for '=' and ';' + params = params->next; + } + + uri_b[num_uri].body.len = body_len; + + num_uri++; + while(*tmp == ',' && (num_uri < NUM_DIVERSION_BODIES)) { + tmp++; + while(tmp < buf + len && (*tmp == ' ' || *tmp == '\t')) + tmp++; + + if(tmp >= buf + len) { + LM_ERR("no content after comma when parsing Diversion body %u " + "'%.*s'\n", + num_uri, len, buf); + // Free params already allocated + while(num_uri >= 0) { + free_to_params(&uri_b[num_uri]); + num_uri--; + } + return -1; + } + + if((tmp < buf + len - 1 && *tmp == '\n') + || (tmp < buf + len - 2 && *tmp == '\r' + && *(tmp + 1) == '\n')) { + if(*tmp == '\n') { + tmp++; + } else { + tmp += 2; + } + if(*tmp != ' ' && *tmp != '\t') { + // TODO: Check if this is the correct error message + LM_ERR("no space after EOL when parsing Diversion body %u " + "'%.*s'\n", + num_uri, len, buf); + // Free params already allocated + while(num_uri >= 0) { + free_to_params(&uri_b[num_uri]); + num_uri--; + } + return -1; + } + tmp++; + } + /* Parse next body */ + tmp = parse_addr_spec(tmp, buf + len, &uri_b[num_uri], 1); + if(uri_b[num_uri].error == PARSE_ERROR) { + LM_ERR("Error parsing Diversion body %u '%.*s'\n", num_uri, len, + buf); + // Free params already allocated + while(num_uri >= 0) { + free_to_params(&uri_b[num_uri]); + num_uri--; + } + return -1; + } + + /* id.body should contain all info including uri and params */ + body_len = uri_b[num_uri].body.len; + + /* Loop over all params */ + params = uri_b[num_uri].param_lst; + while(params) { + body_len += params->name.len + params->value.len + + 2; /* 2 for '=' and ';' */ + params = params->next; + } + + uri_b[num_uri].body.len = body_len; + + num_uri++; + } + if(num_uri >= NUM_DIVERSION_BODIES) { + LM_WARN("Too many bodies in Diversion header '%.*s'\n", len, buf); + LM_WARN("Ignoring bodies beyond %u\n", NUM_DIVERSION_BODIES); + } + *body = pkg_malloc(sizeof(diversion_body_t) + num_uri * sizeof(to_body_t)); + if(*body == NULL) { + PKG_MEM_ERROR; return -1; } + memset(*body, 0, sizeof(diversion_body_t)); + (*body)->id = (to_body_t *)((char *)(*body) + sizeof(diversion_body_t)); + (*body)->num_ids = num_uri; + for(i = 0; i < num_uri; i++) { + memcpy(&(*body)->id[i], &uri_b[i], sizeof(to_body_t)); + } + return 0; +} + +int parse_diversion_header(struct sip_msg *msg) +{ + diversion_body_t *diversion_b; + diversion_body_t **prev_diversion_body; + hdr_field_t *hf; + void **vp; + + if(!msg->diversion) { + if(parse_headers(msg, HDR_DIVERSION_F, 0) < 0) { + LM_ERR("Error parsing Diversion header\n"); + return -1; + } + if(!msg->diversion) { + /* Diversion header not found */ + LM_DBG("Diversion header not found\n"); + return -1; + } + } /* maybe the header is already parsed! */ if(msg->diversion->parsed) return 0; - /* bad luck! :-( - we have to parse it */ - /* first, get some memory */ - diversion_b = pkg_malloc(sizeof(struct to_body)); - if(diversion_b == 0) { - PKG_MEM_ERROR; - goto error; + vp = &msg->diversion->parsed; + /* Set it as the first header in the list */ + prev_diversion_body = (diversion_body_t **)vp; + + /* Loop through all the Diversion headers */ + for(hf = msg->diversion; hf != NULL; hf = next_sibling_hdr(hf)) { + if(parse_diversion_body(hf->body.s, hf->body.len, &diversion_b) < 0) { + LM_ERR("Error parsing Diversion header\n"); + return -1; + } + + hf->parsed = (void *)diversion_b; + *prev_diversion_body = diversion_b; + prev_diversion_body = &diversion_b->next; + + if(parse_headers(msg, HDR_DIVERSION_F, 1) < 0) { + LM_ERR("Error looking for subsequent Diversion header\n"); + return -1; + } } + return 0; +} - /* now parse it!! */ - memset(diversion_b, 0, sizeof(struct to_body)); - parse_addr_spec(msg->diversion->body.s, - msg->diversion->body.s + msg->diversion->body.len + 1, diversion_b, - 1); - if(diversion_b->error == PARSE_ERROR) { - LM_ERR("bad diversion header\n"); - free_to(diversion_b); - goto error; +int free_diversion_body(diversion_body_t *div_b) +{ + for(int i = 0; i < div_b->num_ids; i++) { + /* Free to_body pointer parameters */ + if(div_b->id[i].param_lst) { + free_to_params(&(div_b->id[i])); + } } - msg->diversion->parsed = diversion_b; + if(div_b != NULL) { + pkg_free(div_b); + } return 0; -error: - return -1; } - /*! \brief * Get the value of a given diversion parameter */ @@ -99,7 +240,9 @@ str *get_diversion_param(struct sip_msg *msg, str *name) return 0; } - params = ((struct to_body *)(msg->diversion->parsed))->param_lst; + to_body_t *diversion = + get_diversion(msg)->id; /* This returns the first entry */ + params = diversion->param_lst; while(params) { if((params->name.len == name->len) diff --git a/src/core/parser/parse_diversion.h b/src/core/parser/parse_diversion.h index 271219eba54..8aba7d8f182 100644 --- a/src/core/parser/parse_diversion.h +++ b/src/core/parser/parse_diversion.h @@ -29,10 +29,21 @@ #define PARSE_DIVERSION_H #include "msg_parser.h" +#include "parse_addr_spec.h" + +/*! \brief + * Structure representing a Diversion header + */ +typedef struct diversion_body +{ + to_body_t *id; + int num_ids; + struct diversion_body *next; /*!< Next Diversion in the list */ +} diversion_body_t; /*! \brief casting macro for accessing Diversion body */ -#define get_diversion(p_msg) ((struct to_body *)(p_msg)->diversion->parsed) +#define get_diversion(p_msg) ((diversion_body_t *)(p_msg)->diversion->parsed) /*! \brief @@ -45,4 +56,9 @@ int parse_diversion_header(struct sip_msg *msg); */ str *get_diversion_param(struct sip_msg *msg, str *name); +/*! \brief + * Free the memory allocated for a Diversion header + */ +int free_diversion_body(diversion_body_t *div_b); + #endif /* PARSE_DIVERSION_H */