Ver código fonte

dialog(k): more dialog info stored in db

- profiles the dialog belongs to are stored in xdata column, serialized
  as json document. A restart will restore them
- internal flags are stored and restored from database table, column
  iflags (for now the flag for sending BYE on dialog timeout)
Daniel-Constantin Mierla 13 anos atrás
pai
commit
82fe2bff11

+ 1 - 0
modules_k/dialog/Makefile

@@ -13,4 +13,5 @@ SERLIBPATH=../../lib
 SER_LIBS+=$(SERLIBPATH)/kmi/kmi
 SER_LIBS+=$(SERLIBPATH)/srdb1/srdb1
 SER_LIBS+=$(SERLIBPATH)/kcore/kcore
+SER_LIBS+=$(SERLIBPATH)/srutils/srutils
 include ../../Makefile.modules

+ 57 - 8
modules_k/dialog/dlg_db_handler.c

@@ -39,6 +39,7 @@
 #include "../../socket_info.h"
 #include "dlg_hash.h"
 #include "dlg_var.h"
+#include "dlg_profile.h"
 #include "dlg_db_handler.h"
 
 
@@ -61,8 +62,10 @@ str from_contact_column		=	str_init(FROM_CONTACT_COL);
 str to_sock_column			=	str_init(TO_SOCK_COL);
 str from_sock_column		=	str_init(FROM_SOCK_COL);
 str sflags_column			=	str_init(SFLAGS_COL);
+str iflags_column			=	str_init(IFLAGS_COL);
 str toroute_name_column		=	str_init(TOROUTE_NAME_COL);
 str req_uri_column			=	str_init(REQ_URI_COL);
+str xdata_column			=	str_init(XDATA_COL);
 str dialog_table_name		=	str_init(DIALOG_TABLE_NAME);
 int dlg_db_mode				=	DB_MODE_NONE;
 
@@ -79,6 +82,7 @@ extern int dlg_enable_stats;
 extern int active_dlgs_cnt;
 extern int early_dlgs_cnt;
 
+
 #define SET_STR_VALUE(_val, _str)\
 	do{\
 			VAL_STR((_val)).s 		= (_str).s;\
@@ -229,7 +233,8 @@ static int select_entire_dialog_table(db1_res_t ** res, int fetch_num_rows)
 			&from_cseq_column,	&to_cseq_column,	&from_route_column,
 			&to_route_column, 	&from_contact_column, &to_contact_column,
 			&from_sock_column,	&to_sock_column,    &sflags_column,
-			&toroute_name_column,	&req_uri_column };
+			&toroute_name_column,	&req_uri_column, &xdata_column,
+			&iflags_column};
 
 	if(use_dialog_table() != 0){
 		return -1;
@@ -298,9 +303,10 @@ static int load_dialog_info_from_db(int dlg_hash_size, int fetch_num_rows)
 	str callid, from_uri, to_uri, from_tag, to_tag, req_uri;
 	str cseq1, cseq2, contact1, contact2, rroute1, rroute2;
 	str toroute_name;
+	str xdata;
 	unsigned int next_id;
+	srjson_doc_t jdoc;
 	
-
 	res = 0;
 	if((nr_rows = select_entire_dialog_table(&res, fetch_num_rows)) < 0)
 		goto end;
@@ -374,11 +380,14 @@ static int load_dialog_info_from_db(int dlg_hash_size, int fetch_num_rows)
 				early_dlgs_cnt++;
 			}
 
-			dlg->tl.timeout = (unsigned int)(VAL_INT(values+9)) + get_ticks();
+			dlg->tl.timeout = (unsigned int)(VAL_INT(values+9));
+			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(cseq1, values, 10 , 1, 1);
 			GET_STR_VALUE(cseq2, values, 11 , 1, 1);
@@ -398,10 +407,21 @@ static int load_dialog_info_from_db(int dlg_hash_size, int fetch_num_rows)
 
 			dlg->bind_addr[DLG_CALLER_LEG] = create_socket_info(values, 16);
 			dlg->bind_addr[DLG_CALLEE_LEG] = create_socket_info(values, 17);
-			
+
+			dlg->sflags = (unsigned int)VAL_INT(values+18);
+
 			GET_STR_VALUE(toroute_name, values, 19, 0, 0);
 			dlg_set_toroute(dlg, &toroute_name);
 
+			GET_STR_VALUE(xdata, values, 21, 0, 0);
+			if(xdata.s!=NULL)
+			{
+				srjson_InitDoc(&jdoc, NULL);
+				jdoc.buf = xdata;
+				dlg_json_to_profiles(dlg, &jdoc);
+				srjson_DestroyDoc(&jdoc);
+			}
+			dlg->iflags = (unsigned int)VAL_INT(values+22);
 			/*restore the timer values */
 			if (0 != insert_dlg_timer( &(dlg->tl), (int)dlg->tl.timeout )) {
 				LM_CRIT("Unable to insert dlg %p [%u:%u] "
@@ -414,9 +434,9 @@ static int load_dialog_info_from_db(int dlg_hash_size, int fetch_num_rows)
 				continue;
 			}
 			dlg_ref(dlg,1);
-			LM_DBG("current dialog timeout is %u\n", dlg->tl.timeout);
+			LM_DBG("current dialog timeout is %u (%u)\n", dlg->tl.timeout,
+					get_ticks());
 
-			dlg->lifetime = 0;
 			dlg->dflags = 0;
 			next_dialog:
 			;
@@ -675,6 +695,7 @@ int update_dialog_dbinfo_unsafe(struct dlg_cell * cell)
 {
 	int i;
 	struct dlg_var *var;
+	srjson_doc_t jdoc;
 
 	db_val_t values[DIALOG_TABLE_COL_NO];
 
@@ -685,7 +706,8 @@ int update_dialog_dbinfo_unsafe(struct dlg_cell * cell)
 			&start_time_column,  &state_column,       &timeout_column,
 			&from_cseq_column,   &to_cseq_column,     &from_route_column,
 			&to_route_column,    &from_contact_column,&to_contact_column,
-			&sflags_column,      &toroute_name_column,     &req_uri_column };
+			&sflags_column,      &toroute_name_column,     &req_uri_column,
+			&xdata_column, &iflags_column };
 
 	if( (cell->dflags & DLG_FLAG_NEW) != 0 
 	|| (cell->dflags & DLG_FLAG_CHANGED_VARS) != 0) {
@@ -701,6 +723,8 @@ int update_dialog_dbinfo_unsafe(struct dlg_cell * cell)
 	if(use_dialog_table()!=0)
 		return -1;
 	
+	srjson_InitDoc(&jdoc, NULL);
+
 	if((cell->dflags & DLG_FLAG_NEW) != 0){
 		/* save all the current dialogs information*/
 		VAL_TYPE(values) = VAL_TYPE(values+1) = VAL_TYPE(values+9) = 
@@ -715,6 +739,8 @@ int update_dialog_dbinfo_unsafe(struct dlg_cell * cell)
 		SET_NULL_FLAG(values, i, DIALOG_TABLE_COL_NO-6, 0);
 		VAL_TYPE(values+18) = DB1_INT;
 		VAL_TYPE(values+19) = DB1_STR;
+		VAL_TYPE(values+21) = DB1_STR;
+		VAL_TYPE(values+22) = DB1_INT;
 
 		VAL_INT(values)			= cell->h_entry;
 		VAL_INT(values+1)		= cell->h_id;
@@ -757,6 +783,18 @@ int update_dialog_dbinfo_unsafe(struct dlg_cell * cell)
 		SET_STR_VALUE(values+20, cell->req_uri);
 		SET_PROPER_NULL_FLAG(cell->req_uri, 	values, 20);
 
+		dlg_profiles_to_json(cell, &jdoc);
+		if(jdoc.buf.s!=NULL)
+		{
+			SET_STR_VALUE(values+21, jdoc.buf);
+			SET_PROPER_NULL_FLAG(jdoc.buf, values, 21);
+		} else {
+			VAL_NULL(values+21) = 1;
+		}
+
+		VAL_NULL(values+22) = 0;
+		VAL_INT(values+22)  = cell->iflags;
+
 		if((dialog_dbf.insert(dialog_db_handle, insert_keys, values, 
 								DIALOG_TABLE_COL_NO)) !=0){
 			LM_ERR("could not add another dialog to db\n");
@@ -795,8 +833,20 @@ int update_dialog_dbinfo_unsafe(struct dlg_cell * cell)
 		return 0;
 	}
 
+	if(jdoc.buf.s!=NULL) {
+		jdoc.free_fn(jdoc.buf.s);
+		jdoc.buf.s = NULL;
+	}
+	srjson_DestroyDoc(&jdoc);
+
 	return 0;
+
 error:
+	if(jdoc.buf.s!=NULL) {
+		jdoc.free_fn(jdoc.buf.s);
+		jdoc.buf.s = NULL;
+	}
+	srjson_DestroyDoc(&jdoc);
 	return -1;
 }
 
@@ -842,4 +892,3 @@ void dialog_update_db(unsigned int ticks, void * param)
 error:
 	dlg_unlock( d_table, &entry);
 }
-

+ 5 - 2
modules_k/dialog/dlg_db_handler.h

@@ -50,13 +50,15 @@
 #define FROM_CONTACT_COL		"caller_contact"
 #define FROM_SOCK_COL			"caller_sock"
 #define TO_SOCK_COL				"callee_sock"
+#define IFLAGS_COL				"iflags"
 #define SFLAGS_COL				"sflags"
 #define TOROUTE_NAME_COL		"toroute_name"
 #define REQ_URI_COL				"req_uri"
+#define XDATA_COL				"xdata"
 #define DIALOG_TABLE_NAME		"dialog"
-#define DLG_TABLE_VERSION		5
+#define DLG_TABLE_VERSION		6
 
-#define DIALOG_TABLE_COL_NO 		21
+#define DIALOG_TABLE_COL_NO 		23
 
 #define VARS_HASH_ID_COL 		"hash_id"
 #define VARS_HASH_ENTRY_COL		"hash_entry"
@@ -95,6 +97,7 @@ extern str to_contact_column;
 extern str from_contact_column;
 extern str to_sock_column;
 extern str from_sock_column;
+extern str iflags_column;
 extern str sflags_column;
 extern str toroute_name_column;
 extern str dialog_table_name;

+ 2 - 2
modules_k/dialog/dlg_handlers.c

@@ -852,7 +852,7 @@ int dlg_new_dialog(struct sip_msg *req, struct cell *t, const int run_initial_cb
 	dlg->sflags |= _dlg_ctx.flags;
 
 	if (dlg_send_bye!=0 || _dlg_ctx.to_bye!=0)
-		dlg->dflags |= DLG_FLAG_TOBYE;
+		dlg->iflags |= DLG_IFLAG_TIMEOUTBYE;
 
     if (run_initial_cbs)  run_create_callbacks( dlg, req);
 
@@ -1332,7 +1332,7 @@ void dlg_ontimeout(struct dlg_tl *tl)
 			}
 		}
 
-		if(dlg->dflags&DLG_FLAG_TOBYE)
+		if(dlg->iflags&DLG_IFLAG_TIMEOUTBYE)
 		{
 			dlg_bye_all(dlg, NULL);
 			/* run event route for end of dlg */

+ 7 - 4
modules_k/dialog/dlg_hash.h

@@ -66,11 +66,10 @@
 #define DLG_EVENT_REQBYE       7 /*!< BYE request */
 #define DLG_EVENT_REQ          8 /*!< other requests */
 
-/* dialog flags */
+/* dialog internal flags only in memory */
 #define DLG_FLAG_NEW           (1<<0) /*!< new dialog */
 #define DLG_FLAG_CHANGED       (1<<1) /*!< dialog was changed */
 #define DLG_FLAG_HASBYE        (1<<2) /*!< bye was received */
-#define DLG_FLAG_TOBYE         (1<<3) /*!< flag from dialog context */
 #define DLG_FLAG_CALLERBYE     (1<<4) /*!< bye from caller */
 #define DLG_FLAG_CALLEEBYE     (1<<5) /*!< bye from callee */
 #define DLG_FLAG_LOCALDLG      (1<<6) /*!< local dialog, unused */
@@ -81,6 +80,9 @@
 
 #define DLG_FLAG_TM            (1<<9) /*!< dialog is set in transaction */
 
+/* internal flags stored in db */
+#define DLG_IFLAG_TIMEOUTBYE        (1<<0) /*!< send bye on time-out */
+
 #define DLG_CALLER_LEG         0 /*!< attribute that belongs to a caller leg */
 #define DLG_CALLEE_LEG         1 /*!< attribute that belongs to a callee leg */
 
@@ -110,8 +112,9 @@ typedef struct dlg_cell
 	unsigned int         state;		/*!< dialog state */
 	unsigned int         lifetime;		/*!< dialog lifetime */
 	unsigned int         start_ts;		/*!< start time  (absolute UNIX ts)*/
-	unsigned int         dflags;		/*!< internal dialog flags */
-	unsigned int         sflags;		/*!< script dialog flags */
+	unsigned int         dflags;		/*!< internal dialog memory flags */
+	unsigned int         iflags;		/*!< internal dialog persistent flags */
+	unsigned int         sflags;		/*!< script dialog persistent flags */
 	unsigned int         toroute;		/*!< index of route that is executed on timeout */
 	str                  toroute_name;	/*!< name of route that is executed on timeout */
 	unsigned int         from_rr_nb;	/*!< information from record routing */

+ 202 - 0
modules_k/dialog/dlg_profile.c

@@ -403,6 +403,7 @@ void set_current_dialog(sip_msg_t *msg, dlg_cell_t *dlg)
 	struct dlg_profile_link *linker;
 	struct dlg_profile_link *tlinker;
 
+	LM_DBG("setting current dialog [%u:%u]\n", dlg->h_entry, dlg->h_id);
 	/* if linkers are not from current request, just discard them */
 	if (msg->id!=current_dlg_msg_id || msg->pid!=current_dlg_msg_pid) {
 		current_dlg_msg_id = msg->id;
@@ -468,6 +469,12 @@ int set_dlg_profile(struct sip_msg *msg, str *value, struct dlg_profile_table *p
 		link_dlg_profile( linker, dlg);
 	} else {
 		/* no dialog yet -> set linker as pending */
+		if (msg->id!=current_dlg_msg_id || msg->pid!=current_dlg_msg_pid) {
+			current_dlg_msg_id = msg->id;
+			current_dlg_msg_pid = msg->pid;
+			destroy_linkers(current_pending_linkers);
+		}
+
 		linker->next = current_pending_linkers;
 		current_pending_linkers = linker;
 	}
@@ -479,6 +486,45 @@ error:
 	return -1;
 }
 
+/*!
+ * \brief Add dialog to a profile
+ * \param dlg dialog
+ * \param value value
+ * \param profile dialog profile table
+ * \return 0 on success, -1 on failure
+ */
+int dlg_add_profile(dlg_cell_t *dlg, str *value, struct dlg_profile_table *profile)
+{
+	dlg_profile_link_t *linker;
+
+	if (dlg==NULL)
+		return -1;
+
+	/* build new linker */
+	linker = (struct dlg_profile_link*)shm_malloc(
+		sizeof(struct dlg_profile_link) + (profile->has_value?value->len:0) );
+	if (linker==NULL) {
+		LM_ERR("no more shm memory\n");
+		goto error;
+	}
+	memset(linker, 0, sizeof(struct dlg_profile_link));
+
+	/* set backpointer to profile */
+	linker->profile = profile;
+
+	/* set the value */
+	if (profile->has_value) {
+		linker->hash_linker.value.s = (char*)(linker+1);
+		memcpy( linker->hash_linker.value.s, value->s, value->len);
+		linker->hash_linker.value.len = value->len;
+	}
+
+	/* add linker directly to the dialog and profile */
+	link_dlg_profile( linker, dlg);
+	return 0;
+error:
+	return -1;
+}
 
 /*!
  * \brief Unset a dialog profile
@@ -820,3 +866,159 @@ error:
 	free_mi_tree(rpl_tree);
 	return NULL;
 }
+
+
+/**
+ * json serialization of dialog profiles
+ */
+int dlg_profiles_to_json(dlg_cell_t *dlg, srjson_doc_t *jdoc)
+{
+	dlg_profile_link_t *l;
+	srjson_t *sj = NULL;
+	srjson_t *dj = NULL;
+
+	LM_DBG("serializing profiles for dlg[%u:%u]\n",
+				dlg->h_entry, dlg->h_id);
+	if(dlg==NULL || dlg->profile_links==NULL)
+		return -1;
+	LM_DBG("start of serializing profiles for dlg[%u:%u]\n",
+				dlg->h_entry, dlg->h_id);
+
+	for (l = dlg->profile_links ; l ; l=l->next) {
+		if(l->profile->has_value)
+		{
+			if(dj==NULL)
+			{
+				dj = srjson_CreateObject(jdoc);
+				if(dj==NULL)
+				{
+					LM_ERR("cannot create json dynamic profiles obj\n");
+					goto error;
+				}
+			}
+			srjson_AddStrStrToObject(jdoc, dj,
+					l->profile->name.s, l->profile->name.len,
+					l->hash_linker.value.s, l->hash_linker.value.len);
+		} else {
+			if(sj==NULL)
+			{
+				sj = srjson_CreateArray(jdoc);
+				if(sj==NULL)
+				{
+					LM_ERR("cannot create json static profiles obj\n");
+					goto error;
+				}
+			}
+			srjson_AddItemToArray(jdoc, sj,
+					srjson_CreateStr(jdoc, l->profile->name.s, l->profile->name.len));
+		}
+	}
+
+	if(jdoc->root==NULL)
+	{
+		jdoc->root = srjson_CreateObject(jdoc);
+		if(jdoc->root==NULL)
+		{
+			LM_ERR("cannot create json root\n");
+			goto error;
+		}
+	}
+	if(dj!=NULL)
+		srjson_AddItemToObject(jdoc, jdoc->root, "dprofiles", dj);
+	if(sj!=NULL)
+		srjson_AddItemToObject(jdoc, jdoc->root, "sprofiles", sj);
+	if(jdoc->buf.s != NULL)
+	{
+		jdoc->free_fn(jdoc->buf.s);
+		jdoc->buf.s = NULL;
+		jdoc->buf.len = 0;
+	}
+	jdoc->buf.s = srjson_PrintUnformatted(jdoc, jdoc->root);
+	if(jdoc->buf.s!=NULL)
+	{
+		jdoc->buf.len = strlen(jdoc->buf.s);
+		LM_DBG("serialized profiles for dlg[%u:%u] = [[%.*s]]\n",
+				dlg->h_entry, dlg->h_id, jdoc->buf.len, jdoc->buf.s);
+		return 0;
+	}
+	return -1;
+
+error:
+	srjson_Delete(jdoc, dj);
+	srjson_Delete(jdoc, sj);
+	return -1;
+}
+
+
+/**
+ * json de-serialization of dialog profiles
+ */
+int dlg_json_to_profiles(dlg_cell_t *dlg, srjson_doc_t *jdoc)
+{
+	srjson_t *sj = NULL;
+	srjson_t *dj = NULL;
+	srjson_t *it = NULL;
+	dlg_profile_table_t *profile;
+	str name;
+	str val;
+
+	if(dlg==NULL || jdoc==NULL || jdoc->buf.s==NULL)
+		return -1;
+
+	if(jdoc->root == NULL)
+	{
+		jdoc->root = srjson_Parse(jdoc, jdoc->buf.s);
+		if(jdoc->root == NULL)
+		{
+			LM_ERR("invalid json doc [[%s]]\n", jdoc->buf.s);
+			return -1;
+		}
+	}
+	dj = srjson_GetObjectItem(jdoc, jdoc->root, "dprofiles");
+	sj = srjson_GetObjectItem(jdoc, jdoc->root, "sprofiles");
+	if(dj!=NULL)
+	{
+		for(it=dj->child; it; it = it->next)
+		{
+			name.s = it->string;
+			name.len = strlen(name.s);
+			val.s = it->valuestring;
+			val.len = strlen(val.s);
+			profile = search_dlg_profile(&name);
+			if(profile==NULL)
+			{
+				LM_ERR("profile [%.*s] not found\n", name.len, name.s);
+				continue;
+			}
+			if(profile->has_value)
+			{
+				if(dlg_add_profile(dlg, &val, profile) < 0)
+					LM_ERR("dynamic profile cannot be added, ignore!\n");
+				else
+					LM_DBG("dynamic profile added [%s : %s]\n", name.s, val.s);
+			}
+		}
+	}
+	if(sj!=NULL)
+	{
+		for(it=sj->child; it; it = it->next)
+		{
+			name.s = it->valuestring;
+			name.len = strlen(name.s);
+			profile = search_dlg_profile(&name);
+			if(profile==NULL)
+			{
+				LM_ERR("profile [%.*s] not found\n", name.len, name.s);
+				continue;
+			}
+			if(!profile->has_value)
+			{
+				if(dlg_add_profile(dlg, NULL, profile) < 0)
+					LM_ERR("static profile cannot be added, ignore!\n");
+				else
+					LM_DBG("static profile added [%s]\n", name.s);
+			}
+		}
+	}
+	return 0;
+}

+ 20 - 0
modules_k/dialog/dlg_profile.h

@@ -29,6 +29,7 @@
 #define _DIALOG_DLG_PROFILE_H_
 
 #include "../../parser/msg_parser.h"
+#include "../../lib/srutils/srjson.h"
 #include "../../locking.h"
 #include "../../str.h"
 #include "../../modules/tm/h_table.h"
@@ -193,4 +194,23 @@ struct mi_root * mi_profile_list(struct mi_root *cmd_tree, void *param );
  */
 int is_known_dlg(sip_msg_t *msg);
 
+/*!
+ * \brief Add dialog to a profile
+ * \param dlg dialog
+ * \param value value
+ * \param profile dialog profile table
+ * \return 0 on success, -1 on failure
+ */
+int dlg_add_profile(dlg_cell_t *dlg, str *value, struct dlg_profile_table *profile);
+
+/*!
+ * \brief Serialize dialog profiles to json
+ */
+int dlg_profiles_to_json(dlg_cell_t *dlg, srjson_doc_t *jdoc);
+
+/*!
+ * \brief Deserialize dialog profiles to json
+ */
+int dlg_json_to_profiles(dlg_cell_t *dlg, srjson_doc_t *jdoc);
+
 #endif