Ethereal-dev: [ethereal-dev] Dissector Exceptions
Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.
From: Gilbert Ramirez <gram@xxxxxxxxxx>
Date: Fri, 28 Apr 2000 08:48:32 -0500
I did some work last night and this morning on exceptions for Ethereal (targetted only at the dissectors right now). I also started outlining the API for "tvbuff"'s --- "Testy, Virtual Buffers". I'll post now just to get some early suggestions. I'm using excp.[ch] from kazlib (search Freshmeat). I can compile them w/o modification. The attached file, "exceptions.h", defines the macros for use within Ethereal. "tvbuff.h" shows the API for tvbuff. Here is the struct for tvbuff_t so far: /* (helper-struct) */ typedef struct { /* The backing tvbuff_t */ tvbuff_t *tvb; /* The offset/length of 'tvb' to which I'm privy */ guint offset; guint length; /* Used for quick testing to see if this * is the tvb_backing that a COMPOSITE is * interested in. */ guint parent_ending_offset; } tvb_backing_t; struct tvbuff { /* Record-keeping */ tvbuff_type type; gboolean initialized; guint usage_count; /* Our guint8 data */ union { guint8 *real; tvb_backing_t subset; GPtrArray *composite; } data; /* Length of virtual buffer. */ guint length; /* COMPOSITE's might need to create a flattened * version of their data in tvb_get_ptr() */ guint8 *flattened_data; /* Func to call when actually freed */ tvbuff_free_cb_t free_cb; }; --gilbert
#ifndef __EXCEPTIONS_H__ #define __EXCEPTIONS_H__ #ifndef XCEPT_H #include "except.h" #endif /* Ethereal has only one exception group, to make these macros simple */ #define XCEPT_GROUP_ETHEREAL 1 /* Ethereal's exceptions */ #define BoundsError 1 /* Index is out of range */ #define UninitializedError 2 /* Data/object is uninitialized */ /* Usage: * * TRY { * code; * } * * CATCH(exception) { * code; * } * * CATCH_ALL { * code; * } * * FINALLY { * code; * } * * ENDTRY; * * This is really something like: * * { * x = setjmp() * if (x == 0) { * <TRY code> * } * else if (x == 1) { * <CATCH(1) code> * } * else if (x == 2) { * <CATCH(2) code> * } * else { * <CATCH_ALL code> { * } * <FINALLY code> * }<ENDTRY tag> * * You obviously don't want to 'goto' or 'return' inside a * CATCH/CATCH_ALL block if you intend to do something in the * FINALLY block. * * All CATCH's must precede a CATCH_ALL. * FINALLY must occur after any CATCH or CATCH_ALL. * ENDTRY marks the end of the TRY code. * TRY and ENDTRY are the mandatory parts of a TRY block. * CATCH, CATCH_ALL, and FINALLY are all optional (although * you'll probably use at least one, otherwise why "TRY"?) * * GET_MESSAGE returns string ptr to exception message * * To throw/raise an exception. * * THROW(exception) * RETHROW rethrow the caught exception * * A cleanup callback is a function called in case an exception occurs * and is not caught. It should be used to free any dynamically-allocated data. * A pop or call_and_pop should occur at the same statement-nesting level * as the push. * * CLEANUP_CB_PUSH(func, data) * CLEANUP_CB_POP * CLEANUP_CB_CALL_AND_POP */ #define TRY \ {\ except_t *exc; \ int caught = 0; \ static const except_id_t catch_spec[] = { \ { XCEPT_GROUP_ETHEREAL, XCEPT_CODE_ANY } }; \ except_try_push(catch_spec, 1, &exc); \ if (exc == 0) { \ /* user's code goes here */ #define ENDTRY \ } \ if (exc != 0 && !caught) { \ g_debug("Exception %lu not caught.", exc->except_id.except_code); \ g_assert(caught); \ } \ except_try_pop();\ } #define CATCH(x) \ } \ else if (exc->except_id.except_code == (x)) { \ caught = 1; /* user's code goes here */ #define CATCH_ALL \ } \ else { \ caught = 1; /* user's code goes here */ #define FINALLY \ } \ { \ /* user's code goes here */ #define THROW(x) \ except_throw(XCEPT_GROUP_ETHEREAL, (x), "XCEPT_GROUP_ETHEREAL") #define THROW_MESSAGE(x, y) \ except_throw(XCEPT_GROUP_ETHEREAL, (x), (y)) #define GET_MESSAGE except_message(exc) #define RETHROW except_rethrow(exc) #define CLEANUP_CB_PUSH(x,y) except_cleanup_push((x),(y) #define CLEANUP_CB_POP except_cleanup_push(0) #define CLEANUP_CB_CALL_AND_POP except_cleanup_push(1) #endif /* __EXCEPTIONS_H__ */
/* tvbuff.h * * Testy, Virtual(-izable) Buffer of guint8*'s * * "Testy" -- the buffer gets mad when an attempt is made to access data * beyond the bounds of the buffer. An exception is thrown. * * "Virtual" -- the buffer can have its own data, can use a subset of * the data of a backing tvbuff, or can be a composite of * other tvbuffs. * * $Id$ * * Copyright (c) 2000 by Gilbert Ramirez <gram@xxxxxxxxxx> * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@xxxxxxxx> * Copyright 1998 Gerald Combs * * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __TVBUFF_H__ #define __TVBUFF_H__ #ifndef __GLIB_H__ #include <glib.h> #endif typedef struct tvbuff tvbuff_t; typedef void (*tvbuff_free_cb_t)(void*); /* The different types of tvbuff's */ typedef enum { TVBUFF_REAL_DATA, TVBUFF_SUBSET, TVBUFF_COMPOSITE } tvbuff_type; /* TVBUFF_REAL_DATA contains a guint8* that points to real data. * The data is allocated and contiguous. * * TVBUFF_SUBSET has a backing tvbuff. The TVBUFF_SUBSET is a "window" * through which the program sees only a portion of the backing tvbuff. * * TVBUFF_COMPOSITE combines multiple tvbuffs sequentually to produce * a larger byte array. * * tvbuff's of any type can be used as the backing-tvbuff of a * TVBUFF_SUBSET or as the member of a TVBUFF_COMPOSITE. * TVBUFF_COMPOSITEs can have member-tvbuffs of different types. */ /* "class" initialization. Called once during execution of program * so that tvbuff.c can initialize its data. */ void tvbuff_init(void); /* "class" cleanup. Called once during execution of program * so that tvbuff.c can clean up its data. */ void tvbuff_cleanup(void); /* Returns a pointer to a newly initialized tvbuff. Note that * tvbuff's of types TVBUFF_SUBSET and TVBUFF_COMPOSITE * require further initialization via the appropriate functions */ tvbuff_t* tvb_new(tvbuff_type); /* Marks a tvbuff for freeing. The guint8* data is *never* freed by * the tvbuff routines. The tvbuff is actually freed once its usage * count drops to 0. Usage counts exist for any time the tvbuff is * used as a member of another tvbuff, i.e., as the backing buffer for * a TVBUFF_SUBSET or as a member of a TVBUFF_COMPOSITE. * * The caller can artificially increment/decrement the usage count * with tvbuff_increment_usage_count()/tvbuff_decrement_usage_count(). */ void tvb_free(tvbuff_t*); /* Both return the new usage count, after the increment or decrement */ guint tvbuff_increment_usage_count(tvbuff_t*, guint count); /* If a decrement causes the usage count to drop to 0, a the tvbuff * is immediately freed. Be sure you know exactly what you're doing * if you decide to use this function, as another tvbuff could * still have a pointer to the just-freed tvbuff, causing corrupted data * or a segfault in the future */ guint tvbuff_decrement_usage_count(tvbuff_t*, guint count); /* Set a callback function to call when a tvbuff is actually freed * (once the usage count drops to 0). One argument is passed to * that callback --- the guint* that points to the real data. * Obviously, this only applies to a TVBUFF_REAL_DATA tvbuff. */ void tvb_set_free_cb(tvbuff_t*, tvbuff_free_cb_t); /* Sets parameters for TVBUFF_REAL_DATA */ void tvb_set_real_data(tvbuff_t*, guint8* data, guint length); /* Combination of tvb_new() and tvb_set_real_data() */ tvbuff_t* tvb_new_real_data(guint8* data, guint length); /* Define the subset of the backing buffer to use. * * 'backing_start_offset' can be negative, to indicate bytes from * the end of the backing buffer. * * 'length' can be 0, although the usefulness of the buffer would * be rather limited. * * 'length' of -1 means "to the end of the backing buffer" * * Will throw BoundsError if 'backing_start_offset'/'length' * is beyond the bounds of the backing tvbuff. */ void tvb_set_subset(tvbuff_t* tvb, tvbuff_t* backing, gint backing_start_offset, gint length); /* Combination of tvb_new() and tvb_set_subset() */ tvbuff_t* tvb_new_subset(tvbuff_t* backing, gint backing_start_offset, gint length); /* Append to the list of tvbuffs that make up this composite tvbuff */ void tvb_composite_append(tvbuff_t* tvb, tvbuff_t* member, gint member_start_offset, gint length); /* Prepend to the list of tvbuffs that make up this composite tvbuff */ void tvb_composite_prepend(tvbuff_t* tvb, tvbuff_t* member, gint member_start_offset, gint length); /* Mark a composite tvbuff as initialized. No further appends or prepends * occur, data access can finally happen after this finalization. */ void tvb_composite_finalize(tvbuff_t* tvb); /* Get total length of buffer */ guint tvb_length(tvbuff_t*); /* Computes bytes to end of buffer, from offset (which can be negative, * to indicate bytes from end of buffer) */ guint tvb_length_remaining(tvbuff_t*, gint offset); /* Checks (w/o throwing exception) that the bytes referred to by 'offset'/'length' * actualy exist in the buffer */ gboolean tvb_bytes_exist(tvbuff_t*, gint offset, gint length); /* Checks (w/o throwing exception) that offset exists in buffer */ gboolean tvb_offset_exists(tvbuff_t*, gint offset); /************** START OF ACCESSORS ****************/ /* All accessors will throw UnitializedError or BoundsError if appropriate */ guint8 tvb_get_guint8(tvbuff_t*, gint offset); guint16 tvb_get_ntohs(tvbuff_t*, gint offset); guint32 tvb_get_ntohl(tvbuff_t*, gint offset); guint16 tvb_get_letohs(tvbuff_t*, gint offset); guint32 tvb_get_letohl(tvbuff_t*, gint offset); guint8* tvb_memcpy(tvbuff_t*, guint8* target, gint offset, gint length); /* It is the user's responsibility to g_free() the memory allocated by * tvb_memdup() */ guint8* tvb_memdup(tvbuff_t*, gint offset, gint length); /* WARNING! This function is possibly expensive, temporarily allocating * another copy of the packet data */ /* Will return a ptr into our buffer if the data asked for via 'offset'/'length' * is contiguous (which might not be the case for TVBUFF_COMPOSITE). If the * data is not contiguous, a tvb_memdup() is called for the entire buffer * and the pointer to the newly-contiguous data is returned. This dynamically- * allocated memory will be freed when the tvbuff is freed, after the * tvbuff_free_cb_t() is called, if any. */ guint8* tvb_get_ptr(tvbuff_t*, gint offset, gint length); /* Find length of string by looking for end of string ('\0'), up to * 'max_length' characters'. Returns -1 if 'max_length' reached * before finding EOS. */ gint tvb_strnlen(tvbuff_t*, gint offset, gint max_length); /************** END OF ACCESSORS ****************/ /* Sets pd and offset so that tvbuff's can be used with code * that only understands pd/offset and not tvbuffs. * This is the "compatibility" function */ void tvb_compat(tvbuff_t*, guint8 **pd, int *offset); /* For testing purposes, send hexdump of tvbuff data contents * to stdout. */ void tvb_dump(tvbuff_t*); #endif /* __TVBUFF_H__ */
- Prev by Date: RE: [ethereal-dev] Hex dump problem?
- Next by Date: RE: [ethereal-dev] ISAKMP
- Previous by thread: Re: [ethereal-dev] Patches for SINEC H1-Dissector, request for CVS-tarballs
- Next by thread: Re: [ethereal-dev] capture files that that kill ethereal 0.8.7
- Index(es):