aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGerald Combs <gerald@wireshark.org>2022-05-24 12:33:33 -0700
committerGerald Combs <gerald@wireshark.org>2022-06-05 19:05:33 +0000
commit5cd591129f6ce44f2d8f511cd0d32a51a7675354 (patch)
treea934801e02a9db04e54a4e64a71c5f3996dfbb5f
parent729b4d3b69172ab116dfda2f9873f69408164ebf (diff)
epan: Convert remaining conversation code to elements.
Convert the address+port conversation code to element lists. Make our conversation keys element lists. Document more of the conversation API. Update the Conversation Hash Table dialog to use the new API. Describe an alternative key type and data structure at the top of conversation.c.
-rw-r--r--epan/conversation.c910
-rw-r--r--epan/conversation.h110
-rw-r--r--epan/packet.c1
-rw-r--r--epan/packet_info.h4
-rw-r--r--ui/qt/conversation_hash_tables_dialog.cpp59
5 files changed, 480 insertions, 604 deletions
diff --git a/epan/conversation.c b/epan/conversation.c
index aef2d5f53a..8fc9bba215 100644
--- a/epan/conversation.c
+++ b/epan/conversation.c
@@ -18,9 +18,18 @@
#include "to_str.h"
#include "conversation.h"
-// To do:
-// - Switch the "id" routines (conversation_new_by_id, etc) to elements.
-// - Switch the rest of the routines to elements.
+// The conversation database is a map of maps that contain conversation_t's.
+// Top-level map keys are strings that describe each conversation type.
+// Second-level map keys are conversation_element_t arrays.
+// {
+// "uint,endpoint": {
+// [ { type: CE_ADDR, addr_val: 10.20.30.40}, { type: CE_PORT, uint_val: 80 } ... ]: <conversation_t>
+// [ { type: CE_ADDR, addr_val: 1.1.1.1}, { type: CE_PORT, uint_val: 53 } ... ]: <conversation_t>
+// }
+// }
+// Instead of using strings as keys we could bit-shift conversation endpoint types
+// into a guint64, e.g. 0x0000000102010200 for CE_ADDRESS,CE_PORT,CE_ADDRESS,CE_PORT,CE_ENDPOINT.
+// We could also use this to prepend a type+length indicator for element arrays.
/* define DEBUG_CONVERSATION for pretty debug printing */
/* #define DEBUG_CONVERSATION */
@@ -30,21 +39,33 @@
int _debug_conversation_indent = 0;
#endif
+/*
+ * We could use an element list here, but this is effectively a parameter list
+ * for find_conversation and is more compact.
+ */
struct endpoint {
address addr1;
address addr2;
- endpoint_type etype;
guint32 port1;
guint32 port2;
+ endpoint_type etype;
};
-struct conversation_key {
- // XXX Replace these with conversation_element_t's.
- address addr1;
- address addr2;
- endpoint_type etype;
- guint32 port1;
- guint32 port2;
+/* Element offsets for address+port conversations */
+enum {
+ ADDR1_IDX,
+ PORT1_IDX,
+ ADDR2_IDX,
+ PORT2_IDX,
+ ENDP_EXACT_IDX,
+ EXACT_IDX_COUNT,
+ PORT2_NO_ADDR2_IDX = ADDR2_IDX,
+ ENDP_NO_ADDR2_IDX = PORT2_IDX,
+ ENDP_NO_PORT2_IDX = PORT2_IDX,
+ ENDP_NO_ADDR2_PORT2_IDX = ADDR2_IDX,
+ NO_ADDR2_IDX_COUNT = ENDP_EXACT_IDX,
+ NO_PORT2_IDX_COUNT = ENDP_EXACT_IDX,
+ NO_ADDR2_PORT2_IDX_COUNT = PORT2_IDX,
};
/*
@@ -84,11 +105,12 @@ static guint32 new_index;
*/
static address null_address_ = ADDRESS_INIT_NONE;
-static conversation_t *conversation_lookup_hashtable(wmem_map_t *conversation_hashtable, const guint32 frame_num, conversation_key_t conv_key);
/* Element count including the terminating CE_ENDPOINT */
-#define MAX_CONVERSATION_ELEMENTS 10 // Arbitrary.
-static size_t conversation_element_count(conversation_element_t *elements) {
+#define MAX_CONVERSATION_ELEMENTS 8 // Arbitrary.
+static size_t
+conversation_element_count(conversation_element_t *elements)
+{
size_t count = 0;
while (elements[count].type != CE_ENDPOINT) {
count++;
@@ -100,11 +122,24 @@ static size_t conversation_element_count(conversation_element_t *elements) {
return count;
}
+static endpoint_type
+conversation_endpoint_type(conversation_element_t *elements)
+{
+ size_t count = 0;
+ while (elements[count].type != CE_ENDPOINT) {
+ count++;
+ DISSECTOR_ASSERT(count < MAX_CONVERSATION_ELEMENTS);
+ }
+ return elements[count].endpoint_type_val;
+}
+
/* Create a string based on element types. */
-static char* conversation_element_list_name(wmem_allocator_t *allocator, conversation_element_t *elements) {
+static char*
+conversation_element_list_name(wmem_allocator_t *allocator, conversation_element_t *elements) {
const char *type_names[] = {
"endpoint",
"address",
+ "port",
"string",
"uint",
"uint64",
@@ -120,6 +155,82 @@ static char* conversation_element_list_name(wmem_allocator_t *allocator, convers
return wmem_strbuf_finalize(conv_hash_group);
}
+#if 0 // debugging
+static char* conversation_element_list_values(conversation_element_t *elements) {
+ const char *type_names[] = {
+ "endpoint",
+ "address",
+ "port",
+ "string",
+ "uint",
+ "uint64",
+ };
+ char *sep = "";
+ GString *value_str = g_string_new("");
+ size_t element_count = conversation_element_count(elements);
+ for (size_t i = 0; i < element_count; i++) {
+ conversation_element_t *cur_el = &elements[i];
+ g_string_append_printf(value_str, "%s%s=", sep, type_names[cur_el->type]);
+ sep = ",";
+ switch (cur_el->type) {
+ case CE_ENDPOINT:
+ g_string_append_printf(value_str, "%d", cur_el->endpoint_type_val);
+ break;
+ case CE_ADDRESS:
+ {
+ char *as = address_to_str(NULL, &cur_el->addr_val);
+ g_string_append(value_str, as);
+ g_free(as);
+ }
+ break;
+ case CE_PORT:
+ g_string_append_printf(value_str, "%u", cur_el->port_val);
+ break;
+ case CE_STRING:
+ g_string_append(value_str, cur_el->str_val);
+ break;
+ case CE_UINT:
+ g_string_append_printf(value_str, "%u", cur_el->uint_val);
+ break;
+ case CE_UINT64:
+ g_string_append_printf(value_str, "%" G_GUINT64_FORMAT, cur_el->uint64_val);
+ break;
+ }
+ }
+ return g_string_free(value_str, FALSE);
+}
+#endif
+
+static bool
+is_no_addr2_key(conversation_element_t *key)
+{
+ if (key[ADDR1_IDX].type == CE_ADDRESS && key[PORT1_IDX].type == CE_PORT
+ && key[PORT2_NO_ADDR2_IDX].type == CE_PORT && key[ENDP_NO_ADDR2_IDX].type == CE_ENDPOINT) {
+ return true;
+ }
+ return false;
+}
+
+static bool
+is_no_port2_key(conversation_element_t *key)
+{
+ if (key[ADDR1_IDX].type == CE_ADDRESS && key[PORT1_IDX].type == CE_PORT
+ && key[ADDR2_IDX].type == CE_ADDRESS && key[ENDP_NO_PORT2_IDX].type == CE_ENDPOINT) {
+ return true;
+ }
+ return false;
+}
+
+static bool
+is_no_addr2_port2_key(conversation_element_t *key)
+{
+ if (key[ADDR1_IDX].type == CE_ADDRESS && key[PORT1_IDX].type == CE_PORT
+ && key[ENDP_NO_ADDR2_PORT2_IDX].type == CE_ENDPOINT) {
+ return true;
+ }
+ return false;
+}
+
/*
* Creates a new conversation with known endpoints based on a conversation
* created with the CONVERSATION_TEMPLATE option while keeping the
@@ -137,12 +248,12 @@ static char* conversation_element_list_name(wmem_allocator_t *allocator, convers
static conversation_t *
conversation_create_from_template(conversation_t *conversation, const address *addr2, const guint32 port2)
{
+ endpoint_type etype = conversation_endpoint_type(conversation->key_ptr);
/*
* Add a new conversation and keep the conversation template only if the
* CONVERSATION_TEMPLATE bit is set for a connection oriented protocol.
*/
- if (conversation->options & CONVERSATION_TEMPLATE &&
- conversation->key_ptr->etype != ENDPOINT_UDP)
+ if (conversation->options & CONVERSATION_TEMPLATE && etype != ENDPOINT_UDP)
{
/*
* Set up a new options mask where the conversation template bit and the
@@ -154,8 +265,8 @@ conversation_create_from_template(conversation_t *conversation, const address *a
/*
* Are both the NO_ADDR2 and NO_PORT2 wildcards set in the options mask?
*/
- if (conversation->options & NO_ADDR2 &&
- conversation->options & NO_PORT2)
+ if (conversation->options & NO_ADDR2 && conversation->options & NO_PORT2
+ && is_no_addr2_port2_key(conversation->key_ptr))
{
/*
* The conversation template was created without knowledge of both
@@ -164,11 +275,11 @@ conversation_create_from_template(conversation_t *conversation, const address *a
*/
new_conversation_from_template =
conversation_new(conversation->setup_frame,
- &conversation->key_ptr->addr1, addr2,
- conversation->key_ptr->etype, conversation->key_ptr->port1,
+ &conversation->key_ptr[ADDR1_IDX].addr_val, addr2,
+ etype, conversation->key_ptr[PORT1_IDX].port_val,
port2, options);
}
- else if (conversation->options & NO_PORT2)
+ else if (conversation->options & NO_PORT2 && is_no_port2_key(conversation->key_ptr))
{
/*
* The conversation template was created without knowledge of port 2
@@ -176,11 +287,11 @@ conversation_create_from_template(conversation_t *conversation, const address *a
*/
new_conversation_from_template =
conversation_new(conversation->setup_frame,
- &conversation->key_ptr->addr1, &conversation->key_ptr->addr2,
- conversation->key_ptr->etype, conversation->key_ptr->port1,
+ &conversation->key_ptr[ADDR1_IDX].addr_val, &conversation->key_ptr[ADDR2_IDX].addr_val,
+ etype, conversation->key_ptr[PORT1_IDX].port_val,
port2, options);
}
- else if (conversation->options & NO_ADDR2)
+ else if (conversation->options & NO_ADDR2 && is_no_addr2_key(conversation->key_ptr))
{
/*
* The conversation template was created without knowledge of address
@@ -188,9 +299,9 @@ conversation_create_from_template(conversation_t *conversation, const address *a
*/
new_conversation_from_template =
conversation_new(conversation->setup_frame,
- &conversation->key_ptr->addr1, addr2,
- conversation->key_ptr->etype, conversation->key_ptr->port1,
- conversation->key_ptr->port2, options);
+ &conversation->key_ptr[ADDR1_IDX].addr_val, addr2,
+ etype, conversation->key_ptr[PORT1_IDX].port_val,
+ conversation->key_ptr[PORT2_NO_ADDR2_IDX].port_val, options);
}
else
{
@@ -217,282 +328,6 @@ conversation_create_from_template(conversation_t *conversation, const address *a
}
/*
- * Compute the hash value for two given address/port pairs if the match
- * is to be exact.
- */
-/* https://web.archive.org/web/20070615045827/http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx#existing
- * (formerly at http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx#existing)
- * One-at-a-Time hash
- */
-guint
-conversation_hash_exact(gconstpointer v)
-{
- const conversation_key_t key = (const conversation_key_t)v;
- guint hash_val;
- address tmp_addr;
-
- hash_val = 0;
- tmp_addr.len = 4;
-
- hash_val = add_address_to_hash(hash_val, &key->addr1);
-
- tmp_addr.data = &key->port1;
- hash_val = add_address_to_hash(hash_val, &tmp_addr);
-
- hash_val = add_address_to_hash(hash_val, &key->addr2);
-
- tmp_addr.data = &key->port2;
- hash_val = add_address_to_hash(hash_val, &tmp_addr);
-
- hash_val += ( hash_val << 3 );
- hash_val ^= ( hash_val >> 11 );
- hash_val += ( hash_val << 15 );
-
- return hash_val;
-}
-
-/*
- * Compare two conversation keys for an exact match.
- */
-static gint
-conversation_match_exact(gconstpointer v, gconstpointer w)
-{
- const conversation_key_t v1 = (const conversation_key_t)v;
- const conversation_key_t v2 = (const conversation_key_t)w;
-
- if (v1->etype != v2->etype)
- return 0; /* different types of port */
-
- /*
- * Are the first and second port 1 values the same, the first and
- * second port 2 values the same, the first and second address
- * 1 values the same, and the first and second address 2 values
- * the same?
- */
- if (v1->port1 == v2->port1 &&
- v1->port2 == v2->port2 &&
- addresses_equal(&v1->addr1, &v2->addr1) &&
- addresses_equal(&v1->addr2, &v2->addr2)) {
- /*
- * Yes. It's the same conversation, and the two
- * address/port pairs are going in the same direction.
- */
- return 1;
- }
-
- /*
- * Is the first port 2 the same as the second port 1, the first
- * port 1 the same as the second port 2, the first address 2
- * the same as the second address 1, and the first address 1
- * the same as the second address 2?
- */
- if (v1->port2 == v2->port1 &&
- v1->port1 == v2->port2 &&
- addresses_equal(&v1->addr2, &v2->addr1) &&
- addresses_equal(&v1->addr1, &v2->addr2)) {
- /*
- * Yes. It's the same conversation, and the two
- * address/port pairs are going in opposite directions.
- */
- return 1;
- }
-
- /*
- * The addresses or the ports don't match.
- */
- return 0;
-}
-
-/*
- * Compute the hash value for two given address/port pairs if the match
- * has a wildcard address 2.
- */
-static guint
-conversation_hash_no_addr2(gconstpointer v)
-{
- const conversation_key_t key = (const conversation_key_t)v;
- guint hash_val;
- address tmp_addr;
-
- hash_val = 0;
- tmp_addr.len = 4;
-
- hash_val = add_address_to_hash(hash_val, &key->addr1);
-
- tmp_addr.data = &key->port1;
- hash_val = add_address_to_hash(hash_val, &tmp_addr);
-
- tmp_addr.data = &key->port2;
- hash_val = add_address_to_hash(hash_val, &tmp_addr);
-
- hash_val += ( hash_val << 3 );
- hash_val ^= ( hash_val >> 11 );
- hash_val += ( hash_val << 15 );
-
- return hash_val;
-}
-
-/*
- * Compare two conversation keys, except for the address 2 value.
- * We don't check both directions of the conversation - the routine
- * doing the hash lookup has to do two searches, as the hash key
- * will be different for the two directions.
- */
-static gint
-conversation_match_no_addr2(gconstpointer v, gconstpointer w)
-{
- const conversation_key_t v1 = (const conversation_key_t)v;
- const conversation_key_t v2 = (const conversation_key_t)w;
-
- if (v1->etype != v2->etype)
- return 0; /* different types of port */
-
- /*
- * Are the first and second port 1 values the same, the first and
- * second port 2 valuess the same, and the first and second
- * address 1 values the same?
- */
- if (v1->port1 == v2->port1 &&
- v1->port2 == v2->port2 &&
- addresses_equal(&v1->addr1, &v2->addr1)) {
- /*
- * Yes. It's the same conversation, and the two
- * address/port pairs are going in the same direction.
- */
- return 1;
- }
-
- /*
- * The addresses or the ports don't match.
- */
- return 0;
-}
-
-/*
- * Compute the hash value for two given address/port pairs if the match
- * has a wildcard port 2.
- */
-static guint
-conversation_hash_no_port2(gconstpointer v)
-{
- const conversation_key_t key = (const conversation_key_t)v;
- guint hash_val;
- address tmp_addr;
-
- hash_val = 0;
- tmp_addr.len = 4;
-
- hash_val = add_address_to_hash(hash_val, &key->addr1);
-
- tmp_addr.data = &key->port1;
- hash_val = add_address_to_hash(hash_val, &tmp_addr);
-
- hash_val = add_address_to_hash(hash_val, &key->addr2);
-
- hash_val += ( hash_val << 3 );
- hash_val ^= ( hash_val >> 11 );
- hash_val += ( hash_val << 15 );
-
- return hash_val;
-}
-
-/*
- * Compare two conversation keys, except for the port 2 value.
- * We don't check both directions of the conversation - the routine
- * doing the hash lookup has to do two searches, as the hash key
- * will be different for the two directions.
- */
-static gint
-conversation_match_no_port2(gconstpointer v, gconstpointer w)
-{
- const conversation_key_t v1 = (const conversation_key_t)v;
- const conversation_key_t v2 = (const conversation_key_t)w;
-
- if (v1->etype != v2->etype)
- return 0; /* different types of port */
-
- /*
- * Are the first and second port 1 values the same, the first and
- * second address 1 values the same, and the first and second
- * address 2 values the same?
- */
- if (v1->port1 == v2->port1 &&
- addresses_equal(&v1->addr1, &v2->addr1) &&
- addresses_equal(&v1->addr2, &v2->addr2)) {
- /*
- * Yes. It's the same conversation, and the two
- * address/port pairs are going in the same direction.
- */
- return 1;
- }
-
- /*
- * The addresses or the ports don't match.
- */
- return 0;
-}
-
-/*
- * Compute the hash value for two given address/port pairs if the match
- * has a wildcard address 2 and port 2.
- */
-static guint
-conversation_hash_no_addr2_or_port2(gconstpointer v)
-{
- const conversation_key_t key = (const conversation_key_t)v;
- guint hash_val;
- address tmp_addr;
-
- hash_val = 0;
- tmp_addr.len = 4;
-
- hash_val = add_address_to_hash(hash_val, &key->addr1);
-
- tmp_addr.data = &key->port1;
- hash_val = add_address_to_hash(hash_val, &tmp_addr);
-
- hash_val += ( hash_val << 3 );
- hash_val ^= ( hash_val >> 11 );
- hash_val += ( hash_val << 15 );
-
- return hash_val;
-}
-
-/*
- * Compare the address 1 and port 1 in the two conversation keys.
- * We don't check both directions of the conversation - the routine
- * doing the hash lookup has to do two searches, as the hash key
- * will be different for the two directions.
- */
-static gint
-conversation_match_no_addr2_or_port2(gconstpointer v, gconstpointer w)
-{
- const conversation_key_t v1 = (const conversation_key_t)v;
- const conversation_key_t v2 = (const conversation_key_t)w;
-
- if (v1->etype != v2->etype)
- return 0; /* different types of port */
-
- /*
- * Are the first and second port 1 values the same and the first
- * and second address 1 values the same?
- */
- if (v1->port1 == v2->port1 &&
- addresses_equal(&v1->addr1, &v2->addr1)) {
- /*
- * Yes. It's the same conversation, and the two
- * address/port pairs are going in the same direction.
- */
- return 1;
- }
-
- /*
- * The addresses or the ports don't match.
- */
- return 0;
-}
-
-/*
* Compute the hash value for two given element lists if the match
* is to be exact.
*/
@@ -513,6 +348,11 @@ conversation_hash_element_list(gconstpointer v)
case CE_ADDRESS:
hash_val = add_address_to_hash(hash_val, &element->addr_val);
break;
+ case CE_PORT:
+ tmp_addr.len = (int) sizeof(element->port_val);
+ tmp_addr.data = &element->port_val;
+ hash_val = add_address_to_hash(hash_val, &tmp_addr);
+ break;
case CE_STRING:
tmp_addr.len = (int) strlen(element->str_val);
tmp_addr.data = element->str_val;
@@ -566,6 +406,11 @@ conversation_match_element_list(gconstpointer v1, gconstpointer v2)
return FALSE;
}
break;
+ case CE_PORT:
+ if (element1->port_val != element2->port_val) {
+ return FALSE;
+ }
+ break;
case CE_STRING:
if (strcmp(element1->str_val, element2->str_val)) {
return FALSE;
@@ -611,21 +456,59 @@ conversation_init(void)
* pointed to by conversation data structures that were freed
* above.
*/
- conversation_hashtable_exact_addr_port =
- wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), conversation_hash_exact,
- conversation_match_exact);
- conversation_hashtable_no_addr2 =
- wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), conversation_hash_no_addr2,
- conversation_match_no_addr2);
- conversation_hashtable_no_port2 =
- wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), conversation_hash_no_port2,
- conversation_match_no_port2);
- conversation_hashtable_no_addr2_or_port2 =
- wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), conversation_hash_no_addr2_or_port2,
- conversation_match_no_addr2_or_port2);
-
- conversation_hashtable_element_list =
- wmem_map_new(wmem_epan_scope(), wmem_str_hash, g_str_equal);
+ conversation_hashtable_element_list = wmem_map_new(wmem_epan_scope(), wmem_str_hash, g_str_equal);
+
+ conversation_element_t exact_elements[EXACT_IDX_COUNT] = {
+ { CE_ADDRESS, .addr_val = ADDRESS_INIT_NONE },
+ { CE_PORT, .port_val = 0 },
+ { CE_ADDRESS, .addr_val = ADDRESS_INIT_NONE },
+ { CE_PORT, .port_val = 0 },
+ { CE_ENDPOINT, .endpoint_type_val = ENDPOINT_NONE }
+ };
+ char *exact_map_key = conversation_element_list_name(wmem_epan_scope(), exact_elements);
+ conversation_hashtable_exact_addr_port = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(),
+ conversation_hash_element_list,
+ conversation_match_element_list);
+ wmem_map_insert(conversation_hashtable_element_list, wmem_strdup(wmem_epan_scope(), exact_map_key),
+ conversation_hashtable_exact_addr_port);
+
+ conversation_element_t no_addr2_elements[NO_ADDR2_IDX_COUNT] = {
+ { CE_ADDRESS, .addr_val = ADDRESS_INIT_NONE },
+ { CE_PORT, .port_val = 0 },
+ { CE_PORT, .port_val = 0 },
+ { CE_ENDPOINT, .endpoint_type_val = ENDPOINT_NONE }
+ };
+ char *no_addr2_map_key = conversation_element_list_name(wmem_epan_scope(), no_addr2_elements);
+ conversation_hashtable_no_addr2 = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(),
+ conversation_hash_element_list,
+ conversation_match_element_list);
+ wmem_map_insert(conversation_hashtable_element_list, wmem_strdup(wmem_epan_scope(), no_addr2_map_key),
+ conversation_hashtable_no_addr2);
+
+ conversation_element_t no_port2_elements[NO_PORT2_IDX_COUNT] = {
+ { CE_ADDRESS, .addr_val = ADDRESS_INIT_NONE },
+ { CE_PORT, .port_val = 0 },
+ { CE_ADDRESS, .addr_val = ADDRESS_INIT_NONE },
+ { CE_ENDPOINT, .endpoint_type_val = ENDPOINT_NONE }
+ };
+ char *no_port2_map_key = conversation_element_list_name(wmem_epan_scope(), no_port2_elements);
+ conversation_hashtable_no_port2 = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(),
+ conversation_hash_element_list,
+ conversation_match_element_list);
+ wmem_map_insert(conversation_hashtable_element_list, wmem_strdup(wmem_epan_scope(), no_port2_map_key),
+ conversation_hashtable_no_port2);
+
+ conversation_element_t no_addr2_or_port2_elements[NO_ADDR2_PORT2_IDX_COUNT] = {
+ { CE_ADDRESS, .addr_val = ADDRESS_INIT_NONE },
+ { CE_PORT, .port_val = 0 },
+ { CE_ENDPOINT, .endpoint_type_val = ENDPOINT_NONE }
+ };
+ char *no_addr2_or_port2_map_key = conversation_element_list_name(wmem_epan_scope(), no_addr2_or_port2_elements);
+ conversation_hashtable_no_addr2_or_port2 = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(),
+ conversation_hash_element_list,
+ conversation_match_element_list);
+ wmem_map_insert(conversation_hashtable_element_list, wmem_strdup(wmem_epan_scope(), no_addr2_or_port2_map_key),
+ conversation_hashtable_no_addr2_or_port2);
conversation_element_t id_elements[2] = {
{ CE_UINT, .uint_val = 0 },
@@ -770,48 +653,6 @@ conversation_remove_from_hashtable(wmem_map_t *hashtable, conversation_t *conv)
}
}
-#if 0 // debugging
-static char* conversation_element_list_values(conversation_element_t *elements) {
- const char *type_names[] = {
- "endpoint",
- "address",
- "string",
- "uint",
- "uint64",
- };
- char *sep = "";
- GString *value_str = g_string_new("");
- size_t element_count = conversation_element_count(elements);
- for (size_t i = 0; i < element_count; i++) {
- conversation_element_t *cur_el = &elements[i];
- g_string_append_printf(value_str, "%s%s=", sep, type_names[cur_el->type]);
- sep = ",";
- switch (cur_el->type) {
- case CE_ADDRESS:
- {
- char *as = address_to_str(NULL, &cur_el->addr_val);
- g_string_append(value_str, as);
- g_free(as);
- }
- break;
- case CE_ENDPOINT:
- g_string_append_printf(value_str, "%d", cur_el->endpoint_type_val);
- break;
- case CE_STRING:
- g_string_append(value_str, cur_el->str_val);
- break;
- case CE_UINT:
- g_string_append_printf(value_str, "%u", cur_el->uint_val);
- break;
- case CE_UINT64:
- g_string_append_printf(value_str, "%" G_GUINT64_FORMAT, cur_el->uint64_val);
- break;
- }
- }
- return g_string_free(value_str, FALSE);
-}
-#endif
-
conversation_t *conversation_new_full(const guint32 setup_frame, conversation_element_t *elements)
{
DISSECTOR_ASSERT(elements);
@@ -840,8 +681,7 @@ conversation_t *conversation_new_full(const guint32 setup_frame, conversation_el
new_index++;
- // XXX Overloading conversation_key_t this way is terrible and we shouldn't do it.
- conversation->key_ptr = (conversation_key_t) conv_key;
+ conversation->key_ptr = conv_key;
conversation_insert_into_hashtable(el_list_map, conversation);
return conversation;
}
@@ -863,8 +703,7 @@ conversation_new(const guint32 setup_frame, const address *addr1, const address
"A conversation template may not be constructed without wildcard options");
*/
wmem_map_t* hashtable;
- conversation_t *conversation=NULL;
- conversation_key_t new_key;
+ conversation_t *conversation = NULL;
/*
* Verify that the correct options are used, if any.
*/
@@ -959,34 +798,59 @@ conversation_new(const guint32 setup_frame, const address *addr1, const address
}
#endif
+ // Always allocate an "exact"-sized key in case we call conversation_set_port2
+ // or conversation_set_addr2 later.
+ conversation_element_t *new_key = wmem_alloc(wmem_file_scope(), sizeof(conversation_element_t) * EXACT_IDX_COUNT);
+ size_t addr2_idx = 0;
+ size_t port2_idx = 0;
+ size_t endp_idx;
+
+ new_key[ADDR1_IDX].type = CE_ADDRESS;
+ if (addr1 != NULL) {
+ copy_address_wmem(wmem_file_scope(), &new_key[ADDR1_IDX].addr_val, addr1);
+ } else {
+ clear_address(&new_key[ADDR1_IDX].addr_val);
+ }
+ new_key[PORT1_IDX].type = CE_PORT;
+ new_key[PORT1_IDX].port_val = port1;
+
if (options & NO_ADDR2) {
if (options & (NO_PORT2|NO_PORT2_FORCE)) {
hashtable = conversation_hashtable_no_addr2_or_port2;
+ endp_idx = ENDP_NO_ADDR2_PORT2_IDX;
} else {
hashtable = conversation_hashtable_no_addr2;
+ port2_idx = PORT2_NO_ADDR2_IDX;
+ endp_idx = ENDP_NO_ADDR2_IDX;
}
} else {
+ addr2_idx = ADDR2_IDX;
if (options & (NO_PORT2|NO_PORT2_FORCE)) {
hashtable = conversation_hashtable_no_port2;
+ endp_idx = ENDP_NO_PORT2_IDX;
} else {
hashtable = conversation_hashtable_exact_addr_port;
+ port2_idx = PORT2_IDX;
+ endp_idx = ENDP_EXACT_IDX;
}
}
- new_key = wmem_new0(wmem_file_scope(), struct conversation_key);
- if (addr1 != NULL) {
- copy_address_wmem(wmem_file_scope(), &new_key->addr1, addr1);
- } else {
- clear_address(&new_key->addr1);
+ if (addr2_idx) {
+ new_key[addr2_idx].type = CE_ADDRESS;
+ if (addr2 != NULL) {
+ copy_address_wmem(wmem_file_scope(), &new_key[addr2_idx].addr_val, addr2);
+ } else {
+ clear_address(&new_key[addr2_idx].addr_val);
+ }
}
- if (addr2 != NULL) {
- copy_address_wmem(wmem_file_scope(), &new_key->addr2, addr2);
- } else {
- clear_address(&new_key->addr2);
+
+ if (port2_idx) {
+ new_key[port2_idx].type = CE_PORT;
+ new_key[port2_idx].port_val = port2;
}
- new_key->etype = etype;
- new_key->port1 = port1;
- new_key->port2 = port2;
+
+ new_key[endp_idx].type = CE_ENDPOINT;
+ new_key[endp_idx].endpoint_type_val = etype;
conversation = wmem_new0(wmem_file_scope(), conversation_t);
@@ -1020,15 +884,14 @@ conversation_new_by_id(const guint32 setup_frame, const endpoint_type etype, con
elements[0].uint_val = id;
elements[1].type = CE_ENDPOINT;
elements[1].endpoint_type_val = etype;
- // XXX Overloading conversation_key_t this way is terrible and we shouldn't do it.
- conversation->key_ptr = (conversation_key_t) elements;
+ conversation->key_ptr = elements;
conversation_insert_into_hashtable(conversation_hashtable_id, conversation);
return conversation;
}
/*
- * Set the port 2 value in a key. Remove the original from table,
+ * Set the port 2 value in a key. Remove the original from table,
* update the options and port values, insert the updated key.
*/
void
@@ -1051,11 +914,21 @@ conversation_set_port2(conversation_t *conv, const guint32 port)
} else {
conversation_remove_from_hashtable(conversation_hashtable_no_port2, conv);
}
+
+ // Shift our endpoint element over and set our port. We assume that conv->key_ptr
+ // was created with conversation_new and that we have enough element slots.
conv->options &= ~NO_PORT2;
- conv->key_ptr->port2 = port;
if (conv->options & NO_ADDR2) {
+ // addr1,port1,endp -> addr1,port1,port2,endp
+ conv->key_ptr[ENDP_NO_ADDR2_IDX] = conv->key_ptr[ENDP_NO_ADDR2_PORT2_IDX];
+ conv->key_ptr[PORT2_NO_ADDR2_IDX].type = CE_PORT;
+ conv->key_ptr[PORT2_NO_ADDR2_IDX].port_val = port;
conversation_insert_into_hashtable(conversation_hashtable_no_addr2, conv);
} else {
+ // addr1,port1,addr2,endp -> addr1,port1,addr2,port2,endp
+ conv->key_ptr[ENDP_EXACT_IDX] = conv->key_ptr[ENDP_NO_PORT2_IDX];
+ conv->key_ptr[PORT2_IDX].type = CE_PORT;
+ conv->key_ptr[PORT2_IDX].port_val = port;
conversation_insert_into_hashtable(conversation_hashtable_exact_addr_port, conv);
}
DENDENT();
@@ -1088,17 +961,29 @@ conversation_set_addr2(conversation_t *conv, const address *addr)
} else {
conversation_remove_from_hashtable(conversation_hashtable_no_port2, conv);
}
+
+ // Shift our endpoint and, if needed, our port element over and set our address.
+ // We assume that conv->key_ptr was created with conversation_new and that we have
+ // enough element slots.
conv->options &= ~NO_ADDR2;
- copy_address_wmem(wmem_file_scope(), &conv->key_ptr->addr2, addr);
+ wmem_map_t *hashtable;
if (conv->options & NO_PORT2) {
- conversation_insert_into_hashtable(conversation_hashtable_no_port2, conv);
+ // addr1,port1,endp -> addr1,port1,addr2,endp
+ conv->key_ptr[ENDP_NO_PORT2_IDX] = conv->key_ptr[ENDP_NO_ADDR2_PORT2_IDX];
+ hashtable = conversation_hashtable_no_port2;
} else {
- conversation_insert_into_hashtable(conversation_hashtable_exact_addr_port, conv);
+ // addr1,port1,port2,endp -> addr1,port1,addr2,port2,endp
+ conv->key_ptr[ENDP_EXACT_IDX] = conv->key_ptr[ENDP_NO_ADDR2_IDX];
+ conv->key_ptr[PORT2_IDX] = conv->key_ptr[PORT2_NO_ADDR2_IDX];
+ hashtable = conversation_hashtable_exact_addr_port;
}
+ conv->key_ptr[ADDR2_IDX].type = CE_ADDRESS;
+ copy_address_wmem(wmem_file_scope(), &conv->key_ptr[ADDR2_IDX].addr_val, addr);
+ conversation_insert_into_hashtable(hashtable, conv);
DENDENT();
}
-static conversation_t *conversation_lookup_hashtable(wmem_map_t *conversation_hashtable, const guint32 frame_num, conversation_key_t conv_key)
+static conversation_t *conversation_lookup_hashtable(wmem_map_t *conversation_hashtable, const guint32 frame_num, conversation_element_t *conv_key)
{
conversation_t* convo = NULL;
conversation_t* match = NULL;
@@ -1137,7 +1022,7 @@ conversation_t *find_conversation_full(const guint32 frame_num, conversation_ele
return NULL;
}
- return conversation_lookup_hashtable(el_list_map, frame_num, (conversation_key_t)elements);
+ return conversation_lookup_hashtable(el_list_map, frame_num, elements);
}
/*
@@ -1145,30 +1030,67 @@ conversation_t *find_conversation_full(const guint32 frame_num, conversation_ele
* {addr1, port1, addr2, port2} and set up before frame_num.
*/
static conversation_t *
-conversation_lookup_addr_port(wmem_map_t *hashtable, const guint32 frame_num, const address *addr1, const address *addr2,
- const endpoint_type etype, const guint32 port1, const guint32 port2)
+conversation_lookup_exact(const guint32 frame_num, const address *addr1, const guint32 port1,
+ const address *addr2, const guint32 port2, const endpoint_type etype)
{
- struct conversation_key key;
+ conversation_element_t key[EXACT_IDX_COUNT] = {
+ { CE_ADDRESS, .addr_val = *addr1 },
+ { CE_PORT, .port_val = port1 },
+ { CE_ADDRESS, .addr_val = *addr2 },
+ { CE_PORT, .port_val = port2 },
+ { CE_ENDPOINT, .endpoint_type_val = etype },
+ };
+ return conversation_lookup_hashtable(conversation_hashtable_exact_addr_port, frame_num, key);
+}
- /*
- * We don't make a copy of the address data, we just copy the
- * pointer to it, as "key" disappears when we return.
- */
- if (addr1 != NULL) {
- key.addr1 = *addr1;
- } else {
- clear_address(&key.addr1);
- }
- if (addr2 != NULL) {
- key.addr2 = *addr2;
- } else {
- clear_address(&key.addr2);
- }
- key.etype = etype;
- key.port1 = port1;
- key.port2 = port2;
+/*
+ * Search a particular hash table for a conversation with the specified
+ * {addr1, port1, port2} and set up before frame_num.
+ */
+static conversation_t *
+conversation_lookup_no_addr2(const guint32 frame_num, const address *addr1, const guint32 port1,
+ const guint32 port2, const endpoint_type etype)
+{
+ conversation_element_t key[NO_ADDR2_IDX_COUNT] = {
+ { CE_ADDRESS, .addr_val = *addr1 },
+ { CE_PORT, .port_val = port1 },
+ { CE_PORT, .port_val = port2 },
+ { CE_ENDPOINT, .endpoint_type_val = etype },
+ };
+ return conversation_lookup_hashtable(conversation_hashtable_no_addr2, frame_num, key);
+}
+
+/*
+ * Search a particular hash table for a conversation with the specified
+ * {addr1, port1, addr2} and set up before frame_num.
+ */
+static conversation_t *
+conversation_lookup_no_port2(const guint32 frame_num, const address *addr1, const guint32 port1,
+ const address *addr2, const endpoint_type etype)
+{
+ conversation_element_t key[NO_PORT2_IDX_COUNT] = {
+ { CE_ADDRESS, .addr_val = *addr1 },
+ { CE_PORT, .port_val = port1 },
+ { CE_ADDRESS, .addr_val = *addr2 },
+ { CE_ENDPOINT, .endpoint_type_val = etype },
+ };
+ return conversation_lookup_hashtable(conversation_hashtable_no_port2, frame_num, key);
+}
- return conversation_lookup_hashtable(hashtable, frame_num, &key);
+/*
+ * Search a particular hash table for a conversation with the specified
+ * {addr1, port1, addr2} and set up before frame_num.
+ */
+static conversation_t *
+conversation_lookup_no_addr2_or_port2(const guint32 frame_num, const address *addr1, const guint32 port1,
+ const endpoint_type etype)
+{
+ conversation_element_t key[NO_ADDR2_PORT2_IDX_COUNT] = {
+ { CE_ADDRESS, .addr_val = *addr1 },
+ { CE_PORT, .port_val = port1 },
+ { CE_ENDPOINT, .endpoint_type_val = etype },
+ };
+ return conversation_lookup_hashtable(conversation_hashtable_no_addr2_or_port2, frame_num, key);
}
/*
@@ -1229,18 +1151,12 @@ find_conversation(const guint32 frame_num, const address *addr_a, const address
*/
DPRINT(("trying exact match: %s:%d -> %s:%d",
addr_a_str, port_a, addr_b_str, port_b));
- conversation =
- conversation_lookup_addr_port(conversation_hashtable_exact_addr_port,
- frame_num, addr_a, addr_b, etype,
- port_a, port_b);
+ conversation = conversation_lookup_exact(frame_num, addr_a, port_a, addr_b, port_b, etype);
/* Didn't work, try the other direction */
if (conversation == NULL) {
DPRINT(("trying exact match: %s:%d -> %s:%d",
addr_b_str, port_b, addr_a_str, port_a));
- conversation =
- conversation_lookup_addr_port(conversation_hashtable_exact_addr_port,
- frame_num, addr_b, addr_a, etype,
- port_b, port_a);
+ conversation = conversation_lookup_exact(frame_num, addr_b, port_b, addr_a, port_a, etype);
}
if ((conversation == NULL) && (addr_a->type == AT_FC)) {
/* In Fibre channel, OXID & RXID are never swapped as
@@ -1248,10 +1164,7 @@ find_conversation(const guint32 frame_num, const address *addr_a, const address
*/
DPRINT(("trying exact match: %s:%d -> %s:%d",
addr_b_str, port_a, addr_a_str, port_b));
- conversation =
- conversation_lookup_addr_port(conversation_hashtable_exact_addr_port,
- frame_num, addr_b, addr_a, etype,
- port_a, port_b);
+ conversation = conversation_lookup_exact(frame_num, addr_b, port_a, addr_a, port_b, etype);
}
DPRINT(("exact match %sfound",conversation?"":"not "));
if (conversation != NULL)
@@ -1274,19 +1187,14 @@ find_conversation(const guint32 frame_num, const address *addr_a, const address
*/
DPRINT(("trying wildcarded match: %s:%d -> *:%d",
addr_a_str, port_a, port_b));
- conversation =
- conversation_lookup_addr_port(conversation_hashtable_no_addr2,
- frame_num, addr_a, addr_b, etype, port_a, port_b);
+ conversation = conversation_lookup_no_addr2(frame_num, addr_a, port_a, port_b, etype);
if ((conversation == NULL) && (addr_a->type == AT_FC)) {
/* In Fibre channel, OXID & RXID are never swapped as
* TCP/UDP ports are in TCP/IP.
*/
DPRINT(("trying wildcarded match: %s:%d -> *:%d",
addr_b_str, port_a, port_b));
- conversation =
- conversation_lookup_addr_port(conversation_hashtable_no_addr2,
- frame_num, addr_b, addr_a, etype,
- port_a, port_b);
+ conversation = conversation_lookup_no_addr2(frame_num, addr_b, port_a, port_b, etype);
}
if (conversation != NULL) {
/*
@@ -1329,9 +1237,7 @@ find_conversation(const guint32 frame_num, const address *addr_a, const address
if (!(options & NO_ADDR_B)) {
DPRINT(("trying wildcarded match: %s:%d -> *:%d",
addr_b_str, port_b, port_a));
- conversation =
- conversation_lookup_addr_port(conversation_hashtable_no_addr2,
- frame_num, addr_b, addr_a, etype, port_b, port_a);
+ conversation = conversation_lookup_no_addr2(frame_num, addr_b, port_b, port_a, etype);
if (conversation != NULL) {
/*
* If this is for a connection-oriented
@@ -1374,17 +1280,13 @@ find_conversation(const guint32 frame_num, const address *addr_a, const address
*/
DPRINT(("trying wildcarded match: %s:%d -> %s:*",
addr_a_str, port_a, addr_b_str));
- conversation =
- conversation_lookup_addr_port(conversation_hashtable_no_port2,
- frame_num, addr_a, addr_b, etype, port_a, port_b);
+ conversation = conversation_lookup_no_port2(frame_num, addr_a, port_a, addr_b, etype);
if ((conversation == NULL) && (addr_a->type == AT_FC)) {
/* In Fibre channel, OXID & RXID are never swapped as
* TCP/UDP ports are in TCP/IP
*/
DPRINT(("trying wildcarded match: %s:%d -> %s:*", addr_b_str, port_a, addr_a_str));
- conversation =
- conversation_lookup_addr_port(conversation_hashtable_no_port2,
- frame_num, addr_b, addr_a, etype, port_a, port_b);
+ conversation = conversation_lookup_no_port2(frame_num, addr_b, port_a, addr_a, etype);
}
if (conversation != NULL) {
/*
@@ -1427,9 +1329,7 @@ find_conversation(const guint32 frame_num, const address *addr_a, const address
if (!(options & NO_PORT_B)) {
DPRINT(("trying wildcarded match: %s:%d -> %s:*",
addr_b_str, port_b, addr_a_str));
- conversation =
- conversation_lookup_addr_port(conversation_hashtable_no_port2,
- frame_num, addr_b, addr_a, etype, port_b, port_a);
+ conversation = conversation_lookup_no_port2(frame_num, addr_b, port_b, addr_a, etype);
if (conversation != NULL) {
/*
* If this is for a connection-oriented
@@ -1466,9 +1366,7 @@ find_conversation(const guint32 frame_num, const address *addr_a, const address
* (Neither "addr_b" nor "port_b" take part in this lookup.)
*/
DPRINT(("trying wildcarded match: %s:%d -> *:*", addr_a_str, port_a));
- conversation =
- conversation_lookup_addr_port(conversation_hashtable_no_addr2_or_port2,
- frame_num, addr_a, addr_b, etype, port_a, port_b);
+ conversation = conversation_lookup_no_addr2_or_port2(frame_num, addr_a, port_a, etype);
if (conversation != NULL) {
/*
* If this is for a connection-oriented protocol:
@@ -1521,15 +1419,11 @@ find_conversation(const guint32 frame_num, const address *addr_a, const address
if ((addr_a != NULL) && (addr_a->type == AT_FC)) {
DPRINT(("trying wildcarded match: %s:%d -> *:*",
addr_b_str, port_a));
- conversation =
- conversation_lookup_addr_port(conversation_hashtable_no_addr2_or_port2,
- frame_num, addr_b, addr_a, etype, port_a, port_b);
+ conversation = conversation_lookup_no_addr2_or_port2(frame_num, addr_b, port_a, etype);
} else {
DPRINT(("trying wildcarded match: %s:%d -> *:*",
addr_b_str, port_b));
- conversation =
- conversation_lookup_addr_port(conversation_hashtable_no_addr2_or_port2,
- frame_num, addr_b, addr_a, etype, port_b, port_a);
+ conversation = conversation_lookup_no_addr2_or_port2(frame_num, addr_b, port_b, etype);
}
if (conversation != NULL) {
/*
@@ -1578,7 +1472,7 @@ find_conversation_by_id(const guint32 frame, const endpoint_type etype, const gu
{ CE_ENDPOINT, .endpoint_type_val = etype }
};
- return conversation_lookup_hashtable(conversation_hashtable_id, frame, (conversation_key_t)elements);
+ return conversation_lookup_hashtable(conversation_hashtable_id, frame, elements);
}
void
@@ -1762,7 +1656,7 @@ try_conversation_dissector_by_id(const endpoint_type etype, const guint32 id, tv
conversation_t *
find_conversation_pinfo(packet_info *pinfo, const guint options)
{
- conversation_t *conv=NULL;
+ conversation_t *conv = NULL;
DINSTR(gchar *src_str = address_to_str(NULL, &pinfo->src));
DINSTR(gchar *dst_str = address_to_str(NULL, &pinfo->dst));
@@ -1780,7 +1674,7 @@ find_conversation_pinfo(packet_info *pinfo, const guint options)
pinfo->conv_endpoint->etype, pinfo->conv_endpoint->port1,
pinfo->conv_endpoint->port2, 0)) != NULL) {
DPRINT(("found previous conversation for frame #%u (last_frame=%d)",
- pinfo->num, conv->last_frame));
+ pinfo->num, conv->last_frame));
if (pinfo->num > conv->last_frame) {
conv->last_frame = pinfo->num;
}
@@ -1859,62 +1753,49 @@ conversation_create_endpoint(struct _packet_info *pinfo, address* addr1, address
endpoint_type etype, guint32 port1, guint32 port2)
{
pinfo->conv_endpoint = wmem_new0(pinfo->pool, struct endpoint);
- pinfo->use_endpoint = TRUE;
- if (addr1 != NULL)
+ if (addr1 != NULL) {
copy_address_wmem(pinfo->pool, &pinfo->conv_endpoint->addr1, addr1);
-
- if (addr2 != NULL)
+ }
+ if (addr2 != NULL) {
copy_address_wmem(pinfo->pool, &pinfo->conv_endpoint->addr2, addr2);
+ }
pinfo->conv_endpoint->etype = etype;
pinfo->conv_endpoint->port1 = port1;
pinfo->conv_endpoint->port2 = port2;
+
+ pinfo->use_endpoint = TRUE;
}
void
-conversation_create_endpoint_by_id(struct _packet_info *pinfo,
- endpoint_type etype, guint32 id)
+conversation_create_endpoint_by_id(struct _packet_info *pinfo, endpoint_type etype, guint32 id)
{
- /* Force the lack of a address or port B */
- conversation_create_endpoint(pinfo, &null_address_, &null_address_, etype, id, 0);
+ pinfo->conv_elements = wmem_alloc0(pinfo->pool, sizeof(conversation_element_t) * 2);
+ pinfo->conv_elements[0].type = CE_UINT;
+ pinfo->conv_elements[1].uint_val = id;
+ pinfo->conv_elements[1].type = CE_ENDPOINT;
+ pinfo->conv_elements[1].endpoint_type_val = etype;
+
+ pinfo->use_endpoint = TRUE;
}
guint32
conversation_get_endpoint_by_id(struct _packet_info *pinfo, endpoint_type etype, const guint options)
{
- if (pinfo->conv_endpoint == NULL)
+ if (pinfo->conv_endpoint == NULL) {
return 0;
+ }
- if ((pinfo->conv_endpoint->etype != etype) &&
- ((options & USE_LAST_ENDPOINT) != USE_LAST_ENDPOINT))
+ if (pinfo->conv_elements[0].type != CE_UINT || pinfo->conv_elements[1].type != CE_ENDPOINT) {
return 0;
+ }
- return pinfo->conv_endpoint->port1;
-}
-
-wmem_map_t *
-get_conversation_hashtable_exact(void)
-{
- return conversation_hashtable_exact_addr_port;
-}
-
-wmem_map_t *
-get_conversation_hashtable_no_addr2(void)
-{
- return conversation_hashtable_no_addr2;
-}
-
-wmem_map_t *
-get_conversation_hashtable_no_port2(void)
-{
- return conversation_hashtable_no_port2;
-}
+ if ((pinfo->conv_elements[1].endpoint_type_val != etype) && ((options & USE_LAST_ENDPOINT) != USE_LAST_ENDPOINT)) {
+ return 0;
+ }
-wmem_map_t *
-get_conversation_hashtable_no_addr2_or_port2(void)
-{
- return conversation_hashtable_no_addr2_or_port2;
+ return pinfo->conv_elements[0].uint_val;
}
wmem_map_t *
@@ -1923,28 +1804,50 @@ get_conversation_hashtables(void)
return conversation_hashtable_element_list;
}
-address*
-conversation_key_addr1(const conversation_key_t key)
+const address*
+conversation_key_addr1(const conversation_element_t *key)
{
- return &key->addr1;
+ const address *addr = &null_address_;
+ if (key[ADDR1_IDX].type == CE_ADDRESS) {
+ addr = &key[ADDR1_IDX].addr_val;
+ }
+ return addr;
}
-address*
-conversation_key_addr2(const conversation_key_t key)
+guint32
+conversation_key_port1(const conversation_element_t * key)
{
- return &key->addr2;
+ guint32 port = 0;
+ if (key[ADDR1_IDX].type == CE_ADDRESS && key[PORT1_IDX].type == CE_PORT) {
+ port = key[PORT1_IDX].port_val;
+ }
+ return port;
}
-guint32
-conversation_key_port1(const conversation_key_t key)
+const address*
+conversation_key_addr2(const conversation_element_t * key)
{
- return key->port1;
+ const address *addr = &null_address_;
+ if (key[ADDR1_IDX].type == CE_ADDRESS && key[PORT1_IDX].type == CE_PORT && key[ADDR2_IDX].type == CE_ADDRESS) {
+ addr = &key[ADDR2_IDX].addr_val;
+ }
+ return addr;
}
guint32
-conversation_key_port2(const conversation_key_t key)
+conversation_key_port2(const conversation_element_t * key)
{
- return key->port2;
+ guint32 port = 0;
+ if (key[ADDR1_IDX].type == CE_ADDRESS && key[PORT1_IDX].type == CE_PORT) {
+ if (key[ADDR2_IDX].type == CE_ADDRESS && key[PORT2_IDX].type == CE_PORT) {
+ // Exact
+ port = key[PORT2_IDX].port_val;
+ } else if (key[PORT2_NO_ADDR2_IDX].type == CE_PORT) {
+ // No addr 2
+ port = key[PORT2_NO_ADDR2_IDX].port_val;
+ }
+ }
+ return port;
}
WS_DLL_PUBLIC
@@ -1984,21 +1887,6 @@ endpoint_type conversation_pt_to_endpoint_type(port_type pt)
return ENDPOINT_NONE;
}
-gchar*
-conversation_get_html_hash(const conversation_key_t key)
-{
- gchar *hash, *addr1, *addr2;
-
- addr1 = address_to_str(NULL, &key->addr1);
- addr2 = address_to_str(NULL, &key->addr2);
- hash = wmem_strdup_printf(NULL, "<tr><td>%s</td><td>%d</td><td>%s</td><td>%d</td></tr>\n",
- addr1, key->port1, addr2, key->port2);
- wmem_free(NULL, addr1);
- wmem_free(NULL, addr2);
-
- return hash;
-}
-
/*
* Editor modelines - https://www.wireshark.org/tools/modelines.html
*
diff --git a/epan/conversation.h b/epan/conversation.h
index c34dd9614f..3533116d42 100644
--- a/epan/conversation.h
+++ b/epan/conversation.h
@@ -91,10 +91,32 @@ typedef enum {
} endpoint_type;
/**
- * Key used for identifying a conversation.
+ * Conversation element type.
*/
-struct conversation_key;
-typedef struct conversation_key* conversation_key_t;
+typedef enum {
+ CE_ENDPOINT,
+ CE_ADDRESS,
+ CE_PORT,
+ CE_STRING,
+ CE_UINT,
+ CE_UINT64,
+} conversation_element_type;
+
+/**
+ * Elements used to identify conversations for *_full routines and pinfo->conv_elements.
+ * Arrays must be terminated with an element .type set to CE_ENDPOINT.
+ */
+typedef struct conversation_element {
+ conversation_element_type type;
+ union {
+ endpoint_type endpoint_type_val;
+ address addr_val;
+ unsigned int port_val;
+ const char *str_val;
+ unsigned int uint_val;
+ uint64_t uint64_val;
+ };
+} conversation_element_t;
/**
* Data structure representing a conversation.
@@ -110,17 +132,16 @@ typedef struct conversation {
wmem_tree_t *data_list; /** list of data associated with conversation */
wmem_tree_t *dissector_tree; /** tree containing protocol dissector client associated with conversation */
guint options; /** wildcard flags */
- conversation_key_t key_ptr; /** pointer to the key for this conversation */
+ conversation_element_t *key_ptr; /** Keys are conversation element arrays terminated with a CE_ENDPOINT */
} conversation_t;
-
struct endpoint;
typedef struct endpoint* endpoint_t;
-WS_DLL_PUBLIC address* conversation_key_addr1(const conversation_key_t key);
-WS_DLL_PUBLIC address* conversation_key_addr2(const conversation_key_t key);
-WS_DLL_PUBLIC guint32 conversation_key_port1(const conversation_key_t key);
-WS_DLL_PUBLIC guint32 conversation_key_port2(const conversation_key_t key);
+WS_DLL_PUBLIC const address* conversation_key_addr1(const conversation_element_t *key);
+WS_DLL_PUBLIC guint32 conversation_key_port1(const conversation_element_t *key);
+WS_DLL_PUBLIC const address* conversation_key_addr2(const conversation_element_t *key);
+WS_DLL_PUBLIC guint32 conversation_key_port2(const conversation_element_t *key);
/**
* Create a new hash tables for conversations.
@@ -133,32 +154,6 @@ extern void conversation_init(void);
extern void conversation_epan_reset(void);
/**
- * Conversation element type.
- */
-typedef enum {
- CE_ENDPOINT,
- CE_ADDRESS,
- CE_STRING,
- CE_UINT,
- CE_UINT64,
-} conversation_element_type;
-
-/**
- * Elements used to identify conversations for *_full routines and pinfo->conv_elements.
- * Arrays must be terminated with an element .type set to CE_ENDPOINT.
- */
-typedef struct conversation_element {
- conversation_element_type type;
- union {
- endpoint_type endpoint_type_val;
- address addr_val;
- const char *str_val;
- unsigned int uint_val;
- uint64_t uint64_val;
- };
-} conversation_element_t;
-
-/**
* Create a new conversation identified by a list of elements.
* @param setup_frame The first frame in the conversation.
* @param elements An array of element types and values. Must not be NULL. Must be terminated with a CE_ENDPOINT element.
@@ -297,12 +292,36 @@ WS_DLL_PUBLIC void conversation_set_dissector_from_frame_number(conversation_t *
WS_DLL_PUBLIC dissector_handle_t conversation_get_dissector(conversation_t *conversation, const guint32 frame_num);
+/**
+ * Save address+port information in the current packet info which can be matched by
+ * find_conversation_pinfo. Supports wildcarding.
+ * @param pinfo Packet info.
+ * @param addr1 The first address in the identifying tuple.
+ * @param addr2 The second address in the identifying tuple.
+ * @param etype The endpoint type.
+ * @param port1 The first port in the identifying tuple.
+ * @param port2 The second port in the identifying tuple.
+ */
WS_DLL_PUBLIC void conversation_create_endpoint(struct _packet_info *pinfo, address* addr1, address* addr2,
endpoint_type etype, guint32 port1, guint32 port2);
+/**
+ * Save ID information in the current packet info which can be matched by
+ * conversation_get_endpoint_by_id. Does not support wildcarding.
+ * @param pinfo Packet info.
+ * @param etype The endpoint type.
+ * @param id A unique ID.
+ */
WS_DLL_PUBLIC void conversation_create_endpoint_by_id(struct _packet_info *pinfo,
endpoint_type etype, guint32 id);
+/**
+ * @brief conversation_get_endpoint_by_id
+ * @param pinfo Packet info.
+ * @param etype The endpoint type.
+ * @param options USE_LAST_ENDPOINT or 0.
+ * @return The endpoint ID if successful, or 0 on failure.
+ */
WS_DLL_PUBLIC guint32 conversation_get_endpoint_by_id(struct _packet_info *pinfo,
endpoint_type etype, const guint options);
@@ -325,18 +344,20 @@ WS_DLL_PUBLIC gboolean try_conversation_dissector_by_id(const endpoint_type etyp
/* These routines are used to set undefined values for a conversation */
+/**
+ * Set the second port in a conversation created with conversation_new.
+ * @param conv Conversation. Must be created with conversation_new.
+ * @param port The second port to set.
+ */
WS_DLL_PUBLIC void conversation_set_port2(conversation_t *conv, const guint32 port);
+/**
+ * Set the second address in a conversation created with conversation_new.
+ * @param conv Conversation. Must be created with conversation_new.
+ * @param port The second address to set.
+ */
WS_DLL_PUBLIC void conversation_set_addr2(conversation_t *conv, const address *addr);
-WS_DLL_PUBLIC wmem_map_t *get_conversation_hashtable_exact(void);
-
-WS_DLL_PUBLIC wmem_map_t *get_conversation_hashtable_no_addr2(void);
-
-WS_DLL_PUBLIC wmem_map_t * get_conversation_hashtable_no_port2(void);
-
-WS_DLL_PUBLIC wmem_map_t *get_conversation_hashtable_no_addr2_or_port2(void);
-
/**
* @brief Get a hash table of conversation hash table.
*
@@ -353,9 +374,6 @@ WS_DLL_PUBLIC endpoint_type conversation_pt_to_endpoint_type(port_type pt);
WS_DLL_PUBLIC guint conversation_hash_exact(gconstpointer v);
-/* Provide a wmem_alloced (NULL scope) hash string using HTML tags */
-WS_DLL_PUBLIC gchar *conversation_get_html_hash(const conversation_key_t key);
-
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/epan/packet.c b/epan/packet.c
index 341a38672c..a3f0f865f1 100644
--- a/epan/packet.c
+++ b/epan/packet.c
@@ -591,6 +591,7 @@ dissect_record(epan_dissect_t *edt, int file_type_subtype,
edt->pi.ptype = PT_NONE;
edt->pi.use_endpoint = FALSE;
edt->pi.conv_endpoint = NULL;
+ edt->pi.conv_elements = NULL;
edt->pi.p2p_dir = P2P_DIR_UNKNOWN;
edt->pi.link_dir = LINK_DIR_UNKNOWN;
edt->pi.src_win_scale = -1; /* unknown Rcv.Wind.Shift */
diff --git a/epan/packet_info.h b/epan/packet_info.h
index 41ba15856f..50f5cda733 100644
--- a/epan/packet_info.h
+++ b/epan/packet_info.h
@@ -72,8 +72,8 @@ typedef struct _packet_info {
guint32 match_uint; /**< matched uint for calling subdissector from table */
const char *match_string; /**< matched string for calling subdissector from table */
gboolean use_endpoint; /**< TRUE if endpoint member should be used for conversations */
- struct endpoint* conv_endpoint; /**< Data that can be used for conversations */
- struct conversation_element *conv_elements; /**< Conversation identifier; alternative to conv_endpoint */
+ struct endpoint* conv_endpoint; /**< Data that can be used for address+port conversations, including wildcarding */
+ struct conversation_element *conv_elements; /**< Arbritrary conversation identifier; can't be wildcarded */
guint16 can_desegment; /**< >0 if this segment could be desegmented.
A dissector that can offer this API (e.g.
TCP) sets can_desegment=2, then
diff --git a/ui/qt/conversation_hash_tables_dialog.cpp b/ui/qt/conversation_hash_tables_dialog.cpp
index 9a26838ca9..80dec2e482 100644
--- a/ui/qt/conversation_hash_tables_dialog.cpp
+++ b/ui/qt/conversation_hash_tables_dialog.cpp
@@ -33,6 +33,7 @@ fill_named_table(gpointer key, gpointer value _U_, gpointer user_data)
if (html_table->isEmpty()) {
html_table->append("<tr>");
int addr_count = 1;
+ int port_count = 1;
int string_count = 1;
int uint_count = 1;
int uint64_count = 1;
@@ -42,6 +43,9 @@ fill_named_table(gpointer key, gpointer value _U_, gpointer user_data)
case CE_ADDRESS:
title = QString("Address %1").arg(addr_count++);
break;
+ case CE_PORT:
+ title = QString("Port %1").arg(port_count++);
+ break;
case CE_STRING:
title = QString("String %1").arg(string_count++);
break;
@@ -70,6 +74,9 @@ title_done:
case CE_ADDRESS:
val = address_to_qstring(&cur_el->addr_val);
break;
+ case CE_PORT:
+ val = QString::number(cur_el->port_val);
+ break;
case CE_STRING:
val = cur_el->str_val;
break;
@@ -102,12 +109,7 @@ ConversationHashTablesDialog::ConversationHashTablesDialog(QWidget *parent) :
QString html;
- html += "<h3>Conversation Hash Tables</h3>\n";
-
- html += hashTableToHtmlTable("conversation_hashtable_exact", get_conversation_hashtable_exact());
- html += hashTableToHtmlTable("conversation_hashtable_no_addr2", get_conversation_hashtable_no_addr2());
- html += hashTableToHtmlTable("conversation_hashtable_no_port2", get_conversation_hashtable_no_port2());
- html += hashTableToHtmlTable("conversation_hashtable_no_addr2_or_port2", get_conversation_hashtable_no_addr2_or_port2());
+ html += "<h2>Conversation Hash Tables</h2>\n";
wmem_map_t *conversation_tables = get_conversation_hashtables();
wmem_list_t *table_names = wmem_map_get_keys(NULL, conversation_tables);
@@ -116,7 +118,12 @@ ConversationHashTablesDialog::ConversationHashTablesDialog(QWidget *parent) :
const char *table_name = static_cast<const char *>(wmem_list_frame_data(cur_frame));
wmem_map_t *table = static_cast<wmem_map_t *>(wmem_map_lookup(conversation_tables, table_name));
- html += QString("<p>%1, %2 entries</p>\n").arg(table_name).arg(wmem_map_size(table));
+ if (!table) {
+ html += QString("<h3>%1, Error: table not found</h3>\n").arg(table_name);
+ continue;
+ }
+
+ html += QString("<h3>%1, %2 entries</h3>\n").arg(table_name).arg(wmem_map_size(table));
QString html_table;
html += "<table>\n";
wmem_map_foreach(table, fill_named_table, &html_table);
@@ -131,41 +138,3 @@ ConversationHashTablesDialog::~ConversationHashTablesDialog()
{
delete ui;
}
-
-static void
-populate_html_table(gpointer data, gpointer user_data)
-{
- const conversation_key_t conv_key = (conversation_key_t)data;
- QString* html_table = (QString*)user_data;
- gchar* tmp = conversation_get_html_hash(conv_key);
-
- // XXX Add a column for the hash value.
- (*html_table) += QString(tmp);
- wmem_free(NULL, tmp);
-}
-
-const QString ConversationHashTablesDialog::hashTableToHtmlTable(const QString table_name, wmem_map_t *hash_table)
-{
- wmem_list_t *conversation_keys = NULL;
- guint num_keys = 0;
- if (hash_table)
- {
- conversation_keys = wmem_map_get_keys(NULL, hash_table);
- num_keys = wmem_list_count(conversation_keys);
- }
-
- QString html_table = QString("<p>%1, %2 entries</p>").arg(table_name).arg(num_keys);
- if (num_keys > 0)
- {
- int one_em = fontMetrics().height();
- html_table += QString("<table cellpadding=\"%1\">\n").arg(one_em / 4);
-
- html_table += "<tr><th align=\"left\">Address 1</th><th align=\"left\">Port 1</th><th align=\"left\">Address 2</th><th align=\"left\">Port 2</th></tr>\n";
-
- wmem_list_foreach(conversation_keys, populate_html_table, (void*)&html_table);
- html_table += "</table>\n";
- }
- if (conversation_keys)
- wmem_destroy_list(conversation_keys);
- return html_table;
-}