Bläddra i källkod

modules/dialog_ng: added DB support for dialog_ng
- thanks to a lot of work contributed by Carlos Ruiz Diaz

Jason Penton 11 år sedan
förälder
incheckning
6ea8693fd7

+ 66 - 5
modules/dialog_ng/dialog.c

@@ -31,6 +31,7 @@
 #include "dlg_profile.h"
 #include "dlg_var.h"
 #include "dlg_req_within.h"
+#include "dlg_db_handler.h"
 
 MODULE_VERSION
 
@@ -64,6 +65,14 @@ struct tm_binds d_tmb;
 struct rr_binds d_rrb;
 pv_spec_t timeout_avp;
 
+int active_dlgs_cnt = 0;
+int early_dlgs_cnt	= 0;
+
+/* db stuff */
+int dlg_db_mode_param = DB_MODE_NONE;
+static int db_fetch_rows = 200;
+static str db_url = str_init(DEFAULT_DB_URL);
+static unsigned int db_update_period = DB_DEFAULT_UPDATE_PERIOD;
 
 /* commands wrappers and fixups */
 static int fixup_profile(void** param, int param_no);
@@ -126,11 +135,17 @@ static param_export_t mod_params[] = {
     { "dlg_extra_hdrs", PARAM_STR, &dlg_extra_hdrs},
     //In this new dialog module we always match using DID
     //{ "dlg_match_mode", INT_PARAM, &seq_match_mode},
-    { "detect_spirals", INT_PARAM, &detect_spirals,},
-    { "profiles_with_value", PARAM_STRING, &profiles_wv_s},
-    { "profiles_no_value", PARAM_STRING, &profiles_nv_s},
-    { "bridge_controller", PARAM_STR, &dlg_bridge_controller},
-    { "ruri_pvar", PARAM_STR, &ruri_pvar_param},
+
+    { "db_url",				PARAM_STRING, &db_url 				},
+    { "db_mode",			INT_PARAM, &dlg_db_mode_param		},
+    { "db_update_period",	INT_PARAM, &db_update_period		},
+    { "db_fetch_rows",		INT_PARAM, &db_fetch_rows			}
+    ,
+    { "detect_spirals",		INT_PARAM, &detect_spirals			},
+    { "profiles_with_value",PARAM_STRING, &profiles_wv_s			},
+    { "profiles_no_value",	PARAM_STRING, &profiles_nv_s			},
+    { "bridge_controller",	PARAM_STR, &dlg_bridge_controller	},
+    { "ruri_pvar",			PARAM_STR, &ruri_pvar_param		},
 
     { 0, 0, 0}
 };
@@ -516,16 +531,62 @@ static int mod_init(void) {
         return -1;
     }
 
+    /* if a database should be used to store the dialogs' information */
+	dlg_db_mode = dlg_db_mode_param;
+	if (dlg_db_mode==DB_MODE_NONE) {
+		db_url.s = 0; db_url.len = 0;
+	} else {
+		if (dlg_db_mode!=DB_MODE_REALTIME &&
+		dlg_db_mode!=DB_MODE_DELAYED && dlg_db_mode!=DB_MODE_SHUTDOWN ) {
+			LM_ERR("unsupported db_mode %d\n", dlg_db_mode);
+			return -1;
+		}
+		if ( !db_url.s || db_url.len==0 ) {
+			LM_ERR("db_url not configured for db_mode %d\n", dlg_db_mode);
+			return -1;
+		}
+		if (init_dlg_db(&db_url, dlg_hash_size, db_update_period, db_fetch_rows)!=0) {
+			LM_ERR("failed to initialize the DB support\n");
+			return -1;
+		}
+		run_load_callbacks();
+	}
+
     destroy_dlg_callbacks(DLGCB_LOADED);
 
     return 0;
 }
 
 static int child_init(int rank) {
+	dlg_db_mode = dlg_db_mode_param;
+
+	if ( ((dlg_db_mode==DB_MODE_REALTIME || dlg_db_mode==DB_MODE_DELAYED) &&
+		(rank>0 || rank==PROC_TIMER)) ||
+		(dlg_db_mode==DB_MODE_SHUTDOWN && (rank==PROC_MAIN)) ) {
+			if ( dlg_connect_db(&db_url) ) {
+				LM_ERR("failed to connect to database (rank=%d)\n",rank);
+				return -1;
+			}
+	}
+
+	/* in DB_MODE_SHUTDOWN only PROC_MAIN will do a DB dump at the end, so
+	 * for the rest of the processes will be the same as DB_MODE_NONE */
+	if (dlg_db_mode==DB_MODE_SHUTDOWN && rank!=PROC_MAIN)
+		dlg_db_mode = DB_MODE_NONE;
+	/* in DB_MODE_REALTIME and DB_MODE_DELAYED the PROC_MAIN have no DB handle */
+	if ( (dlg_db_mode==DB_MODE_REALTIME || dlg_db_mode==DB_MODE_DELAYED) &&
+			rank==PROC_MAIN)
+		dlg_db_mode = DB_MODE_NONE;
+
     return 0;
 }
 
 static void mod_destroy(void) {
+	if(dlg_db_mode == DB_MODE_DELAYED || dlg_db_mode == DB_MODE_SHUTDOWN) {
+		dialog_update_db(0, 0);
+		destroy_dlg_db();
+	}
+
     destroy_dlg_table();
     destroy_dlg_timer();
     destroy_dlg_callbacks(DLGCB_CREATED | DLGCB_LOADED);

+ 1176 - 0
modules/dialog_ng/dlg_db_handler.c

@@ -0,0 +1,1176 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2007 Voice System SRL
+ * Copyright (C) 2011 Carsten Bock, [email protected]
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * History:
+ * --------
+ * 2007-05-10  initial version (ancuta)
+ * 2007-07-06 additional information saved in the database: cseq, contact, 
+ *  		   route set and socket_info for both caller and callee (ancuta)
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+
+#include "../../dprint.h"
+#include "../../ut.h"
+#include "../../timer.h"
+#include "../../lib/srdb1/db.h"
+#include "../../str.h"
+#include "../../socket_info.h"
+#include "../../lib/srutils/srjson.h"
+
+#include "dlg_hash.h"
+#include "dlg_var.h"
+#include "dlg_profile.h"
+#include "dlg_db_handler.h"
+
+str id_column			= str_init(ID_COL);		// 0
+str h_entry_column		= str_init(HASH_ENTRY_COL);	// 1
+str h_id_column			= str_init(HASH_ID_COL);	// 2
+str did_column			= str_init(DID_COL);		// 3
+str call_id			= str_init(CALL_ID_COL);	// 4
+str from_uri_column		= str_init(FROM_URI_COL);	// 5
+str from_tag_column		= str_init(FROM_TAG_COL);	// 6
+str caller_original_cseq_column	= str_init(CALLER_ORIGINAL_CSEQ_COL); // 7
+str req_uri_column		= str_init(REQ_URI_COL);	// 8
+str caller_route_set_column	= str_init(CALLER_ROUTESET_COL);// 9
+str caller_contact_column	= str_init(CALLER_CONTACT_COL);	// 10
+str caller_sock_column		= str_init(CALLER_SOCK);	// 11
+str timeout_column		= str_init(TIMEOUT_COL);	// 12
+str state_column		= str_init(STATE_COL);		// 13
+str start_time_column		= str_init(START_TIME_COL);	// 14
+str sflags_column		= str_init(SFLAGS_COL);		// 15
+str to_route_name_column	= str_init(TOROUTE_NAME_COL);	// 16
+str to_route_index_column	= str_init(TOROUTE_INDEX_COL);	// 17
+
+// dialog_out exclusive columns
+str to_uri_column		= str_init(TO_URI_COL);
+str to_tag_column		= str_init(TO_TAG_COL);
+str caller_cseq_column		= str_init(CALLER_CSEQ_COL);
+str callee_cseq_column		= str_init(CALLEE_CSEQ_COL);
+str callee_contact_column	= str_init(CALLEE_CONTACT_COL);
+str callee_routeset_column	= str_init(CALLEE_ROUTESET_COL);
+str callee_sock_column		= str_init(CALLEE_SOCK);
+
+typedef enum dialog_in_field_idx {
+	DLGI_ID_COL_IDX	= 0,
+	DLGI_HASH_ENTRY_COL_IDX,
+	DLGI_HASH_ID_COL_IDX,
+	DLGI_DID_COL_IDX,
+	DLGI_CALLID_COL_IDX,
+	DLGI_FROM_URI_COL_IDX,
+	DLGI_FROM_TAG_COL_IDX,
+	DLGI_CALLER_CSEQ_COL_IDX,
+	DLGI_REQ_URI_COL_IDX,
+	DLGI_CALLER_ROUTESET_COL_IDX,
+	DLGI_CALLER_CONTACT_COL_IDX,
+	DLGI_CALLER_SOCK_IDX,
+	DLGI_TIMEOUT_COL_IDX,
+	DLGI_STATE_COL_IDX,
+	DLGI_START_TIME_COL_IDX,
+	DLGI_SFLAGS_COL_IDX,
+	DLGI_TOROUTE_NAME_COL_IDX,
+	DLGI_TOROUTE_INDEX_COL_IDX
+} dialog_in_field_idx_t;
+
+typedef enum dialog_out_field_idx {
+	DLGO_ID_COL_IDX	= 0,
+	DLGO_HASH_ENTRY_COL_IDX,
+	DLGO_HASH_ID_COL_IDX,
+	DLGO_DID_COL_IDX,
+	DLGO_TO_URI_IDX,
+	DLGO_TO_TAG_IDX,
+	DLGO_CALLER_CSEQ_IDX,
+	DLGO_CALLEE_CSEQ_IDX,
+	DLGO_CALLEE_CONTACT_IDX,
+	DLGO_CALLEE_ROUTESET_IDX,
+	DLGO_CALLEE_SOCK_IDX,
+
+} dialog_out_field_idx_t;
+
+str dialog_in_table_name	=	str_init(DIALOG_IN_TABLE_NAME);
+str dialog_out_table_name	=	str_init(DIALOG_OUT_TABLE_NAME);
+
+int dlg_db_mode			=	DB_MODE_NONE;
+
+str vars_h_id_column		=	str_init(VARS_HASH_ID_COL);
+str vars_h_entry_column		=	str_init(VARS_HASH_ENTRY_COL);
+str vars_key_column		=	str_init(VARS_KEY_COL);
+str vars_value_column		=	str_init(VARS_VALUE_COL);
+str dialog_vars_table_name	=	str_init(DIALOG_VARS_TABLE_NAME);
+
+static db1_con_t* dialog_db_handle    = 0; /* database connection handle */
+static db_func_t dialog_dbf;
+
+extern int dlg_enable_stats;
+extern int active_dlgs_cnt;
+extern int early_dlgs_cnt;
+
+#define GET_FIELD_IDX(_val, _idx)\
+		(_val + _idx)
+
+#define SET_STR_VALUE(_val, _str)\
+	do{\
+			VAL_STR((_val)).s 		= (_str).s;\
+			VAL_STR((_val)).len 	= (_str).len;\
+	}while(0);
+
+#define SET_NULL_FLAG(_vals, _i, _max, _flag)\
+	do{\
+		for((_i) = 0;(_i)<(_max); (_i)++)\
+			VAL_NULL((_vals)+(_i)) = (_flag);\
+	}while(0);
+
+#define SET_PROPER_NULL_FLAG(_str, _vals, _index)\
+	do{\
+		if( (_str).len == 0)\
+			VAL_NULL( (_vals)+(_index) ) = 1;\
+		else\
+			VAL_NULL( (_vals)+(_index) ) = 0;\
+	}while(0);
+
+#define GET_STR_VALUE(_res, _values, _index, _not_null, _unref)\
+	do{\
+		if (VAL_NULL((_values)+ (_index))) { \
+			if (_not_null) {\
+				if (_unref) unref_dlg(dlg,1);\
+				goto next_dialog; \
+			} else { \
+				(_res).s = 0; \
+				(_res).len = 0; \
+			}\
+		} else { \
+			(_res).s = VAL_STR((_values)+ (_index)).s;\
+			(_res).len = strlen(VAL_STR((_values)+ (_index)).s);\
+		} \
+	}while(0);
+
+static int select_dialog_out_by_did(str *did, db1_res_t ** res, int fetch_num_rows);
+static int load_dialog_info_from_db(int dlg_hash_size, int fetch_num_rows);
+static int load_dialog_vars_from_db(int fetch_num_rows);
+
+int dlg_connect_db(const str *db_url)
+{
+	if (dialog_db_handle) {
+		LM_CRIT("BUG - db connection found already open\n");
+		return -1;
+	}
+	if ((dialog_db_handle = dialog_dbf.init(db_url)) == 0)
+		return -1;
+	return 0;
+}
+
+
+int init_dlg_db(const str *db_url, int dlg_hash_size , int db_update_period, int fetch_num_rows)
+{
+	/* Find a database module */
+	if (db_bind_mod(db_url, &dialog_dbf) < 0){
+		LM_ERR("Unable to bind to a database driver\n");
+		return -1;
+	}
+
+	if (dlg_connect_db(db_url)!=0){
+		LM_ERR("unable to connect to the database\n");
+		return -1;
+	}
+
+	if(db_check_table_version(&dialog_dbf, dialog_db_handle, &dialog_in_table_name, DLG_TABLE_VERSION) < 0) {
+		LM_ERR("error during dialog-table version check.\n");
+		return -1;
+	}
+
+	if(db_check_table_version(&dialog_dbf, dialog_db_handle, &dialog_vars_table_name, DLG_VARS_TABLE_VERSION) < 0) {
+		LM_ERR("error during dialog-vars version check.\n");
+		return -1;
+	}
+
+	if( (dlg_db_mode==DB_MODE_DELAYED) && 
+	(register_timer( dialog_update_db, 0, db_update_period)<0 )) {
+		LM_ERR("failed to register update db\n");
+		return -1;
+	}
+
+	if( (load_dialog_info_from_db(dlg_hash_size, fetch_num_rows) ) !=0 ){
+		LM_ERR("unable to load the dialog data\n");
+		return -1;
+	}
+	if( (load_dialog_vars_from_db(fetch_num_rows) ) !=0 ){
+		LM_ERR("unable to load the dialog data\n");
+		return -1;
+	}
+
+	dialog_dbf.close(dialog_db_handle);
+	dialog_db_handle = 0;
+
+	return 0;
+}
+
+void destroy_dlg_db(void)
+{
+	/* close the DB connection */
+	if (dialog_db_handle) {
+		dialog_dbf.close(dialog_db_handle);
+		dialog_db_handle = 0;
+	}
+}
+
+static int use_dialog_out_table(void)
+{
+	if(!dialog_db_handle){
+		LM_ERR("invalid database handle\n");
+		return -1;
+	}
+
+	if (dialog_dbf.use_table(dialog_db_handle, &dialog_out_table_name) < 0) {
+		LM_ERR("Error in use_table\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int use_dialog_table(void)
+{
+	if(!dialog_db_handle){
+		LM_ERR("invalid database handle\n");
+		return -1;
+	}
+
+	if (dialog_dbf.use_table(dialog_db_handle, &dialog_in_table_name) < 0) {
+		LM_ERR("Error in use_table\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int use_dialog_vars_table(void)
+{
+	if(!dialog_db_handle){
+		LM_ERR("invalid database handle\n");
+		return -1;
+	}
+
+	if (dialog_dbf.use_table(dialog_db_handle, &dialog_vars_table_name) < 0) {
+		LM_ERR("Error in use_table\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int select_dialog_out_by_did(str *did, db1_res_t ** res, int fetch_num_rows)
+{
+	db_key_t query_cols[DIALOG_IN_TABLE_COL_NO] = {
+							&id_column, 			&h_entry_column,
+							&h_id_column, 			&did_column,
+							&to_uri_column, 		&to_tag_column,
+							&caller_cseq_column, 	&callee_cseq_column,
+							&callee_contact_column,	&callee_routeset_column,
+							&callee_sock_column };
+
+	db_key_t where[1] = {
+							&did_column
+						};
+	db_val_t values[1];
+
+	if(use_dialog_out_table() != 0) {
+		return -1;
+	}
+
+	VAL_TYPE(values) = DB1_STR;
+	VAL_NULL(values) = 0;
+
+	SET_STR_VALUE(values, (*did));
+
+	if (DB_CAPABILITY(dialog_dbf, DB_CAP_FETCH) && (fetch_num_rows > 0)) {
+		if(dialog_dbf.query(dialog_db_handle, where, 0, values, query_cols, 1, DIALOG_OUT_TABLE_COL_NO, 0, 0) < 0) {
+			LM_ERR("Error while querying (fetch) database\n");
+			return -1;
+		}
+		if(dialog_dbf.fetch_result(dialog_db_handle, res, fetch_num_rows) < 0) {
+			LM_ERR("fetching rows failed\n");
+			return -1;
+		}
+	}
+	else {
+		if(dialog_dbf.query(dialog_db_handle, where, 0, values, query_cols, 1, DIALOG_OUT_TABLE_COL_NO, 0, res) < 0) {
+			LM_ERR("Error while querying database\n");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+static int select_entire_dialog_in_table(db1_res_t ** res, int fetch_num_rows)
+{
+	db_key_t query_cols[DIALOG_IN_TABLE_COL_NO] = {
+						&id_column, 			&h_entry_column,
+						&h_id_column, 			&did_column,
+						&call_id, 				&from_uri_column,
+						&from_tag_column, 		&caller_original_cseq_column,
+						&req_uri_column,		&caller_route_set_column,
+						&caller_contact_column, &caller_sock_column, &timeout_column,
+						&state_column, 			&start_time_column,
+						&sflags_column,
+						&to_route_name_column, 	&to_route_index_column };
+
+	if(use_dialog_table() != 0) {
+		return -1;
+	}
+
+	/* select the whole table and all the columns */
+	if (DB_CAPABILITY(dialog_dbf, DB_CAP_FETCH) && (fetch_num_rows > 0)) {
+		if(dialog_dbf.query(dialog_db_handle,0,0,0,query_cols, 0, 
+		DIALOG_IN_TABLE_COL_NO, 0, 0) < 0) {
+			LM_ERR("Error while querying (fetch) database\n");
+			return -1;
+		}
+		if(dialog_dbf.fetch_result(dialog_db_handle, res, fetch_num_rows) < 0) {
+			LM_ERR("fetching rows failed\n");
+			return -1;
+		}
+	} else {
+		if(dialog_dbf.query(dialog_db_handle,0,0,0,query_cols, 0,
+		DIALOG_IN_TABLE_COL_NO, 0, res) < 0) {
+			LM_ERR("Error while querying database\n");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+struct socket_info * create_socket_info(db_val_t * vals, int n){
+
+	struct socket_info * sock;
+	char* p;
+	str host;
+	int port, proto;
+
+	/* socket name */
+	p = (VAL_STR(vals+n)).s;
+
+	if (VAL_NULL(vals+n) || p==0 || p[0]==0){
+		sock = 0;
+	} else {
+		if (parse_phostport( p, &host.s, &host.len, 
+		&port, &proto)!=0) {
+			LM_ERR("bad socket <%s>\n", p);
+			return 0;
+		}
+		sock = grep_sock_info( &host, (unsigned short)port, proto);
+		if (sock==0) {
+			LM_WARN("non-local socket <%s>...ignoring\n", p);
+		}
+	}
+
+	return sock;
+}
+
+static int load_dialog_out_from_db(struct dlg_cell *dlg, str *did, int fetch_num_rows)
+{
+	db1_res_t * res = NULL;
+	db_val_t * values;
+	db_row_t * rows;
+	int i, nr_rows;
+	str to_uri, to_tag, /*caller_cseq,*/
+		callee_cseq, callee_contact,
+		callee_route_set;
+
+	struct dlg_cell_out *dlg_out;
+	if((nr_rows = select_dialog_out_by_did(did, &res, fetch_num_rows)) < 0) {
+		LM_WARN("No dialog_out for did [%.*s]", did->len, did->s);
+		return -1;
+	}
+
+	nr_rows = RES_ROW_N(res);
+	LM_ALERT("the database has information about %i dialog_out's\n", nr_rows);
+	rows = RES_ROWS(res);
+
+	do {
+		for(i=0; i<nr_rows; i++) {
+			values = ROW_VALUES(rows + i);
+
+			if (VAL_NULL(GET_FIELD_IDX(values, DLGO_TO_URI_IDX)) ||
+				VAL_NULL(GET_FIELD_IDX(values, DLGO_TO_TAG_IDX))) {
+				LM_ERR("Columns [%.*s] or/and [%.*s] cannot be null\n",
+								to_tag_column.len, to_tag_column.s,
+								to_uri_column.len, to_uri_column.s);
+				return -1;
+			}
+
+			GET_STR_VALUE(to_uri,	values, DLGO_TO_URI_IDX, 	1, 0);
+			GET_STR_VALUE(to_tag,	values, DLGO_TO_TAG_IDX, 	1, 0);
+
+			dlg_out	= build_new_dlg_out(dlg, &to_uri, &to_tag);
+
+			if (!dlg_out) {
+				LM_ERR("Error creating dlg_out cell\n");
+				return -1;
+			}
+
+			GET_STR_VALUE(callee_cseq, 		values, DLGO_CALLEE_CSEQ_IDX, 		1, 0);
+			GET_STR_VALUE(callee_contact, 	values, DLGO_CALLEE_CONTACT_IDX,	1, 0);
+			GET_STR_VALUE(callee_route_set, values, DLGO_CALLEE_ROUTESET_IDX, 	1, 0);
+
+			dlg_out->callee_bind_addr = create_socket_info(values, DLGO_CALLEE_SOCK_IDX);
+
+			update_dlg_out_did(dlg_out, did);
+
+			link_dlg_out(dlg, dlg_out, 0);
+
+			if (dlg_set_leg_info(dlg, &to_tag, &callee_route_set, &callee_contact, &callee_cseq, dlg_out->callee_bind_addr, DLG_CALLEE_LEG) < 0) {
+				LM_ERR("Error setting leg info");
+				return -1;
+			}
+
+	next_dialog:
+			;
+		}
+
+		/* any more data to be fetched ?*/
+		if (DB_CAPABILITY(dialog_dbf, DB_CAP_FETCH) && (fetch_num_rows > 0)) {
+			if(dialog_dbf.fetch_result(dialog_db_handle, &res, fetch_num_rows) < 0) {
+				LM_ERR("re-fetching rows failed\n");
+				return -1;
+			}
+			nr_rows = RES_ROW_N(res);
+			rows = RES_ROWS(res);
+		} else
+			nr_rows = 0;
+	}
+	while(nr_rows>0);
+
+	return 0;
+}
+
+static int load_dialog_info_from_db(int dlg_hash_size, int fetch_num_rows)
+{
+	db1_res_t * res;
+	db_val_t * values;
+	db_row_t * rows;
+	struct dlg_entry *d_entry;
+	int i, nr_rows;
+	struct dlg_cell *dlg  = NULL;
+	str callid, from_uri, from_tag, req_uri,
+		caller_cseq, caller_contact, caller_rroute,
+		toroute_name, did;
+	unsigned int next_id;
+	
+	res = 0;
+	if((nr_rows = select_entire_dialog_in_table(&res, fetch_num_rows)) < 0)
+		goto end;
+
+	nr_rows = RES_ROW_N(res);
+
+	LM_ALERT("the database has information about %i dialogs\n", nr_rows);
+
+	rows = RES_ROWS(res);
+
+	do {
+		/* for every row---dialog */
+		for(i=0; i<nr_rows; i++){
+			values = ROW_VALUES(rows + i);
+
+			if (VAL_NULL(GET_FIELD_IDX(values, DLGI_HASH_ID_COL_IDX)) ||
+				VAL_NULL(GET_FIELD_IDX(values, DLGI_HASH_ENTRY_COL_IDX))) {
+				LM_ERR("columns %.*s or/and %.*s cannot be null -> skipping\n",
+					h_entry_column.len, h_entry_column.s,
+					h_id_column.len, h_id_column.s);
+				continue;
+			}
+
+			if (VAL_NULL(GET_FIELD_IDX(values, DLGI_START_TIME_COL_IDX)) ||
+				VAL_NULL(GET_FIELD_IDX(values, DLGI_STATE_COL_IDX))) {
+				LM_ERR("columns %.*s or/and %.*s cannot be null -> skipping\n",
+					start_time_column.len, start_time_column.s,
+					state_column.len, state_column.s);
+				continue;
+			}
+
+			/*restore the dialog info*/
+			GET_STR_VALUE(callid, 	values, DLGI_CALLID_COL_IDX, 	1, 0);
+			GET_STR_VALUE(from_uri, values, DLGI_FROM_URI_COL_IDX, 	1, 0);
+			GET_STR_VALUE(from_tag, values, DLGI_FROM_TAG_COL_IDX, 	1, 0);
+			GET_STR_VALUE(req_uri, 	values, DLGI_REQ_URI_COL_IDX,	1, 0);
+
+
+			if((dlg=build_new_dlg(&callid, &from_uri, &from_tag, &req_uri))==0) {
+				LM_ERR("failed to build new dialog\n");
+				goto error;
+			}
+
+			if(dlg->h_entry != VAL_INT(GET_FIELD_IDX(values, DLGI_HASH_ENTRY_COL_IDX))) {
+				LM_ERR("inconsistent hash data in the dialog database: "
+					"you may have restarted Kamailio using a different "
+					"hash_size: please erase %.*s database and restart\n", 
+					dialog_in_table_name.len, dialog_in_table_name.s);
+				shm_free(dlg);
+				goto error;
+			}
+
+			/*link the dialog*/
+			link_dlg(dlg, 0);
+
+			GET_STR_VALUE(did, 		values, DLGI_DID_COL_IDX,		1, 0);
+			update_dlg_did(dlg, &did);
+
+			dlg->h_id = VAL_INT(GET_FIELD_IDX(values, DLGI_HASH_ID_COL_IDX));
+			next_id = d_table->entries[dlg->h_entry].next_id;
+
+			d_table->entries[dlg->h_entry].next_id = (next_id < dlg->h_id) ? (dlg->h_id+1) : next_id;
+
+			dlg->start_ts	= VAL_INT(GET_FIELD_IDX(values, DLGI_START_TIME_COL_IDX));
+			dlg->state 		= VAL_INT(GET_FIELD_IDX(values, DLGI_STATE_COL_IDX));
+
+			if (dlg->state==DLG_STATE_CONFIRMED) {
+				active_dlgs_cnt++;
+			}
+			else if (dlg->state==DLG_STATE_EARLY) {
+				early_dlgs_cnt++;
+			}
+
+			dlg->tl.timeout = (unsigned int)(VAL_INT(GET_FIELD_IDX(values, DLGI_TIMEOUT_COL_IDX)));
+			LM_DBG("db dialog timeout is %u (%u/%u)\n", dlg->tl.timeout, get_ticks(), (unsigned int)time(0));
+
+			if (dlg->tl.timeout<=(unsigned int)time(0))
+				dlg->tl.timeout = 0;
+			else
+				dlg->tl.timeout -= (unsigned int)time(0);
+
+			dlg->lifetime = dlg->tl.timeout;
+
+			GET_STR_VALUE(caller_cseq, values, DLGI_CALLER_CSEQ_COL_IDX , 1, 1);
+			GET_STR_VALUE(caller_rroute, values, DLGI_CALLER_ROUTESET_COL_IDX, 0, 0);
+			GET_STR_VALUE(caller_contact, values,DLGI_CALLER_CONTACT_COL_IDX, 1, 1);
+
+			dlg->caller_bind_addr = create_socket_info(values, DLGI_CALLER_SOCK_IDX);
+			//dlg->bind_addr[DLG_CALLEE_LEG] = create_socket_info(values, 17);
+
+			if ( (dlg_set_leg_info( dlg, &from_tag, &caller_rroute,
+									&caller_contact, &caller_cseq, dlg->caller_bind_addr,
+									DLG_CALLER_LEG) != 0) ) {
+				LM_ERR("dlg_set_leg_info failed\n");
+				unref_dlg(dlg,1);
+				continue;
+			}
+
+			dlg->sflags = (unsigned int)VAL_INT(GET_FIELD_IDX(values, DLGI_SFLAGS_COL_IDX));
+
+			GET_STR_VALUE(toroute_name, values, DLGI_TOROUTE_NAME_COL_IDX, 0, 0);
+			dlg_set_toroute(dlg, &toroute_name);
+
+			/*restore the timer values */
+			if (0 != insert_dlg_timer( &(dlg->tl), (int)dlg->tl.timeout )) {
+				LM_CRIT("Unable to insert dlg %p [%u:%u] "
+					"with clid '%.*s'\n",
+					dlg, dlg->h_entry, dlg->h_id,
+					dlg->callid.len, dlg->callid.s);
+				unref_dlg(dlg,1);
+				continue;
+			}
+
+			ref_dlg(dlg,1);
+			LM_DBG("current dialog timeout is %u (%u)\n", dlg->tl.timeout,
+					get_ticks());
+
+			dlg->dflags = 0;
+			next_dialog:
+			;
+		}
+
+		/* any more data to be fetched ?*/
+		if (DB_CAPABILITY(dialog_dbf, DB_CAP_FETCH) && (fetch_num_rows > 0)) {
+			if(dialog_dbf.fetch_result(dialog_db_handle, &res, fetch_num_rows) < 0) {
+				LM_ERR("re-fetching rows failed\n");
+				goto error;
+			}
+			nr_rows = RES_ROW_N(res);
+			rows = RES_ROWS(res);
+		} else {
+			nr_rows = 0;
+		}
+
+	}
+	while (nr_rows>0);
+
+	if (dlg != NULL) {
+		d_entry = &(d_table->entries[dlg->h_entry]);
+		dlg		= d_entry->first;
+
+		while (dlg) {
+			load_dialog_out_from_db(dlg, &dlg->did, fetch_num_rows);
+			dlg = dlg->next;
+		}
+	}
+
+	if (dlg_db_mode==DB_MODE_SHUTDOWN) {
+		if (dialog_dbf.delete(dialog_db_handle, 0, 0, 0, 0) < 0) {
+			LM_ERR("failed to clear dialog table\n");
+			goto error;
+		}
+	}
+
+end:
+	dialog_dbf.free_result(dialog_db_handle, res);
+	return 0;
+error:
+	dialog_dbf.free_result(dialog_db_handle, res);
+	return -1;
+
+}
+
+static int select_entire_dialog_vars_table(db1_res_t ** res, int fetch_num_rows)
+{
+	db_key_t query_cols[DIALOG_VARS_TABLE_COL_NO] = {
+			&vars_h_entry_column,
+			&vars_h_id_column,
+			&vars_key_column,
+			&vars_value_column };
+
+	if(use_dialog_vars_table() != 0){
+		return -1;
+	}
+
+	/* select the whole tabel and all the columns */
+	if (DB_CAPABILITY(dialog_dbf, DB_CAP_FETCH) && (fetch_num_rows > 0)) {
+		if(dialog_dbf.query(dialog_db_handle,0,0,0,query_cols, 0, 
+		DIALOG_VARS_TABLE_COL_NO, 0, 0) < 0) {
+			LM_ERR("Error while querying (fetch) database\n");
+			return -1;
+		}
+		if(dialog_dbf.fetch_result(dialog_db_handle, res, fetch_num_rows) < 0) {
+			LM_ERR("fetching rows failed\n");
+			return -1;
+		}
+	} else {
+		if(dialog_dbf.query(dialog_db_handle,0,0,0,query_cols, 0,
+		DIALOG_VARS_TABLE_COL_NO, 0, res) < 0) {
+			LM_ERR("Error while querying database\n");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+static int load_dialog_vars_from_db(int fetch_num_rows)
+{
+	db1_res_t * res;
+	db_val_t * values;
+	db_row_t * rows;
+	struct dlg_cell  * dlg; 
+	int i, nr_rows;
+
+	res = 0;
+	if((nr_rows = select_entire_dialog_vars_table(&res, fetch_num_rows)) < 0)
+		goto end;
+
+	nr_rows = RES_ROW_N(res);
+
+	LM_DBG("the database has information about %i dialog variables\n", nr_rows);
+
+	rows = RES_ROWS(res);
+
+	do {
+		/* for every row---dialog */
+		for(i=0; i<nr_rows; i++){
+
+			values = ROW_VALUES(rows + i);
+
+			if (VAL_NULL(values) || VAL_NULL(values+1)) {
+				LM_ERR("columns %.*s or/and %.*s cannot be null -> skipping\n",
+					vars_h_entry_column.len, vars_h_entry_column.s,
+					vars_h_id_column.len, vars_h_id_column.s);
+				continue;
+			}
+
+			if (VAL_NULL(values+2) || VAL_NULL(values+3)) {
+				LM_ERR("columns %.*s or/and %.*s cannot be null -> skipping\n",
+					vars_key_column.len, vars_key_column.s,
+					vars_value_column.len, vars_value_column.s);
+				continue;
+			}
+			if (VAL_INT(values) < d_table->size) {
+				dlg = (d_table->entries)[VAL_INT(values)].first;
+				while (dlg) {
+					if (dlg->h_id == VAL_INT(values+1)) {
+						str key = { VAL_STR(values+2).s, strlen(VAL_STRING(values+2)) };
+						str value = { VAL_STR(values+3).s, strlen(VAL_STRING(values+3)) };
+						set_dlg_variable_unsafe(dlg, &key, &value, 1);
+						break;
+					}
+					dlg = dlg->next;
+					if (!dlg) {
+						LM_WARN("inconsistent data: the dialog h_entry/h_id does not exist!\n");
+					}
+				}
+			} else {
+				LM_WARN("inconsistent data: the h_entry in the DB does not exist!\n");
+			}
+		}
+
+		/* any more data to be fetched ?*/
+		if (DB_CAPABILITY(dialog_dbf, DB_CAP_FETCH) && (fetch_num_rows > 0)) {
+			if(dialog_dbf.fetch_result(dialog_db_handle, &res, fetch_num_rows) < 0) {
+				LM_ERR("re-fetching rows failed\n");
+				goto error;
+			}
+			nr_rows = RES_ROW_N(res);
+			rows = RES_ROWS(res);
+		} else {
+			nr_rows = 0;
+		}
+
+	}
+	while (nr_rows>0);
+
+	if (dlg_db_mode==DB_MODE_SHUTDOWN) {
+		if (dialog_dbf.delete(dialog_db_handle, 0, 0, 0, 0) < 0) {
+			LM_ERR("failed to clear dialog variable table\n");
+			goto error;
+		}
+	}
+
+end:
+	dialog_dbf.free_result(dialog_db_handle, res);
+	return 0;
+error:
+	dialog_dbf.free_result(dialog_db_handle, res);
+	return -1;
+
+}
+
+/*this is only called from destroy_dlg, where the cell's entry lock is acquired*/
+int remove_dialog_in_from_db(struct dlg_cell * cell)
+{
+	db_val_t values[2];
+	db_key_t match_keys[2] = { &h_entry_column, &h_id_column};
+	db_key_t vars_match_keys[2] = { &vars_h_entry_column, &vars_h_id_column};
+	struct dlg_cell_out *dlg_out	= cell->dlg_entry_out.first;
+
+	/*if the dialog hasn 't been yet inserted in the database*/
+	LM_DBG("trying to remove dialog [%.*s], update_flag is %i\n",
+			cell->callid.len, cell->callid.s,
+			cell->dflags);
+	if (cell->dflags & DLG_FLAG_NEW) 
+		return 0;
+
+	if (use_dialog_table()!=0)
+		return -1;
+
+	VAL_TYPE(values) = DB1_INT;
+	VAL_TYPE(values + 1) = DB1_INT;
+
+	VAL_NULL(values) = 0;
+	VAL_NULL(values + 1) = 0;
+
+	VAL_INT(values)	= cell->h_entry;
+	VAL_INT(values + 1) = cell->h_id;
+
+	if(dialog_dbf.delete(dialog_db_handle, match_keys, 0, values, 2) < 0) {
+		LM_ERR("failed to delete database information\n");
+		return -1;
+	}
+
+	if (use_dialog_vars_table()!=0)
+		return -1;
+
+	if(dialog_dbf.delete(dialog_db_handle, vars_match_keys, 0, values, 2) < 0) {
+		LM_ERR("failed to delete database information\n");
+		return -1;
+	}
+
+	if (use_dialog_out_table() !=0 )
+		return -1;
+
+	while(dlg_out) {
+	    LM_DBG("deleting dlg_out from db with h_entry:h_id [%u:%u]\n", dlg_out->h_entry, dlg_out->h_id);
+		VAL_INT(values)	= dlg_out->h_entry;
+		VAL_INT(values + 1) = dlg_out->h_id;
+
+		if(dialog_dbf.delete(dialog_db_handle, match_keys, 0, values, 2) < 0) {
+			LM_ERR("failed to delete dlg_out row\n");
+			return -1;
+		}
+		dlg_out	= dlg_out->next;
+	}
+
+	LM_DBG("callid was %.*s\n", cell->callid.len, cell->callid.s );
+
+	return 0;
+}
+
+
+int update_dialog_vars_dbinfo(struct dlg_cell * cell, struct dlg_var * var)
+{
+	db_val_t values[DIALOG_VARS_TABLE_COL_NO];
+
+	db_key_t insert_keys[DIALOG_VARS_TABLE_COL_NO] = { &vars_h_entry_column,
+			&vars_h_id_column,	&vars_key_column,	&vars_value_column };
+
+	if(use_dialog_vars_table()!=0)
+		return -1;
+
+	VAL_TYPE(values) = VAL_TYPE(values+1) = DB1_INT;
+	VAL_TYPE(values+2) = VAL_TYPE(values+3) = DB1_STR;
+	VAL_NULL(values) = VAL_NULL(values+1) = VAL_NULL(values+2) = VAL_NULL(values+3) = 0;
+	SET_STR_VALUE(values+2, var->key);
+
+	VAL_INT(values)			= cell->h_entry;
+	VAL_INT(values+1)		= cell->h_id;
+	
+	if((var->vflags & DLG_FLAG_DEL) != 0) {
+		/* delete the current variable */
+		db_key_t vars_match_keys[3] = { &vars_h_entry_column, &vars_h_id_column, &vars_key_column};
+
+		if (use_dialog_vars_table()!=0)
+			return -1;
+
+		if(dialog_dbf.delete(dialog_db_handle, vars_match_keys, 0, values, 3) < 0) {
+			LM_ERR("failed to delete database information\n");
+			return -1;
+		}
+	} else if((var->vflags & DLG_FLAG_NEW) != 0) {
+		/* save all the current dialogs information*/
+		SET_STR_VALUE(values+3, var->value);
+
+		LM_DBG("Inserting into dlg vars table for [%u:%u]\n", cell->h_entry, cell->h_id);
+		if((dialog_dbf.insert(dialog_db_handle, insert_keys, values, 
+								DIALOG_VARS_TABLE_COL_NO)) !=0){
+			LM_ERR("could not add another dialog-var to db\n");
+			goto error;
+		}
+		var->vflags &= ~(DLG_FLAG_NEW|DLG_FLAG_CHANGED);
+	} else if((var->vflags & DLG_FLAG_CHANGED) != 0) {
+		/* save only dialog's state and timeout */
+		SET_STR_VALUE(values+3, var->value);
+
+		if((dialog_dbf.update(dialog_db_handle, insert_keys, 0, 
+						values, (insert_keys+3), (values+3), 3, 1)) !=0){
+			LM_ERR("could not update database info\n");
+			goto error;
+		}
+		var->vflags &= ~DLG_FLAG_CHANGED;
+	} else {
+		return 0;
+	}
+	return 0;
+error:
+	return -1;
+}
+
+int update_dialog_out_dbinfo_unsafe(struct dlg_cell * cell)
+{
+	struct dlg_cell_out *dlg_out	= cell->dlg_entry_out.first;
+
+	if(use_dialog_out_table()!=0)
+		return -1;
+
+	if ((cell->dflags & DLG_FLAG_NEW) != 0) {
+		db_val_t values[DIALOG_OUT_TABLE_COL_NO];
+		db_key_t insert_keys[DIALOG_OUT_TABLE_COL_NO] = {
+								&id_column,				&h_entry_column,
+								&h_id_column, 			&did_column,
+								&to_uri_column,			&to_tag_column,
+								&caller_cseq_column, 	&callee_cseq_column,
+								&callee_contact_column,	&callee_routeset_column,
+								&callee_sock_column		};
+
+		VAL_TYPE(GET_FIELD_IDX(values, DLGO_ID_COL_IDX))		= DB1_INT;
+		VAL_TYPE(GET_FIELD_IDX(values, DLGO_HASH_ENTRY_COL_IDX))= DB1_INT;
+		VAL_TYPE(GET_FIELD_IDX(values, DLGO_HASH_ID_COL_IDX))	= DB1_INT;
+
+		VAL_TYPE(GET_FIELD_IDX(values, DLGO_DID_COL_IDX))		= DB1_STR;
+		VAL_TYPE(GET_FIELD_IDX(values, DLGO_TO_URI_IDX))		= DB1_STR;
+		VAL_TYPE(GET_FIELD_IDX(values, DLGO_TO_TAG_IDX))		= DB1_STR;
+		VAL_TYPE(GET_FIELD_IDX(values, DLGO_CALLER_CSEQ_IDX))	= DB1_STR;
+		VAL_TYPE(GET_FIELD_IDX(values, DLGO_CALLEE_CSEQ_IDX))	= DB1_STR;
+		VAL_TYPE(GET_FIELD_IDX(values, DLGO_CALLEE_CONTACT_IDX))= DB1_STR;
+		VAL_TYPE(GET_FIELD_IDX(values, DLGO_CALLEE_ROUTESET_IDX))= DB1_STR;
+		VAL_TYPE(GET_FIELD_IDX(values, DLGO_CALLEE_SOCK_IDX))	= DB1_STR;
+
+		VAL_NULL(GET_FIELD_IDX(values, DLGO_ID_COL_IDX))= 1;
+		VAL_NULL(GET_FIELD_IDX(values, DLGO_HASH_ENTRY_COL_IDX))= 0;
+		VAL_NULL(GET_FIELD_IDX(values, DLGO_HASH_ID_COL_IDX))	= 0;
+		VAL_NULL(GET_FIELD_IDX(values, DLGO_DID_COL_IDX))		= 0;
+		VAL_NULL(GET_FIELD_IDX(values, DLGO_TO_URI_IDX)) 		= 0;
+		VAL_NULL(GET_FIELD_IDX(values, DLGO_TO_TAG_IDX)) 		= 0;
+		//VAL_NULL(GET_FIELD_IDX(values, DLGO_CALLER_CSEQ_IDX)) 	= 0;
+		//VAL_NULL(GET_FIELD_IDX(values, DLGO_CALLEE_CSEQ_IDX)) 	= 0;
+		VAL_NULL(GET_FIELD_IDX(values, DLGO_CALLEE_CONTACT_IDX))= 0;
+		VAL_NULL(GET_FIELD_IDX(values, DLGO_CALLEE_SOCK_IDX)) 	= 0;
+
+		do {
+		    VAL_INT(GET_FIELD_IDX(values, DLGO_ID_COL_IDX))	= 0;
+		    VAL_INT(GET_FIELD_IDX(values, DLGO_HASH_ENTRY_COL_IDX))	= dlg_out->h_entry;
+		    VAL_INT(GET_FIELD_IDX(values, DLGO_HASH_ID_COL_IDX))	= dlg_out->h_id;
+
+		    SET_STR_VALUE(GET_FIELD_IDX(values, DLGO_DID_COL_IDX), dlg_out->did);
+		    SET_STR_VALUE(GET_FIELD_IDX(values, DLGO_TO_URI_IDX), dlg_out->to_uri);
+		    SET_STR_VALUE(GET_FIELD_IDX(values, DLGO_TO_TAG_IDX), dlg_out->to_tag);
+		    SET_STR_VALUE(GET_FIELD_IDX(values, DLGO_CALLER_CSEQ_IDX), dlg_out->caller_cseq);
+		    SET_STR_VALUE(GET_FIELD_IDX(values, DLGO_CALLEE_CSEQ_IDX), dlg_out->callee_cseq);
+		    SET_STR_VALUE(GET_FIELD_IDX(values, DLGO_CALLEE_CONTACT_IDX), dlg_out->callee_contact);
+		    SET_STR_VALUE(GET_FIELD_IDX(values, DLGO_CALLEE_ROUTESET_IDX), dlg_out->callee_route_set);
+		    SET_STR_VALUE(GET_FIELD_IDX(values, DLGO_CALLEE_SOCK_IDX), dlg_out->callee_bind_addr->sock_str);
+
+		    SET_PROPER_NULL_FLAG(dlg_out->callee_route_set, values, DLGO_CALLEE_ROUTESET_IDX);
+		    SET_PROPER_NULL_FLAG(dlg_out->caller_cseq, values, DLGO_CALLER_CSEQ_IDX);
+		    SET_PROPER_NULL_FLAG(dlg_out->callee_cseq, values, DLGO_CALLEE_CSEQ_IDX);
+
+		    LM_DBG("Inserting into dialog out table for dlg_in: [%u:%u] and dlg_out [%u:%u]\n", cell->h_entry, cell->h_id, dlg_out->h_entry, dlg_out->h_id);
+		    if((dialog_dbf.insert(dialog_db_handle, insert_keys, values, DIALOG_OUT_TABLE_COL_NO)) !=0){
+			    LM_ERR("could not add another dialog_out to db\n");
+			    goto error;
+		    }
+		    dlg_out	= dlg_out->next;
+		}
+		while(dlg_out && dlg_out != cell->dlg_entry_out.first);
+	}
+	else if((cell->dflags & DLG_FLAG_CHANGED) != 0) {
+		db_val_t values[4];
+		db_key_t insert_keys[4] = {	&h_entry_column,	&h_id_column,
+									&caller_cseq_column,&callee_cseq_column
+									};
+
+		/* save only dialog's state and timeout */
+		VAL_TYPE(GET_FIELD_IDX(values, 0))	= DB1_INT;
+		VAL_TYPE(GET_FIELD_IDX(values, 1)) 	= DB1_INT;
+		VAL_TYPE(GET_FIELD_IDX(values, 2)) 	= DB1_STR;
+		VAL_TYPE(GET_FIELD_IDX(values, 3)) 	= DB1_STR;
+
+		VAL_INT(GET_FIELD_IDX(values, 0))	= dlg_out->h_entry;
+		VAL_INT(GET_FIELD_IDX(values, 1))	= dlg_out->h_id;
+		SET_STR_VALUE(GET_FIELD_IDX(values, 2), dlg_out->caller_cseq);
+		SET_STR_VALUE(GET_FIELD_IDX(values, 3), dlg_out->callee_cseq);
+
+		VAL_NULL(GET_FIELD_IDX(values, 0))	= 0;
+		VAL_NULL(GET_FIELD_IDX(values, 1)) 	= 0;
+
+		SET_PROPER_NULL_FLAG(dlg_out->caller_cseq, values, 2);
+		SET_PROPER_NULL_FLAG(dlg_out->callee_cseq, values, 3);
+
+		if((dialog_dbf.update(dialog_db_handle, insert_keys, 0, values, insert_keys, values, 2, 4)) !=0 ){
+			LM_ERR("could not update database info\n");
+			goto error;
+		}
+	}
+
+	return 0;
+
+error:
+	return -1;
+}
+
+int update_dialog_dbinfo_unsafe(struct dlg_cell * cell)
+{
+	struct dlg_var *var;
+
+	if( (cell->dflags & DLG_FLAG_NEW) != 0  || (cell->dflags & DLG_FLAG_CHANGED_VARS) != 0) {
+		/* iterate the list */
+		for(var=cell->vars ; var ; var=var->next) {
+			if (update_dialog_vars_dbinfo(cell, var) != 0)
+				return -1;
+		}
+		/* Remove the flag */
+		cell->dflags &= ~DLG_FLAG_CHANGED_VARS;
+	}
+
+	if (update_dialog_out_dbinfo_unsafe(cell) != 0)
+		goto error;
+
+	if(use_dialog_table()!=0)
+		return -1;
+
+	if((cell->dflags & DLG_FLAG_NEW) != 0){
+		db_val_t values[DIALOG_IN_TABLE_COL_NO];
+		db_key_t insert_keys[DIALOG_IN_TABLE_COL_NO] = {
+								&id_column,				&h_entry_column,
+								&h_id_column, 			&did_column,
+								&call_id, 				&from_uri_column,
+								&from_tag_column, 		&caller_original_cseq_column,
+								&req_uri_column,		&caller_route_set_column,
+								&caller_contact_column, &caller_sock_column, &timeout_column,
+								&state_column, 			&start_time_column,
+								&sflags_column,			&to_route_name_column, 	&to_route_index_column };
+
+		/* save all the current dialogs information*/
+		VAL_TYPE(GET_FIELD_IDX(values, DLGI_ID_COL_IDX)) = DB1_INT;
+		VAL_TYPE(GET_FIELD_IDX(values, DLGI_HASH_ENTRY_COL_IDX))= DB1_INT;
+		VAL_TYPE(GET_FIELD_IDX(values, DLGI_HASH_ID_COL_IDX)) = DB1_INT;
+
+		VAL_TYPE(GET_FIELD_IDX(values, DLGI_STATE_COL_IDX)) = DB1_INT;
+		VAL_TYPE(GET_FIELD_IDX(values, DLGI_START_TIME_COL_IDX)) = DB1_INT;
+		VAL_TYPE(GET_FIELD_IDX(values, DLGI_TIMEOUT_COL_IDX)) = DB1_INT;
+		VAL_TYPE(GET_FIELD_IDX(values, DLGI_SFLAGS_COL_IDX)) = DB1_INT;
+		VAL_TYPE(GET_FIELD_IDX(values, DLGI_TOROUTE_INDEX_COL_IDX))	= DB1_INT;
+
+		VAL_TYPE(GET_FIELD_IDX(values, DLGI_DID_COL_IDX)) = DB1_STR;
+		VAL_TYPE(GET_FIELD_IDX(values, DLGI_CALLID_COL_IDX)) = DB1_STR;
+		VAL_TYPE(GET_FIELD_IDX(values, DLGI_FROM_URI_COL_IDX)) = DB1_STR;
+		VAL_TYPE(GET_FIELD_IDX(values, DLGI_FROM_TAG_COL_IDX)) = DB1_STR;
+		VAL_TYPE(GET_FIELD_IDX(values, DLGI_CALLER_CSEQ_COL_IDX)) = DB1_STR;
+		VAL_TYPE(GET_FIELD_IDX(values, DLGI_REQ_URI_COL_IDX)) = DB1_STR;
+		VAL_TYPE(GET_FIELD_IDX(values, DLGI_CALLER_ROUTESET_COL_IDX))= DB1_STR;
+		VAL_TYPE(GET_FIELD_IDX(values, DLGI_CALLER_CONTACT_COL_IDX))= DB1_STR;
+		VAL_TYPE(GET_FIELD_IDX(values, DLGI_CALLER_SOCK_IDX)) = DB1_STR;
+		VAL_TYPE(GET_FIELD_IDX(values, DLGI_TOROUTE_NAME_COL_IDX))	= DB1_STR;
+
+		VAL_INT(GET_FIELD_IDX(values, DLGI_HASH_ENTRY_COL_IDX))	= cell->h_entry;
+		VAL_INT(GET_FIELD_IDX(values, DLGI_HASH_ID_COL_IDX))	= cell->h_id;
+		VAL_INT(GET_FIELD_IDX(values, DLGI_START_TIME_COL_IDX))	= cell->start_ts;
+		VAL_INT(GET_FIELD_IDX(values, DLGI_STATE_COL_IDX))		= cell->state;
+		VAL_INT(GET_FIELD_IDX(values, DLGI_TIMEOUT_COL_IDX))	= (unsigned int)( (unsigned int)time(0) + cell->tl.timeout - get_ticks() );
+
+		SET_STR_VALUE(GET_FIELD_IDX(values, DLGI_CALLID_COL_IDX), cell->callid);
+		SET_STR_VALUE(GET_FIELD_IDX(values, DLGI_DID_COL_IDX), cell->did);
+		SET_STR_VALUE(GET_FIELD_IDX(values, DLGI_FROM_URI_COL_IDX), cell->from_uri);
+		SET_STR_VALUE(GET_FIELD_IDX(values, DLGI_FROM_TAG_COL_IDX), cell->from_tag);
+		SET_STR_VALUE(GET_FIELD_IDX(values, DLGI_CALLER_CSEQ_COL_IDX), cell->first_req_cseq);
+
+		SET_STR_VALUE(GET_FIELD_IDX(values, DLGI_CALLER_SOCK_IDX), cell->caller_bind_addr->sock_str);
+
+		SET_STR_VALUE(GET_FIELD_IDX(values, DLGI_CALLER_ROUTESET_COL_IDX), cell->caller_route_set);
+		SET_STR_VALUE(GET_FIELD_IDX(values, DLGI_CALLER_CONTACT_COL_IDX), cell->caller_contact);
+
+		SET_PROPER_NULL_FLAG(cell->caller_route_set, values, DLGI_CALLER_ROUTESET_COL_IDX);
+
+		VAL_NULL(GET_FIELD_IDX(values, DLGI_SFLAGS_COL_IDX)) = 0;
+		VAL_INT(GET_FIELD_IDX(values, DLGI_SFLAGS_COL_IDX))  = cell->sflags;
+
+		SET_STR_VALUE(GET_FIELD_IDX(values, DLGI_TOROUTE_NAME_COL_IDX), cell->toroute_name);
+		SET_STR_VALUE(GET_FIELD_IDX(values, DLGI_REQ_URI_COL_IDX), cell->req_uri);
+
+		SET_PROPER_NULL_FLAG(cell->callid, 	values, DLGI_CALLID_COL_IDX);
+		SET_PROPER_NULL_FLAG(cell->did, 	values, DLGI_DID_COL_IDX);
+		SET_PROPER_NULL_FLAG(cell->from_uri,values, DLGI_FROM_URI_COL_IDX);
+		SET_PROPER_NULL_FLAG(cell->from_tag,values, DLGI_FROM_TAG_COL_IDX);
+		SET_PROPER_NULL_FLAG(cell->caller_route_set,values, DLGI_CALLER_ROUTESET_COL_IDX);
+		SET_PROPER_NULL_FLAG(cell->req_uri, values, DLGI_REQ_URI_COL_IDX);
+		SET_PROPER_NULL_FLAG(cell->toroute_name, values, DLGI_TOROUTE_NAME_COL_IDX);
+		SET_PROPER_NULL_FLAG(cell->first_req_cseq, values, DLGI_CALLER_CSEQ_COL_IDX);
+
+		VAL_NULL(GET_FIELD_IDX(values, DLGI_ID_COL_IDX)) = 1;
+		VAL_NULL(GET_FIELD_IDX(values, DLGI_HASH_ENTRY_COL_IDX)) = 0;
+		VAL_NULL(GET_FIELD_IDX(values, DLGI_HASH_ID_COL_IDX)) = 0;
+		VAL_NULL(GET_FIELD_IDX(values, DLGI_STATE_COL_IDX)) = 0;
+		VAL_NULL(GET_FIELD_IDX(values, DLGI_START_TIME_COL_IDX)) = 0;
+		VAL_NULL(GET_FIELD_IDX(values, DLGI_TIMEOUT_COL_IDX)) = 0;
+		VAL_NULL(GET_FIELD_IDX(values, DLGI_CALLER_CONTACT_COL_IDX)) = 0;
+		VAL_NULL(GET_FIELD_IDX(values, DLGI_CALLER_SOCK_IDX)) = 0;
+
+		LM_DBG("Inserting dialog into dialog_in table [%u:%u]\n", cell->h_entry, cell->h_id);
+		if((dialog_dbf.insert(dialog_db_handle, insert_keys, values, DIALOG_IN_TABLE_COL_NO)) !=0){
+			LM_ERR("could not add another dialog_in to db\n");
+			goto error;
+		}
+
+		cell->dflags &= ~(DLG_FLAG_NEW|DLG_FLAG_CHANGED);
+		cell->dflags |= DLG_FLAG_INSERTED;
+		
+	} else if((cell->dflags & DLG_FLAG_CHANGED) != 0) {
+
+		db_val_t values[5];
+		db_key_t insert_keys[5] = {	&h_entry_column,	&h_id_column,
+									&state_column,		&timeout_column,
+									&caller_original_cseq_column};
+
+		/* save only dialog's state and timeout */
+		VAL_TYPE(GET_FIELD_IDX(values, 0))	= DB1_INT;
+		VAL_TYPE(GET_FIELD_IDX(values, 1)) 	= DB1_INT;
+		VAL_TYPE(GET_FIELD_IDX(values, 2)) 	= DB1_INT;
+		VAL_TYPE(GET_FIELD_IDX(values, 3)) 	= DB1_INT;
+		VAL_TYPE(GET_FIELD_IDX(values, 4))	= DB1_STR;
+
+		VAL_INT(GET_FIELD_IDX(values, 0))	= cell->h_entry;
+		VAL_INT(GET_FIELD_IDX(values, 1))	= cell->h_id;
+		VAL_INT(GET_FIELD_IDX(values, 2))	= cell->state;
+		VAL_INT(GET_FIELD_IDX(values, 3))	= (unsigned int)( (unsigned int)time(0) + cell->tl.timeout - get_ticks() );
+		SET_STR_VALUE(GET_FIELD_IDX(values, 4), cell->first_req_cseq);
+
+		VAL_NULL(GET_FIELD_IDX(values, 0))	= 0;
+		VAL_NULL(GET_FIELD_IDX(values, 1)) 	= 0;
+		VAL_NULL(GET_FIELD_IDX(values, 2)) 	= 0;
+		VAL_NULL(GET_FIELD_IDX(values, 3)) 	= 0;
+		VAL_NULL(GET_FIELD_IDX(values, 4)) 	= 0;
+
+		LM_DBG("Updating dialog in dialog_in table [%u:%u]\n", cell->h_entry, cell->h_id);
+		if((dialog_dbf.update(dialog_db_handle, insert_keys, 0, values, insert_keys, values, 2, 4)) !=0 ){
+			LM_ERR("could not update database info\n");
+			goto error;
+		}
+		cell->dflags &= ~(DLG_FLAG_CHANGED);
+	}
+
+	return 0;
+
+error:
+
+	return -1;
+}
+
+int update_dialog_dbinfo(struct dlg_cell * cell)
+{
+	struct dlg_entry entry;
+	/* lock the entry */
+	entry = (d_table->entries)[cell->h_entry];
+	dlg_lock( d_table, &entry);
+	if (update_dialog_dbinfo_unsafe(cell) != 0) {
+		dlg_unlock( d_table, &entry);
+		return -1;
+	} 
+	dlg_unlock( d_table, &entry);
+	return 0;
+}
+
+void dialog_update_db(unsigned int ticks, void * param)
+{
+	int index;
+	struct dlg_entry entry;
+	struct dlg_cell  * cell; 
+
+	LM_DBG("saving current_info \n");
+	
+	for(index = 0; index< d_table->size; index++){
+		/* lock the whole entry */
+		entry = (d_table->entries)[index];
+		dlg_lock( d_table, &entry);
+
+		for(cell = entry.first; cell != NULL; cell = cell->next){
+			if (update_dialog_dbinfo_unsafe(cell) != 0) {
+				dlg_unlock( d_table, &entry);
+				goto error;
+			}
+		}
+		dlg_unlock( d_table, &entry);
+
+	}
+
+	return;
+
+error:
+	dlg_unlock( d_table, &entry);
+}

+ 125 - 0
modules/dialog_ng/dlg_db_handler.h

@@ -0,0 +1,125 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2007 Voice System SRL
+ * Copyright (C) 2011 Carsten Bock, [email protected]
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * History:
+ * --------
+ * 2007-05-10  initial version (ancuta)
+ */
+
+
+#ifndef _DLG_DB_HANDLER_H_
+#define _DLG_DB_HANDLER_H_
+
+#include "../../str.h"
+#include "../../lib/srdb1/db.h"
+
+#define ID_COL					"id"
+#define HASH_ENTRY_COL			"hash_entry"
+#define HASH_ID_COL				"hash_id"
+#define DID_COL					"did"
+#define CALL_ID_COL				"callid"
+#define FROM_URI_COL			"from_uri"
+#define FROM_TAG_COL			"from_tag"
+#define CALLER_ORIGINAL_CSEQ_COL "caller_original_cseq"
+#define REQ_URI_COL				"req_uri"
+#define CALLER_ROUTESET_COL		"caller_route_set"
+#define CALLER_CONTACT_COL		"caller_contact"
+#define CALLER_SOCK				"caller_sock"
+#define STATE_COL				"state"
+#define START_TIME_COL			"start_time"
+#define TIMEOUT_COL				"timeout"
+#define SFLAGS_COL				"sflags"
+#define TOROUTE_NAME_COL		"toroute_name"
+#define TOROUTE_INDEX_COL		"toroute_index"
+
+// dialog_out exclusive columns
+#define TO_URI_COL				"to_uri"
+#define TO_TAG_COL				"to_tag"
+#define CALLER_CSEQ_COL			"caller_cseq"
+#define CALLEE_CSEQ_COL			"callee_cseq"
+#define CALLEE_CONTACT_COL		"callee_contact"
+#define CALLEE_ROUTESET_COL		"callee_route_set"
+#define CALLEE_SOCK				"callee_sock"
+
+//#define XDATA_COL				"xdata"
+#define DIALOG_IN_TABLE_NAME	"dialog_in"
+#define DIALOG_OUT_TABLE_NAME	"dialog_out"
+#define DLG_TABLE_VERSION		7
+#define DIALOG_IN_TABLE_COL_NO 	18
+#define DIALOG_OUT_TABLE_COL_NO 11
+
+#define VARS_HASH_ID_COL 			"hash_id"
+#define VARS_HASH_ENTRY_COL			"hash_entry"
+#define VARS_KEY_COL				"dialog_key"
+#define VARS_VALUE_COL				"dialog_value"
+#define DIALOG_VARS_TABLE_NAME		"dialog_vars"
+#define DLG_VARS_TABLE_VERSION		1
+#define DIALOG_VARS_TABLE_COL_NO 	4
+
+/*every minute the dialogs' information will be refreshed*/
+#define DB_DEFAULT_UPDATE_PERIOD	60
+#define DB_MODE_NONE				0
+#define DB_MODE_REALTIME			1
+#define DB_MODE_DELAYED				2
+#define DB_MODE_SHUTDOWN			3
+
+/* Dialog table */
+extern str call_id_column; 
+extern str from_uri_column;
+extern str from_tag_column;
+extern str to_uri_column;
+extern str to_tag_column;
+extern str h_id_column;
+extern str h_entry_column;
+extern str state_column;
+extern str start_time_column;
+extern str timeout_column;
+extern str to_cseq_column;
+extern str from_cseq_column;
+extern str to_route_column;
+extern str from_route_column;
+extern str to_contact_column;
+extern str from_contact_column;
+extern str to_sock_column;
+extern str from_sock_column;
+extern str sflags_column;
+extern str toroute_name_column;
+extern str dialog_in_table_name;
+extern int dlg_db_mode;
+
+/* Dialog-Vars Table */
+extern str vars_h_id_column;
+extern str vars_h_entry_column;
+extern str vars_key_column;
+extern str vars_value_column;
+extern str dialog_vars_table_name;
+
+
+int init_dlg_db(const str *db_url, int dlg_hash_size, int db_update_period, int fetch_num_rows);
+int dlg_connect_db(const str *db_url);
+void destroy_dlg_db(void);
+
+int remove_dialog_in_from_db(struct dlg_cell * cell);
+int update_dialog_dbinfo(struct dlg_cell * cell);
+void dialog_update_db(unsigned int ticks, void * param);
+
+#endif

+ 29 - 3
modules/dialog_ng/dlg_handlers.c

@@ -29,6 +29,7 @@
 #include "dlg_req_within.h"
 #include "dlg_profile.h"
 #include "dlg_var.h"
+#include "dlg_db_handler.h"
 
 static str rr_param; /*!< record-route parameter for matching */
 static int dlg_flag; /*!< flag for dialog tracking */
@@ -495,8 +496,16 @@ static void dlg_onreply(struct cell* t, int type, struct tmcb_params *param) {
     }
 
     if (new_state == DLG_STATE_EARLY) {
-        run_dlg_callbacks(DLGCB_EARLY, dlg, req, rpl, DLG_DIR_UPSTREAM, 0);
-        return;
+	if ((dlg->dflags & DLG_FLAG_INSERTED) == 0) {
+	    dlg->dflags |= DLG_FLAG_NEW;
+	} else {
+	    dlg->dflags |= DLG_FLAG_CHANGED;
+	}
+	if (dlg_db_mode == DB_MODE_REALTIME)
+	    update_dialog_dbinfo(dlg);
+
+	run_dlg_callbacks(DLGCB_EARLY, dlg, req, rpl, DLG_DIR_UPSTREAM, 0);
+	return;
     }
 
     LM_DBG("new state is %i and old state is %i\n", new_state, old_state);
@@ -528,7 +537,14 @@ static void dlg_onreply(struct cell* t, int type, struct tmcb_params *param) {
         /* save the settings to the database,
          * if realtime saving mode configured- save dialog now
          * else: the next time the timer will fire the update*/
-        dlg->dflags |= DLG_FLAG_NEW;
+        if ((dlg->dflags & DLG_FLAG_INSERTED) == 0) {
+	    dlg->dflags |= DLG_FLAG_NEW;
+	} else {
+	    dlg->dflags |= DLG_FLAG_CHANGED;
+	}
+	if (dlg_db_mode == DB_MODE_REALTIME)
+		update_dialog_dbinfo(dlg);
+	
 
         if (0 != insert_dlg_timer(&dlg->tl, dlg->lifetime)) {
             LM_CRIT("Unable to insert dlg %p [%u:%u] on event %d [%d->%d] "
@@ -1205,6 +1221,10 @@ void dlg_onroute(struct sip_msg* req, str *route_params, void *param) {
             dlg->dflags |= DLG_FLAG_CHANGED;
         }
 
+		if(dlg_db_mode==DB_MODE_REALTIME && (dlg->dflags&DLG_FLAG_CHANGED)) {
+			update_dialog_dbinfo(dlg);
+		}
+
         if (old_state != DLG_STATE_CONFIRMED) {
             LM_DBG("confirming ACK successfully processed\n");
 
@@ -1234,7 +1254,11 @@ void dlg_onroute(struct sip_msg* req, str *route_params, void *param) {
 
     if (new_state == DLG_STATE_CONFIRMED && old_state != DLG_STATE_CONFIRMED) {
         dlg->dflags |= DLG_FLAG_CHANGED;
+
+        if(dlg_db_mode == DB_MODE_REALTIME)
+        	update_dialog_dbinfo(dlg);
     }
+
     return;
 }
 
@@ -1361,6 +1385,7 @@ void internal_print_all_dlg(struct dlg_cell *dlg) {
     struct dlg_entry_out *d_entry_out = &(dlg->dlg_entry_out);
 
     LM_DBG("----------------------------");
+    LM_DBG("Dialog h_entry:h_id = [%u : %u]\n", dlg->h_entry, dlg->h_id);
     LM_DBG("Dialog call-id: %.*s\n", dlg->callid.len, dlg->callid.s);
     LM_DBG("Dialog state: %d\n", dlg->state);
     LM_DBG("Dialog ref counter: %d\n", dlg->ref);
@@ -1378,6 +1403,7 @@ void internal_print_all_dlg(struct dlg_cell *dlg) {
     while (dlg_out) {
 
         LM_DBG("----------");
+	LM_DBG("Dialog out h_entry:h_id = [%u : %u]\n", dlg_out->h_entry, dlg_out->h_id);
         LM_DBG("Dialog out did: %.*s\n", dlg_out->did.len, dlg_out->did.s);
         LM_DBG("Dialog out to_tag: %.*s\n", dlg_out->to_tag.len, dlg_out->to_tag.s);
         LM_DBG("Dialog out caller cseq: %.*s\n", dlg_out->caller_cseq.len, dlg_out->caller_cseq.s);

+ 7 - 1
modules/dialog_ng/dlg_hash.c

@@ -16,10 +16,12 @@
 #include "dlg_hash.h"
 #include "dlg_profile.h"
 #include "dlg_handlers.h"
+#include "dlg_db_handler.h"
 
 #define MAX_LDG_LOCKS  2048
 #define MIN_LDG_LOCKS  2
 
+extern int dlg_db_mode;
 
 /*! global dialog table */
 struct dlg_table *d_table = 0;
@@ -109,7 +111,7 @@ int init_dlg_table(unsigned int size) {
 
     for (i = 0; i < size; i++) {
         memset(&(d_table->entries[i]), 0, sizeof (struct dlg_entry));
-        d_table->entries[i].next_id = rand();
+        d_table->entries[i].next_id = rand() % (3*size);
         d_table->entries[i].lock_idx = i % d_table->locks_no;
     }
 
@@ -189,6 +191,9 @@ inline void destroy_dlg(struct dlg_cell *dlg) {
 
     }
 
+    if (dlg_db_mode)
+    	remove_dialog_in_from_db(dlg);
+
     LM_DBG("About to run dlg callback for destroy\n");
     run_dlg_callbacks(DLGCB_DESTROY, dlg, NULL, NULL, DLG_DIR_NONE, 0);
     LM_DBG("DONE: About to run dlg callback for destroy\n");
@@ -962,6 +967,7 @@ void link_dlg_out(struct dlg_cell *dlg, struct dlg_cell_out *dlg_out, int n) {
 void link_dlg(struct dlg_cell *dlg, int n) {
     struct dlg_entry *d_entry;
 
+    LM_DBG("Linking new dialog with h_entry: %u", dlg->h_entry);
     d_entry = &(d_table->entries[dlg->h_entry]);
 
     dlg_lock(d_table, d_entry);

+ 11 - 0
modules/dialog_ng/dlg_hash.h

@@ -80,6 +80,7 @@
 
 /* dialog-variable flags (in addition to dialog-flags) */
 #define DLG_FLAG_DEL           (1<<8) /*!< delete this var */
+#define DLG_FLAG_INSERTED      (1<<9) /*!< DLG already written to DB - could have been put in by early media or confirmed */
 
 #define DLG_CALLER_LEG         0 /*!< attribute that belongs to a caller leg */
 #define DLG_CALLEE_LEG         1 /*!< attribute that belongs to a callee leg */
@@ -473,15 +474,21 @@ static inline int match_dialog(struct dlg_cell *dlg, str *callid,
             }
         } else {
             if (dlg->callid.len != callid->len) {
+            	LM_DBG("no match cid: %d %d", dlg->callid.len, callid->len);
                 return 0;
             }
 
+            LM_DBG("p: %p ft[%.*s] tt [%.*s]", d_entry_out->first,
+            			dlg->from_tag.len, dlg->from_tag.s,
+            			ttag->len, ttag->s);
             if (dlg->from_tag.len == ttag->len &&
                     strncmp(dlg->from_tag.s, ttag->s, ttag->len) == 0 &&
                     strncmp(dlg->callid.s, callid->s, callid->len) == 0) {
                 //now need to scroll thought d_out_entries to see if to_tag matches!
                 dlg_out = d_entry_out->first;
                 while (dlg_out) {
+                	LM_DBG("dout: tt[%.*s]",
+                			dlg_out->to_tag.len, dlg_out->to_tag.s);
                     if (dlg_out->to_tag.len == ftag->len &&
                             memcmp(dlg_out->to_tag.s, ftag->s, dlg_out->to_tag.len) == 0) {
                         *dir = DLG_DIR_UPSTREAM;
@@ -495,6 +502,8 @@ static inline int match_dialog(struct dlg_cell *dlg, str *callid,
                 //now need to scroll thought d_out_entries to see if to_tag matches!
                 dlg_out = d_entry_out->first;
                 while (dlg_out) {
+                	LM_DBG("dout: tt[%.*s]",
+                	                			dlg_out->to_tag.len, dlg_out->to_tag.s);
                     if (dlg_out->to_tag.len == ttag->len &&
                             memcmp(dlg_out->to_tag.s, ttag->s, dlg_out->to_tag.len) == 0) {
                         *dir = DLG_DIR_DOWNSTREAM;
@@ -503,6 +512,8 @@ static inline int match_dialog(struct dlg_cell *dlg, str *callid,
                     dlg_out = dlg_out->next;
                 }
             }
+            else
+            	LM_DBG("no match tags: ");
         }
     }
     return 0;

+ 1 - 1
modules/dialog_ng/dlg_load.h

@@ -47,7 +47,7 @@ struct dlg_binds {
 	register_dlgcb_f  		register_dlgcb;
 	register_dlgcb_nodlg_f 	register_dlgcb_nodlg;
 	terminate_dlg_f 		terminate_dlg;
-	lookup_terminate_dlg_f 		lookup_terminate_dlg;
+	lookup_terminate_dlg_f 	lookup_terminate_dlg;
 	set_dlg_variable_f 		set_dlg_var;
 	get_dlg_variable_f 		get_dlg_var;
 	get_dlg_expires_f 		get_dlg_expires;

+ 4 - 0
modules/dialog_ng/dlg_req_within.c

@@ -43,11 +43,13 @@
 #include "dlg_timer.h"
 #include "dlg_hash.h"
 #include "dlg_req_within.h"
+#include "dlg_db_handler.h"
 
 #define MAX_FWD_HDR        "Max-Forwards: " MAX_FWD CRLF
 #define MAX_FWD_HDR_LEN    (sizeof(MAX_FWD_HDR) - 1)
 
 extern str dlg_extra_hdrs;
+extern int dlg_db_mode;
 
 int free_tm_dlg(dlg_t *td) {
     if (td) {
@@ -210,6 +212,8 @@ void bye_reply_cb(struct cell* t, int type, struct tmcb_params* ps) {
 
     if (new_state == DLG_STATE_DELETED && old_state == DLG_STATE_DELETED) {
         /* trash the dialog from DB and memory */
+        if (dlg_db_mode)
+        	remove_dialog_in_from_db(dlg);
 
         /* force delete from mem */
         unref_dlg(dlg, 1);

+ 6 - 0
modules/dialog_ng/dlg_var.c

@@ -26,6 +26,7 @@
 #include "dlg_var.h"
 #include "dlg_hash.h"
 #include "dlg_profile.h"
+#include "dlg_db_handler.h"
 
 dlg_ctx_t _dlg_ctx;
 extern int spiral_detected;
@@ -296,6 +297,9 @@ int set_dlg_variable(struct dlg_cell *dlg, str *key, str *val)
     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;
@@ -388,6 +392,8 @@ int pv_set_dlg_variable(struct sip_msg* msg, pv_param_t *param, int op, pv_value
 	if (dlg) {
 		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);