Add support for cloning TVBs, move tvb_new() prototype to wtap-int.h
authorJakub Zawadzki <darkjames-ws@darkjames.pl>
Sat, 13 Jul 2013 17:53:33 +0000 (17:53 -0000)
committerJakub Zawadzki <darkjames-ws@darkjames.pl>
Sat, 13 Jul 2013 17:53:33 +0000 (17:53 -0000)
svn path=/trunk/; revision=50558

epan/tvbuff-int.h
epan/tvbuff.c
epan/tvbuff.h
frame_tvbuff.c

index 2aee4c16a23c4643bf853b47ba085b97fb7ba626..d8d4cba314da379ae294d2be156f597e4b8cbfcd 100644 (file)
@@ -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
index 91701a801fcc8880b4a1f19ec1b495607631736b..6de6b7df3508e8c90b6644a9e3004adf375c93c2 100644 (file)
@@ -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; }
index 7a851112df2346d146cacb36a94f07f57470d707..144e8c9b1a8ff542cc14833025c8e973c199c61a 100644 (file)
@@ -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.
index 5af5b3bc230411dfa0b219c6a8fd416cd09d5730..20635fd9589e89cf6e442708cec8aba793dce2d5 100644 (file)
 #include <epan/tvbuff.h>
 
 #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;
+}