From ef9394581140d5525b6c0983e72938464b91822f Mon Sep 17 00:00:00 2001 From: Jakub Zawadzki Date: Sat, 13 Jul 2013 17:53:33 +0000 Subject: [PATCH] Add support for cloning TVBs, move tvb_new() prototype to wtap-int.h svn path=/trunk/; revision=50558 --- epan/tvbuff-int.h | 3 + epan/tvbuff.c | 42 +++++++++++ epan/tvbuff.h | 8 +-- frame_tvbuff.c | 178 +++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 218 insertions(+), 13 deletions(-) diff --git a/epan/tvbuff-int.h b/epan/tvbuff-int.h index 2aee4c16a2..d8d4cba314 100644 --- a/epan/tvbuff-int.h +++ b/epan/tvbuff-int.h @@ -37,6 +37,8 @@ struct tvb_ops { gint (*tvb_find_guint8)(tvbuff_t *tvb, guint abs_offset, guint limit, guint8 needle); gint (*tvb_pbrk_guint8)(tvbuff_t *tvb, guint abs_offset, guint limit, const guint8 *needles, guchar *found_needle); + + tvbuff_t *(*tvb_clone)(tvbuff_t *tvb, guint abs_offset, guint abs_length); }; typedef struct { @@ -114,5 +116,6 @@ struct tvb_composite { tvb_comp_t composite; }; +WS_DLL_PUBLIC tvbuff_t *tvb_new(const struct tvb_ops *ops); #endif diff --git a/epan/tvbuff.c b/epan/tvbuff.c index 91701a801f..6de6b7df35 100644 --- a/epan/tvbuff.c +++ b/epan/tvbuff.c @@ -629,7 +629,40 @@ tvb_composite_finalize(tvbuff_t *tvb) tvb->initialized = TRUE; } +static tvbuff_t * +tvb_generic_clone_offset_len(tvbuff_t *tvb, guint offset, guint len) +{ + tvbuff_t *cloned_tvb; + guint8 *data = (guint8 *) g_malloc(len); + + tvb_memcpy(tvb, data, offset, len); + + cloned_tvb = tvb_new_real_data(data, len, len); + tvb_set_free_cb(cloned_tvb, g_free); + + return cloned_tvb; +} + +tvbuff_t * +tvb_clone_offset_len(tvbuff_t *tvb, guint offset, guint len) +{ + if (tvb->ops->tvb_clone) { + tvbuff_t *cloned_tvb; + + cloned_tvb = tvb->ops->tvb_clone(tvb, offset, len); + if (cloned_tvb) + return cloned_tvb; + } + + return tvb_generic_clone_offset_len(tvb, offset, len); +} + +tvbuff_t * +tvb_clone(tvbuff_t *tvb) +{ + return tvb_clone_offset_len(tvb, 0, tvb->length); +} guint tvb_length(const tvbuff_t *tvb) @@ -2000,6 +2033,12 @@ subset_pbrk_guint8(tvbuff_t *tvb, guint abs_offset, guint limit, const guint8 *n return tvb_pbrk_guint8(subset_tvb->subset.tvb, subset_tvb->subset.offset + abs_offset, limit, needles, found_needle); } +static tvbuff_t * +subset_clone(tvbuff_t *tvb, guint abs_offset, guint abs_length) +{ + return tvb_clone_offset_len(tvb, abs_offset, abs_length); +} + /* Find size of stringz (NUL-terminated string) by looking for terminating * NUL. The size of the string includes the terminating NUL. * @@ -3645,6 +3684,7 @@ static const struct tvb_ops tvb_real_ops = { NULL, /* memcpy */ NULL, /* find_guint8 */ NULL, /* pbrk_guint8 */ + NULL, /* clone */ }; static inline const struct tvb_ops *get_tvb_real_ops(void) { return &tvb_real_ops; } @@ -3657,6 +3697,7 @@ static const struct tvb_ops tvb_subset_ops = { subset_memcpy, /* memcpy */ subset_find_guint8, /* find_guint8 */ subset_pbrk_guint8, /* pbrk_guint8 */ + subset_clone, /* clone */ }; static inline const struct tvb_ops *get_tvb_subset_ops(void) { return &tvb_subset_ops; } @@ -3669,6 +3710,7 @@ static const struct tvb_ops tvb_composite_ops = { NULL, /* composite_memcpy */ /* memcpy */ NULL, /* find_guint8 XXX */ NULL, /* pbrk_guint8 XXX */ + NULL, /* clone */ }; static inline const struct tvb_ops *get_tvb_composite_ops(void) { return &tvb_composite_ops; } diff --git a/epan/tvbuff.h b/epan/tvbuff.h index 7a851112df..144e8c9b1a 100644 --- a/epan/tvbuff.h +++ b/epan/tvbuff.h @@ -57,8 +57,6 @@ extern "C" { struct tvbuff; typedef struct tvbuff tvbuff_t; -struct tvb_ops; - /** @defgroup tvbuff Testy, Virtual(-izable) Buffers * * Dissector use and management @@ -115,14 +113,16 @@ struct tvb_ops; typedef void (*tvbuff_free_cb_t)(void*); -WS_DLL_PUBLIC tvbuff_t *tvb_new(const struct tvb_ops *ops); - /** Extracts 'number of bits' starting at 'bit offset'. * Returns a pointer to a newly initialized ep_alloc'd REAL_DATA * tvbuff with the bits octet aligned. */ WS_DLL_PUBLIC tvbuff_t* tvb_new_octet_aligned(tvbuff_t *tvb, guint32 bit_offset, gint32 no_of_bits); +WS_DLL_PUBLIC tvbuff_t *tvb_clone(tvbuff_t *tvb); + +WS_DLL_PUBLIC tvbuff_t *tvb_clone_offset_len(tvbuff_t *tvb, guint offset, guint len); + /** Free a tvbuff_t and all tvbuffs chained from it * The tvbuff must be 'the 'head' (initial) tvb of a chain or * must not be in a chain. diff --git a/frame_tvbuff.c b/frame_tvbuff.c index 5af5b3bc23..20635fd958 100644 --- a/frame_tvbuff.c +++ b/frame_tvbuff.c @@ -31,16 +31,119 @@ #include #include "frame_tvbuff.h" +#include "globals.h" -/* XXX, to read data with wtap_seek_read() we need: - * cf->wth, fdata->file_off, fdata->cap_len - * add when ready to structure below - */ +#include "wtap-int.h" /* for ->random_fh */ struct tvb_frame { struct tvbuff tvb; + + Buffer *buf; /* Packet data */ + + wtap *wth; /**< Wiretap session */ + gint64 file_off; /**< File offset */ + + guint offset; }; +static gboolean +frame_read(struct tvb_frame *frame_tvb, struct wtap_pkthdr *phdr, Buffer *buf) +{ + int err; + gchar *err_info; + + /* sanity check, capture file was closed? */ + if (cfile.wth != frame_tvb->wth) + return FALSE; + + if (!wtap_seek_read(frame_tvb->wth, frame_tvb->file_off, phdr, buf, frame_tvb->tvb.length, &err, &err_info)) { + switch (err) { + case WTAP_ERR_UNSUPPORTED_ENCAP: + case WTAP_ERR_BAD_FILE: + g_free(err_info); + break; + } + return FALSE; + } + return TRUE; +} + + +static void +frame_invalidate(struct tvb_frame *frame_tvb) +{ + struct wtap_pkthdr phdr; /* Packet header */ + + if (frame_tvb->buf == NULL) { + frame_tvb->buf = (struct Buffer *) g_malloc(sizeof(struct Buffer)); + + /* XXX, register frame_tvb to some list which frees from time to time not used buffers :] */ + buffer_init(frame_tvb->buf, frame_tvb->tvb.length); + + if (!frame_read(frame_tvb, &phdr, frame_tvb->buf)) + { /* TODO: THROW(???); */ } + } + + frame_tvb->tvb.real_data = buffer_start_ptr(frame_tvb->buf); +} + +static void +frame_free(tvbuff_t *tvb) +{ + struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb; + + if (frame_tvb->buf) { + buffer_free(frame_tvb->buf); + + g_free(frame_tvb->buf); + } +} + +static const guint8 * +frame_get_ptr(tvbuff_t *tvb, guint abs_offset, guint abs_length _U_) +{ + struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb; + + frame_invalidate(frame_tvb); + + return tvb->real_data + abs_offset; +} + +static void * +frame_memcpy(tvbuff_t *tvb, void *target, guint abs_offset, guint abs_length) +{ + struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb; + + frame_invalidate(frame_tvb); + + return memcpy(target, tvb->real_data + abs_offset, abs_length); +} + +static gint +frame_find_guint8(tvbuff_t *tvb, guint abs_offset, guint limit, guint8 needle) +{ + struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb; + const guint8 *result; + + frame_invalidate(frame_tvb); + + result = (const guint8 *)memchr(tvb->real_data + abs_offset, needle, limit); + if (result) + return (gint) (result - tvb->real_data); + else + return -1; +} + +static gint +frame_pbrk_guint8(tvbuff_t *tvb, guint abs_offset, guint limit, const guint8 *needles, guchar *found_needle) +{ + struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb; + + frame_invalidate(frame_tvb); + + return tvb_pbrk_guint8(tvb, abs_offset, limit, needles, found_needle); +} + static gsize frame_sizeof(void) { @@ -50,23 +153,28 @@ frame_sizeof(void) static guint frame_offset(const tvbuff_t *tvb _U_, const guint counter) { + /* XXX: frame_tvb->offset */ return counter; } +static tvbuff_t *frame_clone(tvbuff_t *tvb, guint abs_offset, guint abs_length); + static const struct tvb_ops tvb_frame_ops = { frame_sizeof, /* size */ - NULL, /* free */ + frame_free, /* free */ frame_offset, /* offset */ - NULL, /* get_ptr */ - NULL, /* memcpy */ - NULL, /* find_guint8 */ - NULL, /* pbrk_guint8 */ + frame_get_ptr, /* get_ptr */ + frame_memcpy, /* memcpy */ + frame_find_guint8, /* find_guint8 */ + frame_pbrk_guint8, /* pbrk_guint8 */ + frame_clone, /* clone */ }; /* based on tvb_new_real_data() */ tvbuff_t * frame_tvbuff_new(const frame_data *fd, const guint8 *buf) { + struct tvb_frame *frame_tvb; tvbuff_t *tvb; tvb = tvb_new(&tvb_frame_ops); @@ -104,6 +212,21 @@ frame_tvbuff_new(const frame_data *fd, const guint8 *buf) */ tvb->ds_tvb = tvb; + frame_tvb = (struct tvb_frame *) tvb; + + /* XXX, how to handle fd->file_off == -1 (edited packet) ?? */ + /* don't care, reassemble code was doing whole copy of data, so it'll work the same */ + + /* XXX, wtap_can_seek() */ + if (fd && cfile.wth && cfile.wth->random_fh) { + frame_tvb->wth = cfile.wth; + frame_tvb->file_off = fd->file_off; + frame_tvb->offset = 0; + } else + frame_tvb->wth = NULL; + + frame_tvb->buf = NULL; + return tvb; } @@ -112,3 +235,40 @@ frame_tvbuff_new_buffer(const frame_data *fd, Buffer *buf) { return frame_tvbuff_new(fd, buffer_start_ptr(buf)); } + +static tvbuff_t * +frame_clone(tvbuff_t *tvb, guint abs_offset, guint abs_length) +{ + struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb; + + tvbuff_t *cloned_tvb; + struct tvb_frame *cloned_frame_tvb; + + /* file not seekable */ + if (!frame_tvb->wth) + return NULL; + + abs_offset += frame_tvb->offset; + + cloned_tvb = tvb_new(&tvb_frame_ops); + + /* data will be read when needed */ + cloned_tvb->real_data = NULL; + cloned_tvb->length = abs_length; + cloned_tvb->reported_length = abs_length; /* XXX? */ + cloned_tvb->initialized = TRUE; + + /* + * This is the top-level real tvbuff for this data source, + * so its data source tvbuff is itself. + */ + cloned_tvb->ds_tvb = cloned_tvb; + + cloned_frame_tvb = (struct tvb_frame *) cloned_tvb; + cloned_frame_tvb->wth = frame_tvb->wth; + cloned_frame_tvb->file_off = frame_tvb->file_off; + cloned_frame_tvb->offset = abs_offset; + cloned_frame_tvb->buf = NULL; + + return cloned_tvb; +}