aboutsummaryrefslogtreecommitdiffstats
path: root/doc/README.request_response_tracking
diff options
context:
space:
mode:
authorsahlberg <sahlberg@f5534014-38df-0310-8fa8-9805f1628bb7>2006-07-15 03:33:59 +0000
committersahlberg <sahlberg@f5534014-38df-0310-8fa8-9805f1628bb7>2006-07-15 03:33:59 +0000
commit02bdddb07f37d9060be1e45c6d784e03a2e7928f (patch)
tree08158d438e4e320e71cad1c4f9697b7bb89360d7 /doc/README.request_response_tracking
parent23ee78f5b97bf07e18de1d0793f0be8896519fb2 (diff)
Add a README that explains how to add request/response tracking to
a protocol git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@18739 f5534014-38df-0310-8fa8-9805f1628bb7
Diffstat (limited to 'doc/README.request_response_tracking')
-rw-r--r--doc/README.request_response_tracking189
1 files changed, 189 insertions, 0 deletions
diff --git a/doc/README.request_response_tracking b/doc/README.request_response_tracking
new file mode 100644
index 0000000000..6fbd90ecc6
--- /dev/null
+++ b/doc/README.request_response_tracking
@@ -0,0 +1,189 @@
+It is often useful to enhance dissectors for request/response style protocols
+to match requests with responses.
+This allows you to display useful information in the decode tree
+such as which requests are matched to which response and the response time
+for individual transactions.
+
+This is also useful if you want to pass some data from the request onto the
+dissection of the actual response. The RPC dissector for example does
+something like this since to pass the actual command opcode from the request
+onto the response dissector since the opcode itself is not part of the
+response packet and without the opcode we would not know how to decode the
+data.
+
+It is also useful when you need to track information on a per conversation
+basis such as when some parameters are negotiatiod during a login phase of the
+protocol and when these parameters affect how future commands on that
+session are to be decoded. The iSCSI dissector does something similar to that
+to track which sessions that HeaderDigest is activated for and which ones
+it is not.
+
+
+
+
+The example below shows how simple this is to add to the dissector IF
+1, there is something like a transaction id in the header
+2, it is very unlikely that the transaction identifier is reused for the same conversation
+
+The example is taken from the PANA dissector :
+
+
+First we need to include the definitions for conversations and memory
+magament
+
+ #include <epan/conversation.h>
+ #include <epan/emem.h>
+
+Then we also need a few header fields to show the relations between request
+and response as well as the response time
+
+ static int hf_pana_response_in = -1;
+ static int hf_pana_response_to = -1;
+ static int hf_pana_time = -1;
+
+We need a structure that holds all the information we need to remember
+between the request and the responses.
+One such structure will be allocated for each unique transaction.
+In the example we only keep the frame numbers of the request and the response
+as well as the timestamp for the request.
+But since this structure is persistent and also a unique one is allocated for
+each request/response pair, this is a good place to store other additional
+data you may want to keep track of from a request to a response.
+
+ typedef struct _pana_transaction_t {
+ guint32 req_frame;
+ guint32 rep_frame;
+ nstime_t req_time;
+ } pana_transaction_t;
+
+We also need a structure that holds persistent information for each
+conversation. ( a conversation is identified by SRC/DST address, protocol and SRC/DST port)
+In this case we only want to have keep a binary tree to track the actual
+transactions that occur for this unique conversation.
+Some protocols negotiate session parameters during a login phase and those
+parameters may affect how later commands on the same session is to be decoded,
+this would be a good place to store that additional info you may want to keep
+around.
+
+ typedef struct _pana_conv_info_t {
+ se_tree_t *pdus;
+ } pana_conv_info_t;
+
+
+
+Finally for the meat of it, add the conversation and tracking code to the
+actual dissector
+
+ ...
+ guint32 seq_num;
+ conversation_t *conversation;
+ pana_conv_info_t *pana_info;
+ pana_transaction_t *pana_trans;
+
+ ...
+ /* Get the transaction identifier */
+ seq_num = tvb_get_ntohl(tvb, 8);
+ ...
+
+ /*
+ * We need to track some state for this protocol on a per conversation
+ * basis so we can do neat things like request/response tracking
+ */
+ /*
+ * Do we have a conversation for this connection?
+ */
+ conversation = find_conversation(pinfo->fd->num,
+ &pinfo->src, &pinfo->dst,
+ pinfo->ptype,
+ pinfo->srcport, pinfo->destport, 0);
+ if (conversation == NULL) {
+ /* We don't yet have a conversation, so create one. */
+ conversation = conversation_new(pinfo->fd->num,
+ &pinfo->src, &pinfo->dst,
+ pinfo->ptype,
+ pinfo->srcport, pinfo->destport, 0);
+ }
+ /*
+ * Do we already have a state structure for this conv
+ */
+ pana_info = conversation_get_proto_data(conversation, proto_pana);
+ if (!pana_info) {
+ /* No. Attach that information to the conversation, and add
+ * it to the list of information structures.
+ */
+ pana_info = se_alloc(sizeof(pana_conv_info_t));
+ pana_info->pdus=se_tree_create_non_persistent(SE_TREE_TYPE_RED_BLACK, "pana_pdus");
+
+ conversation_add_proto_data(conversation, proto_pana, pana_info);
+ }
+ if(!pinfo->fd->flags.visited){
+ if(flags&PANA_FLAG_R){
+ /* This is a request */
+ pana_trans=se_alloc(sizeof(pana_transaction_t));
+ pana_trans->req_frame=pinfo->fd->num;
+ pana_trans->rep_frame=0;
+ pana_trans->req_time=pinfo->fd->abs_ts;
+ se_tree_insert32(pana_info->pdus, seq_num, (void *)pana_trans);
+ } else {
+ pana_trans=se_tree_lookup32(pana_info->pdus, seq_num);
+ if(pana_trans){
+ pana_trans->rep_frame=pinfo->fd->num;
+ }
+ }
+ } else {
+ pana_trans=se_tree_lookup32(pana_info->pdus, seq_num);
+ }
+ if(!pana_trans){
+ /* create a "fake" pana_trans structure */
+ pana_trans=ep_alloc(sizeof(pana_transaction_t));
+ pana_trans->req_frame=0;
+ pana_trans->rep_frame=0;
+ pana_trans->req_time=pinfo->fd->abs_ts;
+ }
+
+ /* print state tracking in the tree */
+ if(flags&PANA_FLAG_R){
+ /* This is a request */
+ if(pana_trans->rep_frame){
+ proto_item *it;
+
+ it=proto_tree_add_uint(pana_tree, hf_pana_response_in, tvb, 0, 0, pana_trans->rep_frame);
+ PROTO_ITEM_SET_GENERATED(it);
+ }
+ } else {
+ /* This is a reply */
+ if(pana_trans->req_frame){
+ proto_item *it;
+ nstime_t ns;
+
+ it=proto_tree_add_uint(pana_tree, hf_pana_response_to, tvb, 0, 0, pana_trans->req_frame);
+ PROTO_ITEM_SET_GENERATED(it);
+
+ nstime_delta(&ns, &pinfo->fd->abs_ts, &pana_trans->req_time);
+ it=proto_tree_add_time(pana_tree, hf_pana_time, tvb, 0, 0, &ns);
+ PROTO_ITEM_SET_GENERATED(it);
+ }
+ }
+
+
+
+
+
+
+Then we just need to declare the hf fields we used
+
+ { &hf_pana_response_in,
+ { "Response In", "pana.response_in",
+ FT_FRAMENUM, BASE_DEC, NULL, 0x0,
+ "The response to this PANA request is in this frame", HFILL }
+ },
+ { &hf_pana_response_to,
+ { "Request In", "pana.response_to",
+ FT_FRAMENUM, BASE_DEC, NULL, 0x0,
+ "This is a response to the PANA request in this frame", HFILL }
+ },
+ { &hf_pana_time,
+ { "Time", "pana.time",
+ FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
+ "The time between the Call and the Reply", HFILL }
+ },