|
@@ -31,29 +31,48 @@
|
|
|
|
|
|
#define SIZE_CONF_ID 16
|
|
#define SIZE_CONF_ID 16
|
|
#define P_CHARGING_VECTOR "P-Charging-Vector"
|
|
#define P_CHARGING_VECTOR "P-Charging-Vector"
|
|
|
|
+#define P_CHARGING_VECTOR_HEADERNAME_LEN (sizeof(P_CHARGING_VECTOR) - 1)
|
|
|
|
+#define P_CHARGING_VECTOR_PREFIX_LEN (P_CHARGING_VECTOR_HEADERNAME_LEN + 2)
|
|
#define LOOPBACK_IP 16777343
|
|
#define LOOPBACK_IP 16777343
|
|
|
|
|
|
#define PCV_BUF_SIZE 256
|
|
#define PCV_BUF_SIZE 256
|
|
static char _siputils_pcv_buf[PCV_BUF_SIZE];
|
|
static char _siputils_pcv_buf[PCV_BUF_SIZE];
|
|
static str _siputils_pcv = {_siputils_pcv_buf, 0};
|
|
static str _siputils_pcv = {_siputils_pcv_buf, 0};
|
|
-static str _siputils_pcv_id = {NULL, 0};
|
|
|
|
-static str _siputils_pcv_host = {NULL, 0};
|
|
|
|
-static str _siputils_pcv_orig = {NULL, 0};
|
|
|
|
-static str _siputils_pcv_term = {NULL, 0};
|
|
|
|
|
|
+static str _siputils_pcv_id = STR_NULL;
|
|
|
|
+static str _siputils_pcv_genaddr = STR_NULL;
|
|
|
|
+static str _siputils_pcv_orig = STR_NULL;
|
|
|
|
+static str _siputils_pcv_term = STR_NULL;
|
|
static uint64_t _siputils_pcv_counter = 0;
|
|
static uint64_t _siputils_pcv_counter = 0;
|
|
|
|
+static struct hdr_field *_siputils_pcv_hf_pcv = NULL;
|
|
|
|
|
|
|
|
|
|
enum PCV_Status
|
|
enum PCV_Status
|
|
{
|
|
{
|
|
PCV_NONE = 0,
|
|
PCV_NONE = 0,
|
|
PCV_PARSED = 1,
|
|
PCV_PARSED = 1,
|
|
- PCV_GENERATED = 2
|
|
|
|
|
|
+ PCV_ICID_MISSING = 2,
|
|
|
|
+ PCV_GENERATED = 3,
|
|
|
|
+ PCV_DELETED = 4,
|
|
|
|
+ PCV_REPLACED = 5,
|
|
|
|
+ PCV_NOP = PCV_PARSED
|
|
|
|
+};
|
|
|
|
+static const char *sstatus[] = {
|
|
|
|
+ "NONE", "PARSED", "ICID_MISSING", "GENERATED", "DELETED", "REPLACED"};
|
|
|
|
+
|
|
|
|
+enum PCV_Parameter
|
|
|
|
+{
|
|
|
|
+ PCV_PARAM_ALL = 1,
|
|
|
|
+ PCV_PARAM_GENADDR = 2,
|
|
|
|
+ PCV_PARAM_ID = 3,
|
|
|
|
+ PCV_PARAM_ORIG = 4,
|
|
|
|
+ PCV_PARAM_TERM = 5,
|
|
|
|
+ PCV_PARAM_STATUS = 6
|
|
};
|
|
};
|
|
|
|
|
|
static enum PCV_Status _siputils_pcv_status = PCV_NONE;
|
|
static enum PCV_Status _siputils_pcv_status = PCV_NONE;
|
|
static unsigned int _siputils_pcv_current_msg_id = (unsigned int)-1;
|
|
static unsigned int _siputils_pcv_current_msg_id = (unsigned int)-1;
|
|
|
|
|
|
-static void sip_generate_charging_vector(char *pcv)
|
|
|
|
|
|
+static void sip_generate_charging_vector(char *pcv, const unsigned int maxsize)
|
|
{
|
|
{
|
|
char s[PATH_MAX] = {0};
|
|
char s[PATH_MAX] = {0};
|
|
struct hostent *host = NULL;
|
|
struct hostent *host = NULL;
|
|
@@ -66,8 +85,15 @@ static void sip_generate_charging_vector(char *pcv)
|
|
struct in_addr *in = NULL;
|
|
struct in_addr *in = NULL;
|
|
static struct in_addr ip = {0};
|
|
static struct in_addr ip = {0};
|
|
unsigned char newConferenceIdentifier[SIZE_CONF_ID] = {0};
|
|
unsigned char newConferenceIdentifier[SIZE_CONF_ID] = {0};
|
|
|
|
+ int len = SIZE_CONF_ID;
|
|
|
|
+
|
|
|
|
+ /* if supplied buffer cannot carry 16 (SIZE_CONF_ID) hex characters and a null
|
|
|
|
+ terminator (=33 bytes), then reduce length of generated icid-value */
|
|
|
|
+ if(maxsize < (len * 2 + 1)) {
|
|
|
|
+ LM_WARN("generator buffer too small for new pcv icid-value!\n");
|
|
|
|
+ len = (maxsize - 1) / 2;
|
|
|
|
+ }
|
|
|
|
|
|
- memset(pcv, 0, SIZE_CONF_ID);
|
|
|
|
pid = getpid();
|
|
pid = getpid();
|
|
|
|
|
|
if(ip.s_addr == 0) {
|
|
if(ip.s_addr == 0) {
|
|
@@ -117,19 +143,18 @@ static void sip_generate_charging_vector(char *pcv)
|
|
idx++;
|
|
idx++;
|
|
}
|
|
}
|
|
LM_DBG("PCV generate\n");
|
|
LM_DBG("PCV generate\n");
|
|
- int i = 0;
|
|
|
|
- pcv[0] = '\0';
|
|
|
|
- for(i = 0; i < SIZE_CONF_ID; i++) {
|
|
|
|
- char hex[4] = {0};
|
|
|
|
|
|
+ char *ptr = pcv;
|
|
|
|
+ const char *endptr = ptr + maxsize - 1;
|
|
|
|
|
|
- snprintf(hex, 4, "%02X", newConferenceIdentifier[i]);
|
|
|
|
- strcat(pcv, hex);
|
|
|
|
|
|
+ for(int i = 0; i < len && ptr < endptr; i++) {
|
|
|
|
+ ptr += (snprintf(ptr, 3, "%02X", newConferenceIdentifier[i]) - 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-static unsigned int sip_param_end(const char *s, unsigned int len)
|
|
|
|
|
|
+static unsigned int sip_param_end(const char *s, const char *end)
|
|
{
|
|
{
|
|
unsigned int i;
|
|
unsigned int i;
|
|
|
|
+ unsigned int len = end - s;
|
|
|
|
|
|
for(i = 0; i < len; i++) {
|
|
for(i = 0; i < len; i++) {
|
|
if(s[i] == '\0' || s[i] == ' ' || s[i] == ';' || s[i] == ','
|
|
if(s[i] == '\0' || s[i] == ' ' || s[i] == ';' || s[i] == ','
|
|
@@ -140,61 +165,78 @@ static unsigned int sip_param_end(const char *s, unsigned int len)
|
|
return len;
|
|
return len;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+
|
|
|
|
+static inline void sip_initialize_parse_buffers()
|
|
|
|
+{
|
|
|
|
+ _siputils_pcv_id = (str)STR_NULL;
|
|
|
|
+ _siputils_pcv_genaddr = (str)STR_NULL;
|
|
|
|
+ _siputils_pcv_orig = (str)STR_NULL;
|
|
|
|
+ _siputils_pcv_term = (str)STR_NULL;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static inline void sip_initialize_pcv_buffers()
|
|
|
|
+{
|
|
|
|
+ memset(_siputils_pcv.s, 0, sizeof(_siputils_pcv_buf));
|
|
|
|
+ _siputils_pcv.len = 0;
|
|
|
|
+ sip_initialize_parse_buffers();
|
|
|
|
+}
|
|
|
|
+
|
|
static int sip_parse_charging_vector(const char *pcv_value, unsigned int len)
|
|
static int sip_parse_charging_vector(const char *pcv_value, unsigned int len)
|
|
{
|
|
{
|
|
/* now point to each PCV component */
|
|
/* now point to each PCV component */
|
|
- LM_DBG("parsing PCV header [%s]\n", pcv_value);
|
|
|
|
|
|
+ LM_DBG("parsing PCV header [%.*s]\n", len, pcv_value);
|
|
|
|
|
|
char *s = NULL;
|
|
char *s = NULL;
|
|
|
|
+ const char *pcv_value_end = pcv_value + len;
|
|
|
|
|
|
s = strstr(pcv_value, "icid-value=");
|
|
s = strstr(pcv_value, "icid-value=");
|
|
if(s != NULL) {
|
|
if(s != NULL) {
|
|
_siputils_pcv_id.s = s + strlen("icid-value=");
|
|
_siputils_pcv_id.s = s + strlen("icid-value=");
|
|
- _siputils_pcv_id.len = sip_param_end(_siputils_pcv_id.s, len);
|
|
|
|
|
|
+ _siputils_pcv_id.len = sip_param_end(_siputils_pcv_id.s, pcv_value_end);
|
|
LM_DBG("parsed P-Charging-Vector icid-value=%.*s\n",
|
|
LM_DBG("parsed P-Charging-Vector icid-value=%.*s\n",
|
|
- _siputils_pcv_id.len, _siputils_pcv_id.s);
|
|
|
|
|
|
+ STR_FMT(&_siputils_pcv_id));
|
|
} else {
|
|
} else {
|
|
LM_WARN("mandatory icid-value not found\n");
|
|
LM_WARN("mandatory icid-value not found\n");
|
|
- _siputils_pcv_id.s = NULL;
|
|
|
|
- _siputils_pcv_id.len = 0;
|
|
|
|
|
|
+ _siputils_pcv_id = (str)STR_NULL;
|
|
}
|
|
}
|
|
|
|
|
|
s = strstr(pcv_value, "icid-generated-at=");
|
|
s = strstr(pcv_value, "icid-generated-at=");
|
|
if(s != NULL) {
|
|
if(s != NULL) {
|
|
- _siputils_pcv_host.s = s + strlen("icid-generated-at=");
|
|
|
|
- _siputils_pcv_host.len = sip_param_end(_siputils_pcv_host.s, len);
|
|
|
|
|
|
+ _siputils_pcv_genaddr.s = s + strlen("icid-generated-at=");
|
|
|
|
+ _siputils_pcv_genaddr.len =
|
|
|
|
+ sip_param_end(_siputils_pcv_genaddr.s, pcv_value_end);
|
|
LM_DBG("parsed P-Charging-Vector icid-generated-at=%.*s\n",
|
|
LM_DBG("parsed P-Charging-Vector icid-generated-at=%.*s\n",
|
|
- _siputils_pcv_host.len, _siputils_pcv_host.s);
|
|
|
|
|
|
+ STR_FMT(&_siputils_pcv_genaddr));
|
|
} else {
|
|
} else {
|
|
LM_DBG("icid-generated-at not found\n");
|
|
LM_DBG("icid-generated-at not found\n");
|
|
- _siputils_pcv_host.s = NULL;
|
|
|
|
- _siputils_pcv_host.len = 0;
|
|
|
|
|
|
+ _siputils_pcv_genaddr = (str)STR_NULL;
|
|
}
|
|
}
|
|
|
|
|
|
s = strstr(pcv_value, "orig-ioi=");
|
|
s = strstr(pcv_value, "orig-ioi=");
|
|
if(s != NULL) {
|
|
if(s != NULL) {
|
|
_siputils_pcv_orig.s = s + strlen("orig-ioi=");
|
|
_siputils_pcv_orig.s = s + strlen("orig-ioi=");
|
|
- _siputils_pcv_orig.len = sip_param_end(_siputils_pcv_orig.s, len);
|
|
|
|
|
|
+ _siputils_pcv_orig.len =
|
|
|
|
+ sip_param_end(_siputils_pcv_orig.s, pcv_value_end);
|
|
LM_INFO("parsed P-Charging-Vector orig-ioi=%.*s\n",
|
|
LM_INFO("parsed P-Charging-Vector orig-ioi=%.*s\n",
|
|
- _siputils_pcv_orig.len, _siputils_pcv_orig.s);
|
|
|
|
|
|
+ STR_FMT(&_siputils_pcv_orig));
|
|
} else {
|
|
} else {
|
|
- _siputils_pcv_orig.s = NULL;
|
|
|
|
- _siputils_pcv_orig.len = 0;
|
|
|
|
|
|
+ _siputils_pcv_orig = (str)STR_NULL;
|
|
}
|
|
}
|
|
|
|
|
|
s = strstr(pcv_value, "term-ioi=");
|
|
s = strstr(pcv_value, "term-ioi=");
|
|
if(s != NULL) {
|
|
if(s != NULL) {
|
|
_siputils_pcv_term.s = s + strlen("term-ioi=");
|
|
_siputils_pcv_term.s = s + strlen("term-ioi=");
|
|
- _siputils_pcv_term.len = sip_param_end(_siputils_pcv_term.s, len);
|
|
|
|
|
|
+ _siputils_pcv_term.len =
|
|
|
|
+ sip_param_end(_siputils_pcv_term.s, pcv_value_end);
|
|
LM_INFO("parsed P-Charging-Vector term-ioi=%.*s\n",
|
|
LM_INFO("parsed P-Charging-Vector term-ioi=%.*s\n",
|
|
- _siputils_pcv_term.len, _siputils_pcv_term.s);
|
|
|
|
|
|
+ STR_FMT(&_siputils_pcv_term));
|
|
} else {
|
|
} else {
|
|
- _siputils_pcv_term.s = NULL;
|
|
|
|
- _siputils_pcv_term.len = 0;
|
|
|
|
|
|
+ _siputils_pcv_term = (str)STR_NULL;
|
|
}
|
|
}
|
|
|
|
|
|
// only icid-value is mandatory, log anyway when missing icid-generated-at
|
|
// only icid-value is mandatory, log anyway when missing icid-generated-at
|
|
- if(_siputils_pcv_host.s == NULL && _siputils_pcv_id.s != NULL && len > 0) {
|
|
|
|
|
|
+ if(_siputils_pcv_genaddr.s == NULL && _siputils_pcv_id.s != NULL
|
|
|
|
+ && len > 0) {
|
|
LM_WARN("icid-generated-at is missing %.*s\n", len, pcv_value);
|
|
LM_WARN("icid-generated-at is missing %.*s\n", len, pcv_value);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -205,8 +247,9 @@ static int sip_get_charging_vector(
|
|
struct sip_msg *msg, struct hdr_field **hf_pcv)
|
|
struct sip_msg *msg, struct hdr_field **hf_pcv)
|
|
{
|
|
{
|
|
struct hdr_field *hf;
|
|
struct hdr_field *hf;
|
|
- char *hdrname_cstr = P_CHARGING_VECTOR;
|
|
|
|
- str hdrname = {hdrname_cstr, strlen(hdrname_cstr)};
|
|
|
|
|
|
+ int hf_body_len;
|
|
|
|
+
|
|
|
|
+ str hdrname = STR_STATIC_INIT(P_CHARGING_VECTOR);
|
|
|
|
|
|
/* we need to be sure we have parsed all headers */
|
|
/* we need to be sure we have parsed all headers */
|
|
if(parse_headers(msg, HDR_EOH_F, 0) < 0) {
|
|
if(parse_headers(msg, HDR_EOH_F, 0) < 0) {
|
|
@@ -214,52 +257,55 @@ static int sip_get_charging_vector(
|
|
return -1;
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ sip_initialize_pcv_buffers();
|
|
|
|
+
|
|
for(hf = msg->headers; hf; hf = hf->next) {
|
|
for(hf = msg->headers; hf; hf = hf->next) {
|
|
if(hf->name.s[0] != 'P') {
|
|
if(hf->name.s[0] != 'P') {
|
|
continue;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
|
|
if(cmp_hdrname_str(&hf->name, &hdrname) == 0) {
|
|
if(cmp_hdrname_str(&hf->name, &hdrname) == 0) {
|
|
- /*
|
|
|
|
- * append p charging vector values after the header name "P-Charging-Vector" and
|
|
|
|
- * the ": " (+2)
|
|
|
|
- */
|
|
|
|
- char *pcv_body = _siputils_pcv_buf + strlen(P_CHARGING_VECTOR) + 2;
|
|
|
|
|
|
+
|
|
|
|
+ char *pcv_body = _siputils_pcv_buf;
|
|
|
|
+ *hf_pcv = hf;
|
|
|
|
|
|
if(hf->body.len > 0) {
|
|
if(hf->body.len > 0) {
|
|
- memcpy(pcv_body, hf->body.s, hf->body.len);
|
|
|
|
- _siputils_pcv.len =
|
|
|
|
- hf->body.len + strlen(P_CHARGING_VECTOR) + 2;
|
|
|
|
- pcv_body[hf->body.len] = '\0';
|
|
|
|
- if(sip_parse_charging_vector(pcv_body, hf->body.len) == 0) {
|
|
|
|
|
|
+ if(hf->body.len > sizeof(_siputils_pcv_buf)) {
|
|
|
|
+ LM_WARN("received charging vector header is longer than "
|
|
|
|
+ "reserved buffer - truncating.");
|
|
|
|
+ hf_body_len = sizeof(_siputils_pcv_buf);
|
|
|
|
+ } else
|
|
|
|
+ hf_body_len = hf->body.len;
|
|
|
|
+
|
|
|
|
+ memcpy(pcv_body, hf->body.s, hf_body_len);
|
|
|
|
+ _siputils_pcv.len = hf_body_len;
|
|
|
|
+
|
|
|
|
+ if(sip_parse_charging_vector(pcv_body, hf_body_len) == 0) {
|
|
LM_ERR("P-Charging-Vector header found but failed to parse "
|
|
LM_ERR("P-Charging-Vector header found but failed to parse "
|
|
"value [%s].\n",
|
|
"value [%s].\n",
|
|
pcv_body);
|
|
pcv_body);
|
|
- _siputils_pcv_status = PCV_NONE;
|
|
|
|
- _siputils_pcv.s = NULL;
|
|
|
|
- _siputils_pcv.len = 0;
|
|
|
|
|
|
+ _siputils_pcv_status = PCV_ICID_MISSING;
|
|
|
|
+ sip_initialize_parse_buffers();
|
|
} else {
|
|
} else {
|
|
_siputils_pcv_status = PCV_PARSED;
|
|
_siputils_pcv_status = PCV_PARSED;
|
|
- _siputils_pcv.s = hf->body.s;
|
|
|
|
- _siputils_pcv.len = hf->body.len;
|
|
|
|
}
|
|
}
|
|
return 2;
|
|
return 2;
|
|
} else {
|
|
} else {
|
|
- _siputils_pcv_id.s = 0;
|
|
|
|
- _siputils_pcv_id.len = 0;
|
|
|
|
- _siputils_pcv_host.s = 0;
|
|
|
|
- _siputils_pcv_host.len = 0;
|
|
|
|
- LM_WARN("P-Charging-Vector header found but no value.\n");
|
|
|
|
|
|
+ LM_WARN("P-Charging-Vector header found but has no body.\n");
|
|
|
|
+ _siputils_pcv_status = PCV_ICID_MISSING;
|
|
|
|
+ return 1;
|
|
}
|
|
}
|
|
- *hf_pcv = hf;
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
LM_DBG("No valid P-Charging-Vector header found.\n");
|
|
LM_DBG("No valid P-Charging-Vector header found.\n");
|
|
|
|
+ _siputils_pcv_status = PCV_NONE;
|
|
|
|
+ *hf_pcv = NULL;
|
|
return 1;
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
|
|
// Remove PCV if it is in the inbound request (if it was found by sip_get_charging_vector)
|
|
// Remove PCV if it is in the inbound request (if it was found by sip_get_charging_vector)
|
|
-static int sip_remove_charging_vector(struct sip_msg *msg, struct hdr_field *hf)
|
|
|
|
|
|
+static int sip_remove_charging_vector(
|
|
|
|
+ struct sip_msg *msg, struct hdr_field *hf, struct lump **anchor)
|
|
{
|
|
{
|
|
struct lump *l;
|
|
struct lump *l;
|
|
|
|
|
|
@@ -269,36 +315,58 @@ static int sip_remove_charging_vector(struct sip_msg *msg, struct hdr_field *hf)
|
|
LM_ERR("no memory\n");
|
|
LM_ERR("no memory\n");
|
|
return -1;
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
+ if(anchor != NULL) {
|
|
|
|
+ *anchor = l;
|
|
|
|
+ }
|
|
return 2;
|
|
return 2;
|
|
} else {
|
|
} else {
|
|
return 1;
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-static int sip_add_charging_vector(struct sip_msg *msg)
|
|
|
|
|
|
+static int sip_add_charging_vector(
|
|
|
|
+ struct sip_msg *msg, const str *pcv_hf, struct lump *anchor)
|
|
{
|
|
{
|
|
- struct lump *anchor;
|
|
|
|
- char *s;
|
|
|
|
|
|
+ str buf = STR_NULL;
|
|
|
|
|
|
- anchor = anchor_lump(msg, msg->unparsed - msg->buf, 0, 0);
|
|
|
|
- if(anchor == 0) {
|
|
|
|
- LM_ERR("can't get anchor\n");
|
|
|
|
- return -1;
|
|
|
|
|
|
+ if(anchor == NULL) {
|
|
|
|
+ LM_DBG("add pcv with new lump\n");
|
|
|
|
+ anchor = anchor_lump(msg, msg->unparsed - msg->buf, 0, 0);
|
|
|
|
+ if(anchor == 0) {
|
|
|
|
+ LM_ERR("can't get anchor\n");
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
- s = (char *)pkg_malloc(_siputils_pcv.len);
|
|
|
|
- if(!s) {
|
|
|
|
- PKG_MEM_ERROR;
|
|
|
|
- return -1;
|
|
|
|
- }
|
|
|
|
- memcpy(s, _siputils_pcv.s, _siputils_pcv.len);
|
|
|
|
|
|
+ buf.s = (char *)pkg_malloc(pcv_hf->len);
|
|
|
|
+ if(!buf.s)
|
|
|
|
+ goto out3;
|
|
|
|
+ memcpy(buf.s, pcv_hf->s, pcv_hf->len);
|
|
|
|
+
|
|
|
|
+ if((anchor = insert_new_lump_before(anchor, buf.s, pcv_hf->len, 0)) == 0)
|
|
|
|
+ goto out1;
|
|
|
|
+
|
|
|
|
+ if((anchor = insert_subst_lump_before(anchor, SUBST_SND_IP, 0)) == 0)
|
|
|
|
+ goto out2;
|
|
|
|
+
|
|
|
|
+ buf.s = (char *)pkg_malloc(CRLF_LEN + 1);
|
|
|
|
+ if(!buf.s)
|
|
|
|
+ goto out3;
|
|
|
|
+
|
|
|
|
+ buf.len = sprintf(buf.s, CRLF);
|
|
|
|
+ if((anchor = insert_new_lump_before(anchor, buf.s, buf.len, 0)) == 0)
|
|
|
|
+ goto out1;
|
|
|
|
|
|
- if(insert_new_lump_before(anchor, s, _siputils_pcv.len, 0) == 0) {
|
|
|
|
- LM_ERR("can't insert lump\n");
|
|
|
|
- pkg_free(s);
|
|
|
|
- return -1;
|
|
|
|
- }
|
|
|
|
return 1;
|
|
return 1;
|
|
|
|
+
|
|
|
|
+out1:
|
|
|
|
+ pkg_free(buf.s);
|
|
|
|
+out2:
|
|
|
|
+ LM_ERR("can't insert lump\n");
|
|
|
|
+ return -1;
|
|
|
|
+out3:
|
|
|
|
+ PKG_MEM_ERROR;
|
|
|
|
+ return -1;
|
|
}
|
|
}
|
|
|
|
|
|
int sip_handle_pcv(struct sip_msg *msg, char *flags, char *str2)
|
|
int sip_handle_pcv(struct sip_msg *msg, char *flags, char *str2)
|
|
@@ -307,13 +375,12 @@ int sip_handle_pcv(struct sip_msg *msg, char *flags, char *str2)
|
|
int remove_pcv = 0;
|
|
int remove_pcv = 0;
|
|
int replace_pcv = 0;
|
|
int replace_pcv = 0;
|
|
int i;
|
|
int i;
|
|
- str flag_str;
|
|
|
|
- struct hdr_field *hf_pcv = NULL;
|
|
|
|
|
|
+ int action = PCV_NOP;
|
|
|
|
|
|
- _siputils_pcv.len = 0;
|
|
|
|
- _siputils_pcv_status = PCV_NONE;
|
|
|
|
|
|
+ str flag_str;
|
|
|
|
+ struct lump *deleted_pcv_lump = NULL;
|
|
|
|
|
|
- if(fixup_get_svalue(msg, (gparam_p)flags, &flag_str) < 0) {
|
|
|
|
|
|
+ if(get_str_fparam(&flag_str, msg, (gparam_p)flags) < 0) {
|
|
LM_ERR("failed to retrieve parameter value\n");
|
|
LM_ERR("failed to retrieve parameter value\n");
|
|
return -1;
|
|
return -1;
|
|
}
|
|
}
|
|
@@ -342,16 +409,40 @@ int sip_handle_pcv(struct sip_msg *msg, char *flags, char *str2)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- sip_get_charging_vector(msg, &hf_pcv);
|
|
|
|
|
|
+ if(_siputils_pcv_current_msg_id != msg->id
|
|
|
|
+ || _siputils_pcv_status == PCV_NONE) {
|
|
|
|
+ if(sip_get_charging_vector(msg, &_siputils_pcv_hf_pcv) > 0) {
|
|
|
|
+ _siputils_pcv_current_msg_id = msg->id;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ switch(_siputils_pcv_status) {
|
|
|
|
+ case PCV_GENERATED:
|
|
|
|
+ LM_WARN("P-Charging-Vector can't be changed after generation. "
|
|
|
|
+ "Skipping command '%.*s'!",
|
|
|
|
+ STR_FMT(&flag_str));
|
|
|
|
+ return PCV_NOP;
|
|
|
|
+ case PCV_DELETED:
|
|
|
|
+ /* be consistent with the return value in this case */
|
|
|
|
+ if(remove_pcv)
|
|
|
|
+ return PCV_NOP;
|
|
|
|
+ default:
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
|
|
/*
|
|
/*
|
|
* We need to remove the original PCV if it was present and either
|
|
* We need to remove the original PCV if it was present and either
|
|
* we were asked to remove it or we were asked to replace it
|
|
* we were asked to remove it or we were asked to replace it
|
|
|
|
+ * or when it was broken anyway
|
|
*/
|
|
*/
|
|
- if(_siputils_pcv_status == PCV_PARSED && (replace_pcv || remove_pcv)) {
|
|
|
|
- i = sip_remove_charging_vector(msg, hf_pcv);
|
|
|
|
|
|
+ if((_siputils_pcv_status == PCV_PARSED && (replace_pcv || remove_pcv))
|
|
|
|
+ || _siputils_pcv_status == PCV_ICID_MISSING) {
|
|
|
|
+ i = sip_remove_charging_vector(
|
|
|
|
+ msg, _siputils_pcv_hf_pcv, &deleted_pcv_lump);
|
|
if(i <= 0)
|
|
if(i <= 0)
|
|
return (i == 0) ? -1 : i;
|
|
return (i == 0) ? -1 : i;
|
|
|
|
+ sip_initialize_pcv_buffers();
|
|
|
|
+ _siputils_pcv_status = PCV_DELETED;
|
|
|
|
+ action = PCV_DELETED;
|
|
}
|
|
}
|
|
|
|
|
|
/* Generate PCV if
|
|
/* Generate PCV if
|
|
@@ -361,103 +452,98 @@ int sip_handle_pcv(struct sip_msg *msg, char *flags, char *str2)
|
|
if(replace_pcv
|
|
if(replace_pcv
|
|
|| (generate_pcv && _siputils_pcv_status != PCV_GENERATED
|
|
|| (generate_pcv && _siputils_pcv_status != PCV_GENERATED
|
|
&& _siputils_pcv_status != PCV_PARSED)) {
|
|
&& _siputils_pcv_status != PCV_PARSED)) {
|
|
- strcpy(_siputils_pcv_buf, P_CHARGING_VECTOR);
|
|
|
|
- strcat(_siputils_pcv_buf, ": ");
|
|
|
|
-
|
|
|
|
- char *pcv_body = _siputils_pcv_buf + 19;
|
|
|
|
- char pcv_value[40];
|
|
|
|
-
|
|
|
|
- /* We use the IP address of the interface that received the message as generated-at */
|
|
|
|
- if(msg->rcv.bind_address == NULL
|
|
|
|
- || msg->rcv.bind_address->address_str.s == NULL) {
|
|
|
|
- LM_ERR("No IP address for message. Failed to generate charging "
|
|
|
|
- "vector.\n");
|
|
|
|
- return -2;
|
|
|
|
- }
|
|
|
|
|
|
+ char generated_pcv_buf[PCV_BUF_SIZE] = {0};
|
|
|
|
+ str generated_pcv = {generated_pcv_buf, 0};
|
|
|
|
+
|
|
|
|
+ strcpy(generated_pcv_buf, P_CHARGING_VECTOR);
|
|
|
|
+ strcat(generated_pcv_buf, ": ");
|
|
|
|
|
|
- sip_generate_charging_vector(pcv_value);
|
|
|
|
|
|
+ char *pcv_body = generated_pcv_buf + P_CHARGING_VECTOR_PREFIX_LEN;
|
|
|
|
+ int body_len = 0;
|
|
|
|
+ char pcv_value[40] = {0};
|
|
|
|
|
|
- _siputils_pcv.len = snprintf(pcv_body, PCV_BUF_SIZE - 19,
|
|
|
|
- "icid-value=%.*s; icid-generated-at=%.*s\r\n", 32, pcv_value,
|
|
|
|
- msg->rcv.bind_address->address_str.len,
|
|
|
|
- msg->rcv.bind_address->address_str.s);
|
|
|
|
- _siputils_pcv.len += 19;
|
|
|
|
|
|
+ sip_generate_charging_vector(pcv_value, sizeof(pcv_value));
|
|
|
|
|
|
- _siputils_pcv_status = PCV_GENERATED;
|
|
|
|
|
|
+ body_len = snprintf(pcv_body,
|
|
|
|
+ PCV_BUF_SIZE - P_CHARGING_VECTOR_PREFIX_LEN,
|
|
|
|
+ "icid-value=%.*s;icid-generated-at=", (int)sizeof(pcv_value),
|
|
|
|
+ pcv_value);
|
|
|
|
+ generated_pcv.len = body_len + P_CHARGING_VECTOR_PREFIX_LEN;
|
|
|
|
|
|
- /* if generated, reparse it */
|
|
|
|
- sip_parse_charging_vector(pcv_body, _siputils_pcv.len - 19);
|
|
|
|
/* if it was generated, we need to send it out as a header */
|
|
/* if it was generated, we need to send it out as a header */
|
|
- LM_INFO("Generated PCV header %.*s\n", _siputils_pcv.len - 2,
|
|
|
|
- _siputils_pcv_buf);
|
|
|
|
- i = sip_add_charging_vector(msg);
|
|
|
|
|
|
+ LM_INFO("Generated new PCV header %.*s\n", PCV_BUF_SIZE,
|
|
|
|
+ generated_pcv_buf);
|
|
|
|
+
|
|
|
|
+ i = sip_add_charging_vector(msg, &generated_pcv, deleted_pcv_lump);
|
|
if(i <= 0) {
|
|
if(i <= 0) {
|
|
LM_ERR("Failed to add P-Charging-Vector header\n");
|
|
LM_ERR("Failed to add P-Charging-Vector header\n");
|
|
return (i == 0) ? -1 : i;
|
|
return (i == 0) ? -1 : i;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ /* if generated and added, copy buffer and reparse it */
|
|
|
|
+ sip_initialize_pcv_buffers();
|
|
|
|
+ _siputils_pcv.len = body_len - CRLF_LEN;
|
|
|
|
+ memcpy(_siputils_pcv.s, pcv_body, _siputils_pcv.len);
|
|
|
|
+ if(sip_parse_charging_vector(
|
|
|
|
+ _siputils_pcv_buf, sizeof(_siputils_pcv_buf))) {
|
|
|
|
+ action = (_siputils_pcv_status == PCV_DELETED) ? PCV_REPLACED
|
|
|
|
+ : PCV_GENERATED;
|
|
|
|
+ _siputils_pcv_status = PCV_GENERATED;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
_siputils_pcv_current_msg_id = msg->id;
|
|
_siputils_pcv_current_msg_id = msg->id;
|
|
- return 1;
|
|
|
|
|
|
+ LM_DBG("Charging vector status is now %s\n", sstatus[_siputils_pcv_status]);
|
|
|
|
+ return action;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
int pv_get_charging_vector(
|
|
int pv_get_charging_vector(
|
|
struct sip_msg *msg, pv_param_t *param, pv_value_t *res)
|
|
struct sip_msg *msg, pv_param_t *param, pv_value_t *res)
|
|
{
|
|
{
|
|
- str pcv_pv;
|
|
|
|
|
|
+ str pcv_pv = STR_NULL;
|
|
|
|
|
|
if(_siputils_pcv_current_msg_id != msg->id
|
|
if(_siputils_pcv_current_msg_id != msg->id
|
|
|| _siputils_pcv_status == PCV_NONE) {
|
|
|| _siputils_pcv_status == PCV_NONE) {
|
|
- struct hdr_field *hf_pcv = NULL;
|
|
|
|
- if(sip_get_charging_vector(msg, &hf_pcv) > 0) {
|
|
|
|
|
|
+ if(sip_get_charging_vector(msg, &_siputils_pcv_hf_pcv) > 0) {
|
|
_siputils_pcv_current_msg_id = msg->id;
|
|
_siputils_pcv_current_msg_id = msg->id;
|
|
}
|
|
}
|
|
- LM_DBG("Parsed charging vector for pseudo-var\n");
|
|
|
|
|
|
+ LM_DBG("Parsed charging vector for pseudo-var, current state is %s\n",
|
|
|
|
+ sstatus[_siputils_pcv_status]);
|
|
} else {
|
|
} else {
|
|
- LM_DBG("Charging vector is in state %d for pseudo-var\n",
|
|
|
|
- _siputils_pcv_status);
|
|
|
|
|
|
+ LM_DBG("Charging vector is in state %s for pseudo-var and buffered.",
|
|
|
|
+ sstatus[_siputils_pcv_status]);
|
|
}
|
|
}
|
|
|
|
|
|
- switch(_siputils_pcv_status) {
|
|
|
|
- case PCV_GENERATED:
|
|
|
|
- LM_DBG("pcv_status==PCV_GENERATED\n");
|
|
|
|
- case PCV_PARSED:
|
|
|
|
- LM_DBG("pcv_status==PCV_PARSED\n");
|
|
|
|
- switch(param->pvn.u.isname.name.n) {
|
|
|
|
- case 5:
|
|
|
|
- pcv_pv = _siputils_pcv_term;
|
|
|
|
- break;
|
|
|
|
- case 4:
|
|
|
|
- pcv_pv = _siputils_pcv_orig;
|
|
|
|
- break;
|
|
|
|
- case 2:
|
|
|
|
- pcv_pv = _siputils_pcv_host;
|
|
|
|
- break;
|
|
|
|
-
|
|
|
|
- case 3:
|
|
|
|
- pcv_pv = _siputils_pcv_id;
|
|
|
|
- break;
|
|
|
|
-
|
|
|
|
- case 1:
|
|
|
|
- default:
|
|
|
|
- pcv_pv = _siputils_pcv;
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if(pcv_pv.len > 0)
|
|
|
|
- return pv_get_strval(msg, param, res, &pcv_pv);
|
|
|
|
- else
|
|
|
|
- LM_WARN("No value for pseudo-var $pcv but status was %d.\n",
|
|
|
|
- _siputils_pcv_status);
|
|
|
|
-
|
|
|
|
|
|
+ switch(param->pvn.u.isname.name.n) {
|
|
|
|
+ case PCV_PARAM_TERM:
|
|
|
|
+ pcv_pv = _siputils_pcv_term;
|
|
break;
|
|
break;
|
|
-
|
|
|
|
- case PCV_NONE:
|
|
|
|
|
|
+ case PCV_PARAM_ORIG:
|
|
|
|
+ pcv_pv = _siputils_pcv_orig;
|
|
|
|
+ break;
|
|
|
|
+ case PCV_PARAM_GENADDR:
|
|
|
|
+ pcv_pv = _siputils_pcv_genaddr;
|
|
|
|
+ break;
|
|
|
|
+ case PCV_PARAM_ID:
|
|
|
|
+ pcv_pv = _siputils_pcv_id;
|
|
|
|
+ break;
|
|
|
|
+ case PCV_PARAM_STATUS:
|
|
|
|
+ return pv_get_sintval(msg, param, res, _siputils_pcv_status);
|
|
|
|
+ break;
|
|
|
|
+ case PCV_PARAM_ALL:
|
|
default:
|
|
default:
|
|
|
|
+ pcv_pv = _siputils_pcv;
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if(pcv_pv.len > 0)
|
|
|
|
+ return pv_get_strval(msg, param, res, &pcv_pv);
|
|
|
|
+ else if(param->pvn.u.isname.name.n == PCV_PARAM_ID
|
|
|
|
+ || param->pvn.u.isname.name.n <= PCV_PARAM_ALL)
|
|
|
|
+ LM_WARN("No value for pseudo-var $pcv but status was %s.\n",
|
|
|
|
+ sstatus[_siputils_pcv_status]);
|
|
|
|
+
|
|
return pv_get_null(msg, param, res);
|
|
return pv_get_null(msg, param, res);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -469,27 +555,33 @@ int pv_parse_charging_vector_name(pv_spec_p sp, str *in)
|
|
switch(in->len) {
|
|
switch(in->len) {
|
|
case 3:
|
|
case 3:
|
|
if(strncmp(in->s, "all", 3) == 0)
|
|
if(strncmp(in->s, "all", 3) == 0)
|
|
- sp->pvp.pvn.u.isname.name.n = 1;
|
|
|
|
|
|
+ sp->pvp.pvn.u.isname.name.n = PCV_PARAM_ALL;
|
|
else
|
|
else
|
|
goto error;
|
|
goto error;
|
|
break;
|
|
break;
|
|
case 4:
|
|
case 4:
|
|
if(strncmp(in->s, "orig", 4) == 0)
|
|
if(strncmp(in->s, "orig", 4) == 0)
|
|
- sp->pvp.pvn.u.isname.name.n = 4;
|
|
|
|
|
|
+ sp->pvp.pvn.u.isname.name.n = PCV_PARAM_ORIG;
|
|
else if(strncmp(in->s, "term", 4) == 0)
|
|
else if(strncmp(in->s, "term", 4) == 0)
|
|
- sp->pvp.pvn.u.isname.name.n = 5;
|
|
|
|
|
|
+ sp->pvp.pvn.u.isname.name.n = PCV_PARAM_TERM;
|
|
else
|
|
else
|
|
goto error;
|
|
goto error;
|
|
break;
|
|
break;
|
|
case 5:
|
|
case 5:
|
|
if(strncmp(in->s, "value", 5) == 0)
|
|
if(strncmp(in->s, "value", 5) == 0)
|
|
- sp->pvp.pvn.u.isname.name.n = 3;
|
|
|
|
|
|
+ sp->pvp.pvn.u.isname.name.n = PCV_PARAM_ID;
|
|
|
|
+ else
|
|
|
|
+ goto error;
|
|
|
|
+ break;
|
|
|
|
+ case 6:
|
|
|
|
+ if(strncmp(in->s, "status", 6) == 0)
|
|
|
|
+ sp->pvp.pvn.u.isname.name.n = PCV_PARAM_STATUS;
|
|
else
|
|
else
|
|
goto error;
|
|
goto error;
|
|
break;
|
|
break;
|
|
case 7:
|
|
case 7:
|
|
if(strncmp(in->s, "genaddr", 7) == 0)
|
|
if(strncmp(in->s, "genaddr", 7) == 0)
|
|
- sp->pvp.pvn.u.isname.name.n = 2;
|
|
|
|
|
|
+ sp->pvp.pvn.u.isname.name.n = PCV_PARAM_GENADDR;
|
|
else
|
|
else
|
|
goto error;
|
|
goto error;
|
|
break;
|
|
break;
|