[prev in list] [next in list] [prev in thread] [next in thread]
List: ethereal-dev
Subject: [ethereal-dev] Dissector Exceptions
From: Gilbert Ramirez <gram () xiexie ! org>
Date: 2000-04-28 13:48:32
[Download RAW message or body]
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
["exceptions.h" (text/x-chdr)]
#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" (text/x-chdr)]
/* 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@xiexie.org>
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
* 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 in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic