wireshark源码探索No.5---wireshark的流管理

总览

wireshark中的流管理命名是conversation,可能与好多用session标记流的有些别扭,代码中如果看到conversation或者conv,基本都是指代会话信息。

让我们理清,会话包含什么?首先所有的会话应该在一个大型链表或者数组或者hash中;然后每个会话应该包含源目的;然后源要有地址,目的也要有地址;这样就有了一个大概的结构:conversationS->conversation->src,dst->address,那么在wireshark中这些是如何表示的呢?

所有的会话保存到以下四个hash中:

/*
 * Hash table for conversations with no wildcards.
 */
static GHashTable *conversation_hashtable_exact = NULL;

/*
 * Hash table for conversations with one wildcard address.
 */
static GHashTable *conversation_hashtable_no_addr2 = NULL;

/*
 * Hash table for conversations with one wildcard port.
 */
static GHashTable *conversation_hashtable_no_port2 = NULL;

/*
 * Hash table for conversations with one wildcard address and port.
 */
static GHashTable *conversation_hashtable_no_addr2_or_port2 = NULL;

每一个hash中存储的都是会话的数据结构:

typedef struct conversation_key {
	struct conversation_key *next;
	address	addr1;
	address	addr2;
	port_type ptype;
	guint32	port1;
	guint32	port2;
} conversation_key;

会话中的源目的都是address结构:

typedef struct _address {
    int           type;         /* type of address */
    int           len;          /* length of address, in bytes */
    const void   *data;         /* pointer to address data data指向的内存可能是流管理专门申请的,也有可能是
									tvbuff数据包中的一块数据,具体使用要分场景。*/

    /* private */
    void         *priv;
} address;


address

说完了这个大概的结构,就轮到一一解释每个结构的操作接口等内容了,这次我们反过来介绍,先说address结构,wireshark中所有的address信息包含在两个文件中address.h和address_type.c/h。前者是address的定义以及操作接口,后者是每种address的打印、转换接口,我们主要看前者即可。讲解方法仍然是直接在源码中介绍,我主要在一些地方标记注释。

/* address.h
 * Definitions for structures storing addresses, and for the type of
 * variables holding port-type values
 *
 * 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.
 */

#ifndef __ADDRESS_H__
#define __ADDRESS_H__

#include <string.h>     /* for memcmp */

#include "tvbuff.h"
#include "wmem/wmem.h"

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

/* Types of "global" addresses Wireshark knows about. */
/* Address types can be added here if there are many dissectors that use them or just
 * within a specific dissector.
 * If an address type is added here, it must be "registered" within address_types.c
 * For dissector address types, just use the address_type_dissector_register function
 * from address_types.h
 */
/*
	所有wireshark能够支持的地址类型,从上面的注释知晓,如果你觉得某个地址比较常用,
	可以放到这里面,但是注意要在address_type.c中注册。那么address_type.c是干嘛的呢?

	所有定义的地址类型的展现打印都是在address_type.c里面定义的。
*/
typedef enum {
    AT_NONE,               /* no link-layer address */
    AT_ETHER,              /* MAC (Ethernet, 802.x, FDDI) address */
    AT_IPv4,               /* IPv4 */
    AT_IPv6,               /* IPv6 */
    AT_IPX,                /* IPX */
    AT_FC,                 /* Fibre Channel */
    AT_FCWWN,              /* Fibre Channel WWN */
    AT_STRINGZ,            /* null-terminated string */
    AT_EUI64,              /* IEEE EUI-64 */
    AT_IB,                 /* Infiniband GID/LID */
    AT_AX25,               /* AX.25 */

    AT_END_OF_LIST         /* Must be last in list */
} address_type;

/*
	address结构,wireshark中用到的所有网络数据结构都是基于此,算是会话的基石。
	传统的地址数据结构,基本都是利用union或者多个struct来标注,例如分别定义mac,ipv4,ipv6等等,
	但是这些方式都对操作者造成负担,需要记忆多种数据结构,而且传递参数时容易混乱(例如统一转为void*,
	如何确定真实的值)。在流管理中,多种数据结构也造成了会话的难以创建,(需要多层流管理)。

	wireshark做了一定创新,将所有的数据结构统一定义为data,然后分别用type和len标记data
	的类型,虽然增加了两个int的数据冗余,但是减少了复杂性,而且提高了扩展性。
*/

typedef struct _address {
    int           type;         /* type of address */
    int           len;          /* length of address, in bytes */
    const void   *data;         /* pointer to address data data指向的内存可能是流管理专门申请的,也有可能是
									tvbuff数据包中的一块数据,具体使用要分场景。*/

    /* private */
    void         *priv;
} address;

#define ADDRESS_INIT(type, len, data) {type, len, data, NULL}
#define ADDRESS_INIT_NONE ADDRESS_INIT(AT_NONE, 0, NULL)

/*
	下面全是有关地址的接口函数,从中可以发现都是直接使用的内联函数,
	毕竟地址处理比较频繁,但是操作量又比较小,使用内联,一定程度提高性能。
*/


/*清空地址信息,注意data只是置为空,并未free*/
static inline void
clear_address(address *addr)
{
    addr->type = AT_NONE;
    addr->len  = 0;
    addr->data = NULL;
    addr->priv = NULL;
}

/** Initialize an address with the given values.
 *
 * @param addr [in,out] The address to initialize.
 * @param addr_type [in] Address type.
 * @param addr_len [in] The length in bytes of the address data. For example, 4 for
 *                     AT_IPv4 or sizeof(struct e_in6_addr) for AT_IPv6.
 * @param addr_data [in] Pointer to the address data.
 */
/*设置地址信息,data是直接指向,地址是申请好了的*/
static inline void
set_address(address *addr, int addr_type, int addr_len, const void *addr_data) {
    if (addr_len == 0) {
        /* Zero length must mean no data */
        g_assert(addr_data == NULL);
    } else {
        /* Must not be AT_NONE - AT_NONE must have no data */
        g_assert(addr_type != AT_NONE);
        /* Make sure we *do* have data */
        g_assert(addr_data != NULL);
    }
    addr->type = addr_type;
    addr->len  = addr_len;
    addr->data = addr_data;
    addr->priv = NULL;
}

/** Initialize an address from TVB data.
 *
 * Same as set_address but it takes a TVB and an offset. This is preferred
 * over passing the return value of tvb_get_ptr() to set_address().
 *
 * This calls tvb_get_ptr() (including throwing any exceptions) before
 * modifying the address.
 *
 * @param addr [in,out] The address to initialize.
 * @param addr_type [in] Address type.
 * @param tvb [in] Pointer to the TVB.
 * @param offset [in] Offset within the TVB.
 * @param addr_len [in] The length in bytes of the address data. For example, 4 for
 *                     AT_IPv4 or sizeof(struct e_in6_addr) for AT_IPv6.
 */
/*设置地址信息,data是直接指向tvb中的数据,一般此地址是临时使用,用来做查询等使用*/
static inline void
set_address_tvb(address *addr, int addr_type, int addr_len, tvbuff_t *tvb, int offset) {
    const void *p;

    if (addr_len != 0) {
        /* Must not be AT_NONE - AT_NONE must have no data */
        g_assert(addr_type != AT_NONE);
        p = tvb_get_ptr(tvb, offset, addr_len);
    } else
        p = NULL;
    set_address(addr, addr_type, addr_len, p);
}

/** Initialize an address with the given values, allocating a new buffer
 * for the address data using wmem-scoped memory.
 *
 * @param scope [in] The lifetime of the allocated memory, e.g., wmem_packet_scope()
 * @param addr [in,out] The address to initialize.
 * @param addr_type [in] Address type.
 * @param addr_len [in] The length in bytes of the address data. For example, 4 for
 *                     AT_IPv4 or sizeof(struct e_in6_addr) for AT_IPv6.
 * @param addr_data [in] Pointer to the address data.
 */
/*设置地址信息,data数据调用内存管理申请。一般此地址是长期使用的,例如会话结构中的地址*/
static inline void
alloc_address_wmem(wmem_allocator_t *scope, address *addr,
                        int addr_type, int addr_len, const void *addr_data) {
    g_assert(addr);
    clear_address(addr);
    addr->type = addr_type;
    if (addr_len == 0) {
        /* Zero length must mean no data */
        g_assert(addr_data == NULL);
        /* Nothing to copy */
        return;
    }
    /* Must not be AT_NONE - AT_NONE must have no data */
    g_assert(addr_type != AT_NONE);
    /* Make sure we *do* have data to copy */
    g_assert(addr_data != NULL);
    addr->data = addr->priv = wmem_memdup(scope, addr_data, addr_len);
    addr->len = addr_len;
}

/** Allocate an address from TVB data.
 *
 * Same as alloc_address_wmem but it takes a TVB and an offset.
 *
 * @param scope [in] The lifetime of the allocated memory, e.g., wmem_packet_scope()
 * @param addr [in,out] The address to initialize.
 * @param addr_type [in] Address type.
 * @param addr_len [in] The length in bytes of the address data. For example, 4 for
 *                     AT_IPv4 or sizeof(struct e_in6_addr) for AT_IPv6.
 * @param tvb [in] Pointer to the TVB.
 * @param offset [in] Offset within the TVB.
 */
/*同上,只不过指定了一下地址是从tvb包中获取的*/
static inline void
alloc_address_tvb(wmem_allocator_t *scope, address *addr,
                    int addr_type, int addr_len,  tvbuff_t *tvb, int offset) {
    const void *p;

    p = tvb_get_ptr(tvb, offset, addr_len);
    alloc_address_wmem(scope, addr, addr_type, addr_len, p);
}

/** Compare two addresses.
 *
 * @param addr1 [in] The first address to compare.
 * @param addr2 [in] The second address to compare.
 * @return 0 if the addresses are equal,
 *  A positive number if addr1 > addr2 in some nondefined metric,
 *  A negative number if addr1 < addr2 in some nondefined metric.
 */
 /*地址比较,返回大小*/
static inline int
cmp_address(const address *addr1, const address *addr2) {
    if (addr1->type > addr2->type) return 1;
    if (addr1->type < addr2->type) return -1;
    if (addr1->len  > addr2->len) return 1;
    if (addr1->len  < addr2->len) return -1;
    if (addr1->len == 0) {
        /*
         * memcmp(NULL, NULL, 0) is *not* guaranteed to work, so
         * if both addresses are zero-length, don't compare them
         * (there's nothing to compare, so they're equal).
         */
        return 0;
    }
    return memcmp(addr1->data, addr2->data, addr1->len);
}

/** Check two addresses for equality.
 *
 * Given two addresses, return "true" if they're equal, "false" otherwise.
 * Addresses are equal only if they have the same type and length; if the
 * length is zero, they are then equal, otherwise the data must be the
 * same.
 *
 * @param addr1 [in] The first address to compare.
 * @param addr2 [in] The second address to compare.
 * @return TRUE if the adresses are equal, FALSE otherwise.
 */
 /*地址相等比较,返回真假*/
static inline gboolean
addresses_equal(const address *addr1, const address *addr2) {
    /*
     * memcmp(NULL, NULL, 0) is *not* guaranteed to work, so
     * if both addresses are zero-length, don't compare them
     * (there's nothing to compare, so they're equal).
     */
    if (addr1->type == addr2->type &&
        addr1->len == addr2->len &&
        (addr1->len == 0 ||
         memcmp(addr1->data, addr2->data, addr1->len) == 0))
        return TRUE;
    return FALSE;
}

/** Check the data of two addresses for equality.
 *
 * Given two addresses, return "true" if they have the same length and,
 * their data is equal, "false" otherwise.
 * The address types are ignored. This can be used to compare custom
 * address types defined with address_type_dissector_register.
 *
 * @param addr1 [in] The first address to compare.
 * @param addr2 [in] The second address to compare.
 * @return TRUE if the adresses are equal, FALSE otherwise.
 */
/*地址data比较,返回真假*/
static inline gboolean
addresses_data_equal(const address *addr1, const address *addr2) {
    if ( addr1->len == addr2->len
            && memcmp(addr1->data, addr2->data, addr1->len) == 0
            ) return TRUE;
    return FALSE;
}

/** Perform a shallow copy of the address (both addresses point to the same
 * memory location).
 *
 * @param to [in,out] The destination address.
 * @param from [in] The source address.
 *
 * \warning Make sure 'from' memory stays valid for the lifetime of this object.
 * Also it's strongly recommended to use this function instead of copy-assign.
 */
/*地址拷贝,shallow表示data指向同一内存,两个地址穿同一条裤子,不作拷贝*/
static inline void
copy_address_shallow(address *to, const address *from) {
    set_address(to, from->type, from->len, from->data);
}

/** Copy an address, allocating a new buffer for the address data
 *  using wmem-scoped memory.
 *
 * @param scope [in] The lifetime of the allocated memory, e.g., wmem_packet_scope()
 * @param to [in,out] The destination address.
 * @param from [in] The source address.
 */
/*地址拷贝,vmem表示data不穿一条裤子,重新申请内存。*/
static inline void
copy_address_wmem(wmem_allocator_t *scope, address *to, const address *from) {
    alloc_address_wmem(scope, to, from->type, from->len, from->data);
}

/** Copy an address, allocating a new buffer for the address data.
 *
 * @param to [in,out] The destination address.
 * @param from [in] The source address.
 */
/*地址拷贝,更为通用安全,较为常用*/
static inline void
copy_address(address *to, const address *from) {
    copy_address_wmem(NULL, to, from);
}

/** Free an address allocated with wmem-scoped memory.
 *
 * @param scope [in] The lifetime of the allocated memory, e.g., wmem_packet_scope()
 * @param addr [in,out] The address whose data to free.
 */
/*释放地址内存,释放data部分*/
static inline void
free_address_wmem(wmem_allocator_t *scope, address *addr) {
    /* Because many dissectors set 'type = AT_NONE' to mean clear we check for that */
    if (addr->type != AT_NONE && addr->len > 0 && addr->priv != NULL) {
        /* Make sure API use is correct */
        /* if priv is not null then data == priv */
        g_assert(addr->data == addr->priv);
        wmem_free(scope, addr->priv);
    }
    clear_address(addr);
}

/** Free an address.
 *
 * @param addr [in,out] The address whose data to free.
 */
/*释放内存*/
static inline void
free_address(address *addr) {
    free_address_wmem(NULL, addr);
}

/** Hash an address into a hash value (which must already have been set).
 *
 * @param hash_val The existing hash value.
 * @param addr The address to add.
 * @return The new hash value.
 */
/*生成32位hash key*/
static inline guint
add_address_to_hash(guint hash_val, const address *addr) {
    const guint8 *hash_data = (const guint8 *)(addr)->data;
    int idx;

    for (idx = 0; idx < (addr)->len; idx++) {
        hash_val += hash_data[idx];
        hash_val += ( hash_val << 10 );
        hash_val ^= ( hash_val >> 6 );
    }
    return hash_val;
}

/** Hash an address into a hash value (which must already have been set).
 *  64-bit version of add_address_to_hash().
 *
 * @param hash_val The existing hash value.
 * @param addr The address to add.
 * @return The new hash value.
 */
/*生成64位hash key*/
static inline guint64
add_address_to_hash64(guint64 hash_val, const address *addr) {
    const guint8 *hash_data = (const guint8 *)(addr)->data;
    int idx;

    for (idx = 0; idx < (addr)->len; idx++) {
        hash_val += hash_data[idx];
        hash_val += ( hash_val << 10 );
        hash_val ^= ( hash_val >> 6 );
    }
    return hash_val;
}

WS_DLL_PUBLIC guint address_to_bytes(const address *addr, guint8 *buf, guint buf_len);

/*以上只是地址信息,在最为广泛的流信息-tcp流中,是有端口的。
  wireshark为了将流管理做的通用,所以下面定义了端口类型,
  并且wireshark中端口一律使用数值型,非上面的address类型,需要len,data等信息*/
/* Types of port numbers Wireshark knows about. */
typedef enum {
    PT_NONE,            /* no port number */
    PT_SCTP,            /* SCTP */
    PT_TCP,             /* TCP */
    PT_UDP,             /* UDP */
    PT_DCCP,            /* DCCP */
    PT_IPX,             /* IPX sockets */
    PT_NCP,             /* NCP connection */
    PT_EXCHG,           /* Fibre Channel exchange */
    PT_DDP,             /* DDP AppleTalk connection */
    PT_SBCCS,           /* FICON */
    PT_IDP,             /* XNS IDP sockets */
    PT_TIPC,            /* TIPC PORT */
    PT_USB,             /* USB endpoint 0xffff means the host */
    PT_I2C,
    PT_IBQP,            /* Infiniband QP number */
    PT_BLUETOOTH,
    PT_TDMOP
} port_type;

/* Types of circuit IDs Wireshark knows about. */
/*模拟转数字协议的电路IDs,在电信行业中用的比较多*/
typedef enum {
    CT_NONE,            /* no circuit type */
    CT_DLCI,            /* Frame Relay DLCI */
    CT_ISDN,            /* ISDN channel number 是一个数字电话网络国际标准,是一种典型的电路交换网络系统*/
    CT_X25,             /* X.25 logical channel number */
    CT_ISUP,            /* ISDN User Part CIC */
    CT_IAX2,            /* IAX2 call id */
    CT_H223,            /* H.223 logical channel number */
    CT_BICC,            /* BICC Circuit identifier */
    CT_DVBCI,           /* DVB-CI session number|transport connection id */
    CT_ISO14443         /* ISO14443 connection between terminal and card
                           the circuit ID is always 0, there's only one
                           such connection */
    /* Could also have ATM VPI/VCI pairs */
} circuit_type;

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* __ADDRESS_H__ */

/*
 * 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:
 */

conversation.h

conversation.h中主要定义了会话的结构,以及声明会话的相关操作接口,具体都是在conversation.c中定义的。

/* conversation.h
 * Routines for building lists of packets that are part of a "conversation"
 *
 * 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.
 */

#ifndef __CONVERSATION_H__
#define __CONVERSATION_H__

#include "ws_symbol_export.h"

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

/**
 *@file
 */
/*
 * Flags to pass to "conversation_new()" to indicate that the address 2
 * and/or port 2 values for the conversation should be wildcards.
 * The CONVERSATION_TEMPLATE option tells that any of the other supplied
 * port and / or address wildcards will be used to match an infinite number
 * of new connections to the conversation(s) that have the CONVERSATION_-
 * TEMPLATE flag set. Any conversation created without the CONVERSATION_-
 * TEMPLATE flag will be altered once the first connections (connection
 * oriented protocols only) to include the newly found information which
 * matched the wildcard options.
 */
#define NO_ADDR2 0x01
#define NO_PORT2 0x02
#define NO_PORT2_FORCE 0x04
#define CONVERSATION_TEMPLATE 0x08

/*
 * Flags to pass to "find_conversation()" to indicate that the address B
 * and/or port B search arguments are wildcards.
 */
#define NO_ADDR_B 0x01
#define NO_PORT_B 0x02

#include "packet.h"		/* for conversation dissector type */

/**
 * Data structure representing a conversation.
 */
/*会话key,这里不是hash key值,而是会话地址信息,是data*/
typedef struct conversation_key {
	struct conversation_key *next;
	address	addr1;
	address	addr2;
	port_type ptype;
	guint32	port1;
	guint32	port2;
} conversation_key;

/*会话基本结构*/
typedef struct conversation {
	struct conversation *next;	/** pointer to next conversation on hash chain */
	struct conversation *last;	/** pointer to the last conversation on hash chain */
	struct conversation *latest_found;
								/** pointer to the last conversation on hash chain */
	guint32	conv_index;				/** unique ID for conversation 会话id,在大型网络中,guint32可能值太小*/
	guint32 setup_frame;		/** frame number that setup this conversation 创建这条会话的第一个包序号*/
	/* Assume that setup_frame is also the lowest frame number for now. */
	guint32 last_frame;		/** highest frame number in this conversation 包含这条会话的最后一个包序号*/
	GSList *data_list;			/** list of data associated with conversation 会话的data信息,例如会话所属的协议等,如conv_proto_data*/
	wmem_tree_t *dissector_tree;
								/** tree containing protocol dissector client associated with conversation
									会话的解析树,因为一条会话可能会调用多种解析器,所以这里用了tree来包含这些信息
									因为wireshark是可以随便点开一个包查看信息,所以这种方式可以快速找到其解析handle,
									但在实际数据包解析产品中,一般是不需要此功能,都是一遍过,不会回溯打开*/
	guint	options;			/** wildcard flags */
	conversation_key *key_ptr;	/** pointer to the key for this conversation 会话具体信息值*/
} conversation_t;

/**
 * Destroy all existing conversations
 */
/*
	程序退出等情况下清理所有会话信息,以及hash链表
*/
extern void conversation_cleanup(void);

/**
 * Initialize some variables every time a file is loaded or re-loaded.
 * Create a new hash table for the conversations in the new file.
 */
/*
	会话模块的初始化,如上面的注释,加载某个文件或者重新加载某个文件时,需要重新初始化
*/
extern void conversation_init(void);

/*
 * Given two address/port pairs for a packet, create a new conversation
 * to contain packets between those address/port pairs.
 *
 * The options field is used to specify whether the address 2 value
 * and/or port 2 value are not given and any value is acceptable
 * when searching for this conversation.
 */
/*
	顾名思义,根据给定条件创建一条新的会话,并将其添加到指定的hash链表上
*/
WS_DLL_PUBLIC conversation_t *conversation_new(const guint32 setup_frame, const address *addr1, const address *addr2,
    const port_type ptype, const guint32 port1, const guint32 port2, const guint options);

/**
 * Given two address/port pairs for a packet, search for a conversation
 * containing packets between those address/port pairs.  Returns NULL if
 * not found.
 *
 * We try to find the most exact match that we can, and then proceed to
 * try wildcard matches on the "addr_b" and/or "port_b" argument if a more
 * exact match failed.
 *
 * Either or both of the "addr_b" and "port_b" arguments may be specified as
 * a wildcard by setting the NO_ADDR_B or NO_PORT_B flags in the "options"
 * argument.  We do only wildcard matches on addresses and ports specified
 * as wildcards.
 *
 * I.e.:
 *
 *	if neither "addr_b" nor "port_b" were specified as wildcards, we
 *	do an exact match (addr_a/port_a and addr_b/port_b) and, if that
 *	succeeds, we return a pointer to the matched conversation;
 *
 *	otherwise, if "port_b" wasn't specified as a wildcard, we try to
 *	match any address 2 with the specified port 2 (addr_a/port_a and
 *	{any}/addr_b) and, if that succeeds, we return a pointer to the
 *	matched conversation;
 *
 *	otherwise, if "addr_b" wasn't specified as a wildcard, we try to
 *	match any port 2 with the specified address 2 (addr_a/port_a and
 *	addr_b/{any}) and, if that succeeds, we return a pointer to the
 *	matched conversation;
 *
 *	otherwise, we try to match any address 2 and any port 2
 *	(addr_a/port_a and {any}/{any}) and, if that succeeds, we return
 *	a pointer to the matched conversation;
 *
 *	otherwise, we found no matching conversation, and return NULL.
 */
/*检索会话,根据给定条件,检索某个包所属的会话,没有的话,则返回NULL,程序可能会去创建一个新的*/
WS_DLL_PUBLIC conversation_t *find_conversation(const guint32 frame_num, const address *addr_a, const address *addr_b,
    const port_type ptype, const guint32 port_a, const guint32 port_b, const guint options);

/**  A helper function that calls find_conversation() and, if a conversation is
 *  not found, calls conversation_new().
 *  The frame number and addresses are taken from pinfo.
 *  No options are used, though we could extend this API to include an options
 *  parameter.
 */
/*
	检索外加创建,很容易理解
*/
WS_DLL_PUBLIC conversation_t *find_or_create_conversation(packet_info *pinfo);

/*往会话的data_list上添加数据,proto应为协议注册的id*/
WS_DLL_PUBLIC void conversation_add_proto_data(conversation_t *conv, const int proto,
    void *proto_data);
/*获取会话的data_list上的数据*/
WS_DLL_PUBLIC void *conversation_get_proto_data(const conversation_t *conv, const int proto);
/*删除会话的data_list上的数据*/
WS_DLL_PUBLIC void conversation_delete_proto_data(conversation_t *conv, const int proto);

/*
	设置会话的解析器,解析器是注册协议解析时得到的handle.
	第一次的时候需要根据端口等判断,然后创建会话,下一次的时候就直接查询会话,并从会话中读取
	解析器的handle,直接调用解析即可。

	设置这个信息只是为了后面点开会话中任意一个包的时候能调用相应的解析器解析内部数据,以便
	wireshark展示用。在实际的网络产品开发过程中,一般不会有此需求
*/
WS_DLL_PUBLIC void conversation_set_dissector(conversation_t *conversation,
    const dissector_handle_t handle);
/*
	与conversation_set_dissector功能一样,只不过加了帧的id信息。
	创建会话时,conversation_t中的dissector_tree会根据帧id创建一棵树,左边的节点id小,
	右边的节点id大,也就是从小到大的帧都调用了什么解析器。
	例如一个HTTP的会话,三次握手用TCP解析器,中间用HTTP解析器,四次挥手用TCP解析器,则dissector_tree是如下结构
					HTTP(第4个包开始使用HTTP解析器)
								/          \
							   /			\
							  /				 \
							 /				  \
			TCP(第1个包用TCP解析器)           TCP(倒数第四个包开始用TCP解析器)
*/
WS_DLL_PUBLIC void conversation_set_dissector_from_frame_number(conversation_t *conversation,
    const guint32 starting_frame_num, const dissector_handle_t handle);

/*获取会话的解析器*/
WS_DLL_PUBLIC dissector_handle_t conversation_get_dissector(conversation_t *conversation,
    const guint32 frame_num);

/**
 * Given two address/port pairs for a packet, search for a matching
 * conversation and, if found and it has a conversation dissector,
 * call that dissector and return TRUE, otherwise return FALSE.
 *
 * This helper uses call_dissector_only which will NOT call the default
 * "data" dissector if the packet was rejected.
 * Our caller is responsible to call the data dissector explicitly in case
 * this function returns FALSE.
 */
extern gboolean
try_conversation_dissector(const address *addr_a, const address *addr_b, const port_type ptype,
    const guint32 port_a, const guint32 port_b, tvbuff_t *tvb, packet_info *pinfo,
    proto_tree *tree, void* data);

/* These routines are used to set undefined values for a conversation */

extern void conversation_set_port2(conversation_t *conv, const guint32 port);
extern void conversation_set_addr2(conversation_t *conv, const address *addr);

WS_DLL_PUBLIC
GHashTable *get_conversation_hashtable_exact(void);

WS_DLL_PUBLIC
GHashTable *get_conversation_hashtable_no_addr2(void);

WS_DLL_PUBLIC
GHashTable * get_conversation_hashtable_no_port2(void);

WS_DLL_PUBLIC
GHashTable *get_conversation_hashtable_no_addr2_or_port2(void);


#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* conversation.h */




  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值