Browse code

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, sven.knoblich@1und1.de .

Timo Reimann authored on 02/08/2011 16:29:05
Showing 11 changed files
... ...
@@ -371,6 +371,8 @@ static int fixup_get_profile3(void** param, int param_no)
371 371
 int load_dlg( struct dlg_binds *dlgb )
372 372
 {
373 373
 	dlgb->register_dlgcb = register_dlgcb;
374
+	dlgb->set_dlg_var = set_dlg_variable;
375
+	dlgb->get_dlg_var = get_dlg_variable;
374 376
 	return 1;
375 377
 }
376 378
 
... ...
@@ -1211,7 +1213,7 @@ static inline void internal_rpc_print_dlg(rpc_t *rpc, void *c, struct dlg_cell *
1211 1211
 	if (with_context) {
1212 1212
 		rpc_cb.rpc = rpc;
1213 1213
 		rpc_cb.c = c;
1214
-		run_dlg_callbacks( DLGCB_RPC_CONTEXT, dlg, NULL, DLG_DIR_NONE, (void *)&rpc_cb);
1214
+		run_dlg_callbacks( DLGCB_RPC_CONTEXT, dlg, NULL, NULL, DLG_DIR_NONE, (void *)&rpc_cb);
1215 1215
 	}
1216 1216
 }
1217 1217
 
... ...
@@ -40,7 +40,7 @@ static struct dlg_head_cbl* create_cbs = 0;
40 40
 
41 41
 static struct dlg_head_cbl* load_cbs = 0;
42 42
 
43
-static struct dlg_cb_params params = {NULL, DLG_DIR_NONE, NULL, NULL};
43
+static struct dlg_cb_params params = {NULL, NULL, DLG_DIR_NONE, NULL, NULL};
44 44
 
45 45
 
46 46
 #define POINTER_CLOSED_MARKER  ((void *)(-1))
... ...
@@ -184,7 +184,8 @@ static void run_load_callback(struct dlg_callback *cb)
184 184
 	struct dlg_cell *dlg;
185 185
 	unsigned int i;
186 186
 
187
-	params.msg = NULL;
187
+	params.req = NULL;
188
+	params.rpl = NULL;
188 189
 	params.direction = DLG_DIR_NONE;
189 190
 	params.param = &cb->param;
190 191
 
... ...
@@ -217,7 +218,8 @@ void run_create_callbacks(struct dlg_cell *dlg, struct sip_msg *msg)
217 217
 	if (create_cbs==NULL || create_cbs->first==NULL)
218 218
 		return;
219 219
 
220
-	params.msg = msg;
220
+	params.req = msg;
221
+	params.rpl = NULL;
221 222
 	/* initial request goes DOWNSTREAM all the time */
222 223
 	params.direction = DLG_DIR_DOWNSTREAM;
223 224
 	/* avoid garbage due static structure */
... ...
@@ -233,12 +235,16 @@ void run_create_callbacks(struct dlg_cell *dlg, struct sip_msg *msg)
233 233
 }
234 234
 
235 235
 
236
-void run_dlg_callbacks(int type , struct dlg_cell *dlg, struct sip_msg *msg,
237
-											unsigned int dir, void *dlg_data)
236
+void run_dlg_callbacks( int type ,
237
+						struct dlg_cell *dlg,
238
+						struct sip_msg *req,
239
+						struct sip_msg *rpl,
240
+						unsigned int dir, void *dlg_data)
238 241
 {
239 242
 	struct dlg_callback *cb;
240 243
 
241
-	params.msg = msg;
244
+	params.req = req;
245
+	params.rpl = rpl;
242 246
 	params.direction = dir;
243 247
 	params.dlg_data = dlg_data;
244 248
 
... ...
@@ -37,7 +37,8 @@
37 37
 struct dlg_cell;
38 38
 
39 39
 struct dlg_cb_params {
40
-	struct sip_msg* msg;       /* sip msg related to the callback event */
40
+	struct sip_msg* req;       /* sip request msg related to the callback event */
41
+    struct sip_msg* rpl;       /* sip reply msg related to the callback event */
41 42
 	unsigned int direction;    /* direction of the sip msg */
42 43
 	void *dlg_data;            /* generic paramter, specific to callback */
43 44
 	void **param;              /* parameter passed at callback registration*/
... ...
@@ -52,6 +53,13 @@ typedef void (param_free_cb) (void *param);
52 52
 typedef int (*register_dlgcb_f)(struct dlg_cell* dlg, int cb_types,
53 53
 		dialog_cb f, void *param, param_free_cb ff);
54 54
 
55
+/* method to set a variable within a dialog */
56
+typedef int (*set_dlg_variable_f)( struct dlg_cell* dlg,
57
+                                   str* key,
58
+                                   str* val);
59
+/* method to get a variable from a dialog */
60
+typedef str* (*get_dlg_variable_f)( struct dlg_cell* dlg,
61
+                                    str* key);
55 62
 
56 63
 #define DLGCB_LOADED          (1<<0)
57 64
 #define DLGCB_CREATED         (1<<1)
... ...
@@ -67,6 +75,7 @@ typedef int (*register_dlgcb_f)(struct dlg_cell* dlg, int cb_types,
67 67
 #define DLGCB_RPC_CONTEXT     (1<<11)
68 68
 #define DLGCB_DESTROY         (1<<12)
69 69
 #define DLGCB_SPIRALED        (1<<13)
70
+#define DLGCB_TERMINATED_CONFIRMED (1<<14)
70 71
 
71 72
 struct dlg_callback {
72 73
 	int types;
... ...
@@ -91,8 +100,12 @@ int register_dlgcb( struct dlg_cell* dlg, int types, dialog_cb f, void *param, p
91 91
 
92 92
 void run_create_callbacks(struct dlg_cell *dlg, struct sip_msg *msg);
93 93
 
94
-void run_dlg_callbacks( int type , struct dlg_cell *dlg, struct sip_msg *msg,
95
-		unsigned int dir, void *dlg_data);
94
+void run_dlg_callbacks( int type ,
95
+                        struct dlg_cell *dlg,
96
+                        struct sip_msg *req,
97
+                        struct sip_msg *rpl,
98
+                        unsigned int dir,
99
+                        void *dlg_data);
96 100
 
97 101
 void run_load_callbacks( void );
98 102
 
... ...
@@ -279,6 +279,72 @@ error0:
279 279
 	return -1;
280 280
 }
281 281
 
282
+/*!
283
+ * \brief Function that executes BYE reply callbacks
284
+ * \param t transaction, unused
285
+ * \param type type of the callback, should be TMCB_RESPONSE_FWDED
286
+ * \param param saved dialog structure inside the callback
287
+ */
288
+static void dlg_terminated_confirmed(struct cell* t,
289
+                                     int type,
290
+                                     struct tmcb_params* params)
291
+{
292
+    if(!params || !params->req || !params->param)
293
+    {
294
+        LM_ERR("invalid parameters!\n");
295
+        return;
296
+    }
297
+
298
+    struct dlg_cell* dlg = (struct dlg_cell*)*params->param;
299
+
300
+    if(!dlg)
301
+    {
302
+        LM_ERR("failed to get dialog from params!\n");
303
+        return;
304
+    }
305
+    /* dialog termination confirmed (BYE reply) */
306
+    run_dlg_callbacks(DLGCB_TERMINATED_CONFIRMED,
307
+                      dlg,
308
+                      params->req,
309
+                      params->rpl,
310
+                      DLG_DIR_UPSTREAM,
311
+                      0);
312
+}
313
+
314
+/*!
315
+ * \brief Execute callback for the BYE request and register callback for the BYE reply
316
+ * \param req request message
317
+ * \param dlg corresponding dialog
318
+ * \param dir message direction
319
+ */
320
+static void dlg_terminated(struct sip_msg* req,
321
+                           struct dlg_cell* dlg,
322
+                           unsigned int dir)
323
+{
324
+    if(!req) {
325
+        LM_ERR("request is empty!");
326
+        return;
327
+    }
328
+
329
+    if(!dlg) {
330
+        LM_ERR("dialog is empty!");
331
+        return;
332
+    }
333
+
334
+    /* dialog terminated (BYE) */
335
+    run_dlg_callbacks(DLGCB_TERMINATED, dlg, req, NULL, dir, 0);
336
+
337
+    /* register callback for the coresponding reply */
338
+    if (d_tmb.register_tmcb(req,
339
+                            0,
340
+                            TMCB_RESPONSE_OUT,
341
+                            dlg_terminated_confirmed,
342
+                            (void*) dlg,
343
+                            0 ) <= 0 ) {
344
+        LM_ERR("cannot register response callback for BYE request\n");
345
+        return;
346
+    }
347
+}
282 348
 
283 349
 /*!
284 350
  * \brief Function that is registered as TM callback and called on replies
... ...
@@ -294,20 +360,19 @@ error0:
294 294
  */
295 295
 static void dlg_onreply(struct cell* t, int type, struct tmcb_params *param)
296 296
 {
297
-	struct sip_msg *rpl;
298
-	struct dlg_cell *dlg;
299
-	int new_state, old_state, unref, event;
300
-	str tag;
297
+    struct dlg_cell *dlg;
298
+    int new_state, old_state, unref, event;
299
+    str tag;
300
+    struct sip_msg *req = param->req;
301
+	struct sip_msg *rpl = param->rpl;
301 302
 
302 303
 	dlg = (struct dlg_cell *)(*param->param);
303 304
 	if (shutdown_done || dlg==0)
304 305
 		return;
305 306
 
306
-	rpl = param->rpl;
307
-
308 307
 	if (type==TMCB_RESPONSE_FWDED) {
309 308
 		/* The state does not change, but the msg is mutable in this callback*/
310
-		run_dlg_callbacks(DLGCB_RESPONSE_FWDED, dlg, rpl, DLG_DIR_UPSTREAM, 0);
309
+		run_dlg_callbacks(DLGCB_RESPONSE_FWDED, dlg, req, rpl, DLG_DIR_UPSTREAM, 0);
311 310
 		return;
312 311
 	}
313 312
 
... ...
@@ -323,7 +388,7 @@ static void dlg_onreply(struct cell* t, int type, struct tmcb_params *param)
323 323
 	next_state_dlg( dlg, event, &old_state, &new_state, &unref);
324 324
 
325 325
 	if (new_state==DLG_STATE_EARLY) {
326
-		run_dlg_callbacks(DLGCB_EARLY, dlg, rpl, DLG_DIR_UPSTREAM, 0);
326
+		run_dlg_callbacks(DLGCB_EARLY, dlg, req, rpl, DLG_DIR_UPSTREAM, 0);
327 327
 		if (old_state!=DLG_STATE_EARLY)
328 328
 			if_update_stat(dlg_enable_stats, early_dlgs, 1);
329 329
 		return;
... ...
@@ -379,7 +444,7 @@ static void dlg_onreply(struct cell* t, int type, struct tmcb_params *param)
379 379
 		}
380 380
 
381 381
 		/* dialog confirmed */
382
-		run_dlg_callbacks( DLGCB_CONFIRMED, dlg, rpl, DLG_DIR_UPSTREAM, 0);
382
+		run_dlg_callbacks( DLGCB_CONFIRMED, dlg, req, rpl, DLG_DIR_UPSTREAM, 0);
383 383
 
384 384
 		if (old_state==DLG_STATE_EARLY)
385 385
 			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)
392 392
 	if ( old_state!=DLG_STATE_DELETED && new_state==DLG_STATE_DELETED ) {
393 393
 		LM_DBG("dialog %p failed (negative reply)\n", dlg);
394 394
 		/* dialog setup not completed (3456XX) */
395
-		run_dlg_callbacks( DLGCB_FAILED, dlg, rpl, DLG_DIR_UPSTREAM, 0);
395
+		run_dlg_callbacks( DLGCB_FAILED, dlg, req, rpl, DLG_DIR_UPSTREAM, 0);
396 396
 		/* do unref */
397 397
 		if (unref)
398 398
 			unref_dlg(dlg,unref);
... ...
@@ -428,9 +493,14 @@ static void dlg_seq_onreply_helper(struct cell* t, int type,
428 428
 	if (shutdown_done || dlg==0)
429 429
 		return;
430 430
 
431
-	if (type==TMCB_RESPONSE_FWDED) {
432
-		run_dlg_callbacks(DLGCB_RESPONSE_WITHIN, dlg, param->rpl,
433
-			direction, 0);
431
+	if (type==TMCB_RESPONSE_FWDED)
432
+	{
433
+		run_dlg_callbacks( DLGCB_RESPONSE_WITHIN,
434
+		                   dlg,
435
+		                   param->req,
436
+		                   param->rpl,
437
+		                   direction,
438
+		                   0);
434 439
 		return;
435 440
 	}
436 441
 
... ...
@@ -537,52 +607,12 @@ static inline int pre_match_parse( struct sip_msg *req, str *callid,
537 537
  */
538 538
 void dlg_onreq(struct cell* t, int type, struct tmcb_params *param)
539 539
 {
540
-	struct dlg_cell *dlg;
541
-	str callid;
542
-	str ftag;
543
-	str ttag;
544
-	unsigned int dir;
545
-	unsigned int del;
546 540
 	struct sip_msg *req = param->req;
547 541
 
548 542
 	if((req->flags&dlg_flag)!=dlg_flag)
549 543
 		return;
550 544
 	if (current_dlg_pointer!=NULL)
551 545
 		return;
552
-	if (!detect_spirals)
553
-		goto create;
554
-
555
-	/* skip initial requests - they may end up here because of the
556
-	 * preloaded route */
557
-	if ( (!req->to && parse_headers(req, HDR_TO_F,0)<0) || !req->to ) {
558
-		LM_ERR("bad request or missing TO hdr :-/\n");
559
-		return;
560
-	}
561
-
562
-	dlg = 0;
563
-	dir = DLG_DIR_NONE;
564
-
565
-	if (pre_match_parse( req, &callid, &ftag, &ttag, 0)<0) {
566
-		LM_WARN("pre-matching failed\n");
567
-		return;
568
-	}
569
-	dlg = get_dlg(&callid, &ftag, &ttag, &dir, &del);
570
-	if (del == 1) {
571
-		LM_DBG("dialog marked for deletion, ignoring\n");
572
-		return;
573
-	}
574
-	if (!dlg){
575
-		LM_DBG("Callid '%.*s' not found, must be a new dialog\n",
576
-				req->callid->body.len, req->callid->body.s);
577
-		goto create;
578
-	}
579
-
580
-	run_dlg_callbacks( DLGCB_SPIRALED, dlg, req, DLG_DIR_DOWNSTREAM, 0);
581
-
582
-	unref_dlg(dlg, 1);
583
-	return;
584
-
585
-create:
586 546
 	dlg_new_dialog(req, t);
587 547
 }
588 548
 
... ...
@@ -601,6 +631,18 @@ static void unref_new_dialog(void *dialog)
601 601
 	dlg_onreply(0, TMCB_DESTROY, &p);
602 602
 }
603 603
 
604
+/*!
605
+ * \brief Unreference a dialog (small wrapper to take care of shutdown)
606
+ * \see unref_dlg
607
+ * \param dialog unreferenced dialog
608
+ */
609
+static void unreference_dialog(void *dialog)
610
+{
611
+    // if the dialog table is gone, it means the system is shutting down.
612
+    if (!d_table)
613
+        return;
614
+    unref_dlg((struct dlg_cell*)dialog, 1);
615
+}
604 616
 
605 617
 /*!
606 618
  * \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)
613 613
 	return;
614 614
 }
615 615
 
616
+/*!
617
+ * \brief Release a transaction from a dialog
618
+ * \param t transaction
619
+ * \param type type of the entered callback
620
+ * \param param saved dialog structure in the callback
621
+ */
622
+static void release_dlg_from_tm(struct cell* t,
623
+                                int type,
624
+                                struct tmcb_params *param)
625
+{
626
+    struct dlg_cell *dlg = get_dialog_from_tm(t);
627
+
628
+    if (!dlg)
629
+    {
630
+        LM_ERR("Failed to get and unref dialog from transaction!");
631
+        return;
632
+    }
633
+
634
+    unreference_dialog(dlg);
635
+}
636
+
637
+/*!
638
+ * \brief Register a transaction on a dialog
639
+ * \param t transaction
640
+ * \param type type of the entered callback
641
+ * \param param saved dialog structure in the callback
642
+ */
643
+static void store_dlg_in_tm(struct sip_msg* msg,
644
+                            struct cell* t,
645
+                            struct dlg_cell *dlg)
646
+{
647
+    if( !msg || msg == FAKED_REPLY || !t || !dlg)
648
+    {
649
+        LM_ERR("invalid parameter msg(%p), t(%p), dlg(%p)\n", msg, t, dlg);
650
+        return;
651
+    }
652
+
653
+    if(get_dialog_from_tm(t))
654
+    {
655
+        LM_NOTICE("dialog %p is already set for this transaction!\n",dlg);
656
+        return;
657
+    }
658
+
659
+    if( d_tmb.register_tmcb (msg,
660
+                             t,
661
+                             TMCB_MAX,
662
+                             dlg_tmcb_dummy,
663
+                             (void*)dlg, 0)<0 )
664
+    {
665
+        LM_ERR("failed cache in T the shortcut to dlg %p\n",dlg);
666
+        return;
667
+    }
668
+
669
+    ref_dlg(dlg, 1);
670
+
671
+    if (d_tmb.register_tmcb (msg,
672
+                             t,
673
+                             TMCB_DESTROY,
674
+                             release_dlg_from_tm,
675
+                             (void*)dlg, NULL)<0 )
676
+    {
677
+        LM_ERR("failed to register unref tm for handling dialog-termination\n");
678
+    }
679
+}
680
+
681
+/*!
682
+ * \brief Callback to register a transaction on a dialog
683
+ * \param t transaction, unused
684
+ * \param type type of the entered callback
685
+ * \param param saved dialog structure in the callback
686
+ */
687
+static void store_dlg_in_tm_cb (struct cell* t,
688
+                                int type,
689
+                                struct tmcb_params *param)
690
+{
691
+    struct dlg_cell *dlg = (struct dlg_cell *)(*param->param);
692
+
693
+    struct sip_msg* msg = param->rpl;
694
+    if (msg == NULL || msg == FAKED_REPLY)
695
+    {
696
+        msg = param->req;
697
+    }
698
+
699
+    store_dlg_in_tm (msg, t, dlg);
700
+}
616 701
 
617 702
 /*!
618 703
  * \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)
627 627
  * \param t transaction
628 628
  * \return 0 on success, -1 on failure
629 629
  */ 
630
-int dlg_new_dialog(struct sip_msg *msg, struct cell *t)
630
+int dlg_new_dialog(struct sip_msg *req, struct cell *t)
631 631
 {
632 632
 	struct dlg_cell *dlg;
633 633
 	str s;
634
-	str req_uri;
634
+	str callid;
635
+    str ftag;
636
+    str ttag;
637
+    str req_uri;
638
+    unsigned int dir;
639
+    unsigned int del;
635 640
 
636
-	if((msg->to==NULL && parse_headers(msg, HDR_TO_F,0)<0) || msg->to==NULL)
637
-	{
638
-		LM_ERR("bad request or missing TO hdr\n");
639
-		return -1;
640
-	}
641
-	s = get_to(msg)->tag_value;
642
-	if(s.s!=0 && s.len!=0)
643
-		return -1;
641
+    if(current_dlg_pointer != NULL)
642
+        return -1;
644 643
 
645
-	if(msg->first_line.u.request.method_value==METHOD_CANCEL)
644
+	if(req->first_line.u.request.method_value == METHOD_CANCEL)
646 645
 		return -1;
647 646
 
648
-	if(parse_from_header(msg))
647
+    if(pre_match_parse( req, &callid, &ftag, &ttag, 0)<0) {
648
+        LM_WARN("pre-matching failed\n");
649
+        return -1;
650
+    }
651
+
652
+    if(ttag.s!=0 && ttag.len!=0)
653
+        return -1;
654
+
655
+    if(pv_printf_s(req, ruri_param_model, &req_uri)<0) {
656
+        LM_ERR("error - cannot print the r-uri format\n");
657
+        return -1;
658
+    }
659
+    trim(&req_uri);
660
+
661
+    if (detect_spirals)
662
+    {
663
+        dir = DLG_DIR_NONE;
664
+
665
+        dlg = get_dlg(&callid, &ftag, &ttag, &dir, &del);
666
+        if (del == 1)
667
+        {
668
+            LM_WARN("Failed to get dialog (callid: '%.*s') because it is marked for deletion!\n",
669
+                callid.len, callid.s);
670
+            unref_dlg(dlg, 1);
671
+            return 0;
672
+        }
673
+        if (dlg)
674
+        {
675
+            LM_DBG("Callid '%.*s' found, must be a spiraled request\n",
676
+                callid.len, callid.s);
677
+
678
+            run_dlg_callbacks( DLGCB_SPIRALED, dlg, req, NULL, DLG_DIR_DOWNSTREAM, 0);
679
+
680
+            // get_dlg with del==0 has incremented the ref count by 1
681
+            unref_dlg(dlg, 1);
682
+            goto finish;
683
+        }
684
+    }
685
+
686
+    dlg = build_new_dlg (&callid /*callid*/,
687
+                         &(get_from(req)->uri) /*from uri*/,
688
+                         &(get_to(req)->uri) /*to uri*/,
689
+                         &ftag/*from_tag*/,
690
+                         &req_uri /*r-uri*/ );
691
+
692
+	if (dlg==0)
649 693
 	{
650
-		LM_ERR("bad request or missing FROM hdr\n");
651
-		return -1;
652
-	}
653
-	if((msg->callid==NULL && parse_headers(msg,HDR_CALLID_F,0)<0)
654
-			|| msg->callid==NULL){
655
-		LM_ERR("bad request or missing CALLID hdr\n");
656
-		return -1;
657
-	}
658
-	s = msg->callid->body;
659
-	trim(&s);
660
-
661
-	if (pv_printf_s(msg, ruri_param_model, &req_uri)<0) {
662
-		LM_ERR("error - cannot print the r-uri format\n");
663
-		return -1;
664
-	}
665
-	trim(&req_uri);
666
-
667
-	/* some sanity checks */
668
-	if (s.len==0 || get_from(msg)->tag_value.len==0) {
669
-		LM_ERR("invalid request -> callid (%d) or from TAG (%d) empty\n",
670
-			s.len, get_from(msg)->tag_value.len);
671
-		return -1;
672
-	}
673
-
674
-	dlg = build_new_dlg(&s /*callid*/, &(get_from(msg)->uri) /*from uri*/,
675
-		&(get_to(msg)->uri) /*to uri*/,
676
-		&(get_from(msg)->tag_value)/*from_tag*/, &req_uri /*r-uri*/ );
677
-	if (dlg==0) {
678 694
 		LM_ERR("failed to create new dialog\n");
679 695
 		return -1;
680 696
 	}
681 697
 
682
-	
683
-
684 698
 	/* save caller's tag, cseq, contact and record route*/
685
-	if (populate_leg_info(dlg, msg, t, DLG_CALLER_LEG,
686
-			&(get_from(msg)->tag_value)) !=0)
699
+	if (populate_leg_info(dlg, req, t, DLG_CALLER_LEG,
700
+			&(get_from(req)->tag_value)) !=0)
687 701
 	{
688 702
 		LM_ERR("could not add further info to the dialog\n");
689 703
 		shm_free(dlg);
690 704
 		return -1;
691 705
 	}
692 706
 
693
-	set_current_dialog(msg, dlg);
694
-	_dlg_ctx.dlg = dlg;
695 707
 
696 708
 	/* Populate initial varlist: */
697
-	dlg->vars = get_local_varlist_pointer(msg, 1);
709
+	dlg->vars = get_local_varlist_pointer(req, 1);
710
+
711
+	link_dlg(dlg,0);
698 712
 
699
-	link_dlg(dlg, 2/* extra ref for the callback and current dlg hook */);
713
+    run_create_callbacks(dlg, req);
700 714
 
701 715
 	/* first INVITE seen (dialog created, unconfirmed) */
702 716
 	if ( seq_match_mode!=SEQ_MATCH_NO_ID &&
703
-			add_dlg_rr_param( msg, dlg->h_entry, dlg->h_id)<0 ) {
717
+			add_dlg_rr_param( req, dlg->h_entry, dlg->h_id)<0 ) {
704 718
 		LM_ERR("failed to add RR param\n");
705 719
 		goto error;
706 720
 	}
707 721
 
708
-	if ( d_tmb.register_tmcb( msg, t,
722
+	if ( d_tmb.register_tmcb( req, t,
709 723
 				TMCB_RESPONSE_READY|TMCB_RESPONSE_FWDED,
710 724
 				dlg_onreply, (void*)dlg, unref_new_dialog)<0 ) {
711 725
 		LM_ERR("failed to register TMCB\n");
712 726
 		goto error;
713 727
 	}
728
+    // increase reference counter because of registered callback
729
+    ref_dlg(dlg, 1);
714 730
 
715
-	dlg->lifetime = get_dlg_timeout(msg);
731
+	dlg->lifetime = get_dlg_timeout(req);
716 732
 	s.s   = _dlg_ctx.to_route_name;
717 733
 	s.len = strlen(s.s);
718 734
 	dlg_set_toroute(dlg, &s);
... ...
@@ -721,25 +864,29 @@ int dlg_new_dialog(struct sip_msg *msg, struct cell *t)
721 721
 	if (_dlg_ctx.to_bye!=0)
722 722
 		dlg->dflags |= DLG_FLAG_TOBYE;
723 723
 
724
-	if (t) {
725
-		if ( d_tmb.register_tmcb( msg, t, TMCB_MAX,
726
-					dlg_tmcb_dummy, (void*)dlg, 0)<0 ) {
727
-			LM_ERR("failed cache in T the shortcut to dlg\n");
728
-			goto error;
729
-		}
730
-	}
731
-#if 0
732
-		t->dialog_ctx = (void*) dlg;
733
-#endif
724
+    if_update_stat( dlg_enable_stats, processed_dlgs, 1);
734 725
 
735
-	run_create_callbacks( dlg, msg);
726
+finish:
736 727
 
737
-	if_update_stat( dlg_enable_stats, processed_dlgs, 1);
728
+    set_current_dialog(req, dlg);
729
+    _dlg_ctx.dlg = dlg;
730
+    ref_dlg(dlg, 1);
731
+
732
+	if (t) {
733
+	    store_dlg_in_tm( req, t, dlg);
734
+	}
735
+	else
736
+	{
737
+        if ( d_tmb.register_tmcb( req, NULL, TMCB_REQUEST_FWDED,
738
+                store_dlg_in_tm_cb, (void*)dlg, NULL)<0 ) {
739
+            LM_ERR("failed to store dialog in transaction during dialog creation for later reference\n");
740
+        }
741
+	}
738 742
 
739 743
 	return 0;
740 744
 error:
741 745
 	unref_dlg(dlg,1);
742
-	profile_cleanup(msg, 0, NULL);
746
+	profile_cleanup(req, 0, NULL);
743 747
 	return -1;
744 748
 }
745 749
 
... ...
@@ -802,21 +949,6 @@ static inline int update_cseqs(struct dlg_cell *dlg, struct sip_msg *req,
802 802
 	}
803 803
 }
804 804
 
805
-
806
-/*!
807
- * \brief Unreference a dialog, small wrapper to care for shutdown
808
- * \see unref_dlg 
809
- * \param dialog unreferenced dialog
810
- */
811
-static void unreference_dialog(void *dialog)
812
-{
813
-	// if the dialog table is gone, it means the system is shutting down.
814
-	if (!d_table)
815
-		return;
816
-	unref_dlg((struct dlg_cell*)dialog, 1);
817
-}
818
-
819
-
820 805
 /*!
821 806
  * \brief Unreference a dialog from tm callback (another wrapper)
822 807
  * \param t transaction, unused
... ...
@@ -945,6 +1077,21 @@ void dlg_onroute(struct sip_msg* req, str *route_params, void *param)
945 945
 		}
946 946
 	}
947 947
 
948
+    /* set current dialog - it will keep a ref! */
949
+    set_current_dialog( req, dlg);
950
+    _dlg_ctx.dlg = dlg;
951
+
952
+    if ( d_tmb.register_tmcb( req, NULL, TMCB_REQUEST_FWDED,
953
+            store_dlg_in_tm_cb, (void*)dlg, NULL)<0 ) {
954
+        LM_ERR("failed to store dialog in transaction during dialog creation for later reference\n");
955
+    }
956
+
957
+    if (del == 1) {
958
+        LM_DBG( "Use the dialog (callid: '%.*s') without further handling because it is marked for deletion\n",
959
+            callid.len, callid.s);
960
+        return;
961
+    }
962
+
948 963
 	/* run state machine */
949 964
 	switch ( req->first_line.u.request.method_value ) {
950 965
 		case METHOD_PRACK:
... ...
@@ -963,10 +1110,6 @@ void dlg_onroute(struct sip_msg* req, str *route_params, void *param)
963 963
 	CURR_DLG_LIFETIME = (unsigned int)(time(0))-dlg->start_ts;
964 964
 	CURR_DLG_STATUS = new_state;
965 965
 
966
-	/* set current dialog - it will keep a ref! */
967
-	set_current_dialog( req, dlg);
968
-	_dlg_ctx.dlg = dlg;
969
-
970 966
 	/* delay deletion of dialog until transaction has died off in order
971 967
 	 * to absorb in-air messages */
972 968
 	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)
1002 1002
 			unref++;
1003 1003
 		}
1004 1004
 		/* dialog terminated (BYE) */
1005
-		run_dlg_callbacks( DLGCB_TERMINATED, dlg, req, dir, 0);
1006
-
1007
-		/* delete the dialog from DB */
1008
-		if (dlg_db_mode)
1009
-			remove_dialog_from_db(dlg);
1005
+        dlg_terminated( req, dlg, dir);
1010 1006
 
1011 1007
 		unref_dlg(dlg, unref);
1012 1008
 
... ...
@@ -1033,7 +1172,7 @@ void dlg_onroute(struct sip_msg* req, str *route_params, void *param)
1033 1033
 		}
1034 1034
 
1035 1035
 		/* within dialog request */
1036
-		run_dlg_callbacks( DLGCB_REQ_WITHIN, dlg, req, dir, 0);
1036
+		run_dlg_callbacks( DLGCB_REQ_WITHIN, dlg, req, NULL, dir, 0);
1037 1037
 
1038 1038
 		if ( (event!=DLG_EVENT_REQACK) &&
1039 1039
 		(dlg->cbs.types)&DLGCB_RESPONSE_WITHIN ) {
... ...
@@ -1108,11 +1247,7 @@ void dlg_ontimeout( struct dlg_tl *tl)
1108 1108
 			dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s);
1109 1109
 
1110 1110
 		/* dialog timeout */
1111
-		run_dlg_callbacks( DLGCB_EXPIRED, dlg, 0, DLG_DIR_NONE, 0);
1112
-
1113
-		/* delete the dialog from DB */
1114
-		if (dlg_db_mode)
1115
-			remove_dialog_from_db(dlg);
1111
+		run_dlg_callbacks( DLGCB_EXPIRED, dlg, NULL, NULL, DLG_DIR_NONE, 0);
1116 1112
 
1117 1113
 		unref_dlg(dlg, unref+1);
1118 1114
 
... ...
@@ -61,6 +61,7 @@
61 61
 #include "dlg_hash.h"
62 62
 #include "dlg_profile.h"
63 63
 #include "dlg_req_within.h"
64
+#include "dlg_db_handler.h"
64 65
 
65 66
 #define MAX_LDG_LOCKS  2048
66 67
 #define MIN_LDG_LOCKS  2
... ...
@@ -153,7 +154,12 @@ inline void destroy_dlg(struct dlg_cell *dlg)
153 153
 			dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s);
154 154
 	}
155 155
 
156
-	run_dlg_callbacks( DLGCB_DESTROY , dlg, 0, DLG_DIR_NONE, 0);
156
+	run_dlg_callbacks( DLGCB_DESTROY , dlg, NULL, NULL, DLG_DIR_NONE, 0);
157
+
158
+
159
+	/* delete the dialog from DB*/
160
+	if (dlg_db_mode)
161
+		remove_dialog_from_db(dlg);
157 162
 
158 163
 	if(dlg==get_current_dlg_pointer())
159 164
 		reset_current_dlg_pointer();
... ...
@@ -841,6 +847,11 @@ static inline int internal_mi_print_dlg(struct mi_node *rpl,
841 841
 	if (node1==0)
842 842
 		goto error;
843 843
 
844
+	p= int2str((unsigned long)dlg->ref, &len);
845
+	node1 = add_mi_node_child( node, MI_DUP_VALUE, "ref_count", 9, p, len);
846
+	if (node1==0)
847
+		goto error;
848
+
844 849
 	p= int2str((unsigned long)dlg->start_ts, &len);
845 850
 	node1 = add_mi_node_child(node,MI_DUP_VALUE,"timestart",9, p, len);
846 851
 	if (node1==0)
... ...
@@ -934,8 +945,12 @@ static inline int internal_mi_print_dlg(struct mi_node *rpl,
934 934
 		node1 = add_mi_node_child(node, 0, "context", 7, 0, 0);
935 935
 		if(node1 == 0)
936 936
 			goto error;
937
-		run_dlg_callbacks( DLGCB_MI_CONTEXT, dlg, NULL, 
938
-			DLG_DIR_NONE, (void *)node1);
937
+		run_dlg_callbacks( DLGCB_MI_CONTEXT,
938
+		                   dlg,
939
+		                   NULL,
940
+		                   NULL,
941
+		                   DLG_DIR_NONE,
942
+		                   (void *)node1);
939 943
 	}
940 944
 	return 0;
941 945
 
... ...
@@ -34,6 +34,8 @@
34 34
 
35 35
 struct dlg_binds {
36 36
 	register_dlgcb_f  register_dlgcb;
37
+    set_dlg_variable_f set_dlg_var;
38
+	get_dlg_variable_f get_dlg_var;
37 39
 };
38 40
 
39 41
 
... ...
@@ -327,17 +327,33 @@ int profile_cleanup( struct sip_msg *msg, unsigned int flags, void *param )
327 327
 }
328 328
 
329 329
 
330
+
331
+struct dlg_cell* get_dialog_from_tm(struct cell *t)
332
+{
333
+    if (t==NULL || t==T_UNDEFINED)
334
+        return NULL;
335
+
336
+    struct tm_callback* x = (struct tm_callback*)(t->tmcb_hl.first);
337
+
338
+    while(x){
339
+        membar_depends();
340
+        if (x->types==TMCB_MAX && x->callback==dlg_tmcb_dummy){
341
+            return (struct dlg_cell*)(x->param);
342
+        }
343
+        x=x->next;
344
+    }
345
+
346
+    return NULL;
347
+}
348
+
330 349
 /*!
331 350
  * \brief Get the current dialog for a message, if exists
332 351
  * \param msg SIP message
333 352
  * \return NULL if called in REQUEST_ROUTE, pointer to dialog ctx otherwise
334 353
  */ 
335
-static struct dlg_cell *get_current_dialog(struct sip_msg *msg)
354
+struct dlg_cell *get_current_dialog(struct sip_msg *msg)
336 355
 {
337
-	struct cell *trans;
338
-	struct tm_callback* x;
339
-
340
-	if (is_route_type(REQUEST_ROUTE)) {
356
+	if (is_route_type(REQUEST_ROUTE|BRANCH_ROUTE)) {
341 357
 		/* use the per-process static holder */
342 358
 		if (msg->id==current_dlg_msg_id)
343 359
 			return current_dlg_pointer;
... ...
@@ -348,18 +364,7 @@ static struct dlg_cell *get_current_dialog(struct sip_msg *msg)
348 348
 		return NULL;
349 349
 	} else {
350 350
 		/* use current transaction to get dialog */
351
-		trans = d_tmb.t_gett();
352
-		if (trans==NULL || trans==T_UNDEFINED)
353
-			return NULL;
354
-		x=(struct tm_callback*)(trans->tmcb_hl.first);
355
-		while(x){
356
-			membar_depends();
357
-			if (x->types==TMCB_MAX && x->callback==dlg_tmcb_dummy){
358
-				return (struct dlg_cell*)(x->param);
359
-			}
360
-			x=x->next;
361
-		}
362
-		return NULL;
351
+	    return get_dialog_from_tm(d_tmb.t_gett());
363 352
 	}
364 353
 }
365 354
 
... ...
@@ -33,6 +33,8 @@
33 33
 #include "../../parser/msg_parser.h"
34 34
 #include "../../locking.h"
35 35
 #include "../../str.h"
36
+#include "../../modules/tm/h_table.h"
37
+
36 38
 
37 39
 
38 40
 /*!
... ...
@@ -83,6 +85,10 @@ struct dlg_cell *get_current_dlg_pointer(void);
83 83
 
84 84
 void reset_current_dlg_pointer(void);
85 85
 
86
+struct dlg_cell* get_dialog_from_tm(struct cell *t);
87
+
88
+struct dlg_cell *get_current_dialog(struct sip_msg *msg);
89
+
86 90
 /*!
87 91
  * \brief Add profile definitions to the global list
88 92
  * \see new_dlg_profile
... ...
@@ -175,7 +175,7 @@ void bye_reply_cb(struct cell* t, int type, struct tmcb_params* ps){
175 175
 			unref++;
176 176
 		}
177 177
 		/* dialog terminated (BYE) */
178
-		run_dlg_callbacks( DLGCB_TERMINATED, dlg, ps->req, DLG_DIR_NONE, 0);
178
+		run_dlg_callbacks( DLGCB_TERMINATED, dlg, ps->req, ps->rpl, DLG_DIR_NONE, 0);
179 179
 
180 180
 		LM_DBG("first final reply\n");
181 181
 		/* derefering the dialog */
... ...
@@ -214,6 +214,61 @@ void print_lists(struct dlg_cell *dlg) {
214 214
 	}
215 215
 }
216 216
 
217
+str * get_dlg_variable(struct dlg_cell *dlg, str *key)
218
+{
219
+    str* var = NULL;
220
+
221
+    if( !dlg || !key || key->len > strlen(key->s))
222
+    {
223
+        LM_ERR("BUG - bad parameters\n");
224
+
225
+        return NULL;
226
+    }
227
+
228
+    dlg_lock(d_table, &(d_table->entries[dlg->h_entry]));
229
+    var = get_dlg_variable_unsafe( dlg, key);
230
+    dlg_unlock(d_table, &(d_table->entries[dlg->h_entry]));
231
+
232
+    return var;
233
+}
234
+
235
+int set_dlg_variable(struct dlg_cell *dlg, str *key, str *val)
236
+{
237
+    if( !dlg || !key || key->len > strlen(key->s) || (val && val->len > strlen(val->s)))
238
+    {
239
+        LM_ERR("BUG - bad parameters\n");
240
+        return -1;
241
+    }
242
+
243
+    dlg_lock(d_table, &(d_table->entries[dlg->h_entry]));
244
+
245
+    if( !val)
246
+    {
247
+        if (set_dlg_variable_unsafe(dlg, key, NULL, 1)!=0) {
248
+            LM_ERR("failed to delete dialog variable <%.*s>\n", key->len,key->s);
249
+            goto error;
250
+        }
251
+    } else {
252
+        if (set_dlg_variable_unsafe(dlg, key, val, 1)!=0) {
253
+            LM_ERR("failed to store dialog values <%.*s>\n",key->len,key->s);
254
+            goto error;
255
+        }
256
+    }
257
+
258
+    dlg->dflags &= DLG_FLAG_CHANGED_VARS;
259
+    dlg_unlock(d_table, &(d_table->entries[dlg->h_entry]));
260
+    if ( dlg_db_mode==DB_MODE_REALTIME )
261
+        update_dialog_dbinfo(dlg);
262
+
263
+    print_lists(dlg);
264
+
265
+    return 0;
266
+
267
+error:
268
+    dlg_unlock(d_table, &(d_table->entries[dlg->h_entry]));
269
+    return -1;
270
+}
271
+
217 272
 int pv_get_dlg_variable(struct sip_msg *msg, pv_param_t *param, pv_value_t *res)
218 273
 {
219 274
 	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)
225 225
 	}
226 226
 
227 227
 	/* Retrieve the current dialog */
228
-	dlg=get_current_dlg_pointer();
228
+	dlg=get_current_dialog( msg);
229 229
 
230 230
 	if (dlg) {
231 231
 		/* Lock the dialog */
... ...
@@ -254,7 +309,7 @@ int pv_set_dlg_variable(struct sip_msg* msg, pv_param_t *param, int op, pv_value
254 254
 	struct dlg_cell *dlg;
255 255
 
256 256
 	/* Retrieve the current dialog */
257
-	dlg=get_current_dlg_pointer();
257
+	dlg=get_current_dialog( msg);
258 258
 	
259 259
 	if (dlg) {
260 260
 		/* Lock the dialog */
... ...
@@ -49,6 +49,8 @@ struct dlg_var {
49 49
 	struct dlg_var *next;
50 50
 };
51 51
 
52
+str * get_dlg_variable(struct dlg_cell *dlg, str *key);
53
+int set_dlg_variable(struct dlg_cell *dlg, str *key, str *val);
52 54
 
53 55
 int pv_parse_dialog_var_name(pv_spec_p sp, str *in);
54 56