diff --git a/doc/README.tvbuff b/doc/README.tvbuff index 1cee956508..3284e98a73 100644 --- a/doc/README.tvbuff +++ b/doc/README.tvbuff @@ -1,20 +1,20 @@ -$Id: README.tvbuff,v 1.2 2000/05/17 04:34:20 gram Exp $ +$Id: README.tvbuff,v 1.3 2000/06/08 03:03:43 gram Exp $ TVBUFFs and Exceptions -This document describes the changes made to the Ethereal dissector routines -in post-0.8.8. All protocol dissectors need to be modified, but can be modified -one at a time. During this transition time, this document will stand apart -from 'README.developer'. Once all the protocol dissectors are converted to -use the new tvbuff routines, the information in this document will be merged -into 'README.developer'. +This document describes the changes made to the Ethereal dissector +routines in Ethereal 0.8.9. All protocol dissectors need to be modified, +but can be modified one at a time. During this transition time, this +document will stand apart from 'README.developer'. Once all the protocol +dissectors are converted to use the new tvbuff routines, the information +in this document will be merged into 'README.developer'. While Ethereal does a grand job of dissecting frames that are complete, it has done only a mediocre job of dissecting partial frames. Frames can -be incomplete for two reasons: the user used a capture length which is smaller -than the MTU of the interface (which is the default behavior of tcpdump, BTW), -or the frame on the wire is corrupted. In either case, Ethereal should -gracefully handle the incomplete frame. +be incomplete for two reasons: the user used a capture length which is +smaller than the MTU of the interface (which is the default behavior of +tcpdump, BTW), or the frame on the wire is corrupted. In either case, +Ethereal should gracefully handle the incomplete frame. With the aid of two C preprocessor macros, BYTES_ARE_IN_FRAME() and IS_DATA_IN_FRAME(), dissector authors are supposed to check that the data @@ -23,26 +23,28 @@ used these macros diligently, and others not. In the end we realized that depending on human diligence would get us nowhere and that a programmed solution would be necessary. -The idea was to encapsulate the byte array which represented the data in the -frame with a "class" that would check the enforce limits regarding the boundaries -of the byte array. In the event of an improper data access, it is not enough -to return an error condition since we knew that it would be impractical to -check this error flags after every data access. Instead, we needed to implement -exceptions in Ethereal. Other languages (Java, C++, Python) have exceptions, but -we had to introduce an exception library and some magic C preprocess macros -to implement them in C. +The idea was to encapsulate the byte array which represented the data in +the frame with a "class" that would check the enforce limits regarding the +boundaries of the byte array. In the event of an improper data access, it +is not enough to return an error condition since we knew that it would be +impractical to check this error flags after every data access. Instead, +we needed to implement exceptions in Ethereal. Other languages (Java, +C++, Python) have exceptions, but we had to introduce an exception +library and some magic C preprocess macros to implement them in C. -The encapsulating class is called a "tvbuff", or "testy, virtual(-izable) buffer". -They are testy in that they get mad when an attempt is made to access data beyond -the bounds of their array. In that case, they throw an exception. +The encapsulating class is called a "tvbuff", or "testy, virtual(-izable) +buffer". They are testy in that they get mad when an attempt is made to +access data beyond the bounds of their array. In that case, they throw +an exception. -They are virtualizable in that new tvbuff's can be made from other tvbuffs, while -only the original tvbuff may have data. That is, the new tvbuff has virtual data. +They are virtualizable in that new tvbuff's can be made from other +tvbuffs, while only the original tvbuff may have data. That is, the new +tvbuff has virtual data. There are three types of tvbuffs, defined by an enum in tvbuff.h. -A TVBUFF_REAL_DATA contains a guint8* that points to real data. -The data is allocated by the user and is contiguous, since is an array of guint8's. +A TVBUFF_REAL_DATA contains a guint8* that points to real data. The data +is allocated by the user and is contiguous, since is an array of guint8's. A TVBUFF_SUBSET has a backing tvbuff. The TVBUFF_SUBSET is a "window" through which the program sees only a portion of the backing tvbuff. @@ -51,46 +53,48 @@ A TVBUFF_COMPOSITE combines multiple tvbuffs sequentually to produce a larger byte array. -The top-most dissector, dissect_packet(), creates a TVBUFF_REAL_DATA that points -the frame's data. As each dissector completes its portion of the protocl analysis, -it is expected to create a new tvbuff of type TVBUFF_SUBSET which contains -the payload portion of the protocol (that is, the bytes that are relevant to -the next dissector). +The top-most dissector, dissect_packet(), creates a TVBUFF_REAL_DATA +that points the frame's data. As each dissector completes its portion +of the protocl analysis, it is expected to create a new tvbuff of type +TVBUFF_SUBSET which contains the payload portion of the protocol (that +is, the bytes that are relevant to the next dissector). The syntax for creating a new TVBUFF_SUBSET is: next_tvb = tvb_new_subset(tvb, offset, length, reported_length) Where: - tvb is the tvbuff that the dissector has been working on. It can be - a tvbuff of any type. + tvb is the tvbuff that the dissector has been working on. It + can be a tvbuff of any type. next_tvb is the new TVBUFF_SUBSET. - offset is the byte offset of 'tvb' at which the new tvbuff should start. - The first byte is the 0th byte. + offset is the byte offset of 'tvb' at which the new tvbuff + should start. The first byte is the 0th byte. - length is the number of bytes in the new TVBUFF_SUBSET. A length argument - of -1 says to use as many bytes as are available in 'tvb'. + length is the number of bytes in the new TVBUFF_SUBSET. A length + argument of -1 says to use as many bytes as are available in + 'tvb'. - reported_length is the number of bytes that the current protocol says - should be in the payload. A reported_length of -1 says that the protocol - doesn't say anything about the size of its payload. + reported_length is the number of bytes that the current protocol + says should be in the payload. A reported_length of -1 says that + the protocol doesn't say anything about the size of its payload. -The tvb_new_subset() function will throw an exception if the offset/length pair -go beyond the boundaries of 'tvb'. +The tvb_new_subset() function will throw an exception if the offset/length +pair go beyond the boundaries of 'tvb'. -The tvbuff is an opaque structure. It's definition is in tvbuff.c, not tvbuff.h, so -you can't easily access its members. You must use one of the provided accessor methods -to retrieve data from the tvbuff. All accessors will throw an exception if -an attempt is made to read beyond the boundaries of the data in the tvbuff. +The tvbuff is an opaque structure. It's definition is in tvbuff.c, +not tvbuff.h, so you can't easily access its members. You must use one +of the provided accessor methods to retrieve data from the tvbuff. All +accessors will throw an exception if an attempt is made to read beyond +the boundaries of the data in the tvbuff. -If reported_length is set, then if the attempt to access data goes beyond reported_length, -a ReportedBoundsError exception is thrown. +If reported_length is set, then if the attempt to access data goes beyond +reported_length, a ReportedBoundsError exception is thrown. -Otherwise, if an attempt to access data beyond the bounds of the tvbuff is made, -a BoundsError exception is thrown. +Otherwise, if an attempt to access data beyond the bounds of the tvbuff +is made, a BoundsError exception is thrown. The accessors are: @@ -127,10 +131,11 @@ Pointer-retrieval: */ guint8* tvb_get_ptr(tvbuff_t*, gint offset, gint length); -The reason that tvb_get_ptr() have to allocate a copy of its data only occurs -with TVBUFF_COMPOSITES. If the user request a pointer to a range of bytes that -spans the member tvbuffs that make up the TVBUFF_COMPOSITE, the data will have -to be copied to another memory region to assure that all the bytes are contiguous. +The reason that tvb_get_ptr() have to allocate a copy of its data only +occurs with TVBUFF_COMPOSITES. If the user request a pointer to a range +of bytes that spans the member tvbuffs that make up the TVBUFF_COMPOSITE, +the data will have to be copied to another memory region to assure that +all the bytes are contiguous. Modifications to the Dissectors @@ -139,21 +144,23 @@ The dissector prototype will now be: void/gboolean dissector(tvbuff_t*, packet_info*, proto_tree*) -The packet_info struct now has the frame_data struct that used to be passed -to each dissector. Additionally, packet_info has a char* called 'current_proto'. -The first thing a dissector should do is set pinfo->current_proto to point -to a string referring to the name of the protocol (use the same name that appears -in the COL_PROTO column, if possible). If an exception jumps us out of a dissector, -dissect_packet() will use pinfo->current_proto to report which dissector encountered +The packet_info struct now has the frame_data struct that used to +be passed to each dissector. Additionally, packet_info has a char* +called 'current_proto'. The first thing a dissector should do is set +pinfo->current_proto to point to a string referring to the name of the +protocol (use the same name that appears in the COL_PROTO column, if +possible). If an exception jumps us out of a dissector, dissect_packet() +will use pinfo->current_proto to report which dissector encountered an exception. -The packet_info struct also has a tvbuff_t* called 'compat_top_tvb'. This points -to the same tvbuff_t that dissect_packet() creates. This is useful for creating -a tvbuff (TVBUFF_SUBSET) inside a dissector which itself does not use tvbuffs. -Once all the dissectors are converted to use tvbuffs, 'compat_top_tvb' will be removed. +The packet_info struct also has a tvbuff_t* called 'compat_top_tvb'. This +points to the same tvbuff_t that dissect_packet() creates. This is useful +for creating a tvbuff (TVBUFF_SUBSET) inside a dissector which itself does +not use tvbuffs. Once all the dissectors are converted to use tvbuffs, +'compat_top_tvb' will be removed. -A dissector that uses tvbuffs can call another dissector that does not. This code -snippet shows how: +A dissector that uses tvbuffs can call another dissector that does +not. This code snippet shows how: tvbuff_t *next_tvb; const guint8 *next_pd; @@ -164,17 +171,46 @@ snippet shows how: next_tvb = tvb_new_subset(tvb, offset_of_next_protocol, -1); tvb_compat(next_tvb, &next_pd, &next_offset); -That is, next_pd and next_offset will get assigned values relative to the start of -the byte array, not relative to the tvbuff. This function, tvb_compat(), is only -useful while the dissectors are in transition; once all dissectors are converted, -this function can be removed. +That is, next_pd and next_offset will get assigned values relative to +the start of the byte array, not relative to the tvbuff. This function, +tvb_compat(), is only useful while the dissectors are in transition; +once all dissectors are converted, this function can be removed. + + +A dissector that is called via the dissector tables needs to preserve +its old-style argument list until all such dissectors are converted +to use tvbuffs. The dissector can create its own tvbuff by +using pi.compat_top_tvb, which is the top-level tvbuff created +in dissect_packet(). "compat_top_tvb" will only be available during +the conversion process; once all dissector have been converted to use +tvbuff's, that variable will disappear. Here is an example, from +packet-cops.c, of how to create your own tvbuff. The use of +the #if/#endif block is optional. + +/* Code to actually dissect the packets */ +#if 0 +static void +dissect_cops(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ +#else +static void +dissect_cops(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) +{ + tvbuff_t *tvb; + packet_info *pinfo = π + tvb = tvb_new_subset(pinfo->compat_top_tvb, offset, -1, -1); +#endif + +Once we convert all the dissector-table dissectors, the second +half of the #if-block will disappear. Exceptions -The exception module from Kazlib was copied into the Ethereal tree. A header file -"exceptions.h" was created which defines C preprocess macros that make the usage -of the exception functions easier. The exception routines in Kazlib have a lot of -features, but in Ethereal we only need a subset of those features, so the macros -hide the complexity of the Kazlib calls, and try to emulate the syntax of languages -which have native support for exceptions. +The exception module from Kazlib was copied into the Ethereal tree. A +header file "exceptions.h" was created which defines C preprocess macros +that make the usage of the exception functions easier. The exception +routines in Kazlib have a lot of features, but in Ethereal we only need +a subset of those features, so the macros hide the complexity of the +Kazlib calls, and try to emulate the syntax of languages which have +native support for exceptions.