changeset 1036:aecdc2fbf222

Add fd_msg_dump_full function that dumps a message in human-readable format. (not hooked in yet) For this, add an argument to dump_avp_val if it should print a header before each value or not.
author Thomas Klausner <tk@giga.or.at>
date Tue, 16 Apr 2013 18:53:51 +0200
parents 2f989d1a21e9
children 4f5eb63aef96
files include/freeDiameter/libfdproto.h libfdproto/dictionary.c libfdproto/fdproto-internal.h libfdproto/messages.c
diffstat 4 files changed, 173 insertions(+), 20 deletions(-) [+]
line wrap: on
line diff
--- a/include/freeDiameter/libfdproto.h	Tue Apr 16 18:51:25 2013 +0200
+++ b/include/freeDiameter/libfdproto.h	Tue Apr 16 18:53:51 2013 +0200
@@ -2318,6 +2318,8 @@
  */
 void fd_msg_dump_walk ( int level, msg_or_avp *obj );
 void fd_msg_dump_one  ( int level, msg_or_avp *obj );
+/* Dump full message to log */
+void fd_msg_dump_full ( int level, struct dictionary *dict, const char *prefix, msg_or_avp *obj );
 
 /*
  * FUNCTION:	fd_msg_log
--- a/libfdproto/dictionary.c	Tue Apr 16 18:51:25 2013 +0200
+++ b/libfdproto/dictionary.c	Tue Apr 16 18:53:51 2013 +0200
@@ -1179,7 +1179,7 @@
 				if (enumval->enum_value.os.len < LEN_MAX)
 					n = enumval->enum_value.os.len;
 				for (i=0; i < n; i++)
-					fd_log_debug("0x%02hhX/'%c' ", enumval->enum_value.os.data[i], ASCII(enumval->enum_value.os.data[i]));
+					fd_log_debug("0x%02.2X/'%c' ", enumval->enum_value.os.data[i], ASCII(enumval->enum_value.os.data[i]));
 				if (n == LEN_MAX)
 					fd_log_debug("...");
 			}
@@ -1342,13 +1342,15 @@
 static int dump_val_os(union avp_value * value, char **outstr, size_t *offset, size_t *outlen)
 {
 	int i;
+	CHECK_FCT( dump_add_str(outstr, offset, outlen, "<") );
 	for (i = 0; i < value->os.len; i++) {
-		if (i == 24) { /* Dump only up to 24 bytes of the buffer */
+		if (i == 1024) { /* Dump only up to 1024 bytes of the buffer */
 			CHECK_FCT( dump_add_str(outstr, offset, outlen, "[...] (len=%zd)", value->os.len) );
 			break;
 		}
-		CHECK_FCT( dump_add_str(outstr, offset, outlen, "%02.2X ", value->os.data[i]) );
+		CHECK_FCT( dump_add_str(outstr, offset, outlen, "%s%02.2X", (i==0 ? "" : " "), value->os.data[i]) );
 	}
+	CHECK_FCT( dump_add_str(outstr, offset, outlen, ">") );
 	return 0;
 }
 
@@ -1423,7 +1425,7 @@
 #define INOBJHDR 	"%*s   "
 #define INOBJHDRVAL 	indent<0 ? 1 : indent, indent<0 ? "-" : "|"
 
-/* Formater for the AVP value dump line */
+/* Formatter for the AVP value dump line */
 static int dump_avp_val(union avp_value *avp_value, 
 			int (*def_dump_val_cb)(union avp_value *, char **, size_t *, size_t *), 
 			char * (*dump_val_cb)(union avp_value *), 
@@ -1433,21 +1435,24 @@
 			int indent, 
 			char **outstr, 
 			size_t *offset, 
-			size_t *outlen)
+			size_t *outlen,
+		        int header)
 {
-	/* Header for all AVP values dumps: */
-	CHECK_FCT( dump_add_str(outstr, offset, outlen, INOBJHDR "value ", INOBJHDRVAL) );
+	if (header) {
+		/* Header for all AVP values dumps: */
+		CHECK_FCT( dump_add_str(outstr, offset, outlen, INOBJHDR "value ", INOBJHDRVAL) );
 	
-	/* If the type is provided, write it */
-	if (type_name) {
-		CHECK_FCT( dump_add_str(outstr, offset, outlen, "t: '%s' ", type_name) );
-	}
+		/* If the type is provided, write it */
+		if (type_name) {
+			CHECK_FCT( dump_add_str(outstr, offset, outlen, "t: '%s' ", type_name) );
+		}
 	
-	/* Always give the base datatype anyway */
-	CHECK_FCT( dump_add_str(outstr, offset, outlen, "(%s) ", type_base_name[datatype]) );
-	
-	/* Now, the value */
-	CHECK_FCT( dump_add_str(outstr, offset, outlen, "v: ") );
+		/* Always give the base datatype anyway */
+		CHECK_FCT( dump_add_str(outstr, offset, outlen, "(%s) ", type_base_name[datatype]) );
+
+		/* Now, the value */
+		CHECK_FCT( dump_add_str(outstr, offset, outlen, "v: ") );
+	}
 	if (const_name) {
 		CHECK_FCT( dump_add_str(outstr, offset, outlen, "'%s' (", const_name) );
 	}
@@ -1468,7 +1473,7 @@
 }
 
 /* Dump the value of an AVP of known type into the returned str */
-int fd_dict_dump_avp_value(union avp_value *avp_value, struct dict_object * model, int indent, char **outstr, size_t *offset, size_t *outlen)
+int fd_dict_dump_avp_value(union avp_value *avp_value, struct dict_object * model, int indent, char **outstr, size_t *offset, size_t *outlen, int header)
 {
 	char * (*dump_val_cb)(union avp_value *avp_value) = NULL;
 	struct dict_object * type = NULL;
@@ -1502,7 +1507,7 @@
 	}
 	
 	/* And finally, dump the value */
-	CHECK_FCT( dump_avp_val(avp_value, get_default_dump_val_cb(model->data.avp.avp_basetype), dump_val_cb, model->data.avp.avp_basetype, type_name, const_name, indent, outstr, offset, outlen) );
+	CHECK_FCT( dump_avp_val(avp_value, get_default_dump_val_cb(model->data.avp.avp_basetype), dump_val_cb, model->data.avp.avp_basetype, type_name, const_name, indent, outstr, offset, outlen, header) );
 	return 0;
 }
 
--- a/libfdproto/fdproto-internal.h	Tue Apr 16 18:51:25 2013 +0200
+++ b/libfdproto/fdproto-internal.h	Tue Apr 16 18:53:51 2013 +0200
@@ -59,7 +59,7 @@
 
 /* Dispatch / messages / dictionary API */
 int fd_dict_disp_cb(enum dict_object_type type, struct dict_object *obj, struct fd_list ** cb_list);
-int fd_dict_dump_avp_value(union avp_value *avp_value, struct dict_object * model, int indent, char **outstr, size_t *offset, size_t *outlen);
+int fd_dict_dump_avp_value(union avp_value *avp_value, struct dict_object * model, int indent, char **outstr, size_t *offset, size_t *outlen, int header);
 int fd_disp_call_cb_int( struct fd_list * cb_list, struct msg ** msg, struct avp *avp, struct session *sess, enum disp_action *action, 
 			struct dict_object * obj_app, struct dict_object * obj_cmd, struct dict_object * obj_avp, struct dict_object * obj_enu);
 extern pthread_rwlock_t fd_disp_lock;
--- a/libfdproto/messages.c	Tue Apr 16 18:51:25 2013 +0200
+++ b/libfdproto/messages.c	Tue Apr 16 18:53:51 2013 +0200
@@ -828,7 +828,7 @@
 		if (!avp->avp_model) {
 			CHECK_FCT( dump_add_str(outstr, offset, outlen, INOBJHDR "(data set but no model: ERROR)|", INOBJHDRVAL) );
 		} else {
-			CHECK_FCT( fd_dict_dump_avp_value(avp->avp_public.avp_value, avp->avp_model, indent, outstr, offset, outlen) );
+			CHECK_FCT( fd_dict_dump_avp_value(avp->avp_public.avp_value, avp->avp_model, indent, outstr, offset, outlen, 1) );
 		}
 	}
 
@@ -901,6 +901,152 @@
 	free(outstr);
 }
 
+/* Completely dump a msg_t object */
+static int full_obj_dump_msg (struct msg * msg, struct dictionary *dict, char **outstr, size_t *offset, size_t *outlen)
+{
+	int ret = 0;
+	int success = 0;
+	struct dict_cmd_data dictdata;
+	char buf[20];
+
+	if (!CHECK_MSG(msg)) {
+		CHECK_FCT( dump_add_str(outstr, offset, outlen, "INVALID MESSAGE") );
+		return 0;
+	}
+	
+	if (!msg->msg_model) {
+		fd_msg_parse_dict(msg, dict, NULL);
+	}
+	if (!msg->msg_model) {
+		CHECK_FCT( dump_add_str(outstr, offset, outlen, "(no model) ") );
+	} else {
+		enum dict_object_type dicttype;
+		ret = fd_dict_gettype(msg->msg_model, &dicttype);
+		if (ret || (dicttype != DICT_COMMAND)) {
+			CHECK_FCT( dump_add_str(outstr, offset, outlen, "(invalid model: %d %d) ", ret, dicttype) );
+		} else {
+			ret = fd_dict_getval(msg->msg_model, &dictdata);
+			if (ret != 0) {
+				CHECK_FCT( dump_add_str(outstr, offset, outlen, "(error getting model data: %s) ", strerror(ret)) );
+			} else {
+				success = 1;
+			}
+		}
+	}
+
+	if (msg->msg_public.msg_appl) {
+		snprintf(buf, sizeof(buf), "%u/", msg->msg_public.msg_appl);
+	} else {
+		buf[0] = '\0';
+	}
+	CHECK_FCT( dump_add_str(outstr, offset, outlen, "%s(%s%u)[" DUMP_CMDFL_str "], Length=%u, Hop-By-Hop-Id=0x%08x, End-to-End=0x%08x",
+				success ? dictdata.cmd_name :  "unknown", buf, msg->msg_public.msg_code, DUMP_CMDFL_val(msg->msg_public.msg_flags),
+				msg->msg_public.msg_length, msg->msg_public.msg_hbhid, msg->msg_public.msg_eteid));
+
+	return 0;
+}
+
+/* Dump an avp object completely */
+static int full_obj_dump_avp ( struct avp * avp, char **outstr, size_t *offset, size_t *outlen, int first )
+{
+	int success = 0;
+	struct dict_avp_data dictdata;
+	char buf[20];
+
+	CHECK_FCT( dump_add_str(outstr, offset, outlen, first ? ((*outstr)[*offset-1] == '=' ? "{ " : ", { ") : ", ") );
+
+	if (!CHECK_AVP(avp)) {
+		CHECK_FCT( dump_add_str(outstr, offset, outlen, "INVALID AVP") );
+		return 0;
+	}
+	
+	if (avp->avp_model) {
+		enum dict_object_type dicttype;
+		int ret;
+		ret = fd_dict_gettype(avp->avp_model, &dicttype);
+		if (ret || (dicttype != DICT_AVP)) {
+			CHECK_FCT( dump_add_str(outstr, offset, outlen, "(invalid model: %d %d) ", ret, dicttype) );
+		} else { 
+			ret = fd_dict_getval(avp->avp_model, &dictdata);
+			if (ret != 0) {
+				CHECK_FCT( dump_add_str(outstr, offset, outlen, "(error getting model data: %s) ", strerror(ret)) );
+			} else {
+				success = 1;
+			}
+		}
+	}
+
+	if (avp->avp_public.avp_vendor) {
+		snprintf(buf, sizeof(buf), "%u/", avp->avp_public.avp_vendor);
+	} else {
+		buf[0] = '\0';
+	}
+	/* \todo add full vendorname? */
+	CHECK_FCT(dump_add_str(outstr, offset, outlen, "%s(%s%u)[" DUMP_AVPFL_str "]=", success ? dictdata.avp_name : "unknown", buf, avp->avp_public.avp_code, DUMP_AVPFL_val(avp->avp_public.avp_flags)));
+
+	/* Dump the value if set */
+	if (avp->avp_public.avp_value) {
+		if (!avp->avp_model) {
+			CHECK_FCT( dump_add_str(outstr, offset, outlen, "(unknown data type)") );
+		} else {
+			CHECK_FCT( fd_dict_dump_avp_value(avp->avp_public.avp_value, avp->avp_model, 1, outstr, offset, outlen, 0) );
+		}
+	}
+
+	return 0;
+}
+
+/* Dump full message */
+void fd_msg_dump_full ( int level, struct dictionary *dict, const char *prefix, msg_or_avp *obj )
+{
+	msg_or_avp * ref = obj;
+	char *outstr;
+	int indent = 1;
+	int first = 1;
+	int previous;
+	size_t offset, outlen;
+	CHECK_FCT_DO( dump_init_str(&outstr, &offset, &outlen), 
+		      { fd_log_error("Error initializing string for dumping %p", obj); return; } );
+	CHECK_FCT_DO( dump_add_str(&outstr, &offset, &outlen, "%s: ", prefix),
+		      { fd_log_error("Error while dumping %p", ref); return; });
+
+	do {
+		/* Check the object */
+		if (!VALIDATE_OBJ(ref)) {
+			CHECK_FCT_DO( dump_add_str(&outstr, &offset, &outlen, ">>> invalid object (%p)", ref),
+				      { fd_log_error("Error in error handling dumping %p", ref); break; });
+		}
+		/* Dump the object */
+		switch (_C(ref)->type) {
+		case MSG_AVP:
+			CHECK_FCT_DO( full_obj_dump_avp ( _A(ref), &outstr, &offset, &outlen, first ),
+				      { fd_log_error("Error in error handling dumping %p", ref); });
+			break;
+		case MSG_MSG:
+			CHECK_FCT_DO( full_obj_dump_msg ( _M(obj), dict, &outstr, &offset, &outlen ),
+				      { fd_log_error("Error in error handling dumping %p", ref); });
+			break;
+		default:
+			ASSERT(0);
+		}
+
+		first = 0;
+		previous = indent;
+		/* Now find the next object */
+		CHECK_FCT_DO( fd_msg_browse ( ref, MSG_BRW_WALK, &ref, &indent ), break  );
+		if (previous < indent) {
+			first = 1;
+		} else while (previous-- > indent) {
+			CHECK_FCT_DO( dump_add_str(&outstr, &offset, &outlen, " }"),
+				      { fd_log_error("Error while dumping %p", ref); return; });
+		}
+		/* dump next object */
+	} while (ref);
+
+	fd_log(level, "%s", outstr);
+	free(outstr);
+}
+
 /* Dump a message content -- for debug mostly */
 void fd_msg_dump_walk ( int level, msg_or_avp *obj )
 {
"Welcome to our mercurial repository"