diff --git a/src/modules/dialog/dialog.c b/src/modules/dialog/dialog.c
index 08f0a858825..c70f87ed483 100644
--- a/src/modules/dialog/dialog.c
+++ b/src/modules/dialog/dialog.c
@@ -123,6 +123,9 @@ str dlg_bridge_controller = str_init("sip:controller@kamailio.org");
str dlg_bridge_contact = str_init("sip:controller@kamailio.org:5060");
+int bye_early_code = 480;
+str bye_early_reason = str_init("Temporarily Unavailable");
+
str ruri_pvar_param = str_init("$ru");
pv_elem_t * ruri_param_model = NULL;
str empty_str = STR_NULL;
@@ -199,6 +202,16 @@ static int w_dlg_remote_profile(sip_msg_t *msg, char *cmd, char *pname,
char *pval, char *puid, char *expires);
static int fixup_dlg_remote_profile(void** param, int param_no);
+static int w_dlg_req_with_headers_and_content(struct sip_msg *, char *, char *, char* , char *, char *);
+static int w_dlg_req_with_content(struct sip_msg *, char *, char *, char *, char *);
+static int w_dlg_req_with_headers(struct sip_msg *, char *, char *, char *);
+static int w_dlg_req_within(struct sip_msg *, char *, char *);
+
+static int fixup_dlg_dlg_req_within(void** , int );
+static int fixup_dlg_req_with_headers(void** , int );
+static int fixup_dlg_req_with_content(void** , int );
+static int fixup_dlg_req_with_headers_and_content(void** , int );
+
static cmd_export_t cmds[]={
{"dlg_manage", (cmd_function)w_dlg_manage, 0,0,
0, REQUEST_ROUTE },
@@ -256,6 +269,14 @@ static cmd_export_t cmds[]={
0, ANY_ROUTE },
{"dlg_db_load_extra", (cmd_function)w_dlg_db_load_extra, 0, 0,
0, ANY_ROUTE },
+ {"dlg_req_within", (cmd_function)w_dlg_req_within, 2, fixup_dlg_dlg_req_within,
+ 0, ANY_ROUTE},
+ {"dlg_req_within", (cmd_function)w_dlg_req_with_headers, 3, fixup_dlg_req_with_headers,
+ 0, ANY_ROUTE},
+ {"dlg_req_within", (cmd_function)w_dlg_req_with_content, 4, fixup_dlg_req_with_content,
+ 0, ANY_ROUTE},
+ {"dlg_req_within", (cmd_function)w_dlg_req_with_headers_and_content, 5,
+ fixup_dlg_req_with_headers_and_content, 0, ANY_ROUTE},
{"load_dlg", (cmd_function)load_dlg, 0, 0, 0, 0},
{0,0,0,0,0,0}
@@ -329,6 +350,8 @@ static param_export_t mod_params[]={
{ "h_id_step", PARAM_INT, &dlg_h_id_step },
{ "keep_proxy_rr", INT_PARAM, &dlg_keep_proxy_rr },
{ "dlg_filter_mode", INT_PARAM, &dlg_filter_mode },
+ { "bye_early_code", PARAM_INT, &bye_early_code },
+ { "bye_early_reason", PARAM_STR, &bye_early_reason },
{ 0,0,0 }
};
@@ -1099,6 +1122,232 @@ static int w_dlg_manage(struct sip_msg *msg, char *s1, char *s2)
return dlg_manage(msg);
}
+static int fixup_dlg_dlg_req_within(void** param, int param_no)
+{
+ char *val;
+ int n = 0;
+
+ if (param_no==1) {
+ val = (char*)*param;
+ if (strcasecmp(val,"all")==0) {
+ n = 0;
+ } else if (strcasecmp(val,"caller")==0) {
+ n = 1;
+ } else if (strcasecmp(val,"callee")==0) {
+ n = 2;
+ } else {
+ LM_ERR("invalid param \"%s\"\n", val);
+ return E_CFG;
+ }
+ pkg_free(*param);
+ *param=(void*)(long)n;
+ } else if (param_no==2) {
+ return fixup_spve_null(param, 1);
+ } else {
+ LM_ERR("called with parameter != 1\n");
+ return E_BUG;
+ }
+ return 0;
+}
+
+static int fixup_dlg_req_with_headers(void** param, int param_no)
+{
+ char *val;
+ int n = 0;
+
+ if (param_no==1) {
+ val = (char*)*param;
+ if (strcasecmp(val,"all")==0) {
+ n = 0;
+ } else if (strcasecmp(val,"caller")==0) {
+ n = 1;
+ } else if (strcasecmp(val,"callee")==0) {
+ n = 2;
+ } else {
+ LM_ERR("invalid param \"%s\"\n", val);
+ return E_CFG;
+ }
+ pkg_free(*param);
+ *param=(void*)(long)n;
+ } else if (param_no==2) {
+ return fixup_spve_null(param, 1);
+ } else if (param_no==3) {
+ return fixup_spve_null(param, 1);
+ } else {
+ LM_ERR("called with parameter != 1\n");
+ return E_BUG;
+ }
+ return 0;
+}
+
+
+static int fixup_dlg_req_with_content(void** param, int param_no)
+{
+ char *val;
+ int n = 0;
+
+ if (param_no==1) {
+ val = (char*)*param;
+ if (strcasecmp(val,"all")==0) {
+ n = 0;
+ } else if (strcasecmp(val,"caller")==0) {
+ n = 1;
+ } else if (strcasecmp(val,"callee")==0) {
+ n = 2;
+ } else {
+ LM_ERR("invalid param \"%s\"\n", val);
+ return E_CFG;
+ }
+ pkg_free(*param);
+ *param=(void*)(long)n;
+ } else if (param_no==2) {
+ return fixup_spve_null(param, 1);
+ } else if (param_no==3) {
+ return fixup_spve_null(param, 1);
+ } else if (param_no==4) {
+ return fixup_spve_null(param, 1);
+ } else {
+ LM_ERR("called with parameter != 1\n");
+ return E_BUG;
+ }
+ return 0;
+}
+
+static int fixup_dlg_req_with_headers_and_content(void** param, int param_no)
+{
+ char *val;
+ int n = 0;
+
+ if (param_no==1) {
+ val = (char*)*param;
+ if (strcasecmp(val,"all")==0) {
+ n = 0;
+ } else if (strcasecmp(val,"caller")==0) {
+ n = 1;
+ } else if (strcasecmp(val,"callee")==0) {
+ n = 2;
+ } else {
+ LM_ERR("invalid param \"%s\"\n", val);
+ return E_CFG;
+ }
+ pkg_free(*param);
+ *param=(void*)(long)n;
+ } else if (param_no==2) {
+ return fixup_spve_null(param, 1);
+ } else if (param_no==3) {
+ return fixup_spve_null(param, 1);
+ } else if (param_no==4) {
+ return fixup_spve_null(param, 1);
+ } else if (param_no==5) {
+ return fixup_spve_null(param, 1);
+ } else {
+ LM_ERR("called with parameter != 1\n");
+ return E_BUG;
+ }
+ return 0;
+}
+
+static int w_dlg_req_with_headers_and_content(struct sip_msg *msg, char *side, char *method, char* headers, char *content_type, char *content)
+{
+ dlg_cell_t *dlg = NULL;
+ int n;
+ str str_method = {0,0};
+ str str_headers = {0,0};
+ str str_content_type = {0,0};
+ str str_content = {0,0};
+
+ dlg = dlg_get_ctx_dialog();
+ if(dlg==NULL)
+ return -1;
+
+ if(fixup_get_svalue(msg, (gparam_p)method, &str_method)!=0)
+ {
+ LM_ERR("unable to get Method\n");
+ goto error;
+ }
+ if(str_method.s==NULL || str_method.len == 0)
+ {
+ LM_ERR("invalid Method parameter\n");
+ goto error;
+ }
+
+ if (headers) {
+ if(fixup_get_svalue(msg, (gparam_p)headers, &str_headers)!=0)
+ {
+ LM_ERR("unable to get Method\n");
+ goto error;
+ }
+ if(str_headers.s==NULL || str_headers.len == 0)
+ {
+ LM_ERR("invalid Headers parameter\n");
+ goto error;
+ }
+ }
+ if (content_type && content) {
+ if(fixup_get_svalue(msg, (gparam_p)content_type, &str_content_type)!=0)
+ {
+ LM_ERR("unable to get Content-Type\n");
+ goto error;
+ }
+ if(str_content_type.s==NULL || str_content_type.len == 0)
+ {
+ LM_ERR("invalid Headers parameter\n");
+ goto error;
+ }
+ if(fixup_get_svalue(msg, (gparam_p)content, &str_content)!=0)
+ {
+ LM_ERR("unable to get Content\n");
+ goto error;
+ }
+ if(str_content.s==NULL || str_content.len == 0)
+ {
+ LM_ERR("invalid Content parameter\n");
+ goto error;
+ }
+ }
+
+ n = (int)(long)side;
+ if(n==1)
+ {
+ if(dlg_request_within(msg, dlg, DLG_CALLER_LEG, &str_method, &str_headers, &str_content_type, &str_content)!=0)
+ goto error;
+ goto done;
+ } else if(n==2) {
+ if(dlg_request_within(msg, dlg, DLG_CALLEE_LEG, &str_method, &str_headers, &str_content_type, &str_content)!=0)
+ goto error;
+ goto done;
+ } else {
+ if(dlg_request_within(msg, dlg, DLG_CALLER_LEG, &str_method, &str_headers, &str_content_type, &str_content)!=0)
+ goto error;
+ if(dlg_request_within(msg, dlg, DLG_CALLEE_LEG, &str_method, &str_headers, &str_content_type, &str_content)!=0)
+ goto error;
+ goto done;
+ }
+
+done:
+ dlg_release(dlg);
+ return 1;
+
+error:
+ dlg_release(dlg);
+ return -1;
+}
+
+static int w_dlg_req_with_content(struct sip_msg *msg, char *side, char *method, char *content_type, char *content)
+{
+ return w_dlg_req_with_headers_and_content(msg, side, method, NULL, content_type, content);
+}
+
+static int w_dlg_req_with_headers(struct sip_msg *msg, char *side, char *method, char *headers)
+{
+ return w_dlg_req_with_headers_and_content(msg, side, method, headers, NULL, NULL);
+}
+
+static int w_dlg_req_within(struct sip_msg *msg, char *side, char *method)
+{
+ return w_dlg_req_with_headers_and_content(msg, side, method, NULL, NULL, NULL);
+}
+
static int w_dlg_bye(struct sip_msg *msg, char *side, char *s2)
{
dlg_cell_t *dlg = NULL;
diff --git a/src/modules/dialog/dlg_handlers.c b/src/modules/dialog/dlg_handlers.c
index bf49981b4cd..39f1f83dd75 100644
--- a/src/modules/dialog/dlg_handlers.c
+++ b/src/modules/dialog/dlg_handlers.c
@@ -945,6 +945,8 @@ int dlg_new_dialog(sip_msg_t *req, struct cell *t, const int run_initial_cbs)
LM_ERR("failed to create new dialog\n");
return -1;
}
+ // Store link to Transaction
+ dlg->t = t;
/* save caller's tag, cseq, contact and record route*/
if (populate_leg_info(dlg, req, t, DLG_CALLER_LEG,
diff --git a/src/modules/dialog/dlg_hash.h b/src/modules/dialog/dlg_hash.h
index 7367a1b7839..6913a5a3726 100644
--- a/src/modules/dialog/dlg_hash.h
+++ b/src/modules/dialog/dlg_hash.h
@@ -133,6 +133,7 @@ typedef struct dlg_cell
struct dlg_head_cbl cbs; /*!< dialog callbacks */
struct dlg_profile_link *profile_links; /*!< dialog profiles */
struct dlg_var *vars; /*!< dialog variables */
+ struct cell *t; /*!< Reference to Transaction of the INVITE */
unsigned int ka_src_counter; /*!< keepalive src (caller) counter */
unsigned int ka_dst_counter; /*!< keepalive dst (callee) counter */
} dlg_cell_t;
diff --git a/src/modules/dialog/dlg_req_within.c b/src/modules/dialog/dlg_req_within.c
index bd65d995d2e..9e412a950a6 100644
--- a/src/modules/dialog/dlg_req_within.c
+++ b/src/modules/dialog/dlg_req_within.c
@@ -40,6 +40,7 @@
#include "../../modules/tm/dlg.h"
#include "../../modules/tm/tm_load.h"
#include "../../core/counters.h"
+#include "../../core/parser/contact/parse_contact.h"
#include "dlg_timer.h"
#include "dlg_hash.h"
#include "dlg_handlers.h"
@@ -55,6 +56,9 @@ extern str dlg_lreq_callee_headers;
extern int dlg_ka_failed_limit;
extern int dlg_filter_mode;
+extern int bye_early_code;
+extern str bye_early_reason;
+
/**
*
*/
@@ -378,10 +382,24 @@ static inline int send_bye(struct dlg_cell * cell, int dir, str *hdrs)
dlg_iuid_t *iuid = NULL;
str lhdrs;
- /* do not send BYE request for non-confirmed dialogs (not supported) */
+ /* Send Cancel or final response for non-confirmed dialogs */
if (cell->state != DLG_STATE_CONFIRMED_NA && cell->state != DLG_STATE_CONFIRMED) {
- LM_ERR("terminating non-confirmed dialogs not supported\n");
- return -1;
+ if (cell->t) {
+ if (dir == DLG_CALLER_LEG) {
+ if(d_tmb.t_reply(cell->t->uas.request, bye_early_code, bye_early_reason.s)< 0) {
+ LM_ERR("Failed to send reply to caller\n");
+ return -1;
+ }
+ LM_DBG("\"%d %.*s\" sent to caller\n", bye_early_code, bye_early_reason.len, bye_early_reason.s);
+ } else {
+ d_tmb.cancel_all_uacs(cell->t, 0);
+ LM_DBG("CANCEL sent to callee(s)\n");
+ }
+ return 0;
+ } else {
+ LM_ERR("terminating non-confirmed dialog not possible, transaction not longer available.\n");
+ return -1;
+ }
}
/*verify direction*/
@@ -438,6 +456,262 @@ static inline int send_bye(struct dlg_cell * cell, int dir, str *hdrs)
return -1;
}
+dlg_t * build_dlg_t_early(struct sip_msg *msg, struct dlg_cell * cell, int branch_id, str * rr_set){
+
+ dlg_t* td = NULL;
+ str cseq;
+ unsigned int loc_seq;
+ char nbuf[MAX_URI_SIZE];
+ char dbuf[80];
+ str nuri = STR_NULL;
+ str duri = STR_NULL;
+ size_t sz;
+ char *p;
+ unsigned int own_rr = 0, skip_recs = 0;
+
+ if (cell->state != DLG_STATE_UNCONFIRMED && cell->state != DLG_STATE_EARLY) {
+ LM_ERR("Invalid state for build_dlg_state: %d (only working for unconfirmed or early dialogs)\n", cell->state);
+ goto error;
+ }
+
+ if (msg == NULL || msg->first_line.type != SIP_REPLY) {
+ if (!cell->t) {
+ LM_ERR("No Transaction associated\n");
+ goto error;
+ }
+
+ if (branch_id <= 0 || branch_id > cell->t->nr_of_outgoings) {
+ LM_ERR("Invalid branch %d (%d branches in transaction)\n", branch_id, cell->t->nr_of_outgoings);
+ goto error;
+ }
+ msg = msg;
+ }
+
+ if (!msg->contact && (parse_headers(msg,HDR_CONTACT_F,0)<0
+ || !msg->contact)) {
+ LM_ERR("bad sip message or missing Contact hdr\n");
+ goto error;
+ }
+
+ if ( parse_contact(msg->contact)<0 ||
+ ((contact_body_t *)msg->contact->parsed)->contacts==NULL) {
+ LM_ERR("bad Contact HDR\n");
+ goto error;
+ }
+
+ /*try to restore alias parameter if no route set */
+ nuri.s = nbuf;
+ nuri.len = MAX_URI_SIZE;
+ duri.s = dbuf;
+ duri.len = 80;
+ if(uri_restore_rcv_alias(&((contact_body_t *)msg->contact->parsed)->contacts->uri, &nuri, &duri)<0) {
+ nuri.len = 0;
+ duri.len = 0;
+ }
+
+ if(nuri.len>0 && duri.len>0) {
+ sz = sizeof(dlg_t) + (nuri.len+duri.len+2)*sizeof(char);
+ } else {
+ sz = sizeof(dlg_t);
+ }
+
+ td = (dlg_t*)pkg_malloc(sz);
+ if(!td){
+ LM_ERR("out of pkg memory\n");
+ return NULL;
+ }
+ memset(td, 0, sz);
+
+ /*route set*/
+ if (msg->record_route) {
+ if (cell->t) {
+ LM_DBG("Transaction exists\n");
+ own_rr = (cell->t->flags&TM_UAC_FLAG_R2)?2:
+ (cell->t->flags&TM_UAC_FLAG_RR)?1:0;
+ } else {
+ own_rr = (msg->flags&TM_UAC_FLAG_R2)?2:
+ (msg->flags&TM_UAC_FLAG_RR)?1:0;
+ }
+ skip_recs = cell->from_rr_nb + own_rr;
+
+ LM_DBG("Skipping %u records, %u of myself\n", skip_recs, own_rr);
+
+ if( print_rr_body(msg->record_route, rr_set, DLG_CALLEE_LEG,
+ &skip_recs) != 0 ){
+ LM_ERR("failed to print route records \n");
+ goto error;
+ }
+ LM_DBG("New Route-Set: %.*s\n", STR_FMT(rr_set));
+
+ if( parse_rr_body(rr_set->s, rr_set->len,
+ &td->route_set) !=0){
+ LM_ERR("failed to parse route set\n");
+ goto error;
+ }
+ }
+
+ /*local sequence number*/
+ cseq = cell->cseq[DLG_CALLER_LEG];
+
+ if (cseq.len > 0) {
+ LM_DBG("CSeq is %.*s\n", cseq.len, cseq.s);
+ if(str2int(&cseq, &loc_seq) != 0){
+ LM_ERR("invalid cseq\n");
+ goto error;
+ }
+ } else {
+ LM_DBG("CSeq not set yet, assuming 1\n");
+ loc_seq = 1;
+ }
+
+ /*we don not increase here the cseq as this will be done by TM*/
+ td->loc_seq.value = loc_seq;
+ td->loc_seq.is_set = 1;
+
+ LM_DBG("nuri: %.*s\n", STR_FMT(&nuri));
+ LM_DBG("duri: %.*s\n", STR_FMT(&duri));
+
+ if(nuri.len>0 && duri.len>0) {
+ /* req uri */
+ p = (char*)td + sizeof(dlg_t);
+ strncpy(p, nuri.s, nuri.len);
+ p[nuri.len] = '\0';
+ td->rem_target.s = p;
+ td->rem_target.len = nuri.len;
+ /* dst uri */
+ p += nuri.len + 1;
+ strncpy(p, duri.s, duri.len);
+ p[duri.len] = '\0';
+ td->dst_uri.s = p;
+ td->dst_uri.len = duri.len;
+ } else {
+ td->rem_target = ((contact_body_t *)msg->contact->parsed)->contacts->uri;
+ }
+
+ td->rem_uri = cell->from_uri;
+ td->loc_uri = cell->to_uri;
+ LM_DBG("rem_uri: %.*s\n", STR_FMT(&td->rem_uri));
+ LM_DBG("loc_uri: %.*s\n", STR_FMT(&td->loc_uri));
+
+ LM_DBG("rem_target: %.*s\n", STR_FMT(&td->rem_target));
+ LM_DBG("dst_uri: %.*s\n", STR_FMT(&td->dst_uri));
+
+ td->id.call_id = cell->callid;
+ td->id.rem_tag = cell->tag[DLG_CALLER_LEG];
+ td->id.loc_tag = cell->tag[DLG_CALLEE_LEG];
+
+ td->state= DLG_EARLY;
+ td->send_sock = cell->bind_addr[DLG_CALLER_LEG];
+
+ return td;
+
+error:
+ LM_ERR("Error occured creating early dialog\n");
+ free_tm_dlg(td);
+ return NULL;
+}
+
+int dlg_request_within(struct sip_msg *msg, struct dlg_cell *dlg, int side, str * method, str * hdrs, str * content_type, str * content)
+{
+ uac_req_t uac_r;
+ dlg_t* dialog_info;
+ int result;
+ dlg_iuid_t *iuid = NULL;
+ char rr_set_s[MAX_URI_SIZE];
+ str rr_set = {rr_set_s, 0};
+ str allheaders = {0, 0};
+ str content_type_hdr = {"Content-Type: ", 14};
+ int idx = 0;
+ memset(rr_set_s, 0, 500);
+
+ /* Special treatment for callee in early state*/
+ if (dlg->state != DLG_STATE_CONFIRMED_NA && dlg->state != DLG_STATE_CONFIRMED && side == DLG_CALLEE_LEG) {
+ LM_DBG("Send request to callee in early state...\n");
+
+ if (dlg->t == NULL && d_tmb.t_gett) {
+ dlg->t = d_tmb.t_gett();
+ if (dlg->t && dlg->t != T_UNDEFINED)
+ idx = dlg->t->nr_of_outgoings;
+ }
+ LM_DBG("Branch %i\n", idx);
+
+ /*verify direction*/
+ if ((dialog_info = build_dlg_t_early(msg, dlg, idx, &rr_set)) == 0){
+ LM_ERR("failed to create dlg_t\n");
+ goto err;
+ }
+ } else {
+ LM_DBG("Send request to caller or in confirmed state...\n");
+ /*verify direction*/
+ if ((dialog_info = build_dlg_t(dlg, side)) == 0){
+ LM_ERR("failed to create dlg_t\n");
+ goto err;
+ }
+ }
+
+ LM_DBG("sending %.*s to %s\n", method->len, method->s, (side==DLG_CALLER_LEG)?"caller":"callee");
+
+ iuid = dlg_get_iuid_shm_clone(dlg);
+ if(iuid==NULL)
+ {
+ LM_ERR("failed to create dialog unique id clone\n");
+ goto err;
+ }
+
+ if (hdrs && hdrs->len > 0) {
+ LM_DBG("Extra headers: %.*s\n", STR_FMT(hdrs));
+ allheaders.len += hdrs->len;
+ }
+
+ if (content_type && content_type->s && content && content->s) {
+ LM_DBG("Content-Type: %.*s\n", STR_FMT(content_type));
+ allheaders.len += content_type_hdr.len + content_type->len + 2;
+ }
+ if (allheaders.len > 0) {
+ allheaders.s = (char*)pkg_malloc(allheaders.len);
+ if (allheaders.s == NULL) {
+ PKG_MEM_ERROR;
+ goto err;
+ }
+ allheaders.len = 0;
+ if (hdrs && hdrs->len > 0) {
+ memcpy(allheaders.s, hdrs->s, hdrs->len);
+ allheaders.len += hdrs->len;
+ }
+ if (content_type && content_type->s && content && content->s) {
+ memcpy(allheaders.s + allheaders.len, content_type_hdr.s, content_type_hdr.len);
+ allheaders.len += content_type_hdr.len;
+ memcpy(allheaders.s + allheaders.len, content_type->s, content_type->len);
+ allheaders.len += content_type->len;
+ memcpy(allheaders.s + allheaders.len, "\r\n", 2);
+ allheaders.len += 2;
+ }
+ LM_DBG("All headers: %.*s\n", STR_FMT(&allheaders));
+ }
+
+ set_uac_req(&uac_r, method, allheaders.len?&allheaders:NULL, (content && content->len)?content:NULL, dialog_info, TMCB_LOCAL_COMPLETED,
+ bye_reply_cb, (void*)iuid);
+
+ result = d_tmb.t_request_within(&uac_r);
+
+ if (allheaders.s)
+ pkg_free(allheaders.s);
+
+ if(result < 0){
+ LM_ERR("failed to send request\n");
+ goto err;
+ }
+
+ free_tm_dlg(dialog_info);
+
+ LM_DBG("%.*s sent to %s\n", method->len, method->s, (side==DLG_CALLER_LEG)?"caller":"callee");
+
+ return 0;
+err:
+ if(dialog_info)
+ free_tm_dlg(dialog_info);
+ return -1;
+}
/* send keep-alive
* dlg - pointer to a struct dlg_cell
diff --git a/src/modules/dialog/dlg_req_within.h b/src/modules/dialog/dlg_req_within.h
index 420928ea264..5acf55d8492 100644
--- a/src/modules/dialog/dlg_req_within.h
+++ b/src/modules/dialog/dlg_req_within.h
@@ -52,5 +52,6 @@ int free_tm_dlg(dlg_t *td);
int dlg_bye(struct dlg_cell *dlg, str *hdrs, int side);
int dlg_bye_all(struct dlg_cell *dlg, str *hdrs);
int dlg_send_ka(dlg_cell_t *dlg, int dir);
+int dlg_request_within(struct sip_msg *msg, struct dlg_cell *dlg, int side, str * method, str * hdrs, str * content_type, str * content);
#endif
diff --git a/src/modules/dialog/doc/dialog.xml b/src/modules/dialog/doc/dialog.xml
index 0f4ffd46e5c..8bb460f9b8b 100644
--- a/src/modules/dialog/doc/dialog.xml
+++ b/src/modules/dialog/doc/dialog.xml
@@ -69,8 +69,8 @@
Voice Sistem SRL
- 2011
- Carsten Bock, http://www.ng-voice.com
+ 2011, 2022
+ ng-voice GmbH, Carsten Bock, http://www.ng-voice.com
diff --git a/src/modules/dialog/doc/dialog_admin.xml b/src/modules/dialog/doc/dialog_admin.xml
index f8cbfb2e9c7..3de68fba389 100644
--- a/src/modules/dialog/doc/dialog_admin.xml
+++ b/src/modules/dialog/doc/dialog_admin.xml
@@ -1468,7 +1468,7 @@ modparam("dialog", "timer_procs", 1)
-
+
enable_dmq (int)
If set to 1, the dialog will be synced via dmq.
@@ -1666,6 +1666,47 @@ modparam("dialog", "keep_proxy_rr", 1)
+
+
+ bye_early_code (int)
+
+ This parameter defines the reply-code being used for
+ dialogs being terminated in early stage (e.g. before
+ 200 OK/ACK).
+
+
+ Default value is 480
.
+
+
+ Set bye_early_code parameter
+
+...
+modparam("dialog", "bye_early_code", 503)
+...
+
+
+
+
+
+ bye_early_reason (string)
+
+ This parameter defines the reply-reason being used for
+ dialogs being terminated in early stage (e.g. before
+ 200 OK/ACK).
+
+
+ Default value is Temporarily Unavailable
.
+
+
+ Set bye_early_reason parameter
+
+...
+modparam("dialog", "bye_early_reason", "Call terminated")
+...
+
+
+
+
@@ -1936,7 +1977,9 @@ redlg_setflag("1");
dlg_bye(side)
- Send BYE to both parties of a dialog.
+ Send BYE to parties of a dialog or - if in early stage - a CANCEL to the
+ B-Party and a SIP response to the A-Party (as defined in bye_early_code /
+ bye_early_reason).
Meaning of the parameters is as follows:
@@ -2444,6 +2487,67 @@ dlg_reset_property("timeout-noreset");
+
+
+
+ dlg_req_within(side, method, [headers], [content_type, content])
+
+
+ Sends a in-dialog SIP Request with method to a party of a dialog indicated by the side parameter.
+
+ Meaning of the parameters is as follows:
+
+
+
+ side - where to send the request. It can be:
+ 'caller', 'callee', or 'all' (send to both sides).
+
+
+
+
+ method - Method of the request
+
+
+
+
+ headers (optional) - additional headers to be added to the request.
+
+
+
+
+ content_type (optional) - Content-Type of the request body - will
+ be added as Content-Type Header.
+
+
+
+
+ content (optional) - Content to be sent as body.
+
+
+
+
+ This function can be used from ANY_ROUTE.
+
+
+ dlg_req_within usage
+
+...
+ # Send a simple request:
+ dlg_req_within("all", "OPTIONS");
+...
+ # Send a simple request with extra headers:
+ dlg_req_within("caller", "OPTIONS", "X-Info: Bandwidth granted\r\nX-Info-2: Go ahead\r\n");
+...
+ # Send a simple request with body:
+ dlg_req_within("caller", "UPDATE", "application/sdp", "...some SDP...");
+...
+ # Send a simple request with extra headers and body:
+ dlg_req_within("callee", "INFO", "X-Info: Bandwidth granted\r\n", "application/sdp", "...some SDP...");
+...
+
+
+
+