wireshark/epan/dissectors/packet-aeron.c
Michael Mann 2eb7b05b8c Convert most UDP dissectors to use "auto" preferences.
Similar to the "tcp.port" changes in I99604f95d426ad345f4b494598d94178b886eb67,
convert dissectors that use "udp.port".

More cleanup done on dissectors that use both TCP and UDP dissector
tables, so that less preference callbacks exist.

Change-Id: If07be9b9e850c244336a7069599cd554ce312dd3
Reviewed-on: https://code.wireshark.org/review/18120
Petri-Dish: Michael Mann <mmann78@netscape.net>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Michael Mann <mmann78@netscape.net>
2016-10-13 02:51:18 +00:00

3151 lines
136 KiB
C

/* packet-aeron.c
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include <epan/packet.h>
#include <epan/prefs.h>
#include <epan/expert.h>
#include <epan/uat.h>
#include <epan/tap.h>
#include <epan/conversation.h>
#include <epan/exceptions.h>
#include <epan/to_str.h>
#include <wsutil/inet_aton.h>
#include <wsutil/pint.h>
/* The Aeron protocol is defined at https://github.com/real-logic/Aeron/wiki/Protocol-Specification */
void proto_register_aeron(void);
void proto_reg_handoff_aeron(void);
/* Protocol handle */
static int proto_aeron = -1;
/* Dissector handles */
static dissector_handle_t aeron_dissector_handle;
static heur_dissector_list_t aeron_heuristic_subdissector_list;
/*----------------------------------------------------------------------------*/
/* Preferences. */
/*----------------------------------------------------------------------------*/
static gboolean aeron_sequence_analysis = FALSE;
static gboolean aeron_stream_analysis = FALSE;
static gboolean aeron_reassemble_fragments = FALSE;
static gboolean aeron_use_heuristic_subdissectors = FALSE;
/*----------------------------------------------------------------------------*/
/* Aeron position routines. */
/*----------------------------------------------------------------------------*/
typedef struct
{
guint32 term_id;
guint32 term_offset;
} aeron_pos_t;
static int aeron_pos_roundup(int offset)
{
return ((offset+7) & 0xfffffff8);
}
static int aeron_pos_compare(const aeron_pos_t * pos1, const aeron_pos_t * pos2)
{
/* Returns:
< 0 if pos1 < pos2
== 0 if pos1 == pos2
> 0 if pos1 > pos2
*/
if (pos1->term_id == pos2->term_id)
{
if (pos1->term_offset == pos2->term_offset)
{
return (0);
}
else
{
return ((pos1->term_offset < pos2->term_offset) ? -1 : 1);
}
}
else
{
return ((pos1->term_id < pos2->term_id) ? -1 : 1);
}
}
static guint32 aeron_pos_delta(const aeron_pos_t * pos1, const aeron_pos_t * pos2, guint32 term_size)
{
const aeron_pos_t * p1;
const aeron_pos_t * p2;
guint64 p1_val;
guint64 p2_val;
guint64 delta;
int rc;
rc = aeron_pos_compare(pos1, pos2);
if (rc >= 0)
{
p1 = pos1;
p2 = pos2;
}
else
{
p1 = pos2;
p2 = pos1;
}
p1_val = ((guint64) p1->term_id * term_size) + ((guint64) p1->term_offset);
p2_val = ((guint64) p2->term_id * term_size) + ((guint64) p2->term_offset);
delta = p1_val - p2_val;
return ((guint32) (delta & G_GUINT64_CONSTANT(0x00000000ffffffff)));
}
static gboolean aeron_pos_add_length(aeron_pos_t * pos, guint32 length, guint32 term_length)
{
guint32 next_term_offset;
guint32 rounded_next_term_offset;
next_term_offset = pos->term_offset + length;
if (next_term_offset < pos->term_offset)
return FALSE; /* overflow */
rounded_next_term_offset = aeron_pos_roundup(next_term_offset);
if (rounded_next_term_offset < next_term_offset)
return FALSE; /* overflow */
next_term_offset = rounded_next_term_offset;
if (next_term_offset >= term_length)
{
pos->term_offset = 0;
pos->term_id++;
}
else
{
pos->term_offset = next_term_offset;
}
return TRUE;
}
/*----------------------------------------------------------------------------*/
/* Aeron frame information management. */
/*----------------------------------------------------------------------------*/
static wmem_tree_t * aeron_frame_info_tree = NULL;
struct aeron_frame_info_t_stct;
typedef struct aeron_frame_info_t_stct aeron_frame_info_t;
typedef struct
{
aeron_frame_info_t * frame_info; /* Frame (aeron_frame_info_t) containing the RX data */
guint32 term_offset; /* Term offset of RX data */
guint32 length; /* Length of RX data */
} aeron_rx_info_t;
typedef struct
{
aeron_frame_info_t * frame_info; /* Frame (aeron_frame_info_t) in which this NAK occurs */
wmem_list_t * rx; /* List of RX frames for this NAK */
guint32 flags;
guint32 nak_term_offset; /* Term offset specified by this NAK */
guint32 nak_length; /* NAK length */
guint32 unrecovered_length; /* Number of bytes unrecovered via RX */
} aeron_nak_analysis_t;
typedef struct
{
guint32 flags;
guint32 flags2;
aeron_pos_t high;
aeron_pos_t completed;
guint32 receiver_window;
guint32 outstanding_bytes;
} aeron_stream_analysis_t;
#define AERON_STREAM_ANALYSIS_FLAGS_WINDOW_FULL 0x00000001
#define AERON_STREAM_ANALYSIS_FLAGS_IDLE_RX 0x00000002
#define AERON_STREAM_ANALYSIS_FLAGS_PACING_RX 0x00000004
#define AERON_STREAM_ANALYSIS_FLAGS_OOO 0x00000008
#define AERON_STREAM_ANALYSIS_FLAGS_OOO_GAP 0x00000010
#define AERON_STREAM_ANALYSIS_FLAGS_KEEPALIVE 0x00000020
#define AERON_STREAM_ANALYSIS_FLAGS_WINDOW_RESIZE 0x00000040
#define AERON_STREAM_ANALYSIS_FLAGS_OOO_SM 0x00000080
#define AERON_STREAM_ANALYSIS_FLAGS_KEEPALIVE_SM 0x00000100
#define AERON_STREAM_ANALYSIS_FLAGS_RX 0x00000200
#define AERON_STREAM_ANALYSIS_FLAGS_TERM_ID_CHANGE 0x00000400
#define AERON_STREAM_ANALYSIS_FLAGS2_RCV_VALID 0x00000001
typedef struct
{
guint32 previous;
guint32 next;
} aeron_frame_link_t;
struct aeron_msg_t_stct;
typedef struct aeron_msg_t_stct aeron_msg_t;
struct aeron_frame_info_t_stct
{
guint32 frame;
guint32 ofs;
aeron_frame_link_t transport;
aeron_frame_link_t stream;
aeron_frame_link_t term;
aeron_frame_link_t fragment;
aeron_stream_analysis_t * stream_analysis;
aeron_nak_analysis_t * nak_analysis;
aeron_msg_t * message;
wmem_list_t * rx;
guint32 flags;
};
#define AERON_FRAME_INFO_FLAGS_RETRANSMISSION 0x00000001
#define AERON_FRAME_INFO_FLAGS_KEEPALIVE 0x00000002
#define AERON_FRAME_INFO_FLAGS_REASSEMBLED_MSG 0x00000004
static wmem_tree_key_t * aeron_frame_info_key_build(guint32 frame, guint32 ofs)
{
wmem_tree_key_t * fkey;
guint32 * key;
fkey = wmem_alloc_array(wmem_packet_scope(), wmem_tree_key_t, 2);
key = wmem_alloc_array(wmem_packet_scope(), guint32, 2);
key[0] = frame;
key[1] = ofs;
fkey[0].length = 2;
fkey[0].key = key;
fkey[1].length = 0;
fkey[1].key = NULL;
return (fkey);
}
static aeron_frame_info_t * aeron_frame_info_lookup(wmem_tree_key_t * key)
{
aeron_frame_info_t * fi;
fi = (aeron_frame_info_t *) wmem_tree_lookup32_array(aeron_frame_info_tree, key);
return (fi);
}
static aeron_frame_info_t * aeron_frame_info_find(guint32 frame, guint32 ofs)
{
wmem_tree_key_t * key = aeron_frame_info_key_build(frame, ofs);
return (aeron_frame_info_lookup(key));
}
static aeron_frame_info_t * aeron_frame_info_add(guint32 frame, guint32 ofs)
{
aeron_frame_info_t * fi;
wmem_tree_key_t * key = aeron_frame_info_key_build(frame, ofs);
fi = aeron_frame_info_lookup(key);
if (fi == NULL)
{
fi = wmem_new0(wmem_file_scope(), aeron_frame_info_t);
fi->frame = frame;
fi->ofs = ofs;
if (aeron_sequence_analysis && aeron_stream_analysis)
{
fi->rx = wmem_list_new(wmem_file_scope());
}
wmem_tree_insert32_array(aeron_frame_info_tree, key, (void *) fi);
}
return (fi);
}
/*----------------------------------------------------------------------------*/
/* Aeron channel ID management. */
/*----------------------------------------------------------------------------*/
static guint64 aeron_channel_id = 1;
static guint64 aeron_channel_id_assign(void)
{
return (aeron_channel_id++);
}
static void aeron_channel_id_init(void)
{
aeron_channel_id = 1;
}
/*----------------------------------------------------------------------------*/
/* Aeron transport, stream, term, and fragment structures. */
/*----------------------------------------------------------------------------*/
typedef struct
{
address * addr1;
address * addr2;
port_type ptype;
guint16 port1;
guint16 port2;
} aeron_conversation_info_t;
struct aeron_transport_t_stct;
typedef struct aeron_transport_t_stct aeron_transport_t;
struct aeron_stream_t_stct;
typedef struct aeron_stream_t_stct aeron_stream_t;
struct aeron_term_t_stct;
typedef struct aeron_term_t_stct aeron_term_t;
struct aeron_fragment_t_stct;
typedef struct aeron_fragment_t_stct aeron_fragment_t;
struct aeron_transport_t_stct
{
guint64 channel_id;
wmem_map_t * stream; /* Map of all streams (aeron_stream_t) in this transport, keyed by stream ID */
aeron_frame_info_t * last_frame;
address addr1;
address addr2;
guint32 session_id;
guint16 port1;
guint16 port2;
};
struct aeron_stream_rcv_t_stct;
typedef struct aeron_stream_rcv_t_stct aeron_stream_rcv_t;
struct aeron_stream_rcv_t_stct
{
address addr; /* Receiver's IP address */
guint16 port; /* Receiver's (sending) port */
aeron_pos_t completed;
guint32 receiver_window;
};
struct aeron_stream_t_stct
{
aeron_transport_t * transport; /* Parent transport */
wmem_map_t * term; /* Map of all terms (aeron_term_t) in this stream, keyed by term ID */
wmem_list_t * rcv; /* List of receivers (aeron_stream_rcv_t) */
guint32 rcv_count;
aeron_frame_info_t * last_frame;
guint32 stream_id;
guint32 term_length;
guint32 mtu;
guint32 flags;
aeron_pos_t high;
};
#define AERON_STREAM_FLAGS_HIGH_VALID 0x1
typedef struct
{
aeron_term_t * term; /* Parent term */
aeron_frame_info_t * frame_info; /* Frame info (aeron_frame_info_t) in which this NAK occurred */
guint32 term_offset; /* NAK term offset */
guint32 length; /* Length of NAK */
} aeron_nak_t;
struct aeron_term_t_stct
{
aeron_stream_t * stream; /* Parent stream */
wmem_map_t * fragment; /* Map of all fragments (aeron_fragment_t) in this term, keyed by term offset */
wmem_tree_t * message; /* Tree of all fragmented messages (aeron_msg_t) in this term, keyed by lowest term offset */
wmem_list_t * orphan_fragment;
aeron_frame_info_t * last_frame; /* Pointer to last frame seen for this term */
wmem_list_t * nak; /* List of all NAKs (aeron_nak_t) in this term */
guint32 term_id;
};
struct aeron_fragment_t_stct
{
aeron_term_t * term; /* Parent term */
wmem_list_t * frame; /* List of frames (aeron_frame_info_t) containing this fragment (term offset) */
aeron_frame_info_t * first_frame; /* First frame which contains this fragment (term offset) */
aeron_frame_info_t * last_frame; /* Last frame which contains this fragment (term offset) */
aeron_frame_info_t * first_data_frame; /* First frame which contains this fragment (term offset) as actual data (not as a KA) */
guint32 term_offset;
guint32 length;
guint32 data_length;
guint32 frame_count;
};
/*----------------------------------------------------------------------------*/
/* Aeron transport management. */
/*----------------------------------------------------------------------------*/
static guint aeron_guint32_hash_func(gconstpointer key)
{
guint32 value = *((const guint32 *) key);
return ((guint) value);
}
static gboolean aeron_guint32_compare_func(gconstpointer lhs, gconstpointer rhs)
{
guint32 key1 = *((const guint32 *) lhs);
guint32 key2 = *((const guint32 *) rhs);
return ((key1 == key2) ? TRUE : FALSE);
}
static aeron_transport_t * aeron_transport_add(const aeron_conversation_info_t * cinfo, guint32 session_id, guint32 frame)
{
aeron_transport_t * transport;
conversation_t * conv;
wmem_map_t * session_map;
conv = find_conversation(frame, cinfo->addr1, cinfo->addr2, cinfo->ptype, cinfo->port1, cinfo->port2, 0);
if (conv == NULL)
{
conv = conversation_new(frame, cinfo->addr1, cinfo->addr2, cinfo->ptype, cinfo->port1, cinfo->port2, 0);
}
if (frame > conv->last_frame)
{
conv->last_frame = frame;
}
session_map = (wmem_map_t *) conversation_get_proto_data(conv, proto_aeron);
if (session_map == NULL)
{
session_map = wmem_map_new(wmem_file_scope(), aeron_guint32_hash_func, aeron_guint32_compare_func);
conversation_add_proto_data(conv, proto_aeron, (void *) session_map);
}
transport = (aeron_transport_t *) wmem_map_lookup(session_map, (const void *) &session_id);
if (transport != NULL)
{
return (transport);
}
transport = wmem_new0(wmem_file_scope(), aeron_transport_t);
transport->channel_id = aeron_channel_id_assign();
transport->stream = wmem_map_new(wmem_file_scope(), aeron_guint32_hash_func, aeron_guint32_compare_func);
transport->last_frame = NULL;
copy_address_wmem(wmem_file_scope(), &(transport->addr1), cinfo->addr1);
copy_address_wmem(wmem_file_scope(), &(transport->addr2), cinfo->addr2);
transport->session_id = session_id;
transport->port1 = cinfo->port1;
transport->port2 = cinfo->port2;
wmem_map_insert(session_map, (const void *) &(transport->session_id), (void *) transport);
return (transport);
}
static aeron_stream_t * aeron_transport_stream_find(aeron_transport_t * transport, guint32 stream_id)
{
aeron_stream_t * stream;
stream = (aeron_stream_t *) wmem_map_lookup(transport->stream, (const void *) &stream_id);
return (stream);
}
static aeron_stream_t * aeron_transport_stream_add(aeron_transport_t * transport, guint32 stream_id)
{
aeron_stream_t * stream;
stream = aeron_transport_stream_find(transport, stream_id);
if (stream == NULL)
{
stream = wmem_new0(wmem_file_scope(), aeron_stream_t);
stream->transport = transport;
stream->term = wmem_map_new(wmem_file_scope(), aeron_guint32_hash_func, aeron_guint32_compare_func);
stream->rcv = wmem_list_new(wmem_file_scope());
stream->rcv_count = 0;
stream->last_frame = NULL;
stream->stream_id = stream_id;
stream->term_length = 0;
stream->mtu = 0;
stream->flags = 0;
stream->high.term_id = 0;
stream->high.term_offset = 0;
wmem_map_insert(transport->stream, (const void *) &(stream->stream_id), (void *) stream);
}
return (stream);
}
static void aeron_transport_frame_add(aeron_transport_t * transport, aeron_frame_info_t * finfo, guint32 flags)
{
if (flags != 0)
{
finfo->flags = flags;
}
if (transport->last_frame != NULL)
{
finfo->transport.previous = transport->last_frame->frame;
transport->last_frame->transport.next = finfo->frame;
}
finfo->transport.next = 0;
transport->last_frame = finfo;
}
/*----------------------------------------------------------------------------*/
/* Aeron stream management. */
/*----------------------------------------------------------------------------*/
static aeron_term_t * aeron_stream_term_find(aeron_stream_t * stream, guint32 term_id)
{
aeron_term_t * term;
term = (aeron_term_t *) wmem_map_lookup(stream->term, (const void *) &term_id);
return (term);
}
static aeron_term_t * aeron_stream_term_add(aeron_stream_t * stream, guint32 term_id)
{
aeron_term_t * term;
term = aeron_stream_term_find(stream, term_id);
if (term == NULL)
{
term = wmem_new0(wmem_file_scope(), aeron_term_t);
term->stream = stream;
term->fragment = wmem_map_new(wmem_file_scope(), aeron_guint32_hash_func, aeron_guint32_compare_func);
term->message = wmem_tree_new(wmem_file_scope());
term->orphan_fragment = wmem_list_new(wmem_file_scope());
term->nak = wmem_list_new(wmem_file_scope());
term->term_id = term_id;
wmem_map_insert(stream->term, (const void *) &(term->term_id), (void *) term);
}
return (term);
}
static aeron_stream_rcv_t * aeron_stream_rcv_find(aeron_stream_t * stream, const address * addr, guint16 port)
{
wmem_list_frame_t * lf = wmem_list_head(stream->rcv);
aeron_stream_rcv_t * rcv = NULL;
while (lf != NULL)
{
aeron_stream_rcv_t * cur = (aeron_stream_rcv_t *) wmem_list_frame_data(lf);
if (cur != NULL)
{
if ((cmp_address(&(cur->addr), addr) == 0) && (cur->port == port))
{
rcv = cur;
break;
}
}
lf = wmem_list_frame_next(lf);
}
return (rcv);
}
static aeron_stream_rcv_t * aeron_stream_rcv_add(aeron_stream_t * stream, const address * addr, guint16 port)
{
aeron_stream_rcv_t * rcv;
rcv = aeron_stream_rcv_find(stream, addr, port);
if (rcv != NULL)
{
return (rcv);
}
rcv = wmem_new0(wmem_file_scope(), aeron_stream_rcv_t);
copy_address_wmem(wmem_file_scope(), &(rcv->addr), addr);
rcv->port = port;
rcv->completed.term_id = 0;
rcv->completed.term_offset = 0;
rcv->receiver_window = 0;
wmem_list_append(stream->rcv, (void *) rcv);
stream->rcv_count++;
return (rcv);
}
static void aeron_stream_frame_add(aeron_stream_t * stream, aeron_frame_info_t * finfo, guint32 flags)
{
if (flags != 0)
{
finfo->flags = flags;
}
if (stream->last_frame != NULL)
{
finfo->stream.previous = stream->last_frame->frame;
stream->last_frame->stream.next = finfo->frame;
}
finfo->stream.next = 0;
stream->last_frame = finfo;
aeron_transport_frame_add(stream->transport, finfo, 0);
}
/*----------------------------------------------------------------------------*/
/* Aeron term management. */
/*----------------------------------------------------------------------------*/
static aeron_fragment_t * aeron_term_fragment_find(aeron_term_t * term, guint32 term_offset)
{
aeron_fragment_t * fragment;
fragment = (aeron_fragment_t *) wmem_map_lookup(term->fragment, (const void *) &term_offset);
return (fragment);
}
static aeron_fragment_t * aeron_term_fragment_add(aeron_term_t * term, guint32 term_offset, guint32 length, guint32 data_length)
{
aeron_fragment_t * fragment;
fragment = aeron_term_fragment_find(term, term_offset);
if (fragment == NULL)
{
fragment = wmem_new0(wmem_file_scope(), aeron_fragment_t);
fragment->term = term;
fragment->frame = wmem_list_new(wmem_file_scope());
fragment->first_frame = NULL;
fragment->last_frame = NULL;
fragment->first_data_frame = NULL;
fragment->term_offset = term_offset;
fragment->length = length;
fragment->data_length = data_length;
fragment->frame_count = 0;
wmem_map_insert(term->fragment, (const void *) &(fragment->term_offset), (void *) fragment);
}
return (fragment);
}
static void aeron_term_frame_add(aeron_term_t * term, aeron_frame_info_t * finfo, guint32 flags)
{
if (flags != 0)
{
finfo->flags = flags;
}
if (term->last_frame != NULL)
{
finfo->term.previous = term->last_frame->frame;
term->last_frame->term.next = finfo->frame;
}
finfo->term.next = 0;
term->last_frame = finfo;
aeron_stream_frame_add(term->stream, finfo, 0);
}
/*----------------------------------------------------------------------------*/
/* Aeron fragment management. */
/*----------------------------------------------------------------------------*/
static void aeron_fragment_frame_add(aeron_fragment_t * fragment, aeron_frame_info_t * finfo, guint32 flags, guint32 length)
{
if (flags != 0)
{
finfo->flags = flags;
}
wmem_list_append(fragment->frame, (void *) finfo);
fragment->frame_count++;
if (fragment->last_frame != NULL)
{
finfo->fragment.previous = fragment->last_frame->frame;
fragment->last_frame->fragment.next = finfo->frame;
}
if (fragment->first_frame == NULL)
{
fragment->first_frame = finfo;
}
if (length != 0)
{
if (fragment->first_data_frame == NULL)
{
fragment->first_data_frame = finfo;
}
}
finfo->fragment.next = 0;
fragment->last_frame = finfo;
aeron_term_frame_add(fragment->term, finfo, 0);
}
/*----------------------------------------------------------------------------*/
/* Utility functions. */
/*----------------------------------------------------------------------------*/
static gboolean aeron_is_address_multicast(const address * addr)
{
const guint8 * addr_data = (const guint8 *) addr->data;
switch (addr->type)
{
case AT_IPv4:
if ((addr_data[0] & 0xf0) == 0xe0)
{
return (TRUE);
}
break;
case AT_IPv6:
if (addr_data[0] == 0xff)
{
return (TRUE);
}
break;
default:
break;
}
return (FALSE);
}
static char * aeron_format_transport_uri(const aeron_conversation_info_t * cinfo)
{
wmem_strbuf_t * uri;
uri = wmem_strbuf_new(wmem_packet_scope(), "aeron:");
switch (cinfo->ptype)
{
case PT_UDP:
wmem_strbuf_append(uri, "udp");
break;
default:
wmem_strbuf_append(uri, "unknown");
break;
}
wmem_strbuf_append_c(uri, '?');
if (aeron_is_address_multicast(cinfo->addr2))
{
switch (cinfo->addr2->type)
{
case AT_IPv6:
wmem_strbuf_append_printf(uri, "group=[%s]:%" G_GUINT16_FORMAT, address_to_str(wmem_packet_scope(), cinfo->addr2), cinfo->port2);
break;
case AT_IPv4:
default:
wmem_strbuf_append_printf(uri, "group=%s:%" G_GUINT16_FORMAT, address_to_str(wmem_packet_scope(), cinfo->addr2), cinfo->port2);
break;
}
}
else
{
switch (cinfo->addr2->type)
{
case AT_IPv6:
wmem_strbuf_append_printf(uri, "remote=[%s]:%" G_GUINT16_FORMAT, address_to_str(wmem_packet_scope(), cinfo->addr2), cinfo->port2);
break;
case AT_IPv4:
default:
wmem_strbuf_append_printf(uri, "remote=%s:%" G_GUINT16_FORMAT, address_to_str(wmem_packet_scope(), cinfo->addr2), cinfo->port2);
break;
}
}
return (wmem_strbuf_finalize(uri));
}
/*----------------------------------------------------------------------------*/
/* Packet definitions. */
/*----------------------------------------------------------------------------*/
/* Basic frame offsets */
#define O_AERON_BASIC_FRAME_LENGTH 0
#define O_AERON_BASIC_VERSION 4
#define O_AERON_BASIC_FLAGS 5
#define O_AERON_BASIC_TYPE 6
#define HDR_LENGTH_MIN 12
/* Padding frame */
#define O_AERON_PAD_FRAME_LENGTH 0
#define O_AERON_PAD_VERSION 4
#define O_AERON_PAD_FLAGS 5
#define O_AERON_PAD_TYPE 6
#define O_AERON_PAD_TERM_OFFSET 8
#define O_AERON_PAD_SESSION_ID 12
#define O_AERON_PAD_STREAM_ID 16
#define O_AERON_PAD_TERM_ID 20
#define L_AERON_PAD_MIN 24
/* Data frame */
#define O_AERON_DATA_FRAME_LENGTH 0
#define O_AERON_DATA_VERSION 4
#define O_AERON_DATA_FLAGS 5
#define O_AERON_DATA_TYPE 6
#define O_AERON_DATA_TERM_OFFSET 8
#define O_AERON_DATA_SESSION_ID 12
#define O_AERON_DATA_STREAM_ID 16
#define O_AERON_DATA_TERM_ID 20
#define O_AERON_DATA_DATA 24
#define L_AERON_DATA_MIN 24
/* NAK frame */
#define O_AERON_NAK_FRAME_LENGTH 0
#define O_AERON_NAK_VERSION 4
#define O_AERON_NAK_FLAGS 5
#define O_AERON_NAK_TYPE 6
#define O_AERON_NAK_SESSION_ID 8
#define O_AERON_NAK_STREAM_ID 12
#define O_AERON_NAK_TERM_ID 16
#define O_AERON_NAK_TERM_OFFSET 20
#define O_AERON_NAK_LENGTH 24
#define L_AERON_NAK 28
/* Status message */
#define O_AERON_SM_FRAME_LENGTH 0
#define O_AERON_SM_VERSION 4
#define O_AERON_SM_FLAGS 5
#define O_AERON_SM_TYPE 6
#define O_AERON_SM_SESSION_ID 8
#define O_AERON_SM_STREAM_ID 12
#define O_AERON_SM_TERM_ID 16
#define O_AERON_SM_COMPLETED_TERM_OFFSET 20
#define O_AERON_SM_RECEIVER_WINDOW 24
#define O_AERON_SM_FEEDBACK 28
#define L_AERON_SM_MIN 28
/* Error header */
#define O_AERON_ERR_FRAME_LENGTH 0
#define O_AERON_ERR_VERSION 4
#define O_AERON_ERR_CODE 5
#define O_AERON_ERR_TYPE 6
#define O_AERON_ERR_OFFENDING_FRAME_LENGTH 8
#define O_AERON_ERR_OFFENDING_HEADER 12
#define O_AERON_ERR_TERM_ID 16
#define O_AERON_ERR_COMPLETED_TERM_OFFSET 20
#define O_AERON_ERR_RECEIVER_WINDOW 24
#define O_AERON_ERR_FEEDBACK 28
#define L_AERON_ERR_MIN 12
/* Setup frame */
#define O_AERON_SETUP_FRAME_LENGTH 0
#define O_AERON_SETUP_VERSION 4
#define O_AERON_SETUP_FLAGS 5
#define O_AERON_SETUP_TYPE 6
#define O_AERON_SETUP_TERM_OFFSET 8
#define O_AERON_SETUP_SESSION_ID 12
#define O_AERON_SETUP_STREAM_ID 16
#define O_AERON_SETUP_INITIAL_TERM_ID 20
#define O_AERON_SETUP_ACTIVE_TERM_ID 24
#define O_AERON_SETUP_TERM_LENGTH 28
#define O_AERON_SETUP_MTU 32
#define L_AERON_SETUP 36
#define HDR_TYPE_PAD 0x0000
#define HDR_TYPE_DATA 0x0001
#define HDR_TYPE_NAK 0x0002
#define HDR_TYPE_SM 0x0003
#define HDR_TYPE_ERR 0x0004
#define HDR_TYPE_SETUP 0x0005
#define HDR_TYPE_EXT 0xFFFF
#define DATA_FLAGS_BEGIN 0x80
#define DATA_FLAGS_END 0x40
#define DATA_FLAGS_COMPLETE (DATA_FLAGS_BEGIN | DATA_FLAGS_END)
#define STATUS_FLAGS_SETUP 0x80
/*----------------------------------------------------------------------------*/
/* Value translation tables. */
/*----------------------------------------------------------------------------*/
static const value_string aeron_frame_type[] =
{
{ HDR_TYPE_PAD, "Pad" },
{ HDR_TYPE_DATA, "Data" },
{ HDR_TYPE_NAK, "NAK" },
{ HDR_TYPE_SM, "Status" },
{ HDR_TYPE_ERR, "Error" },
{ HDR_TYPE_SETUP, "Setup" },
{ HDR_TYPE_EXT, "Extension" },
{ 0x0, NULL }
};
/*
Aeron conversations:
UDP unicast:
- The URL specifies the subscriber address and UDP port, and the publisher "connects" to the single subscriber.
- The publisher sends Pad, Data, and Setup frames to the subscriber address and port.
- The subscriber sends NAK and SM frames to the publisher, using as the destination the address and port from
which the Setup and Data frames were received
- So the conversation is defined by [A(publisher),A(subscriber),P(publisher),P(subscriber),PT_UDP]
UDP multicast:
- The URL specifies the data multicast group and UDP port, and must be an odd-numbered address. The control multicast
group is automatically set to be one greater than the data multicast group, and the same port is used.
- The publisher sends Pad, Data, and Setup frames to the data multicast group and port.
- The subscriber sends NAK and SM frames to the control multicast group and port.
- So the conversation is defined by [ControlGroup,DataGroup,port,port,PT_UDP]
*/
static aeron_conversation_info_t * aeron_setup_conversation_info(const packet_info * pinfo, guint16 type)
{
aeron_conversation_info_t * cinfo;
int addr_len = pinfo->dst.len;
cinfo = wmem_new0(wmem_packet_scope(), aeron_conversation_info_t);
cinfo->ptype = pinfo->ptype;
switch (pinfo->dst.type)
{
case AT_IPv4:
{
const guint8 * dst_addr = (const guint8 *) pinfo->dst.data;
cinfo->addr1 = wmem_new0(wmem_packet_scope(), address);
cinfo->addr2 = wmem_new0(wmem_packet_scope(), address);
if (aeron_is_address_multicast(&(pinfo->dst)))
{
guint8 * addr1;
guint8 * addr2;
addr1 = (guint8 *) wmem_memdup(wmem_packet_scope(), (const void *) dst_addr, (size_t) addr_len);
addr2 = (guint8 *) wmem_memdup(wmem_packet_scope(), (const void *) dst_addr, (size_t) addr_len);
if ((dst_addr[addr_len - 1] & 0x1) != 0)
{
/* Address is odd, so it's the data group (in addr2). Increment the last byte of addr1 for the control group. */
addr1[addr_len - 1]++;
}
else
{
/* Address is even, so it's the control group (in addr1). Decrement the last byte of addr2 for the data group. */
addr2[addr_len - 1]--;
}
set_address(cinfo->addr1, AT_IPv4, addr_len, (void *) addr1);
set_address(cinfo->addr2, AT_IPv4, addr_len, (void *) addr2);
cinfo->port1 = pinfo->destport;
cinfo->port2 = cinfo->port1;
}
else
{
switch (type)
{
case HDR_TYPE_PAD:
case HDR_TYPE_DATA:
case HDR_TYPE_SETUP:
/* Destination is a receiver */
copy_address_wmem(wmem_packet_scope(), cinfo->addr1, &(pinfo->src));
cinfo->port1 = pinfo->srcport;
copy_address_wmem(wmem_packet_scope(), cinfo->addr2, &(pinfo->dst));
cinfo->port2 = pinfo->destport;
break;
case HDR_TYPE_NAK:
case HDR_TYPE_SM:
/* Destination is the source */
copy_address_wmem(wmem_packet_scope(), cinfo->addr1, &(pinfo->dst));
cinfo->port1 = pinfo->destport;
copy_address_wmem(wmem_packet_scope(), cinfo->addr2, &(pinfo->src));
cinfo->port2 = pinfo->srcport;
break;
default:
break;
}
}
}
break;
case AT_IPv6:
{
const guint8 * dst_addr = (const guint8 *) pinfo->dst.data;
cinfo->addr1 = wmem_new0(wmem_packet_scope(), address);
cinfo->addr2 = wmem_new0(wmem_packet_scope(), address);
if (aeron_is_address_multicast(&(pinfo->dst)))
{
guint8 * addr1;
guint8 * addr2;
addr1 = (guint8 *) wmem_memdup(wmem_packet_scope(), (const void *) dst_addr, (size_t) addr_len);
addr2 = (guint8 *) wmem_memdup(wmem_packet_scope(), (const void *) dst_addr, (size_t) addr_len);
if ((dst_addr[addr_len - 1] & 0x1) != 0)
{
/* Address is odd, so it's the data group (in addr2). Increment the last byte of addr1 for the control group. */
addr1[addr_len - 1]++;
}
else
{
/* Address is even, so it's the control group (in addr1). Decrement the last byte of addr2 for the data group. */
addr2[addr_len - 1]--;
}
set_address(cinfo->addr1, AT_IPv6, addr_len, (void *) addr1);
set_address(cinfo->addr2, AT_IPv6, addr_len, (void *) addr2);
cinfo->port1 = pinfo->destport;
cinfo->port2 = cinfo->port1;
}
else
{
switch (type)
{
case HDR_TYPE_PAD:
case HDR_TYPE_DATA:
case HDR_TYPE_SETUP:
/* Destination is a receiver */
copy_address_wmem(wmem_packet_scope(), cinfo->addr1, &(pinfo->src));
cinfo->port1 = pinfo->srcport;
copy_address_wmem(wmem_packet_scope(), cinfo->addr2, &(pinfo->dst));
cinfo->port2 = pinfo->destport;
break;
case HDR_TYPE_NAK:
case HDR_TYPE_SM:
/* Destination is the source */
copy_address_wmem(wmem_packet_scope(), cinfo->addr1, &(pinfo->dst));
cinfo->port1 = pinfo->destport;
copy_address_wmem(wmem_packet_scope(), cinfo->addr2, &(pinfo->src));
cinfo->port2 = pinfo->srcport;
break;
default:
break;
}
}
}
break;
default:
return (NULL);
}
return (cinfo);
}
/*----------------------------------------------------------------------------*/
/* Handles of all types. */
/*----------------------------------------------------------------------------*/
/* Dissector tree handles */
static gint ett_aeron = -1;
static gint ett_aeron_pad = -1;
static gint ett_aeron_data = -1;
static gint ett_aeron_data_flags = -1;
static gint ett_aeron_data_reassembly = -1;
static gint ett_aeron_nak = -1;
static gint ett_aeron_sm = -1;
static gint ett_aeron_sm_flags = -1;
static gint ett_aeron_err = -1;
static gint ett_aeron_setup = -1;
static gint ett_aeron_ext = -1;
static gint ett_aeron_sequence_analysis = -1;
static gint ett_aeron_sequence_analysis_retransmission_rx = -1;
static gint ett_aeron_sequence_analysis_nak_rx = -1;
static gint ett_aeron_sequence_analysis_term_offset = -1;
static gint ett_aeron_stream_analysis = -1;
/* Dissector field handles */
static int hf_aeron_channel_id = -1;
static int hf_aeron_pad = -1;
static int hf_aeron_pad_frame_length = -1;
static int hf_aeron_pad_version = -1;
static int hf_aeron_pad_flags = -1;
static int hf_aeron_pad_type = -1;
static int hf_aeron_pad_term_offset = -1;
static int hf_aeron_pad_session_id = -1;
static int hf_aeron_pad_stream_id = -1;
static int hf_aeron_pad_term_id = -1;
static int hf_aeron_data = -1;
static int hf_aeron_data_frame_length = -1;
static int hf_aeron_data_version = -1;
static int hf_aeron_data_flags = -1;
static int hf_aeron_data_flags_b = -1;
static int hf_aeron_data_flags_e = -1;
static int hf_aeron_data_type = -1;
static int hf_aeron_data_term_offset = -1;
static int hf_aeron_data_next_offset = -1;
static int hf_aeron_data_next_offset_term = -1;
static int hf_aeron_data_next_offset_first_frame = -1;
static int hf_aeron_data_session_id = -1;
static int hf_aeron_data_stream_id = -1;
static int hf_aeron_data_term_id = -1;
static int hf_aeron_data_reassembly = -1;
static int hf_aeron_data_reassembly_fragment = -1;
static int hf_aeron_nak = -1;
static int hf_aeron_nak_frame_length = -1;
static int hf_aeron_nak_version = -1;
static int hf_aeron_nak_flags = -1;
static int hf_aeron_nak_type = -1;
static int hf_aeron_nak_session_id = -1;
static int hf_aeron_nak_stream_id = -1;
static int hf_aeron_nak_term_id = -1;
static int hf_aeron_nak_term_offset = -1;
static int hf_aeron_nak_length = -1;
static int hf_aeron_sm = -1;
static int hf_aeron_sm_frame_length = -1;
static int hf_aeron_sm_version = -1;
static int hf_aeron_sm_flags = -1;
static int hf_aeron_sm_flags_s = -1;
static int hf_aeron_sm_type = -1;
static int hf_aeron_sm_session_id = -1;
static int hf_aeron_sm_stream_id = -1;
static int hf_aeron_sm_consumption_term_id = -1;
static int hf_aeron_sm_consumption_term_offset = -1;
static int hf_aeron_sm_receiver_window = -1;
static int hf_aeron_sm_feedback = -1;
static int hf_aeron_err = -1;
static int hf_aeron_err_frame_length = -1;
static int hf_aeron_err_version = -1;
static int hf_aeron_err_code = -1;
static int hf_aeron_err_type = -1;
static int hf_aeron_err_off_frame_length = -1;
static int hf_aeron_err_off_hdr = -1;
static int hf_aeron_err_string = -1;
static int hf_aeron_setup = -1;
static int hf_aeron_setup_frame_length = -1;
static int hf_aeron_setup_version = -1;
static int hf_aeron_setup_flags = -1;
static int hf_aeron_setup_type = -1;
static int hf_aeron_setup_term_offset = -1;
static int hf_aeron_setup_session_id = -1;
static int hf_aeron_setup_stream_id = -1;
static int hf_aeron_setup_initial_term_id = -1;
static int hf_aeron_setup_active_term_id = -1;
static int hf_aeron_setup_term_length = -1;
static int hf_aeron_setup_mtu = -1;
static int hf_aeron_sequence_analysis = -1;
static int hf_aeron_sequence_analysis_channel_prev_frame = -1;
static int hf_aeron_sequence_analysis_channel_next_frame = -1;
static int hf_aeron_sequence_analysis_stream_prev_frame = -1;
static int hf_aeron_sequence_analysis_stream_next_frame = -1;
static int hf_aeron_sequence_analysis_term_prev_frame = -1;
static int hf_aeron_sequence_analysis_term_next_frame = -1;
static int hf_aeron_sequence_analysis_term_offset = -1;
static int hf_aeron_sequence_analysis_term_offset_frame = -1;
static int hf_aeron_sequence_analysis_retransmission = -1;
static int hf_aeron_sequence_analysis_retransmission_rx = -1;
static int hf_aeron_sequence_analysis_retransmission_rx_frame = -1;
static int hf_aeron_sequence_analysis_keepalive = -1;
static int hf_aeron_sequence_analysis_nak_unrecovered = -1;
static int hf_aeron_sequence_analysis_nak_rx = -1;
static int hf_aeron_sequence_analysis_nak_rx_frame = -1;
static int hf_aeron_stream_analysis = -1;
static int hf_aeron_stream_analysis_high_term_id = -1;
static int hf_aeron_stream_analysis_high_term_offset = -1;
static int hf_aeron_stream_analysis_completed_term_id = -1;
static int hf_aeron_stream_analysis_completed_term_offset = -1;
static int hf_aeron_stream_analysis_outstanding_bytes = -1;
/* Expert info handles */
static expert_field ei_aeron_analysis_nak = EI_INIT;
static expert_field ei_aeron_analysis_window_full = EI_INIT;
static expert_field ei_aeron_analysis_idle_rx = EI_INIT;
static expert_field ei_aeron_analysis_pacing_rx = EI_INIT;
static expert_field ei_aeron_analysis_ooo = EI_INIT;
static expert_field ei_aeron_analysis_ooo_gap = EI_INIT;
static expert_field ei_aeron_analysis_keepalive = EI_INIT;
static expert_field ei_aeron_analysis_ooo_sm = EI_INIT;
static expert_field ei_aeron_analysis_keepalive_sm = EI_INIT;
static expert_field ei_aeron_analysis_window_resize = EI_INIT;
static expert_field ei_aeron_analysis_rx = EI_INIT;
static expert_field ei_aeron_analysis_term_id_change = EI_INIT;
static expert_field ei_aeron_analysis_invalid_pad_length = EI_INIT;
static expert_field ei_aeron_analysis_invalid_data_length = EI_INIT;
static expert_field ei_aeron_analysis_invalid_nak_length = EI_INIT;
static expert_field ei_aeron_analysis_invalid_sm_length = EI_INIT;
static expert_field ei_aeron_analysis_invalid_err_length = EI_INIT;
static expert_field ei_aeron_analysis_invalid_setup_length = EI_INIT;
/*----------------------------------------------------------------------------*/
/* Setup packet information */
/*----------------------------------------------------------------------------*/
typedef struct
{
guint32 info_flags;
guint32 stream_id;
guint32 term_id;
guint32 term_offset;
guint32 length;
guint32 data_length;
guint32 receiver_window;
guint32 nak_term_offset;
guint32 nak_length;
guint16 type;
guint8 flags;
} aeron_packet_info_t;
#define AERON_PACKET_INFO_FLAGS_STREAM_ID_VALID 0x00000001
#define AERON_PACKET_INFO_FLAGS_TERM_ID_VALID 0x00000002
#define AERON_PACKET_INFO_FLAGS_TERM_OFFSET_VALID 0x00000004
static void aeron_frame_nak_rx_add(aeron_frame_info_t * nak_info, aeron_frame_info_t * rx_info, guint32 term_offset, guint32 length)
{
if (nak_info->nak_analysis->unrecovered_length >= length)
{
wmem_list_frame_t * lf = wmem_list_head(nak_info->nak_analysis->rx);
aeron_rx_info_t * rx = NULL;
while (lf != NULL)
{
rx = (aeron_rx_info_t *) wmem_list_frame_data(lf);
if (rx != NULL)
{
if ((rx->term_offset == term_offset) && (rx->length == length))
{
/* Already have this RX */
return;
}
}
lf = wmem_list_frame_next(lf);
}
/* This RX frame isn't in the list, so add it */
rx = wmem_new0(wmem_file_scope(), aeron_rx_info_t);
rx->frame_info = rx_info;
rx->term_offset = term_offset;
rx->length = length;
wmem_list_append(nak_info->nak_analysis->rx, (void *) rx);
nak_info->nak_analysis->unrecovered_length -= length;
wmem_list_append(rx_info->rx, (void *) nak_info);
}
}
static void aeron_frame_process_rx(aeron_packet_info_t * info, aeron_frame_info_t * finfo, aeron_term_t * term)
{
wmem_list_frame_t * lf;
lf = wmem_list_head(term->nak);
while (lf != NULL)
{
aeron_nak_t * nak = (aeron_nak_t *) wmem_list_frame_data(lf);
if (nak != NULL)
{
if (nak->frame_info->frame <= finfo->frame)
{
if ((nak->term_offset <= info->term_offset) && (nak->length >= info->length))
{
/* This data frame falls entirely within the NAK range */
aeron_frame_nak_rx_add(nak->frame_info, finfo, info->term_offset, info->length);
}
}
}
lf = wmem_list_frame_next(lf);
}
}
static void aeron_frame_nak_analysis_setup(aeron_packet_info_t * info, aeron_frame_info_t * finfo, aeron_term_t * term)
{
aeron_nak_t * nak = wmem_new0(wmem_file_scope(), aeron_nak_t);
nak->term = term;
nak->frame_info = finfo;
nak->term_offset = info->nak_term_offset;
nak->length = info->nak_length;
wmem_list_append(term->nak, (void *) nak);
finfo->nak_analysis = wmem_new0(wmem_file_scope(), aeron_nak_analysis_t);
finfo->nak_analysis->frame_info = finfo;
finfo->nak_analysis->rx = wmem_list_new(wmem_file_scope());
finfo->nak_analysis->nak_term_offset = info->nak_term_offset;
finfo->nak_analysis->nak_length = info->nak_length;
finfo->nak_analysis->unrecovered_length = info->nak_length;
}
/* return 0 for success and -1 for error */
static int aeron_frame_stream_analysis_setup(packet_info * pinfo, aeron_packet_info_t * info, aeron_frame_info_t * finfo, aeron_stream_t * stream, aeron_term_t * term, gboolean new_term)
{
aeron_stream_rcv_t * rcv = NULL;
/* dp is the current data position (from this frame). */
aeron_pos_t dp = { 0, 0 };
/*
pdp is the previous (high) data position (from the stream).
pdpv is TRUE if pdp is valid (meaning we previously saw a data message).
*/
aeron_pos_t pdp = stream->high;
gboolean pdpv = ((stream->flags & AERON_STREAM_FLAGS_HIGH_VALID) != 0);
/* rp is the current receiver position (from this frame). */
aeron_pos_t rp = { 0, 0 };
/*
prp is the previous (high) receiver completed position (from the stream receiver).
prpv is TRUE if prp is valid (meaning we previously saw a status message).
*/
aeron_pos_t prp = { 0, 0 };
gboolean prpv = FALSE;
guint32 cur_receiver_window = 0;
/* Flags to be used when creating the fragment frame entry */
guint32 frame_flags = 0;
if (info->type == HDR_TYPE_SM)
{
/* Locate the receiver */
rcv = aeron_stream_rcv_find(stream, &(pinfo->src), pinfo->srcport);
if (rcv == NULL)
{
rcv = aeron_stream_rcv_add(stream, &(pinfo->src), pinfo->srcport);
}
else
{
prpv = TRUE;
prp = rcv->completed;
cur_receiver_window = rcv->receiver_window;
}
}
switch (info->type)
{
case HDR_TYPE_DATA:
case HDR_TYPE_PAD:
dp.term_id = info->term_id;
dp.term_offset = info->term_offset;
if (!aeron_pos_add_length(&dp, info->length, stream->term_length))
return -1;
if (pdpv)
{
if (dp.term_id > stream->high.term_id)
{
stream->high.term_id = dp.term_id;
stream->high.term_offset = dp.term_offset;
}
else if (dp.term_offset > stream->high.term_offset)
{
stream->high.term_offset = dp.term_offset;
}
}
else
{
stream->flags |= AERON_STREAM_FLAGS_HIGH_VALID;
stream->high.term_id = dp.term_id;
stream->high.term_offset = dp.term_offset;
}
break;
case HDR_TYPE_SM:
rp.term_id = info->term_id;
rp.term_offset = info->term_offset;
if (prpv)
{
if (rp.term_id > rcv->completed.term_id)
{
rcv->completed.term_id = rp.term_id;
rcv->completed.term_offset = rp.term_offset;
}
else if (rp.term_offset > rcv->completed.term_offset)
{
rcv->completed.term_offset = rp.term_offset;
}
}
else
{
rcv->completed.term_id = rp.term_id;
rcv->completed.term_offset = rp.term_offset;
}
rcv->receiver_window = info->receiver_window;
break;
default:
break;
}
if (aeron_stream_analysis)
{
if ((stream->flags & AERON_STREAM_FLAGS_HIGH_VALID) != 0)
{
finfo->stream_analysis = wmem_new0(wmem_file_scope(), aeron_stream_analysis_t);
}
}
if (finfo->stream_analysis != NULL)
{
switch (info->type)
{
case HDR_TYPE_DATA:
case HDR_TYPE_SM:
case HDR_TYPE_PAD:
finfo->stream_analysis->high.term_id = stream->high.term_id;
finfo->stream_analysis->high.term_offset = stream->high.term_offset;
if (rcv != NULL)
{
finfo->stream_analysis->flags2 |= AERON_STREAM_ANALYSIS_FLAGS2_RCV_VALID;
finfo->stream_analysis->completed.term_id = rcv->completed.term_id;
finfo->stream_analysis->completed.term_offset = rcv->completed.term_offset;
finfo->stream_analysis->receiver_window = rcv->receiver_window;
finfo->stream_analysis->outstanding_bytes = aeron_pos_delta(&(finfo->stream_analysis->high), &(finfo->stream_analysis->completed), stream->term_length);
if (finfo->stream_analysis->outstanding_bytes >= finfo->stream_analysis->receiver_window)
{
finfo->stream_analysis->flags |= AERON_STREAM_ANALYSIS_FLAGS_WINDOW_FULL;
}
}
else
{
finfo->stream_analysis->completed.term_id = 0;
finfo->stream_analysis->completed.term_offset = 0;
finfo->stream_analysis->receiver_window = 0;
finfo->stream_analysis->outstanding_bytes = 0;
}
break;
default:
break;
}
switch (info->type)
{
case HDR_TYPE_DATA:
case HDR_TYPE_PAD:
if (pdpv)
{
/* We have a previous data position. */
int rc = aeron_pos_compare(&dp, &pdp);
if (rc == 0)
{
/* Data position is the same as previous data position. */
if (info->length == 0)
{
finfo->stream_analysis->flags |= AERON_STREAM_ANALYSIS_FLAGS_KEEPALIVE;
frame_flags |= AERON_FRAME_INFO_FLAGS_KEEPALIVE;
}
else
{
if (prpv)
{
/* Previous receiver position is valid */
if (aeron_pos_compare(&dp, &prp) == 0)
{
finfo->stream_analysis->flags |= AERON_STREAM_ANALYSIS_FLAGS_IDLE_RX;
}
else
{
finfo->stream_analysis->flags |= AERON_STREAM_ANALYSIS_FLAGS_PACING_RX;
}
}
else
{
finfo->stream_analysis->flags |= AERON_STREAM_ANALYSIS_FLAGS_IDLE_RX;
}
frame_flags |= AERON_FRAME_INFO_FLAGS_RETRANSMISSION;
}
}
else
{
aeron_pos_t expected_dp;
int erc;
expected_dp.term_id = pdp.term_id;
expected_dp.term_offset = pdp.term_offset;
if (!aeron_pos_add_length(&expected_dp, info->length, stream->term_length))
return -1;
erc = aeron_pos_compare(&expected_dp, &dp);
if (erc > 0)
{
/* Could be OOO - but for now assume it's a RX */
finfo->stream_analysis->flags |= AERON_STREAM_ANALYSIS_FLAGS_RX;
frame_flags |= AERON_FRAME_INFO_FLAGS_RETRANSMISSION;
aeron_frame_process_rx(info, finfo, term);
}
else if (erc < 0)
{
finfo->stream_analysis->flags |= AERON_STREAM_ANALYSIS_FLAGS_OOO_GAP;
}
}
}
if (new_term && (info->term_offset == 0))
{
finfo->stream_analysis->flags |= AERON_STREAM_ANALYSIS_FLAGS_TERM_ID_CHANGE;
}
break;
case HDR_TYPE_SM:
if (prpv)
{
int rc = aeron_pos_compare(&rp, &prp);
if (rc == 0)
{
/* Completed term ID and term offset stayed the same. */
finfo->stream_analysis->flags |= AERON_STREAM_ANALYSIS_FLAGS_KEEPALIVE_SM;
}
else if (rc < 0)
{
finfo->stream_analysis->flags |= AERON_STREAM_ANALYSIS_FLAGS_OOO_SM;
}
if (cur_receiver_window != finfo->stream_analysis->receiver_window)
{
finfo->stream_analysis->flags |= AERON_STREAM_ANALYSIS_FLAGS_WINDOW_RESIZE;
}
}
break;
default:
break;
}
}
if ((info->type == HDR_TYPE_DATA) || (info->type == HDR_TYPE_PAD))
{
aeron_fragment_t * fragment;
fragment = aeron_term_fragment_find(term, info->term_offset);
if (fragment == NULL)
{
fragment = aeron_term_fragment_add(term, info->term_offset, info->length, info->data_length);
}
aeron_fragment_frame_add(fragment, finfo, frame_flags, info->length);
}
else
{
aeron_term_frame_add(term, finfo, frame_flags);
}
return 0;
}
/* return 0 for success and -1 for error */
static int aeron_frame_info_setup(packet_info * pinfo, aeron_transport_t * transport, aeron_packet_info_t * info, aeron_frame_info_t * finfo)
{
if (!transport || !aeron_sequence_analysis || !finfo || PINFO_FD_VISITED(pinfo))
/* XXX - is it an error if transport, aeron_sequence_analysis or finfo are NULL? */
return 0;
if ((info->info_flags & AERON_PACKET_INFO_FLAGS_STREAM_ID_VALID) != 0)
{
aeron_stream_t * stream;
stream = aeron_transport_stream_find(transport, info->stream_id);
if (stream == NULL)
{
stream = aeron_transport_stream_add(transport, info->stream_id);
}
if ((info->info_flags & AERON_PACKET_INFO_FLAGS_TERM_ID_VALID) != 0)
{
aeron_term_t * term;
gboolean new_term = FALSE;
term = aeron_stream_term_find(stream, info->term_id);
if (term == NULL)
{
term = aeron_stream_term_add(stream, info->term_id);
new_term = TRUE;
}
if ((info->info_flags & AERON_PACKET_INFO_FLAGS_TERM_OFFSET_VALID) != 0)
{
if (aeron_frame_stream_analysis_setup(pinfo, info, finfo, stream, term, new_term) < 0)
return -1;
}
else
{
aeron_term_frame_add(term, finfo, 0);
if (info->type == HDR_TYPE_NAK)
{
aeron_frame_nak_analysis_setup(info, finfo, term);
}
}
}
else
{
aeron_stream_frame_add(stream, finfo, 0);
}
}
else
{
aeron_transport_frame_add(transport, finfo, 0);
}
return 0;
}
static void aeron_sequence_report_frame(tvbuff_t * tvb, proto_tree * tree, aeron_frame_info_t * finfo)
{
proto_item * item = NULL;
if ((finfo->flags & AERON_FRAME_INFO_FLAGS_RETRANSMISSION) != 0)
{
item = proto_tree_add_uint_format_value(tree, hf_aeron_sequence_analysis_term_offset_frame, tvb, 0, 0, finfo->frame, "%" G_GUINT32_FORMAT " (RX)", finfo->frame);
}
else if ((finfo->flags & AERON_FRAME_INFO_FLAGS_KEEPALIVE) != 0)
{
item = proto_tree_add_uint_format_value(tree, hf_aeron_sequence_analysis_term_offset_frame, tvb, 0, 0, finfo->frame, "%" G_GUINT32_FORMAT " (KA)", finfo->frame);
}
else
{
item = proto_tree_add_uint(tree, hf_aeron_sequence_analysis_term_offset_frame, tvb, 0, 0, finfo->frame);
}
PROTO_ITEM_SET_GENERATED(item);
}
static void aeron_sequence_report(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, aeron_transport_t * transport, aeron_packet_info_t * info, aeron_frame_info_t * finfo)
{
if (transport != NULL)
{
if (aeron_sequence_analysis && (finfo != NULL))
{
proto_tree * subtree;
proto_item * item;
item = proto_tree_add_item(tree, hf_aeron_sequence_analysis, tvb, 0, 0, ENC_NA);
PROTO_ITEM_SET_GENERATED(item);
subtree = proto_item_add_subtree(item, ett_aeron_sequence_analysis);
if (finfo->transport.previous != 0)
{
item = proto_tree_add_uint(subtree, hf_aeron_sequence_analysis_channel_prev_frame, tvb, 0, 0, finfo->transport.previous);
PROTO_ITEM_SET_GENERATED(item);
}
if (finfo->transport.next != 0)
{
item = proto_tree_add_uint(subtree, hf_aeron_sequence_analysis_channel_next_frame, tvb, 0, 0, finfo->transport.next);
PROTO_ITEM_SET_GENERATED(item);
}
if ((info->info_flags & AERON_PACKET_INFO_FLAGS_STREAM_ID_VALID) != 0)
{
aeron_stream_t * stream;
stream = aeron_transport_stream_find(transport, info->stream_id);
if (stream != NULL)
{
if (finfo->stream.previous != 0)
{
item = proto_tree_add_uint(subtree, hf_aeron_sequence_analysis_stream_prev_frame, tvb, 0, 0, finfo->stream.previous);
PROTO_ITEM_SET_GENERATED(item);
}
if (finfo->stream.next != 0)
{
item = proto_tree_add_uint(subtree, hf_aeron_sequence_analysis_stream_next_frame, tvb, 0, 0, finfo->stream.next);
PROTO_ITEM_SET_GENERATED(item);
}
if ((info->info_flags & AERON_PACKET_INFO_FLAGS_TERM_ID_VALID) != 0)
{
aeron_term_t * term;
term = aeron_stream_term_find(stream, info->term_id);
if (term != NULL)
{
if (finfo->term.previous != 0)
{
item = proto_tree_add_uint(subtree, hf_aeron_sequence_analysis_term_prev_frame, tvb, 0, 0, finfo->term.previous);
PROTO_ITEM_SET_GENERATED(item);
}
if (finfo->term.next != 0)
{
item = proto_tree_add_uint(subtree, hf_aeron_sequence_analysis_term_next_frame, tvb, 0, 0, finfo->term.next);
PROTO_ITEM_SET_GENERATED(item);
}
if ((info->info_flags & AERON_PACKET_INFO_FLAGS_TERM_OFFSET_VALID) != 0)
{
if ((info->type == HDR_TYPE_DATA) || (info->type == HDR_TYPE_PAD))
{
aeron_fragment_t * fragment;
fragment = aeron_term_fragment_find(term, info->term_offset);
if (fragment != NULL)
{
proto_item * fei_item;
gboolean rx = ((finfo->flags & AERON_FRAME_INFO_FLAGS_RETRANSMISSION) != 0);
gboolean ka = ((finfo->flags & AERON_FRAME_INFO_FLAGS_KEEPALIVE) != 0);
if (fragment->frame_count > 1)
{
proto_tree * frame_tree;
proto_item * frame_item;
wmem_list_frame_t * lf;
frame_item = proto_tree_add_item(subtree, hf_aeron_sequence_analysis_term_offset, tvb, 0, 0, ENC_NA);
PROTO_ITEM_SET_GENERATED(frame_item);
frame_tree = proto_item_add_subtree(frame_item, ett_aeron_sequence_analysis_term_offset);
lf = wmem_list_head(fragment->frame);
while (lf != NULL)
{
aeron_frame_info_t * frag_frame = (aeron_frame_info_t *) wmem_list_frame_data(lf);
if (frag_frame != NULL)
{
if (frag_frame->frame != pinfo->num)
{
aeron_sequence_report_frame(tvb, frame_tree, frag_frame);
}
}
lf = wmem_list_frame_next(lf);
}
}
fei_item = proto_tree_add_boolean(subtree, hf_aeron_sequence_analysis_retransmission, tvb, 0, 0, rx);
PROTO_ITEM_SET_GENERATED(fei_item);
if (rx)
{
if (wmem_list_count(finfo->rx) > 0)
{
proto_tree * rx_tree;
proto_item * rx_item;
wmem_list_frame_t * lf;
rx_item = proto_tree_add_item(subtree, hf_aeron_sequence_analysis_retransmission_rx, tvb, 0, 0, ENC_NA);
PROTO_ITEM_SET_GENERATED(rx_item);
rx_tree = proto_item_add_subtree(rx_item, ett_aeron_sequence_analysis_retransmission_rx);
lf = wmem_list_head(finfo->rx);
while (lf != NULL)
{
aeron_frame_info_t * nak = (aeron_frame_info_t *) wmem_list_frame_data(lf);
if (nak != NULL)
{
rx_item = proto_tree_add_uint(rx_tree, hf_aeron_sequence_analysis_retransmission_rx_frame, tvb, 0, 0, nak->frame);
PROTO_ITEM_SET_GENERATED(rx_item);
}
lf = wmem_list_frame_next(lf);
}
}
}
fei_item = proto_tree_add_boolean(subtree, hf_aeron_sequence_analysis_keepalive, tvb, 0, 0, ka);
PROTO_ITEM_SET_GENERATED(fei_item);
}
}
}
else if ((info->type == HDR_TYPE_NAK) && (finfo->nak_analysis != NULL))
{
proto_item * nak_item;
nak_item = proto_tree_add_uint(subtree, hf_aeron_sequence_analysis_nak_unrecovered, tvb, 0, 0, finfo->nak_analysis->unrecovered_length);
PROTO_ITEM_SET_GENERATED(nak_item);
if (wmem_list_count(finfo->nak_analysis->rx) > 0)
{
proto_tree * rx_tree;
proto_item * rx_item;
wmem_list_frame_t * lf;
rx_item = proto_tree_add_item(subtree, hf_aeron_sequence_analysis_nak_rx, tvb, 0, 0, ENC_NA);
PROTO_ITEM_SET_GENERATED(rx_item);
rx_tree = proto_item_add_subtree(rx_item, ett_aeron_sequence_analysis_nak_rx);
lf = wmem_list_head(finfo->nak_analysis->rx);
while (lf != NULL)
{
aeron_rx_info_t * rx = (aeron_rx_info_t *) wmem_list_frame_data(lf);
if (rx != NULL)
{
rx_item = proto_tree_add_uint_format_value(rx_tree, hf_aeron_sequence_analysis_nak_rx_frame, tvb, 0, 0, rx->frame_info->frame,
"%" G_GUINT32_FORMAT ", Term offset=%" G_GUINT32_FORMAT " (0x%08x), Length=%" G_GUINT32_FORMAT, rx->frame_info->frame, rx->term_offset, rx->term_offset, rx->length);
PROTO_ITEM_SET_GENERATED(rx_item);
}
lf = wmem_list_frame_next(lf);
}
}
}
}
}
}
}
}
}
}
static void aeron_stream_report(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, aeron_transport_t * transport, aeron_frame_info_t * finfo)
{
if (transport != NULL)
{
if (aeron_sequence_analysis && aeron_stream_analysis && (finfo != NULL) && (finfo->stream_analysis != NULL))
{
proto_tree * subtree;
proto_item * item;
item = proto_tree_add_item(tree, hf_aeron_stream_analysis, tvb, 0, 0, ENC_NA);
PROTO_ITEM_SET_GENERATED(item);
subtree = proto_item_add_subtree(item, ett_aeron_stream_analysis);
item = proto_tree_add_uint(subtree, hf_aeron_stream_analysis_high_term_id, tvb, 0, 0, finfo->stream_analysis->high.term_id);
if ((finfo->stream_analysis->flags & AERON_STREAM_ANALYSIS_FLAGS_TERM_ID_CHANGE) != 0)
{
expert_add_info(pinfo, item, &ei_aeron_analysis_term_id_change);
}
PROTO_ITEM_SET_GENERATED(item);
item = proto_tree_add_uint(subtree, hf_aeron_stream_analysis_high_term_offset, tvb, 0, 0, finfo->stream_analysis->high.term_offset);
PROTO_ITEM_SET_GENERATED(item);
if ((finfo->stream_analysis->flags & AERON_STREAM_ANALYSIS_FLAGS_IDLE_RX) != 0)
{
expert_add_info(pinfo, item, &ei_aeron_analysis_idle_rx);
}
if ((finfo->stream_analysis->flags & AERON_STREAM_ANALYSIS_FLAGS_PACING_RX) != 0)
{
expert_add_info(pinfo, item, &ei_aeron_analysis_pacing_rx);
}
if ((finfo->stream_analysis->flags & AERON_STREAM_ANALYSIS_FLAGS_OOO) != 0)
{
expert_add_info(pinfo, item, &ei_aeron_analysis_ooo);
}
if ((finfo->stream_analysis->flags & AERON_STREAM_ANALYSIS_FLAGS_OOO_GAP) != 0)
{
expert_add_info(pinfo, item, &ei_aeron_analysis_ooo_gap);
}
if ((finfo->stream_analysis->flags & AERON_STREAM_ANALYSIS_FLAGS_KEEPALIVE) != 0)
{
expert_add_info(pinfo, item, &ei_aeron_analysis_keepalive);
}
if ((finfo->stream_analysis->flags & AERON_STREAM_ANALYSIS_FLAGS_RX) != 0)
{
expert_add_info(pinfo, item, &ei_aeron_analysis_rx);
}
if ((finfo->stream_analysis->flags2 & AERON_STREAM_ANALYSIS_FLAGS2_RCV_VALID) != 0)
{
item = proto_tree_add_uint(subtree, hf_aeron_stream_analysis_completed_term_id, tvb, 0, 0, finfo->stream_analysis->completed.term_id);
PROTO_ITEM_SET_GENERATED(item);
item = proto_tree_add_uint(subtree, hf_aeron_stream_analysis_completed_term_offset, tvb, 0, 0, finfo->stream_analysis->completed.term_offset);
PROTO_ITEM_SET_GENERATED(item);
if ((finfo->stream_analysis->flags & AERON_STREAM_ANALYSIS_FLAGS_OOO_SM) != 0)
{
expert_add_info(pinfo, item, &ei_aeron_analysis_ooo_sm);
}
if ((finfo->stream_analysis->flags & AERON_STREAM_ANALYSIS_FLAGS_KEEPALIVE_SM) != 0)
{
expert_add_info(pinfo, item, &ei_aeron_analysis_keepalive_sm);
}
item = proto_tree_add_uint(subtree, hf_aeron_stream_analysis_outstanding_bytes, tvb, 0, 0, finfo->stream_analysis->outstanding_bytes);
PROTO_ITEM_SET_GENERATED(item);
if ((finfo->stream_analysis->flags & AERON_STREAM_ANALYSIS_FLAGS_WINDOW_FULL) != 0)
{
expert_add_info(pinfo, item, &ei_aeron_analysis_window_full);
}
}
}
}
}
static void aeron_next_offset_report(tvbuff_t * tvb, proto_tree * tree, aeron_transport_t * transport, guint32 stream_id, guint32 term_id, guint32 term_offset, guint32 length)
{
aeron_stream_t * stream;
stream = aeron_transport_stream_find(transport, stream_id);
if (stream != NULL)
{
aeron_term_t * term;
if (stream->term_length == 0)
{
stream->term_length = length;
}
term = aeron_stream_term_find(stream, term_id);
if (term != NULL)
{
aeron_fragment_t * fragment = aeron_term_fragment_find(term, term_offset);
if (fragment != NULL)
{
guint32 next_offset = term_offset + length;
guint32 next_offset_term_id = term_id;
guint32 next_offset_first_frame = 0;
aeron_term_t * next_offset_term = NULL;
proto_item * item;
if (next_offset >= stream->term_length)
{
next_offset = 0;
next_offset_term_id++;
}
item = proto_tree_add_uint(tree, hf_aeron_data_next_offset, tvb, 0, 0, next_offset);
PROTO_ITEM_SET_GENERATED(item);
if (next_offset_term_id != term_id)
{
next_offset_term = aeron_stream_term_find(stream, next_offset_term_id);
item = proto_tree_add_uint(tree, hf_aeron_data_next_offset_term, tvb, 0, 0, next_offset_term_id);
PROTO_ITEM_SET_GENERATED(item);
}
else
{
next_offset_term = term;
}
if (next_offset_term != NULL)
{
aeron_fragment_t * next_offset_fragment;
next_offset_fragment = aeron_term_fragment_find(next_offset_term, next_offset);
if (next_offset_fragment != NULL)
{
if (next_offset_fragment->first_frame != NULL)
{
next_offset_first_frame = next_offset_fragment->first_frame->frame;
item = proto_tree_add_uint(tree, hf_aeron_data_next_offset_first_frame, tvb, 0, 0, next_offset_first_frame);
PROTO_ITEM_SET_GENERATED(item);
}
}
}
}
}
}
}
static void aeron_info_stream_progress_report(packet_info * pinfo, guint16 msgtype, guint8 flags, guint32 term_id, guint32 term_offset, aeron_frame_info_t * finfo)
{
const gchar * type_string = val_to_str_const((guint32) msgtype, aeron_frame_type, "Unknown");
if (aeron_sequence_analysis && aeron_stream_analysis && (finfo != NULL) && (finfo->stream_analysis != NULL))
{
switch (msgtype)
{
case HDR_TYPE_PAD:
case HDR_TYPE_DATA:
if ((finfo->stream_analysis->flags & AERON_STREAM_ANALYSIS_FLAGS_KEEPALIVE) != 0)
{
col_append_sep_fstr(pinfo->cinfo, COL_INFO, ", ", "%s-KA", type_string);
}
else
{
col_append_sep_fstr(pinfo->cinfo, COL_INFO, ", ", "%s (0x%08x:%" G_GUINT32_FORMAT ")",
type_string, term_id, term_offset);
}
break;
case HDR_TYPE_SM:
if ((finfo->stream_analysis->flags & AERON_STREAM_ANALYSIS_FLAGS_KEEPALIVE_SM) != 0)
{
col_append_sep_fstr(pinfo->cinfo, COL_INFO, ", ", "%s-KA", type_string);
}
else
{
if (finfo->stream_analysis->high.term_id == finfo->stream_analysis->completed.term_id)
{
col_append_sep_fstr(pinfo->cinfo, COL_INFO, ", ", "%s (%" G_GUINT32_FORMAT "/%" G_GUINT32_FORMAT " [%" G_GUINT32_FORMAT "])",
type_string, finfo->stream_analysis->high.term_offset, finfo->stream_analysis->completed.term_offset, finfo->stream_analysis->outstanding_bytes);
}
else
{
col_append_sep_fstr(pinfo->cinfo, COL_INFO, ", ", "%s (0x%08x:%" G_GUINT32_FORMAT "/0x%08x:%" G_GUINT32_FORMAT " [%" G_GUINT32_FORMAT "])",
type_string, finfo->stream_analysis->high.term_id, finfo->stream_analysis->high.term_offset, finfo->stream_analysis->completed.term_id, finfo->stream_analysis->completed.term_offset, finfo->stream_analysis->outstanding_bytes);
}
}
break;
}
}
else
{
if ((msgtype == HDR_TYPE_SM) && ((flags & STATUS_FLAGS_SETUP) != 0))
{
col_append_sep_fstr(pinfo->cinfo, COL_INFO, ", ", "%s-SETUP", type_string);
}
else
{
col_append_sep_str(pinfo->cinfo, COL_INFO, ", ", type_string);
}
}
}
/*----------------------------------------------------------------------------*/
/* Payload reassembly. */
/*----------------------------------------------------------------------------*/
struct aeron_msg_fragment_t_stct;
typedef struct aeron_msg_fragment_t_stct aeron_msg_fragment_t;
struct aeron_msg_t_stct
{
wmem_list_t * fragment;
aeron_term_t * term;
tvbuff_t * reassembled_data;
guint32 first_fragment_term_offset;
guint32 next_expected_term_offset;
guint32 length; /* Total message payload length */
guint32 frame_length; /* Total length of all message frames accumulated */
guint32 fragment_count; /* Number of fragments in this message */
guint32 contiguous_length; /* Number of contiguous frame bytes accumulated for this message */
guint32 begin_frame; /* Data frame in which the B flag was set */
guint32 first_frame; /* Lowest-numbered frame which is part of this message */
guint32 end_frame; /* Data frame in which the E flag was set */
guint32 last_frame; /* Highest-numbered frame which is part of this message */
gboolean complete;
};
struct aeron_msg_fragment_t_stct
{
gchar * data;
guint32 term_offset; /* Term offset for entire fragment */
guint32 frame_length; /* Length of entire frame/fragment */
guint32 data_length; /* Payload length */
guint32 frame; /* Frame in which the fragment resides */
gint frame_offset; /* Offset into the frame for the entire Aeron message */
guint8 flags; /* Frame data flags */
};
static void aeron_msg_fragment_add(aeron_msg_t * msg, aeron_msg_fragment_t * fragment)
{
/* Add the fragment to the message */
wmem_list_append(msg->fragment, (void *) fragment);
/* Update the message */
msg->length += fragment->data_length;
msg->contiguous_length += fragment->data_length;
msg->fragment_count++;
if (msg->first_frame > fragment->frame)
{
msg->first_frame = fragment->frame;
}
if (msg->last_frame < fragment->frame)
{
msg->last_frame = fragment->frame;
}
msg->next_expected_term_offset += fragment->frame_length;
if ((fragment->flags & DATA_FLAGS_END) == DATA_FLAGS_END)
{
gchar * buf;
wmem_list_frame_t * lf;
size_t ofs = 0;
size_t accum_len = 0;
guint32 last_frame_offset = 0;
gboolean last_frame_found = FALSE;
aeron_frame_info_t * finfo = NULL;
msg->complete = TRUE;
msg->end_frame = fragment->frame;
buf = (gchar *) wmem_alloc(wmem_file_scope(), (size_t) msg->length);
lf = wmem_list_head(msg->fragment);
while (lf != NULL)
{
aeron_msg_fragment_t * cur_frag = (aeron_msg_fragment_t *) wmem_list_frame_data(lf);
if (cur_frag != NULL)
{
if (cur_frag->frame == msg->last_frame)
{
last_frame_offset = cur_frag->frame_offset;
last_frame_found = TRUE;
}
memcpy((void *) (buf + ofs), (void *) cur_frag->data, (size_t) cur_frag->data_length);
ofs += (size_t) cur_frag->data_length;
accum_len += (size_t) cur_frag->data_length;
}
lf = wmem_list_frame_next(lf);
}
DISSECTOR_ASSERT(accum_len == (size_t) msg->length);
DISSECTOR_ASSERT(last_frame_found == TRUE);
if (last_frame_found)
{
finfo = aeron_frame_info_find(msg->last_frame, last_frame_offset);
}
msg->reassembled_data = tvb_new_real_data(buf, msg->length, msg->length);
DISSECTOR_ASSERT(finfo != NULL);
if (finfo != NULL)
{
finfo->flags |= AERON_FRAME_INFO_FLAGS_REASSEMBLED_MSG;
finfo->message = msg;
}
}
}
static gboolean aeron_msg_process_orphan_fragments_msg_cb(const void *key _U_, void * value, void * userdata)
{
aeron_msg_t * msg = (aeron_msg_t *) value;
aeron_term_t * term = (aeron_term_t *) userdata;
gboolean frag_found = FALSE;
wmem_list_frame_t * lf = NULL;
aeron_msg_fragment_t * frag = NULL;
if (msg->complete)
{
/* This message is complete, no need to check for orphans */
return (FALSE);
}
/* Scan through the orphan fragments */
while (TRUE)
{
lf = wmem_list_head(term->orphan_fragment);
while (lf != NULL)
{
frag = (aeron_msg_fragment_t *) wmem_list_frame_data(lf);
if (frag != NULL)
{
if (msg->next_expected_term_offset == frag->term_offset)
{
/* Found one! Remove it from the orphan list, and add it to the message */
wmem_list_remove_frame(term->orphan_fragment, lf);
aeron_msg_fragment_add(msg, frag);
frag_found = TRUE;
break;
}
}
lf = wmem_list_frame_next(lf);
}
if (!frag_found)
{
break;
}
frag_found = FALSE;
}
return (FALSE);
}
static void aeron_msg_process_orphan_fragments(aeron_term_t * term)
{
/* If we have no orphan fragments to process, nothing to do. */
if (wmem_list_count(term->orphan_fragment) == 0)
{
return;
}
wmem_tree_foreach(term->message, aeron_msg_process_orphan_fragments_msg_cb, (void *) term);
}
static aeron_msg_fragment_t * aeron_msg_fragment_create(tvbuff_t * tvb, int offset, packet_info * pinfo, aeron_packet_info_t * info)
{
aeron_msg_fragment_t * frag;
frag = wmem_new0(wmem_file_scope(), aeron_msg_fragment_t);
frag->term_offset = info->term_offset;
frag->frame_length = info->length;
frag->data_length = info->data_length;
frag->frame = pinfo->num;
frag->frame_offset = offset;
frag->data = (gchar *) tvb_memdup(wmem_file_scope(), tvb, frag->frame_offset + O_AERON_DATA_DATA, (size_t) frag->data_length);
frag->flags = info->flags;
return (frag);
}
static aeron_msg_fragment_t * aeron_msg_fragment_find(aeron_msg_t * message, aeron_packet_info_t * info)
{
aeron_msg_fragment_t * frag = NULL;
wmem_list_frame_t * lf;
if (message->next_expected_term_offset < info->term_offset)
{
return (NULL);
}
lf = wmem_list_head(message->fragment);
while (lf != NULL)
{
frag = (aeron_msg_fragment_t *) wmem_list_frame_data(lf);
if (frag != NULL)
{
if (frag->term_offset == info->term_offset)
{
break;
}
}
lf = wmem_list_frame_next(lf);
}
return (frag);
}
static aeron_msg_t * aeron_term_msg_find_le(aeron_term_t * term, guint32 term_offset)
{
/* Return the last aeron_msg_t with starting_fragment_term_offset <= offset */
aeron_msg_t * msg = (aeron_msg_t *) wmem_tree_lookup32_le(term->message, term_offset);
return (msg);
}
static aeron_msg_t * aeron_term_msg_add(aeron_term_t * term, packet_info * pinfo, aeron_packet_info_t * info)
{
aeron_msg_t * pos;
aeron_msg_t * msg;
pos = aeron_term_msg_find_le(term, info->term_offset);
if ((pos != NULL) && (pos->first_fragment_term_offset == info->term_offset))
{
return (pos);
}
msg = wmem_new0(wmem_file_scope(), aeron_msg_t);
msg->fragment = wmem_list_new(wmem_file_scope());
msg->term = term;
msg->reassembled_data = NULL;
msg->first_fragment_term_offset = info->term_offset;
msg->next_expected_term_offset = info->term_offset;
msg->length = 0;
msg->frame_length = 0;
msg->fragment_count = 0;
msg->contiguous_length = 0;
msg->begin_frame = pinfo->num;
msg->first_frame = pinfo->num;
msg->end_frame = 0;
msg->last_frame = 0;
msg->complete = FALSE;
wmem_tree_insert32(term->message, msg->first_fragment_term_offset, (void *) msg);
return (msg);
}
static void aeron_msg_process(tvbuff_t * tvb, int offset, packet_info * pinfo, aeron_transport_t * transport, aeron_packet_info_t * info, aeron_frame_info_t * finfo _U_)
{
if (aeron_reassemble_fragments && (PINFO_FD_VISITED(pinfo) == 0))
{
if ((info->flags & DATA_FLAGS_COMPLETE) != DATA_FLAGS_COMPLETE)
{
aeron_stream_t * stream = aeron_transport_stream_find(transport, info->stream_id);
if (stream != NULL)
{
aeron_term_t * term = aeron_stream_term_find(stream, info->term_id);
if (term != NULL)
{
aeron_msg_t * msg = NULL;
aeron_msg_fragment_t * frag = NULL;
if ((info->flags & DATA_FLAGS_BEGIN) == DATA_FLAGS_BEGIN)
{
/* Beginning of a message. First see if this message already exists. */
msg = aeron_term_msg_find_le(term, info->term_offset);
if (msg != NULL)
{
if (msg->first_fragment_term_offset != info->term_offset)
{
/*
A message start with a term offset:
1) Between two existing messages for this term, or
2) Less than the first message for this term
Likely this was caused by an RX or out-of-order packet. Need to create a new one.
*/
msg = NULL;
}
}
if (msg == NULL)
{
msg = aeron_term_msg_add(term, pinfo, info);
}
}
else
{
/* End of message, or middle of message. See if we already have a message with a smaller starting term offset */
msg = aeron_term_msg_find_le(term, info->term_offset);
if (msg != NULL)
{
/* Is this the next expexted term offset? */
if (msg->next_expected_term_offset == info->term_offset)
{
/* Yes - we can add the fragment to the message */
}
else
{
/* Do we already have this fragment? */
frag = aeron_msg_fragment_find(msg, info);
if (frag != NULL)
{
/* Already have it, so nothing to do */
return;
}
else
{
/* Not the next fragment, so no known message associated with it. */
msg = NULL;
}
}
}
}
/* Create the fragment */
frag = aeron_msg_fragment_create(tvb, offset, pinfo, info);
if (msg == NULL)
{
/* Add the fragment to the list of orphaned fragments */
wmem_list_append(term->orphan_fragment, (void *) frag);
}
else
{
/* Add the fragment to the message */
aeron_msg_fragment_add(msg, frag);
}
/* Process the orphan list */
aeron_msg_process_orphan_fragments(term);
}
}
}
}
}
/*----------------------------------------------------------------------------*/
/* Aeron pad message packet dissection functions. */
/*----------------------------------------------------------------------------*/
static int dissect_aeron_pad(tvbuff_t * tvb, int offset, packet_info * pinfo, proto_tree * tree, aeron_conversation_info_t * cinfo, aeron_frame_info_t * finfo)
{
proto_tree * subtree;
proto_item * pad_item;
proto_item * channel_item;
proto_item * frame_length_item;
guint32 frame_length;
guint32 pad_length;
aeron_transport_t * transport;
guint32 session_id;
guint32 stream_id;
guint32 term_id;
guint32 term_offset;
int rounded_length;
aeron_packet_info_t pktinfo;
frame_length = tvb_get_letohl(tvb, offset + O_AERON_PAD_FRAME_LENGTH);
rounded_length = (int) aeron_pos_roundup(frame_length);
if (rounded_length < 0)
return 0;
term_offset = tvb_get_letohl(tvb, offset + O_AERON_PAD_TERM_OFFSET);
session_id = tvb_get_letohl(tvb, offset + O_AERON_PAD_SESSION_ID);
transport = aeron_transport_add(cinfo, session_id, pinfo->num);
stream_id = tvb_get_letohl(tvb, offset + O_AERON_PAD_STREAM_ID);
term_id = tvb_get_letohl(tvb, offset + O_AERON_PAD_TERM_ID);
pad_length = frame_length - L_AERON_PAD_MIN;
memset((void *) &pktinfo, 0, sizeof(aeron_packet_info_t));
pktinfo.stream_id = stream_id;
pktinfo.term_id = term_id;
pktinfo.term_offset = term_offset;
pktinfo.info_flags = AERON_PACKET_INFO_FLAGS_STREAM_ID_VALID | AERON_PACKET_INFO_FLAGS_TERM_ID_VALID | AERON_PACKET_INFO_FLAGS_TERM_OFFSET_VALID;
pktinfo.length = frame_length;
pktinfo.data_length = pad_length;
pktinfo.type = HDR_TYPE_PAD;
pktinfo.flags = tvb_get_guint8(tvb, offset + O_AERON_PAD_FLAGS);
if (aeron_frame_info_setup(pinfo, transport, &pktinfo, finfo) < 0)
return 0;
aeron_info_stream_progress_report(pinfo, HDR_TYPE_PAD, pktinfo.flags, term_id, term_offset, finfo);
pad_item = proto_tree_add_none_format(tree, hf_aeron_pad, tvb, offset, -1, "Pad Frame: Term 0x%x, Ofs %" G_GUINT32_FORMAT ", Len %" G_GUINT32_FORMAT "(%d)",
term_id, term_offset, frame_length, rounded_length);
subtree = proto_item_add_subtree(pad_item, ett_aeron_pad);
channel_item = proto_tree_add_uint64(subtree, hf_aeron_channel_id, tvb, 0, 0, transport->channel_id);
PROTO_ITEM_SET_GENERATED(channel_item);
frame_length_item = proto_tree_add_item(subtree, hf_aeron_pad_frame_length, tvb, offset + O_AERON_PAD_FRAME_LENGTH, 4, ENC_LITTLE_ENDIAN);
proto_tree_add_item(subtree, hf_aeron_pad_version, tvb, offset + O_AERON_PAD_VERSION, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(subtree, hf_aeron_pad_flags, tvb, offset + O_AERON_PAD_FLAGS, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(subtree, hf_aeron_pad_type, tvb, offset + O_AERON_PAD_TYPE, 2, ENC_LITTLE_ENDIAN);
proto_tree_add_item(subtree, hf_aeron_pad_term_offset, tvb, offset + O_AERON_PAD_TERM_OFFSET, 4, ENC_LITTLE_ENDIAN);
aeron_next_offset_report(tvb, subtree, transport, stream_id, term_id, term_offset, (guint32) rounded_length);
proto_tree_add_item(subtree, hf_aeron_pad_session_id, tvb, offset + O_AERON_PAD_SESSION_ID, 4, ENC_LITTLE_ENDIAN);
proto_tree_add_item(subtree, hf_aeron_pad_stream_id, tvb, offset + O_AERON_PAD_STREAM_ID, 4, ENC_LITTLE_ENDIAN);
proto_tree_add_item(subtree, hf_aeron_pad_term_id, tvb, offset + O_AERON_PAD_TERM_ID, 4, ENC_LITTLE_ENDIAN);
aeron_sequence_report(tvb, pinfo, subtree, transport, &pktinfo, finfo);
aeron_stream_report(tvb, pinfo, subtree, transport, finfo);
proto_item_set_len(pad_item, rounded_length);
if (frame_length < L_AERON_PAD_MIN)
{
expert_add_info(pinfo, frame_length_item, &ei_aeron_analysis_invalid_pad_length);
return (-rounded_length);
}
return (rounded_length);
}
/*----------------------------------------------------------------------------*/
/* Aeron data message packet dissection functions. */
/*----------------------------------------------------------------------------*/
static void dissect_aeron_reassembled_data(packet_info * pinfo, proto_tree * tree, aeron_frame_info_t * finfo)
{
proto_item * frag_item;
proto_tree * frag_tree;
aeron_msg_t * msg;
wmem_list_frame_t * lf;
gboolean first_item = TRUE;
guint32 msg_ofs = 0;
if (finfo->message == NULL)
{
return;
}
msg = finfo->message;
add_new_data_source(pinfo, msg->reassembled_data, "Reassembled Data");
frag_item = proto_tree_add_none_format(tree,
hf_aeron_data_reassembly,
msg->reassembled_data,
0,
tvb_reported_length_remaining(msg->reassembled_data, 0),
"%" G_GUINT32_FORMAT " Reassembled Fragments (%" G_GUINT32_FORMAT " bytes):",
msg->fragment_count,
msg->length);
frag_tree = proto_item_add_subtree(frag_item, ett_aeron_data_reassembly);
lf = wmem_list_head(msg->fragment);
while (lf != NULL)
{
aeron_msg_fragment_t * frag = (aeron_msg_fragment_t *) wmem_list_frame_data(lf);
if (frag != NULL)
{
proto_item * pi;
pi = proto_tree_add_uint_format_value(frag_tree,
hf_aeron_data_reassembly_fragment,
msg->reassembled_data,
msg_ofs,
frag->data_length,
frag->frame,
"Frame: %" G_GUINT32_FORMAT ", payload: %" G_GUINT32_FORMAT "-%" G_GUINT32_FORMAT " (%" G_GUINT32_FORMAT " bytes)",
frag->frame,
msg_ofs,
(msg_ofs + frag->data_length) - 1,
frag->data_length);
PROTO_ITEM_SET_GENERATED(pi);
if (first_item)
{
proto_item_append_text(frag_item, " #%" G_GUINT32_FORMAT "(%" G_GUINT32_FORMAT ")", frag->frame, frag->data_length);
}
else
{
proto_item_append_text(frag_item, ", #%" G_GUINT32_FORMAT "(%" G_GUINT32_FORMAT ")", frag->frame, frag->data_length);
}
msg_ofs += frag->data_length;
first_item = FALSE;
}
lf = wmem_list_frame_next(lf);
}
PROTO_ITEM_SET_GENERATED(frag_item);
}
static int dissect_aeron_data(tvbuff_t * tvb, int offset, packet_info * pinfo, proto_tree * tree, aeron_conversation_info_t * cinfo, aeron_frame_info_t * finfo)
{
proto_tree * subtree;
proto_item * data_item;
proto_item * channel_item;
proto_item * frame_length_item;
guint32 frame_length;
static const int * flags[] =
{
&hf_aeron_data_flags_b,
&hf_aeron_data_flags_e,
NULL
};
aeron_transport_t * transport;
guint32 session_id;
guint32 stream_id;
guint32 term_id;
guint32 term_offset;
guint32 data_length;
int rounded_length = 0;
aeron_packet_info_t pktinfo;
guint32 offset_increment = 0;
frame_length = tvb_get_letohl(tvb, offset + O_AERON_DATA_FRAME_LENGTH);
if (frame_length == 0)
{
rounded_length = O_AERON_DATA_DATA;
data_length = 0;
offset_increment = 0;
}
else
{
offset_increment = aeron_pos_roundup(frame_length);
rounded_length = (int) offset_increment;
if (rounded_length < 0)
return 0;
data_length = frame_length - O_AERON_DATA_DATA;
}
term_offset = tvb_get_letohl(tvb, offset + O_AERON_DATA_TERM_OFFSET);
session_id = tvb_get_letohl(tvb, offset + O_AERON_DATA_SESSION_ID);
transport = aeron_transport_add(cinfo, session_id, pinfo->num);
stream_id = tvb_get_letohl(tvb, offset + O_AERON_DATA_STREAM_ID);
term_id = tvb_get_letohl(tvb, offset + O_AERON_DATA_TERM_ID);
memset((void *) &pktinfo, 0, sizeof(aeron_packet_info_t));
pktinfo.stream_id = stream_id;
pktinfo.term_id = term_id;
pktinfo.term_offset = term_offset;
pktinfo.info_flags = AERON_PACKET_INFO_FLAGS_STREAM_ID_VALID | AERON_PACKET_INFO_FLAGS_TERM_ID_VALID | AERON_PACKET_INFO_FLAGS_TERM_OFFSET_VALID;
pktinfo.length = frame_length;
pktinfo.data_length = data_length;
pktinfo.type = HDR_TYPE_DATA;
pktinfo.flags = tvb_get_guint8(tvb, offset + O_AERON_DATA_FLAGS);
if (aeron_frame_info_setup(pinfo, transport, &pktinfo, finfo) < 0)
return 0;
aeron_info_stream_progress_report(pinfo, HDR_TYPE_DATA, pktinfo.flags, term_id, term_offset, finfo);
data_item = proto_tree_add_none_format(tree, hf_aeron_data, tvb, offset, -1, "Data Frame: Term 0x%x, Ofs %" G_GUINT32_FORMAT ", Len %" G_GUINT32_FORMAT "(%d)",
(guint32) term_id, term_offset, frame_length, rounded_length);
subtree = proto_item_add_subtree(data_item, ett_aeron_data);
channel_item = proto_tree_add_uint64(subtree, hf_aeron_channel_id, tvb, 0, 0, transport->channel_id);
PROTO_ITEM_SET_GENERATED(channel_item);
frame_length_item = proto_tree_add_item(subtree, hf_aeron_data_frame_length, tvb, offset + O_AERON_DATA_FRAME_LENGTH, 4, ENC_LITTLE_ENDIAN);
proto_tree_add_item(subtree, hf_aeron_data_version, tvb, offset + O_AERON_DATA_VERSION, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_bitmask(subtree, tvb, offset + O_AERON_DATA_FLAGS, hf_aeron_data_flags, ett_aeron_data_flags, flags, ENC_LITTLE_ENDIAN);
proto_tree_add_item(subtree, hf_aeron_data_type, tvb, offset + O_AERON_DATA_TYPE, 2, ENC_LITTLE_ENDIAN);
proto_tree_add_item(subtree, hf_aeron_data_term_offset, tvb, offset + O_AERON_DATA_TERM_OFFSET, 4, ENC_LITTLE_ENDIAN);
aeron_next_offset_report(tvb, subtree, transport, stream_id, term_id, term_offset, offset_increment);
proto_tree_add_item(subtree, hf_aeron_data_session_id, tvb, offset + O_AERON_DATA_SESSION_ID, 4, ENC_LITTLE_ENDIAN);
proto_tree_add_item(subtree, hf_aeron_data_stream_id, tvb, offset + O_AERON_DATA_STREAM_ID, 4, ENC_LITTLE_ENDIAN);
proto_tree_add_item(subtree, hf_aeron_data_term_id, tvb, offset + O_AERON_DATA_TERM_ID, 4, ENC_LITTLE_ENDIAN);
if (data_length > 0)
{
tvbuff_t * data_tvb = NULL;
gboolean can_call_subdissector = FALSE;
gboolean dissector_found = FALSE;
heur_dtbl_entry_t * hdtbl_entry;
aeron_msg_process(tvb, offset, pinfo, transport, &pktinfo, finfo);
if ((pktinfo.flags & DATA_FLAGS_COMPLETE) == DATA_FLAGS_COMPLETE)
{
can_call_subdissector = TRUE;
}
if (finfo != NULL)
{
if ((finfo->flags & AERON_FRAME_INFO_FLAGS_REASSEMBLED_MSG) != 0)
{
dissect_aeron_reassembled_data(pinfo, subtree, finfo);
data_tvb = finfo->message->reassembled_data;
can_call_subdissector = TRUE;
}
else
{
data_tvb = tvb_new_subset_length(tvb, offset + O_AERON_DATA_DATA, data_length);
}
}
else
{
data_tvb = tvb_new_subset_length(tvb, offset + O_AERON_DATA_DATA, data_length);
}
if (can_call_subdissector && aeron_use_heuristic_subdissectors)
{
dissector_found = dissector_try_heuristic(aeron_heuristic_subdissector_list, data_tvb, pinfo, subtree, &hdtbl_entry, NULL);
}
if (!dissector_found)
{
call_data_dissector(data_tvb, pinfo, subtree);
}
}
aeron_sequence_report(tvb, pinfo, subtree, transport, &pktinfo, finfo);
aeron_stream_report(tvb, pinfo, subtree, transport, finfo);
proto_item_set_len(data_item, rounded_length);
if ((frame_length != 0) && (frame_length < L_AERON_DATA_MIN))
{
expert_add_info(pinfo, frame_length_item, &ei_aeron_analysis_invalid_data_length);
return (-rounded_length);
}
return (rounded_length);
}
/*----------------------------------------------------------------------------*/
/* Aeron NAK packet dissection functions. */
/*----------------------------------------------------------------------------*/
static int dissect_aeron_nak(tvbuff_t * tvb, int offset, packet_info * pinfo, proto_tree * tree, aeron_conversation_info_t * cinfo, aeron_frame_info_t * finfo)
{
proto_tree * subtree;
proto_item * nak_item;
proto_item * frame_length_item;
proto_item * channel_item;
proto_item * nak_offset_item;
guint32 frame_length;
aeron_transport_t * transport;
guint32 session_id;
guint32 stream_id;
guint32 term_id;
guint32 nak_term_offset;
guint32 nak_length;
int rounded_length;
aeron_packet_info_t pktinfo;
frame_length = tvb_get_letohl(tvb, offset + O_AERON_NAK_FRAME_LENGTH);
rounded_length = (int) aeron_pos_roundup(frame_length);
if (rounded_length < 0)
return 0;
session_id = tvb_get_letohl(tvb, offset + O_AERON_NAK_SESSION_ID);
transport = aeron_transport_add(cinfo, session_id, pinfo->num);
stream_id = tvb_get_letohl(tvb, offset + O_AERON_NAK_STREAM_ID);
term_id = tvb_get_letohl(tvb, offset + O_AERON_NAK_TERM_ID);
nak_term_offset = tvb_get_letohl(tvb, offset + O_AERON_NAK_TERM_OFFSET);
nak_length = tvb_get_letohl(tvb, offset + O_AERON_NAK_LENGTH);
memset((void *) &pktinfo, 0, sizeof(aeron_packet_info_t));
pktinfo.stream_id = stream_id;
pktinfo.term_id = term_id;
pktinfo.info_flags = AERON_PACKET_INFO_FLAGS_STREAM_ID_VALID | AERON_PACKET_INFO_FLAGS_TERM_ID_VALID;
pktinfo.nak_term_offset = nak_term_offset;
pktinfo.nak_length = nak_length;
pktinfo.type = HDR_TYPE_NAK;
pktinfo.flags = tvb_get_guint8(tvb, offset + O_AERON_NAK_FLAGS);
if (aeron_frame_info_setup(pinfo, transport, &pktinfo, finfo) < 0)
return 0;
col_append_sep_str(pinfo->cinfo, COL_INFO, ", ", "NAK");
nak_item = proto_tree_add_none_format(tree, hf_aeron_nak, tvb, offset, -1, "NAK Frame: Term 0x%x, Ofs %" G_GUINT32_FORMAT ", Len %" G_GUINT32_FORMAT,
term_id, nak_term_offset, nak_length);
subtree = proto_item_add_subtree(nak_item, ett_aeron_nak);
channel_item = proto_tree_add_uint64(subtree, hf_aeron_channel_id, tvb, 0, 0, transport->channel_id);
PROTO_ITEM_SET_GENERATED(channel_item);
frame_length_item = proto_tree_add_item(subtree, hf_aeron_nak_frame_length, tvb, offset + O_AERON_NAK_FRAME_LENGTH, 4, ENC_LITTLE_ENDIAN);
proto_tree_add_item(subtree, hf_aeron_nak_version, tvb, offset + O_AERON_NAK_VERSION, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(subtree, hf_aeron_nak_flags, tvb, offset + O_AERON_NAK_FLAGS, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(subtree, hf_aeron_nak_type, tvb, offset + O_AERON_NAK_TYPE, 2, ENC_LITTLE_ENDIAN);
proto_tree_add_item(subtree, hf_aeron_nak_session_id, tvb, offset + O_AERON_NAK_SESSION_ID, 4, ENC_LITTLE_ENDIAN);
proto_tree_add_item(subtree, hf_aeron_nak_stream_id, tvb, offset + O_AERON_NAK_STREAM_ID, 4, ENC_LITTLE_ENDIAN);
proto_tree_add_item(subtree, hf_aeron_nak_term_id, tvb, offset + O_AERON_NAK_TERM_ID, 4, ENC_LITTLE_ENDIAN);
nak_offset_item = proto_tree_add_item(subtree, hf_aeron_nak_term_offset, tvb, offset + O_AERON_NAK_TERM_OFFSET, 4, ENC_LITTLE_ENDIAN);
proto_tree_add_item(subtree, hf_aeron_nak_length, tvb, offset + O_AERON_NAK_LENGTH, 4, ENC_LITTLE_ENDIAN);
expert_add_info_format(pinfo, nak_offset_item, &ei_aeron_analysis_nak, "NAK offset %" G_GUINT32_FORMAT " length %" G_GUINT32_FORMAT, nak_term_offset, nak_length);
aeron_sequence_report(tvb, pinfo, subtree, transport, &pktinfo, finfo);
proto_item_set_len(nak_item, rounded_length);
if (frame_length != L_AERON_NAK)
{
expert_add_info(pinfo, frame_length_item, &ei_aeron_analysis_invalid_nak_length);
return (-rounded_length);
}
return (rounded_length);
}
/*----------------------------------------------------------------------------*/
/* Aeron status message packet dissection functions. */
/*----------------------------------------------------------------------------*/
static void aeron_window_resize_report(packet_info * pinfo, proto_item * item, aeron_frame_info_t * finfo)
{
if (aeron_sequence_analysis && aeron_stream_analysis && (finfo != NULL) && (finfo->stream_analysis != NULL))
{
if ((finfo->stream_analysis->flags & AERON_STREAM_ANALYSIS_FLAGS_WINDOW_RESIZE) != 0)
{
expert_add_info(pinfo, item, &ei_aeron_analysis_window_resize);
}
}
}
static int dissect_aeron_sm(tvbuff_t * tvb, int offset, packet_info * pinfo, proto_tree * tree, aeron_conversation_info_t * cinfo, aeron_frame_info_t * finfo)
{
proto_tree * subtree;
proto_item * sm_item;
proto_item * frame_length_item;
proto_item * item;
proto_item * rcv_window_item;
guint32 frame_length;
static const int * flags[] =
{
&hf_aeron_sm_flags_s,
NULL
};
guint32 feedback_length;
aeron_transport_t * transport;
guint32 session_id;
guint32 stream_id;
guint32 term_id;
guint32 consumption_offset;
guint32 rcv_window;
int rounded_length;
aeron_packet_info_t pktinfo;
frame_length = tvb_get_letohl(tvb, offset + O_AERON_SM_FRAME_LENGTH);
feedback_length = frame_length - O_AERON_SM_FEEDBACK;
rounded_length = (int) aeron_pos_roundup(frame_length);
if (rounded_length < 0)
return 0;
session_id = tvb_get_letohl(tvb, offset + O_AERON_SM_SESSION_ID);
transport = aeron_transport_add(cinfo, session_id, pinfo->num);
stream_id = tvb_get_letohl(tvb, offset + O_AERON_SM_STREAM_ID);
term_id = tvb_get_letohl(tvb, offset + O_AERON_SM_TERM_ID);
consumption_offset = tvb_get_letohl(tvb, offset + O_AERON_SM_COMPLETED_TERM_OFFSET);
rcv_window = tvb_get_letohl(tvb, offset + O_AERON_SM_RECEIVER_WINDOW);
memset((void *) &pktinfo, 0, sizeof(aeron_packet_info_t));
pktinfo.stream_id = stream_id;
pktinfo.info_flags = AERON_PACKET_INFO_FLAGS_STREAM_ID_VALID;
pktinfo.flags = tvb_get_guint8(tvb, offset + O_AERON_SM_FLAGS);
if ((pktinfo.flags & STATUS_FLAGS_SETUP) == 0)
{
pktinfo.term_id = term_id;
pktinfo.term_offset = consumption_offset;
pktinfo.info_flags |= (AERON_PACKET_INFO_FLAGS_TERM_ID_VALID | AERON_PACKET_INFO_FLAGS_TERM_OFFSET_VALID);
pktinfo.receiver_window = rcv_window;
}
else
{
pktinfo.term_id = 0;
pktinfo.term_offset = 0;
pktinfo.receiver_window = 0;
}
pktinfo.length = 0;
pktinfo.data_length = 0;
pktinfo.type = HDR_TYPE_SM;
if (aeron_frame_info_setup(pinfo, transport, &pktinfo, finfo) < 0)
return 0;
aeron_info_stream_progress_report(pinfo, HDR_TYPE_SM, pktinfo.flags, term_id, consumption_offset, finfo);
sm_item = proto_tree_add_none_format(tree, hf_aeron_sm, tvb, offset, -1, "Status Message: Term 0x%x, ConsumptionOfs %" G_GUINT32_FORMAT ", RcvWindow %" G_GUINT32_FORMAT,
term_id, consumption_offset, rcv_window);
subtree = proto_item_add_subtree(sm_item, ett_aeron_sm);
item = proto_tree_add_uint64(subtree, hf_aeron_channel_id, tvb, 0, 0, transport->channel_id);
PROTO_ITEM_SET_GENERATED(item);
frame_length_item = proto_tree_add_item(subtree, hf_aeron_sm_frame_length, tvb, offset + O_AERON_SM_FRAME_LENGTH, 4, ENC_LITTLE_ENDIAN);
proto_tree_add_item(subtree, hf_aeron_sm_version, tvb, offset + O_AERON_SM_VERSION, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_bitmask(subtree, tvb, offset + O_AERON_SM_FLAGS, hf_aeron_sm_flags, ett_aeron_sm_flags, flags, ENC_LITTLE_ENDIAN);
proto_tree_add_item(subtree, hf_aeron_sm_type, tvb, offset + O_AERON_SM_TYPE, 2, ENC_LITTLE_ENDIAN);
proto_tree_add_item(subtree, hf_aeron_sm_session_id, tvb, offset + O_AERON_SM_SESSION_ID, 4, ENC_LITTLE_ENDIAN);
proto_tree_add_item(subtree, hf_aeron_sm_stream_id, tvb, offset + O_AERON_SM_STREAM_ID, 4, ENC_LITTLE_ENDIAN);
proto_tree_add_item(subtree, hf_aeron_sm_consumption_term_id, tvb, offset + O_AERON_SM_TERM_ID, 4, ENC_LITTLE_ENDIAN);
proto_tree_add_item(subtree, hf_aeron_sm_consumption_term_offset, tvb, offset + O_AERON_SM_COMPLETED_TERM_OFFSET, 4, ENC_LITTLE_ENDIAN);
rcv_window_item = proto_tree_add_item(subtree, hf_aeron_sm_receiver_window, tvb, offset + O_AERON_SM_RECEIVER_WINDOW, 4, ENC_LITTLE_ENDIAN);
aeron_window_resize_report(pinfo, rcv_window_item, finfo);
if (feedback_length > 0)
{
proto_tree_add_item(subtree, hf_aeron_sm_feedback, tvb, offset + O_AERON_SM_FEEDBACK, feedback_length, ENC_NA);
}
aeron_sequence_report(tvb, pinfo, subtree, transport, &pktinfo, finfo);
aeron_stream_report(tvb, pinfo, subtree, transport, finfo);
proto_item_set_len(sm_item, rounded_length);
if (frame_length < L_AERON_SM_MIN)
{
expert_add_info(pinfo, frame_length_item, &ei_aeron_analysis_invalid_sm_length);
return (-rounded_length);
}
return (rounded_length);
}
/*----------------------------------------------------------------------------*/
/* Aeron error packet dissection functions. */
/*----------------------------------------------------------------------------*/
static int dissect_aeron_err(tvbuff_t * tvb, int offset, packet_info * pinfo, proto_tree * tree)
{
proto_tree * subtree;
proto_item * err_item;
proto_item * frame_length_item;
int rounded_length;
guint32 bad_frame_length;
gint string_length;
guint32 frame_length;
int ofs;
frame_length = tvb_get_letohl(tvb, offset + O_AERON_ERR_FRAME_LENGTH);
col_append_sep_str(pinfo->cinfo, COL_INFO, ", ", "Error");
err_item = proto_tree_add_item(tree, hf_aeron_err, tvb, offset, -1, ENC_NA);
subtree = proto_item_add_subtree(err_item, ett_aeron_err);
frame_length_item = proto_tree_add_item(subtree, hf_aeron_err_frame_length, tvb, offset + O_AERON_ERR_FRAME_LENGTH, 4, ENC_LITTLE_ENDIAN);
proto_tree_add_item(subtree, hf_aeron_err_version, tvb, offset + O_AERON_ERR_VERSION, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(subtree, hf_aeron_err_code, tvb, offset + O_AERON_ERR_CODE, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(subtree, hf_aeron_err_type, tvb, offset + O_AERON_ERR_TYPE, 2, ENC_LITTLE_ENDIAN);
proto_tree_add_item(subtree, hf_aeron_err_off_frame_length, tvb, offset + O_AERON_ERR_OFFENDING_FRAME_LENGTH, 4, ENC_LITTLE_ENDIAN);
bad_frame_length = tvb_get_letohl(tvb, offset + O_AERON_ERR_OFFENDING_FRAME_LENGTH);
ofs = offset + O_AERON_ERR_OFFENDING_HEADER;
proto_tree_add_item(subtree, hf_aeron_err_off_hdr, tvb, offset + ofs, bad_frame_length, ENC_NA);
ofs += bad_frame_length;
string_length = frame_length - ofs;
if (string_length > 0)
{
proto_tree_add_item(subtree, hf_aeron_err_string, tvb, offset + ofs, string_length, ENC_ASCII|ENC_NA);
}
rounded_length = (int) aeron_pos_roundup(frame_length);
if (rounded_length < 0)
return 0;
proto_item_set_len(err_item, rounded_length);
if (frame_length < L_AERON_ERR_MIN)
{
expert_add_info(pinfo, frame_length_item, &ei_aeron_analysis_invalid_err_length);
return (-rounded_length);
}
return (rounded_length);
}
/*----------------------------------------------------------------------------*/
/* Aeron setup packet dissection functions. */
/*----------------------------------------------------------------------------*/
static void aeron_set_stream_mtu_term_length(packet_info * pinfo, aeron_transport_t * transport, guint32 stream_id, guint32 mtu, guint32 term_length)
{
if (PINFO_FD_VISITED(pinfo) == 0)
{
aeron_stream_t * stream = aeron_transport_stream_find(transport, stream_id);
if (stream != NULL)
{
stream->term_length = term_length;
stream->mtu = mtu;
}
}
}
static int dissect_aeron_setup(tvbuff_t * tvb, int offset, packet_info * pinfo, proto_tree * tree, aeron_conversation_info_t * cinfo, aeron_frame_info_t * finfo)
{
proto_tree * subtree;
proto_item * setup_item;
proto_item * frame_length_item;
guint32 frame_length;
proto_item * channel_item;
aeron_transport_t * transport;
guint32 session_id;
guint32 stream_id;
guint32 active_term_id;
guint32 initial_term_id;
guint32 term_offset;
guint32 term_length;
guint32 mtu;
int rounded_length;
aeron_packet_info_t pktinfo;
frame_length = tvb_get_letohl(tvb, offset + O_AERON_SETUP_FRAME_LENGTH);
rounded_length = (int) aeron_pos_roundup(frame_length);
if (rounded_length < 0)
return 0;
term_offset = tvb_get_letohl(tvb, offset + O_AERON_SETUP_TERM_OFFSET);
session_id = tvb_get_letohl(tvb, offset + O_AERON_SETUP_SESSION_ID);
transport = aeron_transport_add(cinfo, session_id, pinfo->num);
stream_id = tvb_get_letohl(tvb, offset + O_AERON_SETUP_STREAM_ID);
initial_term_id = tvb_get_letohl(tvb, offset + O_AERON_SETUP_INITIAL_TERM_ID);
active_term_id = tvb_get_letohl(tvb, offset + O_AERON_SETUP_ACTIVE_TERM_ID);
memset((void *) &pktinfo, 0, sizeof(aeron_packet_info_t));
pktinfo.stream_id = stream_id;
pktinfo.term_id = active_term_id;
pktinfo.term_offset = 0;
pktinfo.info_flags = AERON_PACKET_INFO_FLAGS_STREAM_ID_VALID | AERON_PACKET_INFO_FLAGS_TERM_ID_VALID;
pktinfo.length = 0;
pktinfo.data_length = 0;
pktinfo.receiver_window = 0;
pktinfo.type = HDR_TYPE_SETUP;
pktinfo.flags = 0;
if (aeron_frame_info_setup(pinfo, transport, &pktinfo, finfo) < 0)
return 0;
term_length = tvb_get_letohl(tvb, offset + O_AERON_SETUP_TERM_LENGTH);
mtu = tvb_get_letohl(tvb, offset + O_AERON_SETUP_MTU);
aeron_set_stream_mtu_term_length(pinfo, transport, stream_id, mtu, term_length);
col_append_sep_str(pinfo->cinfo, COL_INFO, ", ", "Setup");
setup_item = proto_tree_add_none_format(tree, hf_aeron_setup, tvb, offset, -1, "Setup Frame: InitTerm 0x%x, ActiveTerm 0x%x, TermLen %" G_GUINT32_FORMAT ", Ofs %" G_GUINT32_FORMAT ", MTU %" G_GUINT32_FORMAT,
initial_term_id, (guint32) active_term_id, term_length, term_offset, mtu);
subtree = proto_item_add_subtree(setup_item, ett_aeron_setup);
channel_item = proto_tree_add_uint64(subtree, hf_aeron_channel_id, tvb, 0, 0, transport->channel_id);
PROTO_ITEM_SET_GENERATED(channel_item);
frame_length_item = proto_tree_add_item(subtree, hf_aeron_setup_frame_length, tvb, offset + O_AERON_SETUP_FRAME_LENGTH, 4, ENC_LITTLE_ENDIAN);
proto_tree_add_item(subtree, hf_aeron_setup_version, tvb, offset + O_AERON_SETUP_VERSION, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(subtree, hf_aeron_setup_flags, tvb, offset + O_AERON_SETUP_FLAGS, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(subtree, hf_aeron_setup_type, tvb, offset + O_AERON_SETUP_TYPE, 2, ENC_LITTLE_ENDIAN);
proto_tree_add_item(subtree, hf_aeron_setup_term_offset, tvb, offset + O_AERON_SETUP_TERM_OFFSET, 4, ENC_LITTLE_ENDIAN);
proto_tree_add_item(subtree, hf_aeron_setup_session_id, tvb, offset + O_AERON_SETUP_SESSION_ID, 4, ENC_LITTLE_ENDIAN);
proto_tree_add_item(subtree, hf_aeron_setup_stream_id, tvb, offset + O_AERON_SETUP_STREAM_ID, 4, ENC_LITTLE_ENDIAN);
proto_tree_add_item(subtree, hf_aeron_setup_initial_term_id, tvb, offset + O_AERON_SETUP_INITIAL_TERM_ID, 4, ENC_LITTLE_ENDIAN);
proto_tree_add_item(subtree, hf_aeron_setup_active_term_id, tvb, offset + O_AERON_SETUP_ACTIVE_TERM_ID, 4, ENC_LITTLE_ENDIAN);
proto_tree_add_item(subtree, hf_aeron_setup_term_length, tvb, offset + O_AERON_SETUP_TERM_LENGTH, 4, ENC_LITTLE_ENDIAN);
proto_tree_add_item(subtree, hf_aeron_setup_mtu, tvb, offset + O_AERON_SETUP_MTU, 4, ENC_LITTLE_ENDIAN);
aeron_sequence_report(tvb, pinfo, subtree, transport, &pktinfo, finfo);
proto_item_set_len(setup_item, rounded_length);
if (frame_length != L_AERON_SETUP)
{
expert_add_info(pinfo, frame_length_item, &ei_aeron_analysis_invalid_setup_length);
return (-rounded_length);
}
return (rounded_length);
}
/*----------------------------------------------------------------------------*/
/* Aeron packet dissector. */
/*----------------------------------------------------------------------------*/
static int dissect_aeron(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, void * user_data _U_)
{
int total_dissected_length = 0;
guint16 frame_type;
proto_tree * aeron_tree;
proto_item * aeron_item;
int dissected_length = 0;
int offset = 0;
int length_remaining;
aeron_conversation_info_t * cinfo;
/* Get enough information to determine the conversation info.
Make sure that we don't throw an exception before we know that
this packet contains our protocol. */
if (tvb_captured_length_remaining(tvb, offset) < 2)
return 0;
frame_type = tvb_get_letohs(tvb, offset + O_AERON_BASIC_TYPE);
cinfo = aeron_setup_conversation_info(pinfo, frame_type);
if (!cinfo)
return 0;
col_add_str(pinfo->cinfo, COL_PROTOCOL, "Aeron");
col_clear(pinfo->cinfo, COL_INFO);
col_add_str(pinfo->cinfo, COL_INFO, aeron_format_transport_uri(cinfo));
col_set_fence(pinfo->cinfo, COL_INFO);
length_remaining = tvb_reported_length(tvb);
aeron_item = proto_tree_add_protocol_format(tree, proto_aeron, tvb, offset, -1, "Aeron Protocol");
aeron_tree = proto_item_add_subtree(aeron_item, ett_aeron);
while (length_remaining > 0)
{
aeron_frame_info_t * finfo = NULL;
if (aeron_sequence_analysis)
{
finfo = aeron_frame_info_add(pinfo->num, (guint32) offset);
}
frame_type = tvb_get_letohs(tvb, offset + O_AERON_BASIC_TYPE);
cinfo = aeron_setup_conversation_info(pinfo, frame_type);
switch (frame_type)
{
case HDR_TYPE_PAD:
dissected_length = dissect_aeron_pad(tvb, offset, pinfo, aeron_tree, cinfo, finfo);
break;
case HDR_TYPE_DATA:
dissected_length = dissect_aeron_data(tvb, offset, pinfo, aeron_tree, cinfo, finfo);
break;
case HDR_TYPE_NAK:
dissected_length = dissect_aeron_nak(tvb, offset, pinfo, aeron_tree, cinfo, finfo);
break;
case HDR_TYPE_SM:
dissected_length = dissect_aeron_sm(tvb, offset, pinfo, aeron_tree, cinfo, finfo);
break;
case HDR_TYPE_ERR:
dissected_length = dissect_aeron_err(tvb, offset, pinfo, aeron_tree);
break;
case HDR_TYPE_SETUP:
dissected_length = dissect_aeron_setup(tvb, offset, pinfo, aeron_tree, cinfo, finfo);
break;
case HDR_TYPE_EXT:
default:
return (total_dissected_length);
}
if (dissected_length <= 0)
{
total_dissected_length += -dissected_length;
proto_item_set_len(aeron_item, total_dissected_length);
return (total_dissected_length);
}
total_dissected_length += dissected_length;
offset += dissected_length;
length_remaining -= dissected_length;
proto_item_set_len(aeron_item, total_dissected_length);
}
return (total_dissected_length);
}
static gboolean test_aeron_packet(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, void * user_data)
{
guint8 ver;
guint16 packet_type;
gint length;
gint length_remaining;
int rc;
length_remaining = tvb_captured_length_remaining(tvb, 0);
if (length_remaining < HDR_LENGTH_MIN)
{
return (FALSE);
}
/* We know we have at least HDR_LENGTH_MIN (12) bytes captured */
ver = tvb_get_guint8(tvb, O_AERON_BASIC_VERSION);
if (ver != 0)
{
return (FALSE);
}
packet_type = tvb_get_letohs(tvb, O_AERON_BASIC_TYPE);
switch (packet_type)
{
case HDR_TYPE_PAD:
case HDR_TYPE_DATA:
case HDR_TYPE_NAK:
case HDR_TYPE_SM:
case HDR_TYPE_ERR:
case HDR_TYPE_SETUP:
case HDR_TYPE_EXT:
break;
default:
return (FALSE);
}
length = (gint) (tvb_get_letohl(tvb, O_AERON_BASIC_FRAME_LENGTH) & 0x7fffffff);
if (!((packet_type == HDR_TYPE_DATA) && (length == 0)))
{
if (length < HDR_LENGTH_MIN)
{
return (FALSE);
}
}
if (packet_type == HDR_TYPE_PAD)
{
/* Pad frames can't have a zero term offset */
guint32 term_offset = tvb_get_letohl(tvb, O_AERON_PAD_TERM_OFFSET);
if (term_offset == 0)
{
return (FALSE);
}
}
else
{
if (length > length_remaining)
{
return (FALSE);
}
}
rc = dissect_aeron(tvb, pinfo, tree, user_data);
if (rc == 0)
{
return (FALSE);
}
return (TRUE);
}
static void aeron_init(void)
{
aeron_channel_id_init();
}
/* Register all the bits needed with the filtering engine */
void proto_register_aeron(void)
{
static hf_register_info hf[] =
{
{ &hf_aeron_channel_id,
{ "Channel ID", "aeron.channel_id", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_pad,
{ "Pad Frame", "aeron.pad", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_pad_frame_length,
{ "Frame Length", "aeron.pad.frame_length", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_pad_version,
{ "Version", "aeron.pad.version", FT_UINT8, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_pad_flags,
{ "Flags", "aeron.pad.flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_pad_type,
{ "Type", "aeron.pad.type", FT_UINT16, BASE_DEC_HEX, VALS(aeron_frame_type), 0x0, NULL, HFILL } },
{ &hf_aeron_pad_term_offset,
{ "Term Offset", "aeron.pad.term_offset", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_pad_session_id,
{ "Session ID", "aeron.pad.session_id", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_pad_stream_id,
{ "Stream ID", "aeron.pad.stream_id", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_pad_term_id,
{ "Term ID", "aeron.pad.term_id", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_data,
{ "Data Frame", "aeron.data", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_data_frame_length,
{ "Frame Length", "aeron.data.frame_length", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_data_version,
{ "Version", "aeron.data.version", FT_UINT8, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_data_flags,
{ "Flags", "aeron.data.flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_data_flags_b,
{ "Begin Message", "aeron.data.flags.b", FT_BOOLEAN, 8, TFS(&tfs_set_notset), DATA_FLAGS_BEGIN, NULL, HFILL } },
{ &hf_aeron_data_flags_e,
{ "End Message", "aeron.data.flags.e", FT_BOOLEAN, 8, TFS(&tfs_set_notset), DATA_FLAGS_END, NULL, HFILL } },
{ &hf_aeron_data_type,
{ "Type", "aeron.data.type", FT_UINT16, BASE_DEC_HEX, VALS(aeron_frame_type), 0x0, NULL, HFILL } },
{ &hf_aeron_data_term_offset,
{ "Term Offset", "aeron.data.term_offset", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_data_next_offset,
{ "Next Offset", "aeron.data.next_offset", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_data_next_offset_term,
{ "Next Offset Term", "aeron.data.next_offset_term", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_data_next_offset_first_frame,
{ "Next Offset First Frame", "aeron.data.next_offset_first_frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_data_session_id,
{ "Session ID", "aeron.data.session_id", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_data_stream_id,
{ "Stream ID", "aeron.data.stream_id", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_data_term_id,
{ "Term ID", "aeron.data.term_id", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_data_reassembly,
{ "Reassembled Fragments", "aeron.data.reassembly", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_data_reassembly_fragment,
{ "Fragment", "aeron.data.reassembly.fragment", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_nak,
{ "NAK Frame", "aeron.nak", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_nak_frame_length,
{ "Frame Length", "aeron.nak.frame_length", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_nak_version,
{ "Version", "aeron.nak.version", FT_UINT8, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_nak_flags,
{ "Flags", "aeron.nak.flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_nak_type,
{ "Type", "aeron.nak.type", FT_UINT16, BASE_DEC_HEX, VALS(aeron_frame_type), 0x0, NULL, HFILL } },
{ &hf_aeron_nak_session_id,
{ "Session ID", "aeron.nak.session_id", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_nak_stream_id,
{ "Stream ID", "aeron.nak.stream_id", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_nak_term_id,
{ "Term ID", "aeron.nak.term_id", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_nak_term_offset,
{ "Term Offset", "aeron.nak.term_offset", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_nak_length,
{ "Length", "aeron.nak.length", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_sm,
{ "Status Message", "aeron.sm", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_sm_frame_length,
{ "Frame Length", "aeron.sm.frame_length", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_sm_version,
{ "Version", "aeron.sm.version", FT_UINT8, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_sm_flags,
{ "Flags", "aeron.sm.flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_sm_flags_s,
{ "Setup", "aeron.sm.flags.s", FT_BOOLEAN, 8, TFS(&tfs_set_notset), STATUS_FLAGS_SETUP, NULL, HFILL } },
{ &hf_aeron_sm_type,
{ "Type", "aeron.sm.type", FT_UINT16, BASE_DEC_HEX, VALS(aeron_frame_type), 0x0, NULL, HFILL } },
{ &hf_aeron_sm_session_id,
{ "Session ID", "aeron.sm.session_id", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_sm_stream_id,
{ "Stream ID", "aeron.sm.stream_id", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_sm_consumption_term_id,
{ "Consumption Term ID", "aeron.sm.consumption_term_id", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_sm_consumption_term_offset,
{ "Consumption Term Offset", "aeron.sm.consumption_term_offset", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_sm_receiver_window,
{ "Receiver Window", "aeron.sm.receiver_window", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_sm_feedback,
{ "Application-specific Feedback", "aeron.sm.feedback", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_err,
{ "Error Header", "aeron.err", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_err_frame_length,
{ "Frame Length", "aeron.err.frame_length", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_err_version,
{ "Version", "aeron.err.version", FT_UINT8, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_err_code,
{ "Error Code", "aeron.err.code", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_err_type,
{ "Type", "aeron.err.type", FT_UINT16, BASE_DEC_HEX, VALS(aeron_frame_type), 0x0, NULL, HFILL } },
{ &hf_aeron_err_off_frame_length,
{ "Offending Frame Length", "aeron.err.off_frame_length", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_err_off_hdr,
{ "Offending Header", "aeron.err.off_hdr", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_err_string,
{ "Error String", "aeron.err.string", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_setup,
{ "Setup Frame", "aeron.setup", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_setup_frame_length,
{ "Frame Length", "aeron.setup.frame_length", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_setup_version,
{ "Version", "aeron.setup.version", FT_UINT8, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_setup_flags,
{ "Flags", "aeron.setup.flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_setup_type,
{ "Type", "aeron.setup.type", FT_UINT16, BASE_DEC_HEX, VALS(aeron_frame_type), 0x0, NULL, HFILL } },
{ &hf_aeron_setup_term_offset,
{ "Term Offset", "aeron.setup.term_offset", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_setup_session_id,
{ "Session ID", "aeron.setup.session_id", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_setup_stream_id,
{ "Stream ID", "aeron.setup.stream_id", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_setup_initial_term_id,
{ "Initial Term ID", "aeron.setup.initial_term_id", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_setup_active_term_id,
{ "Active Term ID", "aeron.setup.active_term_id", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_setup_term_length,
{ "Term Length", "aeron.setup.term_length", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_setup_mtu,
{ "MTU", "aeron.setup.mtu", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_sequence_analysis,
{ "Sequence Analysis", "aeron.sequence_analysis", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_sequence_analysis_channel_prev_frame,
{ "Previous Channel Frame", "aeron.sequence_analysis.prev_channel_frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_sequence_analysis_channel_next_frame,
{ "Next Channel Frame", "aeron.sequence_analysis.next_channel_frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_sequence_analysis_stream_prev_frame,
{ "Previous Stream Frame", "aeron.sequence_analysis.prev_stream_frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_sequence_analysis_stream_next_frame,
{ "Next Stream Frame", "aeron.sequence_analysis.next_stream_frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_sequence_analysis_term_prev_frame,
{ "Previous Term Frame", "aeron.sequence_analysis.prev_term_frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_sequence_analysis_term_next_frame,
{ "Next Term Frame", "aeron.sequence_analysis.next_term_frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_sequence_analysis_term_offset,
{ "Offset also in", "aeron.sequence_analysis.term_offset", FT_NONE, BASE_NONE, NULL, 0x0, "Offset also appears in these frames", HFILL } },
{ &hf_aeron_sequence_analysis_term_offset_frame,
{ "Frame", "aeron.sequence_analysis.term_offset.frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_sequence_analysis_retransmission,
{ "Frame is a retransmission", "aeron.sequence_analysis.retransmission", FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_sequence_analysis_retransmission_rx,
{ "List of NAK frames to which this retransmission applies", "aeron.sequence_analysis.retransmission.rx", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_sequence_analysis_retransmission_rx_frame,
{ "Retransmission applies to frame", "aeron.sequence_analysis.retransmission.rx.frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_sequence_analysis_nak_unrecovered,
{ "Unrecovered Bytes", "aeron.sequence_analysis.nak_unrecovered", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_sequence_analysis_nak_rx,
{ "List of RX Frames for this NAK", "aeron.sequence_analysis.nak_rx", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_sequence_analysis_nak_rx_frame,
{ "RX Frame for this NAK", "aeron.sequence_analysis.nak_rx.frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_sequence_analysis_keepalive,
{ "Frame is a keepalive", "aeron.sequence_analysis.keepalive", FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_stream_analysis,
{ "Stream Analysis", "aeron.stream_analysis", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_stream_analysis_high_term_id,
{ "Highest sent term ID", "aeron.stream_analysis.high_term_id", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_stream_analysis_high_term_offset,
{ "Highest sent term offset", "aeron.stream_analysis.high_term_offset", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_stream_analysis_completed_term_id,
{ "Completed term ID", "aeron.stream_analysis.completed_term_id", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_stream_analysis_completed_term_offset,
{ "Completed term offset", "aeron.stream_analysis.completed_term_offset", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
{ &hf_aeron_stream_analysis_outstanding_bytes,
{ "Outstanding bytes", "aeron.stream_analysis.outstanding_bytes", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }
};
static gint * ett[] =
{
&ett_aeron,
&ett_aeron_pad,
&ett_aeron_data,
&ett_aeron_data_flags,
&ett_aeron_data_reassembly,
&ett_aeron_nak,
&ett_aeron_sm,
&ett_aeron_sm_flags,
&ett_aeron_err,
&ett_aeron_setup,
&ett_aeron_ext,
&ett_aeron_sequence_analysis,
&ett_aeron_sequence_analysis_retransmission_rx,
&ett_aeron_sequence_analysis_nak_rx,
&ett_aeron_sequence_analysis_term_offset,
&ett_aeron_stream_analysis
};
static ei_register_info ei[] =
{
{ &ei_aeron_analysis_nak, { "aeron.analysis.nak", PI_SEQUENCE, PI_NOTE, "NAK", EXPFILL } },
{ &ei_aeron_analysis_window_full, { "aeron.analysis.window_full", PI_SEQUENCE, PI_NOTE, "Receiver window is full", EXPFILL } },
{ &ei_aeron_analysis_idle_rx, { "aeron.analysis.idle_rx", PI_SEQUENCE, PI_NOTE, "This frame contains an Idle RX", EXPFILL } },
{ &ei_aeron_analysis_pacing_rx, { "aeron.analysis.pacing_rx", PI_SEQUENCE, PI_NOTE, "This frame contains a Pacing RX", EXPFILL } },
{ &ei_aeron_analysis_ooo, { "aeron.analysis.ooo", PI_SEQUENCE, PI_NOTE, "This frame contains Out-of-order data", EXPFILL } },
{ &ei_aeron_analysis_ooo_gap, { "aeron.analysis.ooo_gap", PI_SEQUENCE, PI_NOTE, "This frame is an Out-of-order gap", EXPFILL } },
{ &ei_aeron_analysis_keepalive, { "aeron.analysis.keepalive", PI_SEQUENCE, PI_NOTE, "This frame contains a Keepalive", EXPFILL } },
{ &ei_aeron_analysis_window_resize, { "aeron.analysis.window_resize", PI_SEQUENCE, PI_NOTE, "Receiver window resized", EXPFILL } },
{ &ei_aeron_analysis_ooo_sm, { "aeron.analysis.ooo_sm", PI_SEQUENCE, PI_NOTE, "This frame contains an Out-of-order SM", EXPFILL } },
{ &ei_aeron_analysis_keepalive_sm, { "aeron.analysis.keepalive_sm", PI_SEQUENCE, PI_NOTE, "This frame contains a Keepalive SM", EXPFILL } },
{ &ei_aeron_analysis_rx, { "aeron.analysis.rx", PI_SEQUENCE, PI_NOTE, "This frame contains a (likely) retransmission", EXPFILL } },
{ &ei_aeron_analysis_term_id_change, { "aeron.analysis.term_id_change", PI_SEQUENCE, PI_CHAT, "This frame contains a new term ID", EXPFILL } },
{ &ei_aeron_analysis_invalid_pad_length, { "aeron.analysis.invalid_pad_length", PI_MALFORMED, PI_ERROR, "Invalid pad frame length", EXPFILL } },
{ &ei_aeron_analysis_invalid_data_length, { "aeron.analysis.invalid_data_length", PI_MALFORMED, PI_ERROR, "Invalid data frame length", EXPFILL } },
{ &ei_aeron_analysis_invalid_nak_length, { "aeron.analysis.invalid_nak_length", PI_MALFORMED, PI_ERROR, "Invalid NAK frame length", EXPFILL } },
{ &ei_aeron_analysis_invalid_sm_length, { "aeron.analysis.invalid_sm_length", PI_MALFORMED, PI_ERROR, "Invalid SM frame length", EXPFILL } },
{ &ei_aeron_analysis_invalid_err_length, { "aeron.analysis.invalid_err_length", PI_MALFORMED, PI_ERROR, "Invalid error frame length", EXPFILL } },
{ &ei_aeron_analysis_invalid_setup_length, { "aeron.analysis.invalid_setup_length", PI_MALFORMED, PI_ERROR, "Invalid setup frame length", EXPFILL } }
};
module_t * aeron_module;
expert_module_t * expert_aeron;
proto_aeron = proto_register_protocol("Aeron Protocol", "Aeron", "aeron");
proto_register_field_array(proto_aeron, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
expert_aeron = expert_register_protocol(proto_aeron);
expert_register_field_array(expert_aeron, ei, array_length(ei));
aeron_module = prefs_register_protocol(proto_aeron, proto_reg_handoff_aeron);
aeron_heuristic_subdissector_list = register_heur_dissector_list("aeron_msg_payload", proto_aeron);
prefs_register_bool_preference(aeron_module,
"sequence_analysis",
"Analyze transport sequencing",
"Include next/previous frame for channel, stream, and term, and other transport sequence analysis.",
&aeron_sequence_analysis);
prefs_register_bool_preference(aeron_module,
"stream_analysis",
"Analyze stream sequencing",
"Include stream analysis, tracking publisher and subscriber positions. Requires \"Analyze transport sequencing\".",
&aeron_stream_analysis);
prefs_register_bool_preference(aeron_module,
"reassemble_fragments",
"Reassemble fragmented data",
"Reassemble fragmented data messages. Requires \"Analyze transport sequencing\" and \"Analyze stream sequencing\".",
&aeron_reassemble_fragments);
prefs_register_bool_preference(aeron_module,
"use_heuristic_subdissectors",
"Use heuristic sub-dissectors",
"Use a registered heuristic sub-dissector to decode the payload data. Requires \"Analyze transport sequencing\", \"Analyze stream sequencing\", and \"Reassemble fragmented data\".",
&aeron_use_heuristic_subdissectors);
register_init_routine(aeron_init);
aeron_frame_info_tree = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
}
/* The registration hand-off routine */
void proto_reg_handoff_aeron(void)
{
aeron_dissector_handle = create_dissector_handle(dissect_aeron, proto_aeron);
dissector_add_for_decode_as_with_preference("udp.port", aeron_dissector_handle);
heur_dissector_add("udp", test_aeron_packet, "Aeron over UDP", "aeron_udp", proto_aeron, HEURISTIC_DISABLE);
}
/*
* Editor modelines - http://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* vi: set shiftwidth=4 tabstop=8 expandtab:
* :indentSize=4:tabSize=8:noTabs=true:
*/