mirror of https://github.com/sipwise/kamailio.git
Change-Id: I65cd77ac6e3520676c10172a65b64b3d7df60ecdchanges/54/10354/1
parent
262ed002a3
commit
298ee6bc00
@ -1,837 +0,0 @@
|
||||
From a9d5d28b8b750b06736b78680da66cfbd3d67e69 Mon Sep 17 00:00:00 2001
|
||||
From: Victor Seva <linuxmaniac@torreviejawireless.org>
|
||||
Date: Fri, 21 Mar 2014 21:59:41 +0100
|
||||
Subject: [PATCH] textops: functions to convert, append and remove multipart
|
||||
bodies
|
||||
|
||||
---
|
||||
modules/textops/textops.c | 767 ++++++++++++++++++++++++++++++++++++++++------
|
||||
1 file changed, 673 insertions(+), 94 deletions(-)
|
||||
|
||||
diff --git a/modules/textops/textops.c b/modules/textops/textops.c
|
||||
index 12bcf88..82c8ee8 100644
|
||||
--- a/modules/textops/textops.c
|
||||
+++ b/modules/textops/textops.c
|
||||
@@ -123,6 +123,14 @@ static int append_time_f(struct sip_msg* msg, char* , char *);
|
||||
static int append_time_request_f(struct sip_msg* msg, char* , char *);
|
||||
static int set_body_f(struct sip_msg* msg, char*, char *);
|
||||
static int set_rpl_body_f(struct sip_msg* msg, char*, char *);
|
||||
+static int set_multibody_0(struct sip_msg* msg, char*, char *, char *);
|
||||
+static int set_multibody_1(struct sip_msg* msg, char*, char *, char *);
|
||||
+static int set_multibody_2(struct sip_msg* msg, char*, char *, char *);
|
||||
+static int set_multibody_3(struct sip_msg* msg, char*, char *, char *);
|
||||
+static int append_multibody_2(struct sip_msg* msg, char*, char *);
|
||||
+static int append_multibody_3(struct sip_msg* msg, char*, char *, char *);
|
||||
+static int fixup_multibody_f(void** param, int param_no);
|
||||
+static int remove_multibody_f(struct sip_msg *msg, char *);
|
||||
static int is_method_f(struct sip_msg* msg, char* , char *);
|
||||
static int has_body_f(struct sip_msg *msg, char *type, char *str2 );
|
||||
static int in_list_f(struct sip_msg* _msg, char* _subject, char* _list,
|
||||
@@ -275,6 +283,27 @@ static cmd_export_t cmds[]={
|
||||
|
||||
{"bind_textops", (cmd_function)bind_textops, 0, 0, 0,
|
||||
0},
|
||||
+ {"set_body_multipart", (cmd_function)set_multibody_0, 0,
|
||||
+ 0, 0,
|
||||
+ REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
|
||||
+ {"set_body_multipart", (cmd_function)set_multibody_1, 1,
|
||||
+ fixup_spve_null, 0,
|
||||
+ REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
|
||||
+ {"set_body_multipart", (cmd_function)set_multibody_2, 2,
|
||||
+ fixup_spve_spve, 0,
|
||||
+ REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
|
||||
+ {"set_body_multipart", (cmd_function)set_multibody_3, 3,
|
||||
+ fixup_multibody_f, 0,
|
||||
+ REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
|
||||
+ {"append_body_part", (cmd_function)append_multibody_2, 2,
|
||||
+ fixup_spve_spve, 0,
|
||||
+ REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
|
||||
+ {"append_body_part", (cmd_function)append_multibody_3, 3,
|
||||
+ fixup_multibody_f, 0,
|
||||
+ REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
|
||||
+ {"remove_body_part", (cmd_function)remove_multibody_f, 1,
|
||||
+ fixup_spve_null, 0,
|
||||
+ REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
|
||||
|
||||
{0,0,0,0,0,0}
|
||||
};
|
||||
@@ -866,6 +895,23 @@ static inline int find_line_start(char *text, unsigned int text_len,
|
||||
return 0;
|
||||
}
|
||||
|
||||
+/**
|
||||
+ * return:
|
||||
+ * 1: multipart
|
||||
+ */
|
||||
+static int check_multipart(struct sip_msg *msg)
|
||||
+{
|
||||
+ int mime;
|
||||
+
|
||||
+ /* the function search for and parses the Content-Type hdr */
|
||||
+ mime = parse_content_type_hdr (msg);
|
||||
+ if(mime<0) {
|
||||
+ LM_ERR("failed to extract content type hdr\n");
|
||||
+ return -1;
|
||||
+ }
|
||||
+ if(mime!=MIMETYPE(MULTIPART,MIXED)) return 0;
|
||||
+ return 1;
|
||||
+}
|
||||
|
||||
/* Filters multipart/mixed body by leaving out everything else except
|
||||
* first body part of given content type. */
|
||||
@@ -874,10 +920,8 @@ static int filter_body_f(struct sip_msg* msg, char* _content_type,
|
||||
{
|
||||
char *start;
|
||||
unsigned int len;
|
||||
- str *content_type, body, params, boundary;
|
||||
- param_hooks_t hooks;
|
||||
- param_t *p, *list;
|
||||
- unsigned int mime;
|
||||
+ str *content_type, body;
|
||||
+ str boundary = {0,0};
|
||||
|
||||
body.s = get_body(msg);
|
||||
if (body.s == 0) {
|
||||
@@ -889,106 +933,73 @@ static int filter_body_f(struct sip_msg* msg, char* _content_type,
|
||||
LM_DBG("message body has zero length\n");
|
||||
return -1;
|
||||
}
|
||||
-
|
||||
- content_type = (str *)_content_type;
|
||||
|
||||
- mime = parse_content_type_hdr(msg);
|
||||
- if (mime <= 0) {
|
||||
- LM_ERR("failed to parse Content-Type hdr\n");
|
||||
- return -1;
|
||||
- }
|
||||
- if (mime != ((TYPE_MULTIPART << 16) + SUBTYPE_MIXED)) {
|
||||
- LM_ERR("content type is not multipart/mixed\n");
|
||||
- return -1;
|
||||
- }
|
||||
-
|
||||
- params.s = memchr(msg->content_type->body.s, ';',
|
||||
- msg->content_type->body.len);
|
||||
- if (params.s == NULL) {
|
||||
- LM_ERR("Content-Type hdr has no params\n");
|
||||
- return -1;
|
||||
- }
|
||||
- params.len = msg->content_type->body.len -
|
||||
- (params.s - msg->content_type->body.s);
|
||||
- if (parse_params(¶ms, CLASS_ANY, &hooks, &list) < 0) {
|
||||
- LM_ERR("while parsing Content-Type params\n");
|
||||
- return -1;
|
||||
- }
|
||||
- boundary.s = NULL;
|
||||
- boundary.len = 0;
|
||||
- for (p = list; p; p = p->next) {
|
||||
- if ((p->name.len == 8)
|
||||
- && (strncasecmp(p->name.s, "boundary", 8) == 0)) {
|
||||
- boundary.s = pkg_malloc(p->body.len + 2);
|
||||
- if (boundary.s == NULL) {
|
||||
- free_params(list);
|
||||
- LM_ERR("no memory for boundary string\n");
|
||||
- return -1;
|
||||
- }
|
||||
- *(boundary.s) = '-';
|
||||
- *(boundary.s + 1) = '-';
|
||||
- memcpy(boundary.s + 2, p->body.s, p->body.len);
|
||||
- boundary.len = 2 + p->body.len;
|
||||
- LM_DBG("boundary is <%.*s>\n", boundary.len, boundary.s);
|
||||
- break;
|
||||
- }
|
||||
+ if(check_multipart(msg)!=1) {
|
||||
+ LM_WARN("body not multipart\n");
|
||||
+ return -1;
|
||||
}
|
||||
- free_params(list);
|
||||
- if (boundary.s == NULL) {
|
||||
- LM_ERR("no mandatory param \";boundary\"\n");
|
||||
- return -1;
|
||||
+ if(get_boundary(msg, &boundary)!=0) {
|
||||
+ return -1;
|
||||
}
|
||||
-
|
||||
+ content_type = (str *)_content_type;
|
||||
start = body.s;
|
||||
len = body.len;
|
||||
-
|
||||
- while (find_line_start("Content-Type: ", 14, &start, &len)) {
|
||||
- start = start + 14;
|
||||
- len = len - 14;
|
||||
- if (len > content_type->len + 2) {
|
||||
- if (strncasecmp(start, content_type->s, content_type->len)
|
||||
- == 0) {
|
||||
- LM_DBG("found content type %.*s\n",
|
||||
- content_type->len, content_type->s);
|
||||
- start = start + content_type->len;
|
||||
- if ((*start != 13) || (*(start + 1) != 10)) {
|
||||
- LM_ERR("no CRLF found after content type\n");
|
||||
- goto err;
|
||||
- }
|
||||
- start = start + 2;
|
||||
- len = len - content_type->len - 2;
|
||||
- while ((len > 0) && ((*start == 13) || (*start == 10))) {
|
||||
- len = len - 1;
|
||||
- start = start + 1;
|
||||
- }
|
||||
- if (del_lump(msg, body.s - msg->buf, start - body.s, 0)
|
||||
- == 0) {
|
||||
- LM_ERR("deleting lump <%.*s> failed\n",
|
||||
- (int)(start - body.s), body.s);
|
||||
- goto err;
|
||||
- }
|
||||
- if (find_line_start(boundary.s, boundary.len, &start,
|
||||
- &len)) {
|
||||
- if (del_lump(msg, start - msg->buf, len, 0) == 0) {
|
||||
- LM_ERR("deleting lump <%.*s> failed\n",
|
||||
- len, start);
|
||||
- goto err;
|
||||
- } else {
|
||||
- pkg_free(boundary.s);
|
||||
- return 1;
|
||||
+
|
||||
+ while (find_line_start("Content-Type: ", 14, &start, &len))
|
||||
+ {
|
||||
+ start = start + 14;
|
||||
+ len = len - 14;
|
||||
+ LM_DBG("line: [%.*s]\n", len, start);
|
||||
+ if (len > content_type->len + 2) {
|
||||
+ if (strncasecmp(start, content_type->s, content_type->len)== 0)
|
||||
+ {
|
||||
+ LM_DBG("found content type %.*s\n",
|
||||
+ content_type->len, content_type->s);
|
||||
+ start = start + content_type->len;
|
||||
+ if ((*start != 13) || (*(start + 1) != 10))
|
||||
+ {
|
||||
+ LM_ERR("no CRLF found after content type\n");
|
||||
+ goto err;
|
||||
+ }
|
||||
+ start = start + 2;
|
||||
+ len = len - content_type->len - 2;
|
||||
+ while ((len > 0) && ((*start == 13) || (*start == 10)))
|
||||
+ {
|
||||
+ len = len - 1;
|
||||
+ start = start + 1;
|
||||
+ }
|
||||
+ if (del_lump(msg, body.s - msg->buf, start - body.s, 0)== 0)
|
||||
+ {
|
||||
+ LM_ERR("deleting lump <%.*s> failed\n",
|
||||
+ (int)(start - body.s), body.s);
|
||||
+ goto err;
|
||||
+ }
|
||||
+ if (find_line_start(boundary.s, boundary.len, &start,
|
||||
+ &len))
|
||||
+ {
|
||||
+ if (del_lump(msg, start - msg->buf, len, 0) == 0)
|
||||
+ {
|
||||
+ LM_ERR("deleting lump <%.*s> failed\n", len, start);
|
||||
+ goto err;
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ pkg_free(boundary.s);
|
||||
+ return 1;
|
||||
+ }
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ LM_ERR("boundary not found after content\n");
|
||||
+ goto err;
|
||||
+ }
|
||||
}
|
||||
- } else {
|
||||
- LM_ERR("boundary not found after content\n");
|
||||
+ } else {
|
||||
goto err;
|
||||
- }
|
||||
}
|
||||
- } else {
|
||||
- pkg_free(boundary.s);
|
||||
- return -1;
|
||||
- }
|
||||
}
|
||||
err:
|
||||
- pkg_free(boundary.s);
|
||||
+ if(boundary.s) pkg_free(boundary.s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1444,7 +1455,575 @@ static int set_rpl_body_f(struct sip_msg* msg, char* p1, char* p2)
|
||||
return 1;
|
||||
}
|
||||
|
||||
+static str* generate_boundary(str txt, str content_type,
|
||||
+ str content_disposition, str delimiter, unsigned int initial)
|
||||
+{
|
||||
+ unsigned int i = 0;
|
||||
+ str cth = {"Content-Type: ", 14};
|
||||
+ str cdh = {"Content-Disposition: ", 21};
|
||||
+ str* n;
|
||||
+ unsigned int flag = 0;
|
||||
|
||||
+ if(txt.len==0||content_type.len==0||delimiter.len==0)
|
||||
+ {
|
||||
+ LM_ERR("invalid parameters\n");
|
||||
+ return NULL;
|
||||
+ }
|
||||
+ n = pkg_malloc(sizeof(str));
|
||||
+ if(n==NULL)
|
||||
+ {
|
||||
+ LM_ERR("out of pkg memory\n");
|
||||
+ return NULL;
|
||||
+ }
|
||||
+ n->len = delimiter.len + 2 + CRLF_LEN;
|
||||
+ if(initial) n->len = 2*n->len;
|
||||
+ if(strncmp("\r\n\r\n", txt.s+txt.len-4,4)!=0)
|
||||
+ {
|
||||
+ n->len = n->len + CRLF_LEN;
|
||||
+ flag = 1;
|
||||
+ LM_DBG("adding final CRLF+CRLF\n");
|
||||
+ }
|
||||
+ n->len=n->len + cth.len + content_type.len + 2*CRLF_LEN;
|
||||
+ if(content_disposition.len>0)
|
||||
+ {
|
||||
+ n->len = n->len + cdh.len + content_disposition.len + CRLF_LEN;
|
||||
+ }
|
||||
+ n->len = n->len + txt.len;
|
||||
+
|
||||
+ n->s = pkg_malloc(sizeof(char)*(n->len));
|
||||
+ if(n->s==0)
|
||||
+ {
|
||||
+ LM_ERR("out of pkg memory\n");
|
||||
+ pkg_free(n);
|
||||
+ return NULL;
|
||||
+ }
|
||||
+ if(initial)
|
||||
+ {
|
||||
+ memcpy(n->s, "--", 2); i=2;
|
||||
+ memcpy(n->s+i, delimiter.s, delimiter.len); i=i+delimiter.len;
|
||||
+ memcpy(n->s+i, CRLF, CRLF_LEN); i=i+CRLF_LEN;
|
||||
+ }
|
||||
+
|
||||
+ memcpy(n->s+i, cth.s, cth.len); i=i+cth.len;
|
||||
+ memcpy(n->s+i, content_type.s, content_type.len); i=i+content_type.len;
|
||||
+ memcpy(n->s+i, CRLF, CRLF_LEN); i=i+CRLF_LEN;
|
||||
+
|
||||
+ if(content_disposition.len>0)
|
||||
+ {
|
||||
+ memcpy(n->s+i, cdh.s, cdh.len); i=i+cdh.len;
|
||||
+ memcpy(n->s+i, content_disposition.s, content_disposition.len);
|
||||
+ i=i+content_disposition.len;
|
||||
+ memcpy(n->s+i, CRLF, CRLF_LEN); i=i+CRLF_LEN;
|
||||
+ }
|
||||
+ memcpy(n->s+i, CRLF, CRLF_LEN); i=i+CRLF_LEN;
|
||||
+
|
||||
+ memcpy(n->s+i, txt.s, txt.len); i=i+txt.len;
|
||||
+ if(flag) { memcpy(n->s+i, CRLF, CRLF_LEN); i=i+CRLF_LEN; }
|
||||
+
|
||||
+ memcpy(n->s+i, "--", 2); i=i+2;
|
||||
+ memcpy(n->s+i, delimiter.s, delimiter.len); i=i+delimiter.len;
|
||||
+ memcpy(n->s+i, CRLF, CRLF_LEN); i=i+CRLF_LEN;
|
||||
+
|
||||
+ if(i!=n->len)
|
||||
+ {
|
||||
+ LM_ERR("out of bounds\n");
|
||||
+ }
|
||||
+ return n;
|
||||
+}
|
||||
+
|
||||
+int set_multibody_helper(struct sip_msg* msg, char* p1, char* p2, char* p3)
|
||||
+{
|
||||
+ struct lump *anchor;
|
||||
+ char* buf = NULL;
|
||||
+ int len;
|
||||
+ char* value_s;
|
||||
+ int value_len;
|
||||
+ str body = {0,0};
|
||||
+ str nb = {0,0};
|
||||
+ str oc = {0,0};
|
||||
+ str cd = {0,0};
|
||||
+ str delimiter = {0,0};
|
||||
+ str default_delimiter = {"unique-boundary-1", 17};
|
||||
+ str nc = {0,0};
|
||||
+ str cth = {"Content-Type: ", 14};
|
||||
+ str* nbb;
|
||||
+ unsigned int convert = 0;
|
||||
+ fparam_t header;
|
||||
+ header.orig = NULL;
|
||||
+ header.type = FPARAM_STR;
|
||||
+ header.v.str.s = "Mime-Version: 1.0\r\n";
|
||||
+ header.v.str.len = 19;
|
||||
+
|
||||
+ if(p3==0)
|
||||
+ {
|
||||
+ delimiter.s = default_delimiter.s;
|
||||
+ delimiter.len = default_delimiter.len;
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ if(fixup_get_svalue(msg, (gparam_p)p3, &delimiter)!=0)
|
||||
+ {
|
||||
+ LM_ERR("unable to get p3\n");
|
||||
+ return -1;
|
||||
+ }
|
||||
+ if(delimiter.s==NULL || delimiter.len == 0)
|
||||
+ {
|
||||
+ LM_ERR("invalid boundary parameter\n");
|
||||
+ return -1;
|
||||
+ }
|
||||
+ }
|
||||
+ LM_DBG("delimiter<%d>:[%.*s]\n", delimiter.len, delimiter.len, delimiter.s);
|
||||
+ if(p1==0 || p2==0)
|
||||
+ {
|
||||
+ if(check_multipart(msg)==1) {
|
||||
+ LM_WARN("body is already multipart. Do nothing\n");
|
||||
+ return -1;
|
||||
+ }
|
||||
+ convert = 1;
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ if(fixup_get_svalue(msg, (gparam_p)p1, &nb)!=0)
|
||||
+ {
|
||||
+ LM_ERR("unable to get p1\n");
|
||||
+ return -1;
|
||||
+ }
|
||||
+ if(nb.s==NULL || nb.len == 0)
|
||||
+ {
|
||||
+ LM_ERR("invalid body parameter\n");
|
||||
+ return -1;
|
||||
+ }
|
||||
+ if(fixup_get_svalue(msg, (gparam_p)p2, &oc)!=0)
|
||||
+ {
|
||||
+ LM_ERR("unable to get p2\n");
|
||||
+ return -1;
|
||||
+ }
|
||||
+ if(oc.s==NULL || oc.len==0)
|
||||
+ {
|
||||
+ LM_ERR("invalid content-type parameter\n");
|
||||
+ return -1;
|
||||
+ }
|
||||
+ if(check_multipart(msg)==1) {
|
||||
+ convert = -1;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ body.len = 0;
|
||||
+ body.s = get_body(msg);
|
||||
+ if(body.s==0)
|
||||
+ {
|
||||
+ LM_ERR("malformed sip message\n");
|
||||
+ return -1;
|
||||
+ }
|
||||
+ body.len = msg->len -(int)(body.s-msg->buf);
|
||||
+
|
||||
+ del_nonshm_lump( &(msg->body_lumps) );
|
||||
+ msg->body_lumps = NULL;
|
||||
+
|
||||
+ if(msg->content_length)
|
||||
+ {
|
||||
+ if(body.len > 0)
|
||||
+ {
|
||||
+ if(body.s+body.len>msg->buf+msg->len)
|
||||
+ {
|
||||
+ LM_ERR("invalid content length: %d\n", body.len);
|
||||
+ return -1;
|
||||
+ }
|
||||
+ if(convert==1)
|
||||
+ {
|
||||
+ /* need to copy body */
|
||||
+ nb.s=pkg_malloc(sizeof(char)*body.len);
|
||||
+ if (nb.s==0)
|
||||
+ {
|
||||
+ LM_ERR("out of pkg memory\n");
|
||||
+ return -1;
|
||||
+ }
|
||||
+ memcpy(nb.s, body.s, body.len);
|
||||
+ nb.len = body.len;
|
||||
+ if(msg->content_type!=NULL && msg->content_type->body.s!=NULL)
|
||||
+ {
|
||||
+ oc.len = msg->content_type->body.len;
|
||||
+ oc.s=pkg_malloc(sizeof(char)*oc.len);
|
||||
+ if (oc.s==0)
|
||||
+ {
|
||||
+ LM_ERR("out of pkg memory\n");
|
||||
+ goto error;
|
||||
+ }
|
||||
+ memcpy(oc.s, msg->content_type->body.s, oc.len);
|
||||
+ }
|
||||
+ }
|
||||
+ if(del_lump(msg, body.s-msg->buf, body.len, 0) == 0)
|
||||
+ {
|
||||
+ LM_ERR("cannot delete existing body");
|
||||
+ goto error;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ anchor = anchor_lump(msg, msg->unparsed-msg->buf, 0, 0);
|
||||
+ if(anchor==0)
|
||||
+ {
|
||||
+ LM_ERR("failed to get anchor\n");
|
||||
+ goto error;
|
||||
+ }
|
||||
+
|
||||
+ /* get initial boundary */
|
||||
+ nbb = generate_boundary(nb, oc, cd, delimiter, 1);
|
||||
+ if(nbb==NULL)
|
||||
+ {
|
||||
+ LM_ERR("couldn't create initial boundary\n");
|
||||
+ goto error;
|
||||
+ }
|
||||
+
|
||||
+ if(msg->content_length==0)
|
||||
+ {
|
||||
+ /* need to add Content-Length */
|
||||
+ len = nbb->len;
|
||||
+ value_s=int2str(len, &value_len);
|
||||
+
|
||||
+ len=CONTENT_LENGTH_LEN+value_len+CRLF_LEN;
|
||||
+ buf=pkg_malloc(sizeof(char)*len);
|
||||
+
|
||||
+ if (buf==0)
|
||||
+ {
|
||||
+ LM_ERR("out of pkg memory\n");
|
||||
+ goto error;
|
||||
+ }
|
||||
+
|
||||
+ memcpy(buf, CONTENT_LENGTH, CONTENT_LENGTH_LEN);
|
||||
+ memcpy(buf+CONTENT_LENGTH_LEN, value_s, value_len);
|
||||
+ memcpy(buf+CONTENT_LENGTH_LEN+value_len, CRLF, CRLF_LEN);
|
||||
+ if (insert_new_lump_after(anchor, buf, len, 0) == 0)
|
||||
+ {
|
||||
+ LM_ERR("failed to insert content-length lump\n");
|
||||
+ goto error;
|
||||
+ }
|
||||
+ buf = NULL;
|
||||
+ }
|
||||
+
|
||||
+ if(convert!=-1)
|
||||
+ {
|
||||
+ /* set new content type with delimiter */
|
||||
+ nc.len = delimiter.len + 27;
|
||||
+ nc.s = pkg_malloc(sizeof(char)*nc.len);
|
||||
+ memcpy(nc.s, "multipart/mixed;boundary=\"", 26);
|
||||
+ memcpy(nc.s+26, delimiter.s, delimiter.len);
|
||||
+ nc.s[26+delimiter.len] = '"';
|
||||
+ LM_DBG("content-type<%d>:[%.*s]\n", nc.len, nc.len, nc.s);
|
||||
+ /* add content-type */
|
||||
+ if(msg->content_type==NULL || msg->content_type->body.len!=nc.len
|
||||
+ || strncmp(msg->content_type->body.s, nc.s, nc.len)!=0)
|
||||
+ {
|
||||
+ if(msg->content_type!=NULL)
|
||||
+ if(del_lump(msg, msg->content_type->name.s-msg->buf,
|
||||
+ msg->content_type->len, 0) == 0)
|
||||
+ {
|
||||
+ LM_ERR("failed to delete content type\n");
|
||||
+ goto error;
|
||||
+ }
|
||||
+ value_len = nc.len;
|
||||
+ len = cth.len + value_len + CRLF_LEN;
|
||||
+ buf = pkg_malloc(sizeof(char)*len);
|
||||
+
|
||||
+ if(buf==0)
|
||||
+ {
|
||||
+ LM_ERR("out of pkg memory\n");
|
||||
+ goto error;
|
||||
+ }
|
||||
+ memcpy(buf, cth.s, cth.len);
|
||||
+ memcpy(buf + cth.len, nc.s, value_len);
|
||||
+ memcpy(buf + cth.len + value_len, CRLF, CRLF_LEN);
|
||||
+ if (insert_new_lump_after(anchor, buf, len, 0) == 0)
|
||||
+ {
|
||||
+ LM_ERR("failed to insert content-type lump\n");
|
||||
+ goto error;
|
||||
+ }
|
||||
+ buf = NULL;
|
||||
+ }
|
||||
+ /* add Mime-Version header */
|
||||
+ if(add_hf_helper(msg, 0, 0, &header, 0, 0)<0)
|
||||
+ {
|
||||
+ LM_ERR("failed to add Mime-Version header\n");
|
||||
+ goto error;
|
||||
+ }
|
||||
+ }
|
||||
+ anchor = anchor_lump(msg, body.s - msg->buf, 0, 0);
|
||||
+ if(anchor==0)
|
||||
+ {
|
||||
+ LM_ERR("failed to get body anchor\n");
|
||||
+ goto error;
|
||||
+ }
|
||||
+
|
||||
+ if(insert_new_lump_after(anchor, nbb->s, nbb->len, 0)==0)
|
||||
+ {
|
||||
+ LM_ERR("failed to insert body lump\n");
|
||||
+ goto error;
|
||||
+ }
|
||||
+ pkg_free(nbb);
|
||||
+ if(nc.s!=NULL) pkg_free(nc.s);
|
||||
+ LM_DBG("set flag FL_BODY_MULTIPART\n");
|
||||
+ msg->msg_flags |= FL_BODY_MULTIPART;
|
||||
+ return 1;
|
||||
+
|
||||
+error:
|
||||
+ if(nbb!=NULL) { pkg_free(nbb->s); pkg_free(nbb); }
|
||||
+ if(nc.s!=NULL) pkg_free(nc.s);
|
||||
+ if(buf!=NULL) pkg_free(buf);
|
||||
+ if(convert && nb.s!=NULL) pkg_free(nb.s);
|
||||
+ if(convert && oc.s!=NULL) pkg_free(oc.s);
|
||||
+ return -1;
|
||||
+}
|
||||
+
|
||||
+static int set_multibody_0(struct sip_msg* msg, char* p1, char* p2, char* p3)
|
||||
+{
|
||||
+ return set_multibody_helper(msg, NULL, NULL, NULL);
|
||||
+}
|
||||
+
|
||||
+static int set_multibody_1(struct sip_msg* msg, char* p1, char* p2, char* p3)
|
||||
+{
|
||||
+ return set_multibody_helper(msg, NULL, NULL, p1);
|
||||
+}
|
||||
+
|
||||
+static int set_multibody_2(struct sip_msg* msg, char* p1, char* p2, char* p3)
|
||||
+{
|
||||
+ return set_multibody_helper(msg, p1, p2, NULL);
|
||||
+}
|
||||
+
|
||||
+static int set_multibody_3(struct sip_msg* msg, char* p1, char* p2, char *p3)
|
||||
+{
|
||||
+ return set_multibody_helper(msg, p1, p2, p3);
|
||||
+}
|
||||
+
|
||||
+int append_multibody_helper(struct sip_msg* msg, char* p1, char* p2, char* p3)
|
||||
+{
|
||||
+ struct lump *l;
|
||||
+ int off;
|
||||
+ str body = {0,0};
|
||||
+ str nc = {0,0};
|
||||
+ str cd = {0,0};
|
||||
+ str txt = {0,0};
|
||||
+ str* nbb = NULL;
|
||||
+ str delimiter = {0,0};
|
||||
+
|
||||
+ if(p1==0 || p2==0)
|
||||
+ {
|
||||
+ LM_ERR("invalid parameters\n");
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ if(fixup_get_svalue(msg, (gparam_p)p1, &txt)!=0)
|
||||
+ {
|
||||
+ LM_ERR("unable to get p1\n");
|
||||
+ return -1;
|
||||
+ }
|
||||
+ if(txt.s==NULL || txt.len==0)
|
||||
+ {
|
||||
+ LM_ERR("invalid body parameter\n");
|
||||
+ return -1;
|
||||
+ }
|
||||
+ if(fixup_get_svalue(msg, (gparam_p)p2, &nc)!=0)
|
||||
+ {
|
||||
+ LM_ERR("unable to get p2\n");
|
||||
+ return -1;
|
||||
+ }
|
||||
+ if(nc.s==NULL || nc.len==0)
|
||||
+ {
|
||||
+ LM_ERR("invalid content-type parameter\n");
|
||||
+ return -1;
|
||||
+ }
|
||||
+ if(p3!=NULL)
|
||||
+ {
|
||||
+ if(fixup_get_svalue(msg, (gparam_p)p3, &cd)!=0)
|
||||
+ {
|
||||
+ LM_ERR("unable to get p3\n");
|
||||
+ return -1;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ body.s = get_body(msg);
|
||||
+ if(body.s==0) {
|
||||
+ LM_ERR("failed to get the message body\n");
|
||||
+ return -1;
|
||||
+ }
|
||||
+ body.len = msg->len -(int)(body.s-msg->buf);
|
||||
+ if(body.len==0) {
|
||||
+ LM_DBG("message body has zero length\n");
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ off=body.s-msg->buf;
|
||||
+ if((l=anchor_lump(msg, off+body.len, 0, 0))==0)
|
||||
+ {
|
||||
+ LM_ERR("WTF\n");
|
||||
+ return -1;
|
||||
+ }
|
||||
+ /* get boundary */
|
||||
+ if(get_boundary(msg, &delimiter)!=0) {
|
||||
+ LM_ERR("Cannot get boundary. Is body multipart?\n");
|
||||
+ return -1;
|
||||
+ }
|
||||
+ nbb = generate_boundary(txt, nc, cd, delimiter, 0);
|
||||
+ if(nbb==NULL)
|
||||
+ {
|
||||
+ LM_ERR("couldn't create initial boundary\n");
|
||||
+ pkg_free(delimiter.s);
|
||||
+ return -1;
|
||||
+ }
|
||||
+ pkg_free(delimiter.s);
|
||||
+ if(insert_new_lump_after(l, nbb->s, nbb->len, 0)==0){
|
||||
+ LM_ERR("could not insert new lump\n");
|
||||
+ pkg_free(nbb->s); pkg_free(nbb);
|
||||
+ return -1;
|
||||
+ }
|
||||
+ pkg_free(nbb);
|
||||
+ if(!(msg->msg_flags&FL_BODY_MULTIPART))
|
||||
+ {
|
||||
+ LM_DBG("set flag FL_BODY_MULTIPART\n");
|
||||
+ msg->msg_flags |= FL_BODY_MULTIPART;
|
||||
+ }
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
+static int append_multibody_2(struct sip_msg* msg, char* p1, char* p2)
|
||||
+{
|
||||
+ return append_multibody_helper(msg, p1, p2, NULL);
|
||||
+}
|
||||
+
|
||||
+static int append_multibody_3(struct sip_msg* msg, char* p1, char* p2, char *p3)
|
||||
+{
|
||||
+ return append_multibody_helper(msg, p1, p2, p3);
|
||||
+}
|
||||
+
|
||||
+static int fixup_multibody_f(void** param, int param_no)
|
||||
+{
|
||||
+ int ret;
|
||||
+ fparam_t* fp;
|
||||
+
|
||||
+ if(param_no<=3){
|
||||
+ if((ret=fix_param_types(FPARAM_PVE, param))<0){
|
||||
+ ERR("Cannot convert function parameter %d to spve \n",
|
||||
+ param_no);
|
||||
+ return E_UNSPEC;
|
||||
+ } else {
|
||||
+ fp=(fparam_t*)*param;
|
||||
+ if((ret==0) && (fp->v.pve->spec==0
|
||||
+ || fp->v.pve->spec->getf==0)){
|
||||
+ fparam_free_restore(param);
|
||||
+ return fix_param_types(FPARAM_STR, param);
|
||||
+ } else if(ret==1)
|
||||
+ return fix_param_types(FPARAM_STR, param);
|
||||
+ return ret;
|
||||
+ }
|
||||
+ } else {
|
||||
+ LM_ERR("wrong number of parameters\n");
|
||||
+ return E_UNSPEC;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static inline int get_line(char *s, int len)
|
||||
+{
|
||||
+ char *ch;
|
||||
+
|
||||
+ if ((ch = memchr(s, 13, len))) {
|
||||
+ if (*(ch + 1) != 10) {
|
||||
+ LM_ERR("No LF after CR\n");
|
||||
+ return 0;
|
||||
+ }
|
||||
+ return ch - s + 2;
|
||||
+ } else {
|
||||
+ LM_ERR("No CRLF found\n");
|
||||
+ return len;
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int remove_multibody_f(struct sip_msg* msg, char* p1)
|
||||
+{
|
||||
+ char *start, *end;
|
||||
+ unsigned int len, t;
|
||||
+ str content_type, body;
|
||||
+ str boundary = {0,0};
|
||||
+
|
||||
+ if(p1==0)
|
||||
+ {
|
||||
+ LM_ERR("invalid parameters\n");
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ if(fixup_get_svalue(msg, (gparam_p)p1, &content_type)!=0)
|
||||
+ {
|
||||
+ LM_ERR("unable to get p1\n");
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ body.s = get_body(msg);
|
||||
+ if (body.s == 0) {
|
||||
+ LM_ERR("failed to get the message body\n");
|
||||
+ return -1;
|
||||
+ }
|
||||
+ body.len = msg->len - (int)(body.s - msg->buf);
|
||||
+ if (body.len == 0) {
|
||||
+ LM_DBG("message body has zero length\n");
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ if(get_boundary(msg, &boundary)!=0) {
|
||||
+ LM_ERR("Cannot get boundary. Is body multipart?\n");
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ start = body.s;
|
||||
+ len = body.len;
|
||||
+
|
||||
+ while (find_line_start("Content-Type: ", 14, &start, &len))
|
||||
+ {
|
||||
+ end = start + 14;
|
||||
+ len = len - 14;
|
||||
+ if (len > (content_type.len + 2)) {
|
||||
+ if (strncasecmp(end, content_type.s, content_type.len)== 0)
|
||||
+ {
|
||||
+ LM_DBG("found content type %.*s\n",
|
||||
+ content_type.len, content_type.s);
|
||||
+ end = end + content_type.len;
|
||||
+ if ((*end != 13) || (*(end + 1) != 10))
|
||||
+ {
|
||||
+ LM_ERR("no CRLF found after content type\n");
|
||||
+ goto err;
|
||||
+ }
|
||||
+ end = end + 2;
|
||||
+ len = len - content_type.len - 2;
|
||||
+ if (find_line_start(boundary.s, boundary.len, &end,
|
||||
+ &len))
|
||||
+ {
|
||||
+ LM_DBG("found boundary %.*s\n", boundary.len, boundary.s);
|
||||
+ end = end + boundary.len;
|
||||
+ len = len - boundary.len;
|
||||
+ if (!(t = get_line(end, len))) goto err;
|
||||
+ end += t; len = end-start;
|
||||
+ if (del_lump(msg, start - msg->buf, len, 0) == 0)
|
||||
+ {
|
||||
+ LM_ERR("deleting lump <%.*s> failed\n", len, start);
|
||||
+ goto err;
|
||||
+ }
|
||||
+ pkg_free(boundary.s);
|
||||
+ if(!(msg->msg_flags&FL_BODY_MULTIPART))
|
||||
+ {
|
||||
+ LM_DBG("set flag FL_BODY_MULTIPART\n");
|
||||
+ msg->msg_flags |= FL_BODY_MULTIPART;
|
||||
+ }
|
||||
+ return 1;
|
||||
+ }
|
||||
+ LM_ERR("boundary not found after content\n");
|
||||
+ goto err;
|
||||
+ }
|
||||
+ start = end;
|
||||
+ }
|
||||
+ else goto err;
|
||||
+ }
|
||||
+ err:
|
||||
+ pkg_free(boundary.s);
|
||||
+ return -1;
|
||||
+}
|
||||
|
||||
static int append_to_reply_f(struct sip_msg* msg, char* key, char* str0)
|
||||
{
|
||||
--
|
||||
2.0.0.rc0
|
||||
|
@ -1,163 +0,0 @@
|
||||
From 2be579ffa48c1445a5c768b4a9b6a6532ac58363 Mon Sep 17 00:00:00 2001
|
||||
From: Victor Seva <linuxmaniac@torreviejawireless.org>
|
||||
Date: Sun, 16 Mar 2014 10:04:38 +0100
|
||||
Subject: [PATCH] textops: add new multipart functions documentation
|
||||
|
||||
---
|
||||
modules/textops/doc/textops_admin.xml | 140 ++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 140 insertions(+)
|
||||
|
||||
diff --git a/modules/textops/doc/textops_admin.xml b/modules/textops/doc/textops_admin.xml
|
||||
index e76e921..af9057a 100644
|
||||
--- a/modules/textops/doc/textops_admin.xml
|
||||
+++ b/modules/textops/doc/textops_admin.xml
|
||||
@@ -1358,6 +1358,146 @@ if (starts_with("$rU", "+358"))
|
||||
</example>
|
||||
</section>
|
||||
|
||||
+ <section id="textops.f.set_body_multipart">
|
||||
+ <title>
|
||||
+ <function moreinfo="none">set_body_multipart([txt,content_type][,boundary])</function>
|
||||
+ </title>
|
||||
+ <para>
|
||||
+ Set multipart body to a SIP message. If called with no parameters, will convert
|
||||
+ present body to multipart.
|
||||
+ </para>
|
||||
+ <para>Meaning of the parameters is as follows:</para>
|
||||
+ <itemizedlist>
|
||||
+ <listitem>
|
||||
+ <para><emphasis>txt</emphasis> - text for the body, can include
|
||||
+ pseudo-variables.
|
||||
+ </para>
|
||||
+ </listitem>
|
||||
+ <listitem>
|
||||
+ <para><emphasis>content_type</emphasis> - value of Content-Type header,
|
||||
+ can include pseudo-variables.
|
||||
+ </para>
|
||||
+ </listitem>
|
||||
+ <listitem>
|
||||
+ <para><emphasis>boundary</emphasis> - string to use as boundary,
|
||||
+ can include pseudo-variables. Default: unique-boundary-1
|
||||
+ </para>
|
||||
+ </listitem>
|
||||
+ </itemizedlist>
|
||||
+ <para>
|
||||
+ This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE.
|
||||
+ </para>
|
||||
+ <para>
|
||||
+ The core will take care of the last boundary ending "--". Detecting wich one is
|
||||
+ the last and fixing the others if needed.
|
||||
+ </para>
|
||||
+ <example>
|
||||
+ <title><function>set_body_multipart</function> usage</title>
|
||||
+ <programlisting format="linespecific">
|
||||
+...
|
||||
+set_body_multipart("test", "text/plain", "delimiter");
|
||||
+...
|
||||
+Will produce:
|
||||
+...
|
||||
+Content-Type: multipart/mixed;boundary="delimiter"
|
||||
+Mime-Version: 1.0
|
||||
+
|
||||
+--delimiter
|
||||
+Content-Type: text/plain
|
||||
+
|
||||
+text
|
||||
+
|
||||
+--delimiter
|
||||
+...
|
||||
+</programlisting>
|
||||
+ </example>
|
||||
+ </section>
|
||||
+
|
||||
+ <section id="textops.f.append_body_part">
|
||||
+ <title>
|
||||
+ <function moreinfo="none">append_body_part(txt,content_type[, content_disposition])</function>
|
||||
+ </title>
|
||||
+ <para>
|
||||
+ Append a part on multipart body SIP message. Will use "unique-boundary-1" as boundary.
|
||||
+ </para>
|
||||
+ <para>Meaning of the parameters is as follows:</para>
|
||||
+ <itemizedlist>
|
||||
+ <listitem>
|
||||
+ <para><emphasis>txt</emphasis> - text for the multipart body, can include
|
||||
+ pseudo-variables.
|
||||
+ </para>
|
||||
+ </listitem>
|
||||
+ <listitem>
|
||||
+ <para><emphasis>content_type</emphasis> - value of Content-Type header,
|
||||
+ can include pseudo-variables.
|
||||
+ </para>
|
||||
+ </listitem>
|
||||
+ <listitem>
|
||||
+ <para><emphasis>content_disposition</emphasis> - value of Content-Disposition header,
|
||||
+ can include pseudo-variables.
|
||||
+ </para>
|
||||
+ </listitem>
|
||||
+ </itemizedlist>
|
||||
+ <para>
|
||||
+ This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE.
|
||||
+ </para>
|
||||
+ <para>
|
||||
+ The core will take care of the last boundary ending "--". Detecting wich one is
|
||||
+ the last and fixing the others if needed.
|
||||
+ </para>
|
||||
+ <example>
|
||||
+ <title><function>append_body_part</function> usage</title>
|
||||
+ <programlisting format="linespecific">
|
||||
+...
|
||||
+$var(b) = "7e Od 04 55 75 69 20 4d 61 6b 65 43 61 6c 6c"
|
||||
+append_body_part("$var(b)", "application/vnd.cirpack.isdn-ext", "signal;handling=required");
|
||||
+...
|
||||
+Will append this the body:
|
||||
+...
|
||||
+Content-Type: application/vnd.cirpack.isdn-ext
|
||||
+Content-Disposition: signal;handling=required
|
||||
+
|
||||
+7e Od 04 55 75 69 20 4d 61 6b 65 43 61 6c 6c
|
||||
+
|
||||
+--unique-boundary-1
|
||||
+...
|
||||
+</programlisting>
|
||||
+ </example>
|
||||
+ </section>
|
||||
+
|
||||
+ <section id="textops.f.remove_body_part">
|
||||
+ <title>
|
||||
+ <function moreinfo="none">remove_body_part(content_type)</function>
|
||||
+ </title>
|
||||
+ <para>
|
||||
+ Remove a part on a multipart body SIP message.
|
||||
+ </para>
|
||||
+ <para>Meaning of the parameters is as follows:</para>
|
||||
+ <itemizedlist>
|
||||
+ <listitem>
|
||||
+ <para><emphasis>content_type</emphasis> - value of Content-Type header
|
||||
+ of the part to be removed. If more than one exists the first
|
||||
+ occurrence will be removed.
|
||||
+ </para>
|
||||
+ </listitem>
|
||||
+ </itemizedlist>
|
||||
+ <para>
|
||||
+ This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE.
|
||||
+ </para>
|
||||
+ <para>
|
||||
+ The core will take care of the last boundary ending "--". Detecting wich one is
|
||||
+ the last and fixing the others if needed.
|
||||
+ </para>
|
||||
+ <example>
|
||||
+ <title><function>remove_body_part</function> usage</title>
|
||||
+ <programlisting format="linespecific">
|
||||
+...
|
||||
+remove_body_part("application/vnd.cirpack.isdn-ext");
|
||||
+...
|
||||
+</programlisting>
|
||||
+ </example>
|
||||
+ </section>
|
||||
+
|
||||
</section>
|
||||
<section>
|
||||
<title>Known Limitations</title>
|
||||
--
|
||||
2.0.0.rc0
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,290 +0,0 @@
|
||||
From d03bed3fae3426b19b064129d4296a707bce1de8 Mon Sep 17 00:00:00 2001
|
||||
From: Sipwise Development Team <support@sipwise.com>
|
||||
Date: Wed, 20 May 2015 15:10:55 +0200
|
||||
Subject: [PATCH] db_postgres-timeout
|
||||
|
||||
Gbp-Pq-Topic: sipwise
|
||||
---
|
||||
modules/db_postgres/km_dbase.c | 43 +++++++++++++++++++++++++++++++++++++++++
|
||||
modules/db_postgres/km_pg_con.c | 36 ++++++++++++++++++++++++++++++++--
|
||||
modules/db_postgres/pg_con.c | 38 +++++++++++++++++++++++++++++++-----
|
||||
modules/db_postgres/pg_mod.c | 4 ++++
|
||||
modules/db_postgres/pg_mod.h | 2 ++
|
||||
5 files changed, 116 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/modules/db_postgres/km_dbase.c b/modules/db_postgres/km_dbase.c
|
||||
index 21c9cea..633959d 100644
|
||||
--- a/modules/db_postgres/km_dbase.c
|
||||
+++ b/modules/db_postgres/km_dbase.c
|
||||
@@ -167,6 +167,10 @@ static int db_postgres_submit_query(const db1_con_t* _con, const str* _s)
|
||||
int i, retries;
|
||||
ExecStatusType pqresult;
|
||||
PGresult *res = NULL;
|
||||
+ int sock, ret;
|
||||
+ fd_set fds;
|
||||
+ time_t max_time;
|
||||
+ struct timeval wait_time;
|
||||
|
||||
if(! _con || !_s || !_s->s)
|
||||
{
|
||||
@@ -217,6 +221,44 @@ static int db_postgres_submit_query(const db1_con_t* _con, const str* _s)
|
||||
/* exec the query */
|
||||
|
||||
if (PQsendQuery(CON_CONNECTION(_con), s)) {
|
||||
+ if (pg_timeout <= 0)
|
||||
+ goto do_read;
|
||||
+
|
||||
+ max_time = time(NULL) + pg_timeout;
|
||||
+
|
||||
+ while (1) {
|
||||
+ sock = PQsocket(CON_CONNECTION(_con));
|
||||
+ FD_ZERO(&fds);
|
||||
+ FD_SET(sock, &fds);
|
||||
+
|
||||
+ wait_time.tv_usec = 0;
|
||||
+ wait_time.tv_sec = max_time - time(NULL);
|
||||
+ if (wait_time.tv_sec <= 0 || wait_time.tv_sec > 0xffffff)
|
||||
+ goto timeout;
|
||||
+
|
||||
+ ret = select(sock + 1, &fds, NULL, NULL, &wait_time);
|
||||
+ if (ret < 0) {
|
||||
+ if (errno == EINTR)
|
||||
+ continue;
|
||||
+ LM_WARN("select() error\n");
|
||||
+ goto reset;
|
||||
+ }
|
||||
+ if (!ret) {
|
||||
+timeout:
|
||||
+ LM_WARN("timeout waiting for postgres reply\n");
|
||||
+ goto reset;
|
||||
+ }
|
||||
+
|
||||
+ if (!PQconsumeInput(CON_CONNECTION(_con))) {
|
||||
+ LM_WARN("error reading data from postgres server: %s\n",
|
||||
+ PQerrorMessage(CON_CONNECTION(_con)));
|
||||
+ goto reset;
|
||||
+ }
|
||||
+ if (!PQisBusy(CON_CONNECTION(_con)))
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+do_read:
|
||||
/* Get the result of the query */
|
||||
while ((res = PQgetResult(CON_CONNECTION(_con))) != NULL) {
|
||||
db_postgres_free_query(_con);
|
||||
@@ -239,6 +281,7 @@ static int db_postgres_submit_query(const db1_con_t* _con, const str* _s)
|
||||
PQerrorMessage(CON_CONNECTION(_con)));
|
||||
if(PQstatus(CON_CONNECTION(_con))!=CONNECTION_OK)
|
||||
{
|
||||
+reset:
|
||||
LM_DBG("reseting the connection to postgress server\n");
|
||||
PQreset(CON_CONNECTION(_con));
|
||||
}
|
||||
diff --git a/modules/db_postgres/km_pg_con.c b/modules/db_postgres/km_pg_con.c
|
||||
index 92acc75..9cac456 100644
|
||||
--- a/modules/db_postgres/km_pg_con.c
|
||||
+++ b/modules/db_postgres/km_pg_con.c
|
||||
@@ -26,12 +26,15 @@
|
||||
*/
|
||||
|
||||
#include "km_pg_con.h"
|
||||
+#include "pg_mod.h"
|
||||
#include "../../mem/mem.h"
|
||||
#include "../../dprint.h"
|
||||
#include "../../ut.h"
|
||||
#include "../../tls_hooks_init.h"
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
+#include <netinet/in.h>
|
||||
+#include <netinet/tcp.h>
|
||||
|
||||
|
||||
/*!
|
||||
@@ -46,6 +49,9 @@ struct pg_con* db_postgres_new_connection(struct db_id* id)
|
||||
{
|
||||
struct pg_con* ptr;
|
||||
char *ports;
|
||||
+ int i = 0;
|
||||
+ const char *keywords[10], *values[10];
|
||||
+ char to[16];
|
||||
|
||||
LM_DBG("db_id = %p\n", id);
|
||||
|
||||
@@ -67,6 +73,8 @@ struct pg_con* db_postgres_new_connection(struct db_id* id)
|
||||
|
||||
if (id->port) {
|
||||
ports = int2str(id->port, 0);
|
||||
+ keywords[i] = "port";
|
||||
+ values[i++] = ports;
|
||||
LM_DBG("opening connection: postgres://xxxx:xxxx@%s:%d/%s\n", ZSW(id->host),
|
||||
id->port, ZSW(id->database));
|
||||
} else {
|
||||
@@ -75,11 +83,27 @@ struct pg_con* db_postgres_new_connection(struct db_id* id)
|
||||
ZSW(id->database));
|
||||
}
|
||||
|
||||
+ keywords[i] = "host";
|
||||
+ values[i++] = id->host;
|
||||
+ keywords[i] = "dbname";
|
||||
+ values[i++] = id->database;
|
||||
+ keywords[i] = "user";
|
||||
+ values[i++] = id->username;
|
||||
+ keywords[i] = "password";
|
||||
+ values[i++] = id->password;
|
||||
+ if (pg_timeout > 0) {
|
||||
+ snprintf(to, sizeof(to)-1, "%d", pg_timeout + 3);
|
||||
+ keywords[i] = "connect_timeout";
|
||||
+ values[i++] = to;
|
||||
+ }
|
||||
+
|
||||
+ keywords[i] = values[i] = NULL;
|
||||
+
|
||||
/* don't attempt to re-init openssl if done already */
|
||||
if(tls_loaded()) PQinitSSL(0);
|
||||
|
||||
- ptr->con = PQsetdbLogin(id->host, ports, NULL, NULL, id->database, id->username, id->password);
|
||||
- LM_DBG("PQsetdbLogin(%p)\n", ptr->con);
|
||||
+ ptr->con = PQconnectdbParams(keywords, values, 1);
|
||||
+ LM_DBG("PQconnectdbParams(%p)\n", ptr->con);
|
||||
|
||||
if( (ptr->con == 0) || (PQstatus(ptr->con) != CONNECTION_OK) )
|
||||
{
|
||||
@@ -92,6 +116,14 @@ struct pg_con* db_postgres_new_connection(struct db_id* id)
|
||||
ptr->timestamp = time(0);
|
||||
ptr->id = id;
|
||||
|
||||
+#if defined(SO_KEEPALIVE) && defined(TCP_KEEPIDLE)
|
||||
+ if (pg_keepalive) {
|
||||
+ i = 1;
|
||||
+ setsockopt(PQsocket(ptr->con), SOL_SOCKET, SO_KEEPALIVE, &i, sizeof(i));
|
||||
+ setsockopt(PQsocket(ptr->con), IPPROTO_TCP, TCP_KEEPIDLE, &pg_keepalive, sizeof(pg_keepalive));
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
return ptr;
|
||||
|
||||
err:
|
||||
diff --git a/modules/db_postgres/pg_con.c b/modules/db_postgres/pg_con.c
|
||||
index 32b9be7..86c68fa 100644
|
||||
--- a/modules/db_postgres/pg_con.c
|
||||
+++ b/modules/db_postgres/pg_con.c
|
||||
@@ -39,6 +39,7 @@
|
||||
#include "pg_con.h"
|
||||
#include "pg_uri.h"
|
||||
#include "pg_sql.h"
|
||||
+#include "pg_mod.h"
|
||||
|
||||
#include "../../mem/mem.h"
|
||||
#include "../../dprint.h"
|
||||
@@ -47,6 +48,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <netinet/in.h>
|
||||
+#include <netinet/tcp.h>
|
||||
#include <time.h>
|
||||
|
||||
|
||||
@@ -237,7 +239,9 @@ int pg_con_connect(db_con_t* con)
|
||||
struct pg_con* pcon;
|
||||
struct pg_uri* puri;
|
||||
char* port_str;
|
||||
- int ret;
|
||||
+ int ret, i = 0;
|
||||
+ const char *keywords[10], *values[10];
|
||||
+ char to[16];
|
||||
|
||||
pcon = DB_GET_PAYLOAD(con);
|
||||
puri = DB_GET_PAYLOAD(con->uri);
|
||||
@@ -251,6 +255,8 @@ int pg_con_connect(db_con_t* con)
|
||||
|
||||
if (puri->port > 0) {
|
||||
port_str = int2str(puri->port, 0);
|
||||
+ keywords[i] = "port";
|
||||
+ values[i++] = port_str;
|
||||
} else {
|
||||
port_str = NULL;
|
||||
}
|
||||
@@ -260,12 +266,26 @@ int pg_con_connect(db_con_t* con)
|
||||
pcon->con = NULL;
|
||||
}
|
||||
|
||||
- pcon->con = PQsetdbLogin(puri->host, port_str,
|
||||
- NULL, NULL, puri->database,
|
||||
- puri->username, puri->password);
|
||||
+ keywords[i] = "host";
|
||||
+ values[i++] = puri->host;
|
||||
+ keywords[i] = "dbname";
|
||||
+ values[i++] = puri->database;
|
||||
+ keywords[i] = "user";
|
||||
+ values[i++] = puri->username;
|
||||
+ keywords[i] = "password";
|
||||
+ values[i++] = puri->password;
|
||||
+ if (pg_timeout > 0) {
|
||||
+ snprintf(to, sizeof(to)-1, "%d", pg_timeout + 3);
|
||||
+ keywords[i] = "connect_timeout";
|
||||
+ values[i++] = to;
|
||||
+ }
|
||||
+
|
||||
+ keywords[i] = values[i] = NULL;
|
||||
+
|
||||
+ pcon->con = PQconnectdbParams(keywords, values, 1);
|
||||
|
||||
if (pcon->con == NULL) {
|
||||
- ERR("postgres: PQsetdbLogin ran out of memory\n");
|
||||
+ ERR("postgres: PQconnectdbParams ran out of memory\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
@@ -285,6 +305,14 @@ int pg_con_connect(db_con_t* con)
|
||||
PQprotocolVersion(pcon->con), 0 );
|
||||
#endif
|
||||
|
||||
+#if defined(SO_KEEPALIVE) && defined(TCP_KEEPIDLE)
|
||||
+ if (pg_keepalive) {
|
||||
+ i = 1;
|
||||
+ setsockopt(PQsocket(pcon->con), SOL_SOCKET, SO_KEEPALIVE, &i, sizeof(i));
|
||||
+ setsockopt(PQsocket(pcon->con), IPPROTO_TCP, TCP_KEEPIDLE, &pg_keepalive, sizeof(pg_keepalive));
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
ret = timestamp_format(pcon->con);
|
||||
if (ret == 1 || ret == -1) {
|
||||
/* Assume INT8 representation if detection fails */
|
||||
diff --git a/modules/db_postgres/pg_mod.c b/modules/db_postgres/pg_mod.c
|
||||
index 1b2d9f7..14f50a3 100644
|
||||
--- a/modules/db_postgres/pg_mod.c
|
||||
+++ b/modules/db_postgres/pg_mod.c
|
||||
@@ -61,6 +61,8 @@ int pg_retries = 2; /* How many times should the module try re-execute failed c
|
||||
* 0 disables reconnecting */
|
||||
|
||||
int pg_lockset = 4;
|
||||
+int pg_timeout = 0; /* default = no timeout */
|
||||
+int pg_keepalive = 0;
|
||||
|
||||
/*
|
||||
* Postgres module interface
|
||||
@@ -92,6 +94,8 @@ static cmd_export_t cmds[] = {
|
||||
static param_export_t params[] = {
|
||||
{"retries", PARAM_INT, &pg_retries },
|
||||
{"lockset", PARAM_INT, &pg_lockset },
|
||||
+ {"timeout", PARAM_INT, &pg_timeout },
|
||||
+ {"tcp_keepalive", PARAM_INT, &pg_keepalive },
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
diff --git a/modules/db_postgres/pg_mod.h b/modules/db_postgres/pg_mod.h
|
||||
index 10c0535..194c7df 100644
|
||||
--- a/modules/db_postgres/pg_mod.h
|
||||
+++ b/modules/db_postgres/pg_mod.h
|
||||
@@ -41,6 +41,8 @@
|
||||
*/
|
||||
|
||||
extern int pg_retries;
|
||||
+extern int pg_timeout;
|
||||
+extern int pg_keepalive;
|
||||
|
||||
/** @} */
|
||||
|
||||
--
|
||||
2.1.4
|
||||
|
@ -1,220 +0,0 @@
|
||||
--- a/modules/nathelper/nathelper.c
|
||||
+++ b/modules/nathelper/nathelper.c
|
||||
@@ -344,6 +344,7 @@
|
||||
static int natping_disable_flag = -1;
|
||||
static int natping_processes = 1;
|
||||
static int contact_only = 0;
|
||||
+static int filter_socket = 0;
|
||||
|
||||
static str nortpproxy_str = str_init("a=nortpproxy:yes");
|
||||
|
||||
@@ -426,6 +427,7 @@
|
||||
{"keepalive_timeout", INT_PARAM, &nh_keepalive_timeout },
|
||||
{"udpping_from_path", INT_PARAM, &udpping_from_path },
|
||||
{"contact_only", INT_PARAM, &contact_only },
|
||||
+ {"filter_socket", INT_PARAM, &filter_socket },
|
||||
|
||||
{0, 0, 0}
|
||||
};
|
||||
@@ -2075,6 +2077,7 @@
|
||||
char *path_ip_str = NULL;
|
||||
unsigned int path_ip = 0;
|
||||
unsigned short path_port = 0;
|
||||
+ unsigned int options = 0;
|
||||
|
||||
if((*natping_state) == 0)
|
||||
goto done;
|
||||
@@ -2087,10 +2090,13 @@
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
+
|
||||
+ if(contact_only) options |= GAU_OPT_ONLY_CONTACT;
|
||||
+ if(filter_socket) options |= GAU_OPT_FILTER_SOCKET;
|
||||
+
|
||||
rval = ul.get_all_ucontacts_opt(buf, cblen, (ping_nated_only?ul.nat_flag:0),
|
||||
((unsigned int)(unsigned long)timer_idx)*natping_interval+iteration,
|
||||
- natping_processes*natping_interval,
|
||||
- contact_only ? GAU_OPT_ONLY_CONTACT : 0);
|
||||
+ natping_processes*natping_interval, options);
|
||||
if (rval<0) {
|
||||
LM_ERR("failed to fetch contacts\n");
|
||||
goto done;
|
||||
@@ -2106,8 +2112,7 @@
|
||||
}
|
||||
rval = ul.get_all_ucontacts_opt(buf,cblen,(ping_nated_only?ul.nat_flag:0),
|
||||
((unsigned int)(unsigned long)timer_idx)*natping_interval+iteration,
|
||||
- natping_processes*natping_interval,
|
||||
- contact_only ? GAU_OPT_ONLY_CONTACT : 0);
|
||||
+ natping_processes*natping_interval, options);
|
||||
if (rval != 0) {
|
||||
pkg_free(buf);
|
||||
goto done;
|
||||
--- a/modules/usrloc/dlist.c
|
||||
+++ b/modules/usrloc/dlist.c
|
||||
@@ -79,6 +79,44 @@
|
||||
return 1;
|
||||
}
|
||||
|
||||
+int sprint_all_socket_lists(char **buf, int len)
|
||||
+{
|
||||
+ struct socket_info *si;
|
||||
+ struct socket_info** list;
|
||||
+ struct addr_info* ai;
|
||||
+ unsigned short proto=PROTO_UDP;
|
||||
+ unsigned int pos = 0;
|
||||
+ size_t size = 0;
|
||||
+ str s_proto = STR_NULL;
|
||||
+ char *s = *buf;
|
||||
+
|
||||
+ list=get_sock_info_list(proto);
|
||||
+ s_proto.s = get_valid_proto_name(proto);
|
||||
+ s_proto.len = strlen(s_proto.s);
|
||||
+
|
||||
+ for(si=list?*list:0; si; si=si->next){
|
||||
+ if (si->addr_info_lst)
|
||||
+ {
|
||||
+ for (ai=si->addr_info_lst; ai; ai=ai->next)
|
||||
+ {
|
||||
+ size = 5 + s_proto.len + ai->address_str.len + si->port_no_str.len;
|
||||
+ if (pos + size + 1>len) return -1;
|
||||
+ snprintf(s + pos, len-pos, ",'%s:%s:%s'",
|
||||
+ s_proto.s, ai->address_str.s, si->port_no_str.s);
|
||||
+ pos = pos + size;
|
||||
+ }
|
||||
+ }else{
|
||||
+ size = 5 + s_proto.len + si->name.len + si->port_no_str.len;
|
||||
+ if (pos + size + 1>len) return -1;
|
||||
+ snprintf(s + pos, len-pos, ",'%s:%s:%s'",
|
||||
+ s_proto.s, si->name.s, si->port_no_str.s);
|
||||
+ pos = pos + size;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ s[0] = '('; s[pos] = ')'; pos = pos + 1;
|
||||
+ return pos;
|
||||
+}
|
||||
|
||||
/*!
|
||||
* \brief Get all contacts from the database, in partitions if wanted
|
||||
@@ -96,6 +134,8 @@
|
||||
unsigned int options)
|
||||
{
|
||||
static char query_buf[512];
|
||||
+ static char socket_list[256];
|
||||
+ static str socket_str;
|
||||
static str query_str;
|
||||
|
||||
struct socket_info *sock;
|
||||
@@ -115,8 +155,50 @@
|
||||
int i;
|
||||
void *cp;
|
||||
int shortage, needed;
|
||||
+ char *query_format = NULL;
|
||||
+ db1_con_t* dbh = NULL;
|
||||
+ db_func_t* dbf = NULL;
|
||||
+
|
||||
+ if (options & GAU_OPT_FILTER_SOCKET)
|
||||
+ {
|
||||
+ socket_str.s = socket_list;
|
||||
+ socket_str.len = sprint_all_socket_lists(&socket_str.s, 256);
|
||||
+ if(socket_str.len<0) {
|
||||
+ LM_ERR("error generating socket_list parameter\n");
|
||||
+ return -1;
|
||||
+ }
|
||||
+ query_format = "select %.*s, %.*s, %.*s,"
|
||||
+ " %.*s, %.*s, %.*s from %s where %.*s > %.*s and"
|
||||
+#ifdef ORACLE_USRLOC
|
||||
+ " bitand(%.*s, %d) = %d and mod(id, %u) = %u and %.*s in %.*s";
|
||||
+#else
|
||||
+ " %.*s & %d = %d and id %% %u = %u and %.*s in %.*s";
|
||||
+#endif
|
||||
+ if(!ul_dbh_ro) {
|
||||
+ LM_ERR("read-only connection not available. Using db_url\n");
|
||||
+ dbh = ul_dbh;
|
||||
+ dbf = &ul_dbf;
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ dbh = ul_dbh_ro;
|
||||
+ dbf = &ul_dbf_ro;
|
||||
+ }
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ query_format = "select %.*s, %.*s, %.*s,"
|
||||
+ " %.*s, %.*s, %.*s from %s where %.*s > %.*s and"
|
||||
+#ifdef ORACLE_USRLOC
|
||||
+ " bitand(%.*s, %d) = %d and mod(id, %u) = %u";
|
||||
+#else
|
||||
+ " %.*s & %d = %d and id %% %u = %u";
|
||||
+#endif
|
||||
+ dbh = ul_dbh;
|
||||
+ dbf = &ul_dbf;
|
||||
+ }
|
||||
|
||||
- if(ul_dbf.raw_query==NULL) {
|
||||
+ if(dbf->raw_query==NULL) {
|
||||
LM_WARN("DB raw query support is required, but not implemented\n");
|
||||
return -1;
|
||||
}
|
||||
@@ -136,13 +218,8 @@
|
||||
|
||||
for (dom = root; dom!=NULL ; dom=dom->next) {
|
||||
/* build query */
|
||||
- i = snprintf( query_buf, sizeof(query_buf), "select %.*s, %.*s, %.*s,"
|
||||
- " %.*s, %.*s, %.*s from %s where %.*s > %.*s and"
|
||||
-#ifdef ORACLE_USRLOC
|
||||
- " bitand(%.*s, %d) = %d and mod(id, %u) = %u",
|
||||
-#else
|
||||
- " %.*s & %d = %d and id %% %u = %u",
|
||||
-#endif
|
||||
+ i = snprintf( query_buf, sizeof(query_buf),
|
||||
+ query_format,
|
||||
received_col.len, received_col.s,
|
||||
contact_col.len, contact_col.s,
|
||||
sock_col.len, sock_col.s,
|
||||
@@ -153,19 +230,21 @@
|
||||
expires_col.len, expires_col.s,
|
||||
now_len, now_s,
|
||||
cflags_col.len, cflags_col.s,
|
||||
- flags, flags, part_max, part_idx);
|
||||
+ flags, flags, part_max, part_idx,
|
||||
+ sock_col.len, sock_col.s,
|
||||
+ socket_str.len, socket_str.s);
|
||||
if ( i>=sizeof(query_buf) ) {
|
||||
LM_ERR("DB query too long\n");
|
||||
return -1;
|
||||
}
|
||||
query_str.s = query_buf;
|
||||
query_str.len = i;
|
||||
- if ( ul_dbf.raw_query( ul_dbh, &query_str, &res)<0 ) {
|
||||
+ if ( dbf->raw_query( dbh, &query_str, &res)<0 ) {
|
||||
LM_ERR("raw_query failed\n");
|
||||
return -1;
|
||||
}
|
||||
if( RES_ROW_N(res)==0 ) {
|
||||
- ul_dbf.free_result(ul_dbh, res);
|
||||
+ dbf->free_result(dbh, res);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -269,7 +348,7 @@
|
||||
len -= needed;
|
||||
} /* row cycle */
|
||||
|
||||
- ul_dbf.free_result(ul_dbh, res);
|
||||
+ dbf->free_result(dbh, res);
|
||||
} /* domain cycle */
|
||||
|
||||
/* len < 0 is possible, if size of the buffer < sizeof(c->c.len) */
|
||||
--- a/modules/usrloc/usrloc.h
|
||||
+++ b/modules/usrloc/usrloc.h
|
||||
@@ -43,6 +43,7 @@
|
||||
#define DB_READONLY 4
|
||||
|
||||
#define GAU_OPT_ONLY_CONTACT (1<<0) /* ignore "received" address and always return contact */
|
||||
+#define GAU_OPT_FILTER_SOCKET (1<<1) /* filter query by socket field */
|
||||
|
||||
/*forward declaration necessary for udomain*/
|
||||
|
Loading…
Reference in new issue