From Michael Mann via https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=6377, with...
[obnox/wireshark/wip.git] / doc / README.request_response_tracking
index 3a72676d7c75e8dc69d4b3ca29cc5a5bea93377a..5bc5e6a9273e74240725eaf9e5012c8660fed39d 100644 (file)
@@ -1,52 +1,53 @@
+$Id$
+
+1. Introduction
+
 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 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 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.
-
-
+something like this 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 negotiated 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
+2. Implementation
 
-The example is taken from the PANA dissector :
+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
+management.
 
        #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
+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.
+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 
+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.
 
@@ -56,9 +57,10 @@ data you may want to keep track of from a request to a response.
                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 
+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, see README.developer.
+In this case we only want to have 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,
@@ -66,13 +68,11 @@ 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;
+               emem_tree_t *pdus;
        } pana_conv_info_t;
 
-
-
-Finally for the meat of it,  add the conversation and tracking code to the 
-actual dissector
+Finally for the meat of it, add the conversation and tracking code to the
+actual dissector.
 
        ...
        guint32 seq_num;
@@ -85,92 +85,79 @@ actual dissector
        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);
-       }
+       conversation = find_or_create_conversation(pinfo);
+
        /*
         * 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
+               /*
+                 * 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");
+               pana_info->pdus = se_tree_create_non_persistent(
+                                       EMEM_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){
+       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;
+                       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;
+                       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);
+               pana_trans = se_tree_lookup32(pana_info->pdus, seq_num);
        }
-       if(!pana_trans){
+       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;
+               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){
+       if (flags&PANA_FLAG_R) {
                /* This is a request */
-               if(pana_trans->rep_frame){
+               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);
+                       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){
+               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);
+                       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);
+                       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
+Then we just need to declare the hf fields we used.
 
        { &hf_pana_response_in,
                { "Response In", "pana.response_in",