# HG changeset patch # User Thomas Klausner # Date 1366131231 -7200 # Node ID aecdc2fbf2227150cb230411a8633379e527e429 # Parent 2f989d1a21e953318b55f7d646e29fe8ca05e074 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. diff -r 2f989d1a21e9 -r aecdc2fbf222 include/freeDiameter/libfdproto.h --- 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 diff -r 2f989d1a21e9 -r aecdc2fbf222 libfdproto/dictionary.c --- 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; } diff -r 2f989d1a21e9 -r aecdc2fbf222 libfdproto/fdproto-internal.h --- 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; diff -r 2f989d1a21e9 -r aecdc2fbf222 libfdproto/messages.c --- 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 ) {