浏览代码

modules_k/dialog: Add multiple features.

- Set and get dialog variables programmatically (needed in certain
  cases where PV access does not suffice).
- Change dialog callback signature to pass both request and
  response message instead of just the request. This is to enable
  access to at least one type of message when the other is not
  available; e.g., DLGCB_FAILED callbacks due to a local timeout
  (408) do not provide requests but responses only.
  Also, adapt callback usages accordingly at multiple spots.
- Provide additional callback DLGCB_TERMINATED_CONFIRMED that is
  executed whenever the response to a BYE request is sent.
- Move unreference_dialog() to a more suitable location.
- Provide functions to add and remove a dialog from a transaction
  (required for referencing at certain occassions).
- Move spiral detection functionality into dlg_new_dialog() to
  faciliate spiral detection when dlg_manage() is used.
- Add a dialog's reference count to list of printable statistics.

Credits to Sven Knoblich, [email protected] .
Timo Reimann 14 年之前
父节点
当前提交
c021559e41

+ 3 - 1
modules_k/dialog/dialog.c

@@ -371,6 +371,8 @@ static int fixup_get_profile3(void** param, int param_no)
 int load_dlg( struct dlg_binds *dlgb )
 {
 	dlgb->register_dlgcb = register_dlgcb;
+	dlgb->set_dlg_var = set_dlg_variable;
+	dlgb->get_dlg_var = get_dlg_variable;
 	return 1;
 }
 
@@ -1211,7 +1213,7 @@ static inline void internal_rpc_print_dlg(rpc_t *rpc, void *c, struct dlg_cell *
 	if (with_context) {
 		rpc_cb.rpc = rpc;
 		rpc_cb.c = c;
-		run_dlg_callbacks( DLGCB_RPC_CONTEXT, dlg, NULL, DLG_DIR_NONE, (void *)&rpc_cb);
+		run_dlg_callbacks( DLGCB_RPC_CONTEXT, dlg, NULL, NULL, DLG_DIR_NONE, (void *)&rpc_cb);
 	}
 }
 

+ 12 - 6
modules_k/dialog/dlg_cb.c

@@ -40,7 +40,7 @@ static struct dlg_head_cbl* create_cbs = 0;
 
 static struct dlg_head_cbl* load_cbs = 0;
 
-static struct dlg_cb_params params = {NULL, DLG_DIR_NONE, NULL, NULL};
+static struct dlg_cb_params params = {NULL, NULL, DLG_DIR_NONE, NULL, NULL};
 
 
 #define POINTER_CLOSED_MARKER  ((void *)(-1))
@@ -184,7 +184,8 @@ static void run_load_callback(struct dlg_callback *cb)
 	struct dlg_cell *dlg;
 	unsigned int i;
 
-	params.msg = NULL;
+	params.req = NULL;
+	params.rpl = NULL;
 	params.direction = DLG_DIR_NONE;
 	params.param = &cb->param;
 
@@ -217,7 +218,8 @@ void run_create_callbacks(struct dlg_cell *dlg, struct sip_msg *msg)
 	if (create_cbs==NULL || create_cbs->first==NULL)
 		return;
 
-	params.msg = msg;
+	params.req = msg;
+	params.rpl = NULL;
 	/* initial request goes DOWNSTREAM all the time */
 	params.direction = DLG_DIR_DOWNSTREAM;
 	/* avoid garbage due static structure */
@@ -233,12 +235,16 @@ void run_create_callbacks(struct dlg_cell *dlg, struct sip_msg *msg)
 }
 
 
-void run_dlg_callbacks(int type , struct dlg_cell *dlg, struct sip_msg *msg,
-											unsigned int dir, void *dlg_data)
+void run_dlg_callbacks( int type ,
+						struct dlg_cell *dlg,
+						struct sip_msg *req,
+						struct sip_msg *rpl,
+						unsigned int dir, void *dlg_data)
 {
 	struct dlg_callback *cb;
 
-	params.msg = msg;
+	params.req = req;
+	params.rpl = rpl;
 	params.direction = dir;
 	params.dlg_data = dlg_data;
 

+ 16 - 3
modules_k/dialog/dlg_cb.h

@@ -37,7 +37,8 @@
 struct dlg_cell;
 
 struct dlg_cb_params {
-	struct sip_msg* msg;       /* sip msg related to the callback event */
+	struct sip_msg* req;       /* sip request msg related to the callback event */
+    struct sip_msg* rpl;       /* sip reply msg related to the callback event */
 	unsigned int direction;    /* direction of the sip msg */
 	void *dlg_data;            /* generic paramter, specific to callback */
 	void **param;              /* parameter passed at callback registration*/
@@ -52,6 +53,13 @@ typedef void (param_free_cb) (void *param);
 typedef int (*register_dlgcb_f)(struct dlg_cell* dlg, int cb_types,
 		dialog_cb f, void *param, param_free_cb ff);
 
+/* method to set a variable within a dialog */
+typedef int (*set_dlg_variable_f)( struct dlg_cell* dlg,
+                                   str* key,
+                                   str* val);
+/* method to get a variable from a dialog */
+typedef str* (*get_dlg_variable_f)( struct dlg_cell* dlg,
+                                    str* key);
 
 #define DLGCB_LOADED          (1<<0)
 #define DLGCB_CREATED         (1<<1)
@@ -67,6 +75,7 @@ typedef int (*register_dlgcb_f)(struct dlg_cell* dlg, int cb_types,
 #define DLGCB_RPC_CONTEXT     (1<<11)
 #define DLGCB_DESTROY         (1<<12)
 #define DLGCB_SPIRALED        (1<<13)
+#define DLGCB_TERMINATED_CONFIRMED (1<<14)
 
 struct dlg_callback {
 	int types;
@@ -91,8 +100,12 @@ int register_dlgcb( struct dlg_cell* dlg, int types, dialog_cb f, void *param, p
 
 void run_create_callbacks(struct dlg_cell *dlg, struct sip_msg *msg);
 
-void run_dlg_callbacks( int type , struct dlg_cell *dlg, struct sip_msg *msg,
-		unsigned int dir, void *dlg_data);
+void run_dlg_callbacks( int type ,
+                        struct dlg_cell *dlg,
+                        struct sip_msg *req,
+                        struct sip_msg *rpl,
+                        unsigned int dir,
+                        void *dlg_data);
 
 void run_load_callbacks( void );
 

+ 282 - 147
modules_k/dialog/dlg_handlers.c

@@ -279,6 +279,72 @@ error0:
 	return -1;
 }
 
+/*!
+ * \brief Function that executes BYE reply callbacks
+ * \param t transaction, unused
+ * \param type type of the callback, should be TMCB_RESPONSE_FWDED
+ * \param param saved dialog structure inside the callback
+ */
+static void dlg_terminated_confirmed(struct cell* t,
+                                     int type,
+                                     struct tmcb_params* params)
+{
+    if(!params || !params->req || !params->param)
+    {
+        LM_ERR("invalid parameters!\n");
+        return;
+    }
+
+    struct dlg_cell* dlg = (struct dlg_cell*)*params->param;
+
+    if(!dlg)
+    {
+        LM_ERR("failed to get dialog from params!\n");
+        return;
+    }
+    /* dialog termination confirmed (BYE reply) */
+    run_dlg_callbacks(DLGCB_TERMINATED_CONFIRMED,
+                      dlg,
+                      params->req,
+                      params->rpl,
+                      DLG_DIR_UPSTREAM,
+                      0);
+}
+
+/*!
+ * \brief Execute callback for the BYE request and register callback for the BYE reply
+ * \param req request message
+ * \param dlg corresponding dialog
+ * \param dir message direction
+ */
+static void dlg_terminated(struct sip_msg* req,
+                           struct dlg_cell* dlg,
+                           unsigned int dir)
+{
+    if(!req) {
+        LM_ERR("request is empty!");
+        return;
+    }
+
+    if(!dlg) {
+        LM_ERR("dialog is empty!");
+        return;
+    }
+
+    /* dialog terminated (BYE) */
+    run_dlg_callbacks(DLGCB_TERMINATED, dlg, req, NULL, dir, 0);
+
+    /* register callback for the coresponding reply */
+    if (d_tmb.register_tmcb(req,
+                            0,
+                            TMCB_RESPONSE_OUT,
+                            dlg_terminated_confirmed,
+                            (void*) dlg,
+                            0 ) <= 0 ) {
+        LM_ERR("cannot register response callback for BYE request\n");
+        return;
+    }
+}
 
 /*!
  * \brief Function that is registered as TM callback and called on replies
@@ -294,20 +360,19 @@ error0:
  */
 static void dlg_onreply(struct cell* t, int type, struct tmcb_params *param)
 {
-	struct sip_msg *rpl;
-	struct dlg_cell *dlg;
-	int new_state, old_state, unref, event;
-	str tag;
+    struct dlg_cell *dlg;
+    int new_state, old_state, unref, event;
+    str tag;
+    struct sip_msg *req = param->req;
+	struct sip_msg *rpl = param->rpl;
 
 	dlg = (struct dlg_cell *)(*param->param);
 	if (shutdown_done || dlg==0)
 		return;
 
-	rpl = param->rpl;
-
 	if (type==TMCB_RESPONSE_FWDED) {
 		/* The state does not change, but the msg is mutable in this callback*/
-		run_dlg_callbacks(DLGCB_RESPONSE_FWDED, dlg, rpl, DLG_DIR_UPSTREAM, 0);
+		run_dlg_callbacks(DLGCB_RESPONSE_FWDED, dlg, req, rpl, DLG_DIR_UPSTREAM, 0);
 		return;
 	}
 
@@ -323,7 +388,7 @@ static void dlg_onreply(struct cell* t, int type, struct tmcb_params *param)
 	next_state_dlg( dlg, event, &old_state, &new_state, &unref);
 
 	if (new_state==DLG_STATE_EARLY) {
-		run_dlg_callbacks(DLGCB_EARLY, dlg, rpl, DLG_DIR_UPSTREAM, 0);
+		run_dlg_callbacks(DLGCB_EARLY, dlg, req, rpl, DLG_DIR_UPSTREAM, 0);
 		if (old_state!=DLG_STATE_EARLY)
 			if_update_stat(dlg_enable_stats, early_dlgs, 1);
 		return;
@@ -379,7 +444,7 @@ static void dlg_onreply(struct cell* t, int type, struct tmcb_params *param)
 		}
 
 		/* dialog confirmed */
-		run_dlg_callbacks( DLGCB_CONFIRMED, dlg, rpl, DLG_DIR_UPSTREAM, 0);
+		run_dlg_callbacks( DLGCB_CONFIRMED, dlg, req, rpl, DLG_DIR_UPSTREAM, 0);
 
 		if (old_state==DLG_STATE_EARLY)
 			if_update_stat(dlg_enable_stats, early_dlgs, -1);
@@ -392,7 +457,7 @@ static void dlg_onreply(struct cell* t, int type, struct tmcb_params *param)
 	if ( old_state!=DLG_STATE_DELETED && new_state==DLG_STATE_DELETED ) {
 		LM_DBG("dialog %p failed (negative reply)\n", dlg);
 		/* dialog setup not completed (3456XX) */
-		run_dlg_callbacks( DLGCB_FAILED, dlg, rpl, DLG_DIR_UPSTREAM, 0);
+		run_dlg_callbacks( DLGCB_FAILED, dlg, req, rpl, DLG_DIR_UPSTREAM, 0);
 		/* do unref */
 		if (unref)
 			unref_dlg(dlg,unref);
@@ -428,9 +493,14 @@ static void dlg_seq_onreply_helper(struct cell* t, int type,
 	if (shutdown_done || dlg==0)
 		return;
 
-	if (type==TMCB_RESPONSE_FWDED) {
-		run_dlg_callbacks(DLGCB_RESPONSE_WITHIN, dlg, param->rpl,
-			direction, 0);
+	if (type==TMCB_RESPONSE_FWDED)
+	{
+		run_dlg_callbacks( DLGCB_RESPONSE_WITHIN,
+		                   dlg,
+		                   param->req,
+		                   param->rpl,
+		                   direction,
+		                   0);
 		return;
 	}
 
@@ -537,52 +607,12 @@ static inline int pre_match_parse( struct sip_msg *req, str *callid,
  */
 void dlg_onreq(struct cell* t, int type, struct tmcb_params *param)
 {
-	struct dlg_cell *dlg;
-	str callid;
-	str ftag;
-	str ttag;
-	unsigned int dir;
-	unsigned int del;
 	struct sip_msg *req = param->req;
 
 	if((req->flags&dlg_flag)!=dlg_flag)
 		return;
 	if (current_dlg_pointer!=NULL)
 		return;
-	if (!detect_spirals)
-		goto create;
-
-	/* skip initial requests - they may end up here because of the
-	 * preloaded route */
-	if ( (!req->to && parse_headers(req, HDR_TO_F,0)<0) || !req->to ) {
-		LM_ERR("bad request or missing TO hdr :-/\n");
-		return;
-	}
-
-	dlg = 0;
-	dir = DLG_DIR_NONE;
-
-	if (pre_match_parse( req, &callid, &ftag, &ttag, 0)<0) {
-		LM_WARN("pre-matching failed\n");
-		return;
-	}
-	dlg = get_dlg(&callid, &ftag, &ttag, &dir, &del);
-	if (del == 1) {
-		LM_DBG("dialog marked for deletion, ignoring\n");
-		return;
-	}
-	if (!dlg){
-		LM_DBG("Callid '%.*s' not found, must be a new dialog\n",
-				req->callid->body.len, req->callid->body.s);
-		goto create;
-	}
-
-	run_dlg_callbacks( DLGCB_SPIRALED, dlg, req, DLG_DIR_DOWNSTREAM, 0);
-
-	unref_dlg(dlg, 1);
-	return;
-
-create:
 	dlg_new_dialog(req, t);
 }
 
@@ -601,6 +631,18 @@ static void unref_new_dialog(void *dialog)
 	dlg_onreply(0, TMCB_DESTROY, &p);
 }
 
+/*!
+ * \brief Unreference a dialog (small wrapper to take care of shutdown)
+ * \see unref_dlg
+ * \param dialog unreferenced dialog
+ */
+static void unreference_dialog(void *dialog)
+{
+    // if the dialog table is gone, it means the system is shutting down.
+    if (!d_table)
+        return;
+    unref_dlg((struct dlg_cell*)dialog, 1);
+}
 
 /*!
  * \brief Dummy callback just to keep the compiler happy
@@ -613,6 +655,91 @@ void dlg_tmcb_dummy(struct cell* t, int type, struct tmcb_params *param)
 	return;
 }
 
+/*!
+ * \brief Release a transaction from a dialog
+ * \param t transaction
+ * \param type type of the entered callback
+ * \param param saved dialog structure in the callback
+ */
+static void release_dlg_from_tm(struct cell* t,
+                                int type,
+                                struct tmcb_params *param)
+{
+    struct dlg_cell *dlg = get_dialog_from_tm(t);
+
+    if (!dlg)
+    {
+        LM_ERR("Failed to get and unref dialog from transaction!");
+        return;
+    }
+
+    unreference_dialog(dlg);
+}
+
+/*!
+ * \brief Register a transaction on a dialog
+ * \param t transaction
+ * \param type type of the entered callback
+ * \param param saved dialog structure in the callback
+ */
+static void store_dlg_in_tm(struct sip_msg* msg,
+                            struct cell* t,
+                            struct dlg_cell *dlg)
+{
+    if( !msg || msg == FAKED_REPLY || !t || !dlg)
+    {
+        LM_ERR("invalid parameter msg(%p), t(%p), dlg(%p)\n", msg, t, dlg);
+        return;
+    }
+
+    if(get_dialog_from_tm(t))
+    {
+        LM_NOTICE("dialog %p is already set for this transaction!\n",dlg);
+        return;
+    }
+
+    if( d_tmb.register_tmcb (msg,
+                             t,
+                             TMCB_MAX,
+                             dlg_tmcb_dummy,
+                             (void*)dlg, 0)<0 )
+    {
+        LM_ERR("failed cache in T the shortcut to dlg %p\n",dlg);
+        return;
+    }
+
+    ref_dlg(dlg, 1);
+
+    if (d_tmb.register_tmcb (msg,
+                             t,
+                             TMCB_DESTROY,
+                             release_dlg_from_tm,
+                             (void*)dlg, NULL)<0 )
+    {
+        LM_ERR("failed to register unref tm for handling dialog-termination\n");
+    }
+}
+
+/*!
+ * \brief Callback to register a transaction on a dialog
+ * \param t transaction, unused
+ * \param type type of the entered callback
+ * \param param saved dialog structure in the callback
+ */
+static void store_dlg_in_tm_cb (struct cell* t,
+                                int type,
+                                struct tmcb_params *param)
+{
+    struct dlg_cell *dlg = (struct dlg_cell *)(*param->param);
+
+    struct sip_msg* msg = param->rpl;
+    if (msg == NULL || msg == FAKED_REPLY)
+    {
+        msg = param->req;
+    }
+
+    store_dlg_in_tm (msg, t, dlg);
+}
 
 /*!
  * \brief Create a new dialog from a sip message
@@ -627,92 +754,108 @@ void dlg_tmcb_dummy(struct cell* t, int type, struct tmcb_params *param)
  * \param t transaction
  * \return 0 on success, -1 on failure
  */ 
-int dlg_new_dialog(struct sip_msg *msg, struct cell *t)
+int dlg_new_dialog(struct sip_msg *req, struct cell *t)
 {
 	struct dlg_cell *dlg;
 	str s;
-	str req_uri;
+	str callid;
+    str ftag;
+    str ttag;
+    str req_uri;
+    unsigned int dir;
+    unsigned int del;
 
-	if((msg->to==NULL && parse_headers(msg, HDR_TO_F,0)<0) || msg->to==NULL)
-	{
-		LM_ERR("bad request or missing TO hdr\n");
-		return -1;
-	}
-	s = get_to(msg)->tag_value;
-	if(s.s!=0 && s.len!=0)
-		return -1;
+    if(current_dlg_pointer != NULL)
+        return -1;
 
-	if(msg->first_line.u.request.method_value==METHOD_CANCEL)
+	if(req->first_line.u.request.method_value == METHOD_CANCEL)
 		return -1;
 
-	if(parse_from_header(msg))
+    if(pre_match_parse( req, &callid, &ftag, &ttag, 0)<0) {
+        LM_WARN("pre-matching failed\n");
+        return -1;
+    }
+
+    if(ttag.s!=0 && ttag.len!=0)
+        return -1;
+
+    if(pv_printf_s(req, ruri_param_model, &req_uri)<0) {
+        LM_ERR("error - cannot print the r-uri format\n");
+        return -1;
+    }
+    trim(&req_uri);
+
+    if (detect_spirals)
+    {
+        dir = DLG_DIR_NONE;
+
+        dlg = get_dlg(&callid, &ftag, &ttag, &dir, &del);
+        if (del == 1)
+        {
+            LM_WARN("Failed to get dialog (callid: '%.*s') because it is marked for deletion!\n",
+                callid.len, callid.s);
+            unref_dlg(dlg, 1);
+            return 0;
+        }
+        if (dlg)
+        {
+            LM_DBG("Callid '%.*s' found, must be a spiraled request\n",
+                callid.len, callid.s);
+
+            run_dlg_callbacks( DLGCB_SPIRALED, dlg, req, NULL, DLG_DIR_DOWNSTREAM, 0);
+
+            // get_dlg with del==0 has incremented the ref count by 1
+            unref_dlg(dlg, 1);
+            goto finish;
+        }
+    }
+
+    dlg = build_new_dlg (&callid /*callid*/,
+                         &(get_from(req)->uri) /*from uri*/,
+                         &(get_to(req)->uri) /*to uri*/,
+                         &ftag/*from_tag*/,
+                         &req_uri /*r-uri*/ );
+
+	if (dlg==0)
 	{
-		LM_ERR("bad request or missing FROM hdr\n");
-		return -1;
-	}
-	if((msg->callid==NULL && parse_headers(msg,HDR_CALLID_F,0)<0)
-			|| msg->callid==NULL){
-		LM_ERR("bad request or missing CALLID hdr\n");
-		return -1;
-	}
-	s = msg->callid->body;
-	trim(&s);
-
-	if (pv_printf_s(msg, ruri_param_model, &req_uri)<0) {
-		LM_ERR("error - cannot print the r-uri format\n");
-		return -1;
-	}
-	trim(&req_uri);
-
-	/* some sanity checks */
-	if (s.len==0 || get_from(msg)->tag_value.len==0) {
-		LM_ERR("invalid request -> callid (%d) or from TAG (%d) empty\n",
-			s.len, get_from(msg)->tag_value.len);
-		return -1;
-	}
-
-	dlg = build_new_dlg(&s /*callid*/, &(get_from(msg)->uri) /*from uri*/,
-		&(get_to(msg)->uri) /*to uri*/,
-		&(get_from(msg)->tag_value)/*from_tag*/, &req_uri /*r-uri*/ );
-	if (dlg==0) {
 		LM_ERR("failed to create new dialog\n");
 		return -1;
 	}
 
-	
-
 	/* save caller's tag, cseq, contact and record route*/
-	if (populate_leg_info(dlg, msg, t, DLG_CALLER_LEG,
-			&(get_from(msg)->tag_value)) !=0)
+	if (populate_leg_info(dlg, req, t, DLG_CALLER_LEG,
+			&(get_from(req)->tag_value)) !=0)
 	{
 		LM_ERR("could not add further info to the dialog\n");
 		shm_free(dlg);
 		return -1;
 	}
 
-	set_current_dialog(msg, dlg);
-	_dlg_ctx.dlg = dlg;
 
 	/* Populate initial varlist: */
-	dlg->vars = get_local_varlist_pointer(msg, 1);
+	dlg->vars = get_local_varlist_pointer(req, 1);
+
+	link_dlg(dlg,0);
 
-	link_dlg(dlg, 2/* extra ref for the callback and current dlg hook */);
+    run_create_callbacks(dlg, req);
 
 	/* first INVITE seen (dialog created, unconfirmed) */
 	if ( seq_match_mode!=SEQ_MATCH_NO_ID &&
-			add_dlg_rr_param( msg, dlg->h_entry, dlg->h_id)<0 ) {
+			add_dlg_rr_param( req, dlg->h_entry, dlg->h_id)<0 ) {
 		LM_ERR("failed to add RR param\n");
 		goto error;
 	}
 
-	if ( d_tmb.register_tmcb( msg, t,
+	if ( d_tmb.register_tmcb( req, t,
 				TMCB_RESPONSE_READY|TMCB_RESPONSE_FWDED,
 				dlg_onreply, (void*)dlg, unref_new_dialog)<0 ) {
 		LM_ERR("failed to register TMCB\n");
 		goto error;
 	}
+    // increase reference counter because of registered callback
+    ref_dlg(dlg, 1);
 
-	dlg->lifetime = get_dlg_timeout(msg);
+	dlg->lifetime = get_dlg_timeout(req);
 	s.s   = _dlg_ctx.to_route_name;
 	s.len = strlen(s.s);
 	dlg_set_toroute(dlg, &s);
@@ -721,25 +864,29 @@ int dlg_new_dialog(struct sip_msg *msg, struct cell *t)
 	if (_dlg_ctx.to_bye!=0)
 		dlg->dflags |= DLG_FLAG_TOBYE;
 
-	if (t) {
-		if ( d_tmb.register_tmcb( msg, t, TMCB_MAX,
-					dlg_tmcb_dummy, (void*)dlg, 0)<0 ) {
-			LM_ERR("failed cache in T the shortcut to dlg\n");
-			goto error;
-		}
-	}
-#if 0
-		t->dialog_ctx = (void*) dlg;
-#endif
+    if_update_stat( dlg_enable_stats, processed_dlgs, 1);
 
-	run_create_callbacks( dlg, msg);
+finish:
 
-	if_update_stat( dlg_enable_stats, processed_dlgs, 1);
+    set_current_dialog(req, dlg);
+    _dlg_ctx.dlg = dlg;
+    ref_dlg(dlg, 1);
+
+	if (t) {
+	    store_dlg_in_tm( req, t, dlg);
+	}
+	else
+	{
+        if ( d_tmb.register_tmcb( req, NULL, TMCB_REQUEST_FWDED,
+                store_dlg_in_tm_cb, (void*)dlg, NULL)<0 ) {
+            LM_ERR("failed to store dialog in transaction during dialog creation for later reference\n");
+        }
+	}
 
 	return 0;
 error:
 	unref_dlg(dlg,1);
-	profile_cleanup(msg, 0, NULL);
+	profile_cleanup(req, 0, NULL);
 	return -1;
 }
 
@@ -802,21 +949,6 @@ static inline int update_cseqs(struct dlg_cell *dlg, struct sip_msg *req,
 	}
 }
 
-
-/*!
- * \brief Unreference a dialog, small wrapper to care for shutdown
- * \see unref_dlg 
- * \param dialog unreferenced dialog
- */
-static void unreference_dialog(void *dialog)
-{
-	// if the dialog table is gone, it means the system is shutting down.
-	if (!d_table)
-		return;
-	unref_dlg((struct dlg_cell*)dialog, 1);
-}
-
-
 /*!
  * \brief Unreference a dialog from tm callback (another wrapper)
  * \param t transaction, unused
@@ -945,6 +1077,21 @@ void dlg_onroute(struct sip_msg* req, str *route_params, void *param)
 		}
 	}
 
+    /* set current dialog - it will keep a ref! */
+    set_current_dialog( req, dlg);
+    _dlg_ctx.dlg = dlg;
+
+    if ( d_tmb.register_tmcb( req, NULL, TMCB_REQUEST_FWDED,
+            store_dlg_in_tm_cb, (void*)dlg, NULL)<0 ) {
+        LM_ERR("failed to store dialog in transaction during dialog creation for later reference\n");
+    }
+
+    if (del == 1) {
+        LM_DBG( "Use the dialog (callid: '%.*s') without further handling because it is marked for deletion\n",
+            callid.len, callid.s);
+        return;
+    }
+
 	/* run state machine */
 	switch ( req->first_line.u.request.method_value ) {
 		case METHOD_PRACK:
@@ -963,10 +1110,6 @@ void dlg_onroute(struct sip_msg* req, str *route_params, void *param)
 	CURR_DLG_LIFETIME = (unsigned int)(time(0))-dlg->start_ts;
 	CURR_DLG_STATUS = new_state;
 
-	/* set current dialog - it will keep a ref! */
-	set_current_dialog( req, dlg);
-	_dlg_ctx.dlg = dlg;
-
 	/* delay deletion of dialog until transaction has died off in order
 	 * to absorb in-air messages */
 	if (new_state==DLG_STATE_DELETED && old_state!=DLG_STATE_DELETED) {
@@ -1002,11 +1145,7 @@ void dlg_onroute(struct sip_msg* req, str *route_params, void *param)
 			unref++;
 		}
 		/* dialog terminated (BYE) */
-		run_dlg_callbacks( DLGCB_TERMINATED, dlg, req, dir, 0);
-
-		/* delete the dialog from DB */
-		if (dlg_db_mode)
-			remove_dialog_from_db(dlg);
+        dlg_terminated( req, dlg, dir);
 
 		unref_dlg(dlg, unref);
 
@@ -1033,7 +1172,7 @@ void dlg_onroute(struct sip_msg* req, str *route_params, void *param)
 		}
 
 		/* within dialog request */
-		run_dlg_callbacks( DLGCB_REQ_WITHIN, dlg, req, dir, 0);
+		run_dlg_callbacks( DLGCB_REQ_WITHIN, dlg, req, NULL, dir, 0);
 
 		if ( (event!=DLG_EVENT_REQACK) &&
 		(dlg->cbs.types)&DLGCB_RESPONSE_WITHIN ) {
@@ -1108,11 +1247,7 @@ void dlg_ontimeout( struct dlg_tl *tl)
 			dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s);
 
 		/* dialog timeout */
-		run_dlg_callbacks( DLGCB_EXPIRED, dlg, 0, DLG_DIR_NONE, 0);
-
-		/* delete the dialog from DB */
-		if (dlg_db_mode)
-			remove_dialog_from_db(dlg);
+		run_dlg_callbacks( DLGCB_EXPIRED, dlg, NULL, NULL, DLG_DIR_NONE, 0);
 
 		unref_dlg(dlg, unref+1);
 

+ 18 - 3
modules_k/dialog/dlg_hash.c

@@ -61,6 +61,7 @@
 #include "dlg_hash.h"
 #include "dlg_profile.h"
 #include "dlg_req_within.h"
+#include "dlg_db_handler.h"
 
 #define MAX_LDG_LOCKS  2048
 #define MIN_LDG_LOCKS  2
@@ -153,7 +154,12 @@ inline void destroy_dlg(struct dlg_cell *dlg)
 			dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s);
 	}
 
-	run_dlg_callbacks( DLGCB_DESTROY , dlg, 0, DLG_DIR_NONE, 0);
+	run_dlg_callbacks( DLGCB_DESTROY , dlg, NULL, NULL, DLG_DIR_NONE, 0);
+
+
+	/* delete the dialog from DB*/
+	if (dlg_db_mode)
+		remove_dialog_from_db(dlg);
 
 	if(dlg==get_current_dlg_pointer())
 		reset_current_dlg_pointer();
@@ -841,6 +847,11 @@ static inline int internal_mi_print_dlg(struct mi_node *rpl,
 	if (node1==0)
 		goto error;
 
+	p= int2str((unsigned long)dlg->ref, &len);
+	node1 = add_mi_node_child( node, MI_DUP_VALUE, "ref_count", 9, p, len);
+	if (node1==0)
+		goto error;
+
 	p= int2str((unsigned long)dlg->start_ts, &len);
 	node1 = add_mi_node_child(node,MI_DUP_VALUE,"timestart",9, p, len);
 	if (node1==0)
@@ -934,8 +945,12 @@ static inline int internal_mi_print_dlg(struct mi_node *rpl,
 		node1 = add_mi_node_child(node, 0, "context", 7, 0, 0);
 		if(node1 == 0)
 			goto error;
-		run_dlg_callbacks( DLGCB_MI_CONTEXT, dlg, NULL, 
-			DLG_DIR_NONE, (void *)node1);
+		run_dlg_callbacks( DLGCB_MI_CONTEXT,
+		                   dlg,
+		                   NULL,
+		                   NULL,
+		                   DLG_DIR_NONE,
+		                   (void *)node1);
 	}
 	return 0;
 

+ 2 - 0
modules_k/dialog/dlg_load.h

@@ -34,6 +34,8 @@
 
 struct dlg_binds {
 	register_dlgcb_f  register_dlgcb;
+    set_dlg_variable_f set_dlg_var;
+	get_dlg_variable_f get_dlg_var;
 };
 
 

+ 22 - 17
modules_k/dialog/dlg_profile.c

@@ -327,17 +327,33 @@ int profile_cleanup( struct sip_msg *msg, unsigned int flags, void *param )
 }
 
 
+
+struct dlg_cell* get_dialog_from_tm(struct cell *t)
+{
+    if (t==NULL || t==T_UNDEFINED)
+        return NULL;
+
+    struct tm_callback* x = (struct tm_callback*)(t->tmcb_hl.first);
+
+    while(x){
+        membar_depends();
+        if (x->types==TMCB_MAX && x->callback==dlg_tmcb_dummy){
+            return (struct dlg_cell*)(x->param);
+        }
+        x=x->next;
+    }
+
+    return NULL;
+}
+
 /*!
  * \brief Get the current dialog for a message, if exists
  * \param msg SIP message
  * \return NULL if called in REQUEST_ROUTE, pointer to dialog ctx otherwise
  */ 
-static struct dlg_cell *get_current_dialog(struct sip_msg *msg)
+struct dlg_cell *get_current_dialog(struct sip_msg *msg)
 {
-	struct cell *trans;
-	struct tm_callback* x;
-
-	if (is_route_type(REQUEST_ROUTE)) {
+	if (is_route_type(REQUEST_ROUTE|BRANCH_ROUTE)) {
 		/* use the per-process static holder */
 		if (msg->id==current_dlg_msg_id)
 			return current_dlg_pointer;
@@ -348,18 +364,7 @@ static struct dlg_cell *get_current_dialog(struct sip_msg *msg)
 		return NULL;
 	} else {
 		/* use current transaction to get dialog */
-		trans = d_tmb.t_gett();
-		if (trans==NULL || trans==T_UNDEFINED)
-			return NULL;
-		x=(struct tm_callback*)(trans->tmcb_hl.first);
-		while(x){
-			membar_depends();
-			if (x->types==TMCB_MAX && x->callback==dlg_tmcb_dummy){
-				return (struct dlg_cell*)(x->param);
-			}
-			x=x->next;
-		}
-		return NULL;
+	    return get_dialog_from_tm(d_tmb.t_gett());
 	}
 }
 

+ 6 - 0
modules_k/dialog/dlg_profile.h

@@ -33,6 +33,8 @@
 #include "../../parser/msg_parser.h"
 #include "../../locking.h"
 #include "../../str.h"
+#include "../../modules/tm/h_table.h"
+
 
 
 /*!
@@ -83,6 +85,10 @@ struct dlg_cell *get_current_dlg_pointer(void);
 
 void reset_current_dlg_pointer(void);
 
+struct dlg_cell* get_dialog_from_tm(struct cell *t);
+
+struct dlg_cell *get_current_dialog(struct sip_msg *msg);
+
 /*!
  * \brief Add profile definitions to the global list
  * \see new_dlg_profile

+ 1 - 1
modules_k/dialog/dlg_req_within.c

@@ -175,7 +175,7 @@ void bye_reply_cb(struct cell* t, int type, struct tmcb_params* ps){
 			unref++;
 		}
 		/* dialog terminated (BYE) */
-		run_dlg_callbacks( DLGCB_TERMINATED, dlg, ps->req, DLG_DIR_NONE, 0);
+		run_dlg_callbacks( DLGCB_TERMINATED, dlg, ps->req, ps->rpl, DLG_DIR_NONE, 0);
 
 		LM_DBG("first final reply\n");
 		/* derefering the dialog */

+ 57 - 2
modules_k/dialog/dlg_var.c

@@ -214,6 +214,61 @@ void print_lists(struct dlg_cell *dlg) {
 	}
 }
 
+str * get_dlg_variable(struct dlg_cell *dlg, str *key)
+{
+    str* var = NULL;
+
+    if( !dlg || !key || key->len > strlen(key->s))
+    {
+        LM_ERR("BUG - bad parameters\n");
+
+        return NULL;
+    }
+
+    dlg_lock(d_table, &(d_table->entries[dlg->h_entry]));
+    var = get_dlg_variable_unsafe( dlg, key);
+    dlg_unlock(d_table, &(d_table->entries[dlg->h_entry]));
+
+    return var;
+}
+
+int set_dlg_variable(struct dlg_cell *dlg, str *key, str *val)
+{
+    if( !dlg || !key || key->len > strlen(key->s) || (val && val->len > strlen(val->s)))
+    {
+        LM_ERR("BUG - bad parameters\n");
+        return -1;
+    }
+
+    dlg_lock(d_table, &(d_table->entries[dlg->h_entry]));
+
+    if( !val)
+    {
+        if (set_dlg_variable_unsafe(dlg, key, NULL, 1)!=0) {
+            LM_ERR("failed to delete dialog variable <%.*s>\n", key->len,key->s);
+            goto error;
+        }
+    } else {
+        if (set_dlg_variable_unsafe(dlg, key, val, 1)!=0) {
+            LM_ERR("failed to store dialog values <%.*s>\n",key->len,key->s);
+            goto error;
+        }
+    }
+
+    dlg->dflags &= DLG_FLAG_CHANGED_VARS;
+    dlg_unlock(d_table, &(d_table->entries[dlg->h_entry]));
+    if ( dlg_db_mode==DB_MODE_REALTIME )
+        update_dialog_dbinfo(dlg);
+
+    print_lists(dlg);
+
+    return 0;
+
+error:
+    dlg_unlock(d_table, &(d_table->entries[dlg->h_entry]));
+    return -1;
+}
+
 int pv_get_dlg_variable(struct sip_msg *msg, pv_param_t *param, pv_value_t *res)
 {
 	struct dlg_cell *dlg;
@@ -225,7 +280,7 @@ int pv_get_dlg_variable(struct sip_msg *msg, pv_param_t *param, pv_value_t *res)
 	}
 
 	/* Retrieve the current dialog */
-	dlg=get_current_dlg_pointer();
+	dlg=get_current_dialog( msg);
 
 	if (dlg) {
 		/* Lock the dialog */
@@ -254,7 +309,7 @@ int pv_set_dlg_variable(struct sip_msg* msg, pv_param_t *param, int op, pv_value
 	struct dlg_cell *dlg;
 
 	/* Retrieve the current dialog */
-	dlg=get_current_dlg_pointer();
+	dlg=get_current_dialog( msg);
 	
 	if (dlg) {
 		/* Lock the dialog */

+ 2 - 0
modules_k/dialog/dlg_var.h

@@ -49,6 +49,8 @@ struct dlg_var {
 	struct dlg_var *next;
 };
 
+str * get_dlg_variable(struct dlg_cell *dlg, str *key);
+int set_dlg_variable(struct dlg_cell *dlg, str *key, str *val);
 
 int pv_parse_dialog_var_name(pv_spec_p sp, str *in);