/** @file
 *
 * Definitions for handling circuit-switched protocols
 * which are handled as streams, and don't have lengths
 * and IDs such as are required for reassemble.h
 *
 * Wireshark - Network traffic analyzer
 * By Gerald Combs <gerald@wireshark.org>
 * Copyright 1998 Gerald Combs
 *
 * SPDX-License-Identifier: GPL-2.0-or-later
 */
#pragma once
#include <epan/tvbuff.h>
#include <epan/reassemble.h>
#include "ws_symbol_export.h"

struct _fragment_items;

/* A stream represents the concept of an arbitrary stream of data,
   divided up into frames for transmission, where the frames have
   little or no correspondence to the PDUs of the protocol being
   streamed, and those PDUs are just delineated by a magic number.

   For example, we stream H.223 over IAX2. IAX2 has no concept of
   H.223 PDUs and just divides the H.223 stream into 160-byte
   frames. H.223 PDUs are delineated by two-byte magic numbers (which
   may, of course, straddle an IAX2 frame boundary).

   Essentially we act as a wrapper to reassemble.h, by making up
   PDU ids and keeping some additional data on fragments to allow the
   PDUs to be defragmented again.
*/


/* A stream_t represents a stream. There might be one or two streams
   in a circuit, depending on whether that circuit is mono- or bi-directional.
*/
typedef struct stream stream_t;

/* Fragments in a PDU are represented using a stream_pdu_fragment_t,
   and placed in a linked-list with other fragments in the PDU.

   (They're also placed in a hash so we can find them again later)
*/
typedef struct stream_pdu_fragment stream_pdu_fragment_t;


struct conversation;

/**
 * @brief Initialise a new stream. Call this when you first identify a distinct
 * stream. The conversation pointer is just used as a key to look up the stream.
 * @param conv Pointer to the conversation structure.
 * @param p2p_dir The peer-to-peer direction.
 * @return Pointer to the newly created stream, or NULL on failure.
 */
WS_DLL_PUBLIC stream_t *stream_new ( const struct conversation *conv, int p2p_dir );

/**
 * @brief Retrieve a previously-created stream.
 * @param conv Pointer to the conversation structure.
 * @param p2p_dir The peer-to-peer direction.
 * @return Pointer to the retrieved stream, or NULL if not found.
 */
WS_DLL_PUBLIC stream_t *find_stream ( const struct conversation *conv, int p2p_dir );



/**
 * @brief See if we've seen this fragment before.
 * @param stream Pointer to the stream structure.
 * @param framenum The frame number.
 * @param offset The byte offset within the frame.
 * @return Pointer to the found fragment, or NULL if not found.
 */
WS_DLL_PUBLIC stream_pdu_fragment_t *stream_find_frag( stream_t *stream, uint32_t framenum, uint32_t offset );

/**
 *
 * @brief Add a new fragment to the fragment tables for the stream.
 *
 *  The framenum and
 * offset are keys allowing future access with stream_find_frag(), tvb is the
 * fragment to be added, and pinfo is the information for the frame containing
 * this fragment. more_frags should be set if this is the final fragment in the
 * PDU.
 *
 * * the fragment must be later in the stream than any previous fragment
 *   (ie, framenum.offset must be greater than those passed on the previous
 *   call)
 *
 * This essentially means that you can only add fragments on the first pass
 * through the stream.
 * @param stream Pointer to the stream structure.
 * @param framenum The frame number of the fragment.
 * @param offset The byte offset within the frame.
 * @param tvb The TVBuffer containing the fragment data.
 * @param pinfo Pointer to the packet information structure for the frame containing this fragment.
 * @param more_frags Set to true if this is the final fragment in the PDU, false otherwise.
 * @return Pointer to the newly added fragment, or NULL on failure.
 */
WS_DLL_PUBLIC stream_pdu_fragment_t *stream_add_frag( stream_t *stream, uint32_t framenum, uint32_t offset,
					tvbuff_t *tvb, packet_info *pinfo, bool more_frags );

/**
 * @brief Get the length of a fragment previously found by stream_find_frag().
 * @param frag A fragment within the PDU.
 * @return The length of the fragment.
 */
extern uint32_t stream_get_frag_length( const stream_pdu_fragment_t *frag);

/**
 * @brief Get a handle on the top of the chain of fragment_datas underlying this PDU
 *
 * frag can be any fragment within a PDU, and it will always return the head of
 * the chain
 *
 * Returns NULL until the last fragment is added.
 *
 * @param frag A fragment within the PDU.
 * @return A pointer to the fragment list for the PDU, or NULL if not complete
 */
WS_DLL_PUBLIC fragment_head *stream_get_frag_data( const stream_pdu_fragment_t *frag);

/**
 * @brief Process reassembled data; if this is the last fragment, put the fragment
 * information into the protocol tree, and construct a tvbuff with the
 * reassembled data, otherwise just put a "reassembled in" item into the
 * protocol tree.
 *
 * @param tvb The original TVBuffer containing the fragment data.
 * @param offset The offset within the TVBuffer where the fragment starts.
 * @param pinfo Packet information structure.
 * @param name Name of the reassembled data source.
 * @param frag A fragment within the PDU.
 * @param fit Pointer to the fragment items structure.
 * @param update_col_infop Pointer to a boolean indicating whether to update column info.
 * @param tree Protocol tree for displaying fragment information.
 * @return A new TVBuffer containing the reassembled data, or NULL if not applicable.
 */
WS_DLL_PUBLIC tvbuff_t *stream_process_reassembled(
    tvbuff_t *tvb, int offset, packet_info *pinfo,
    const char *name, const stream_pdu_fragment_t *frag,
    const struct _fragment_items *fit,
    bool *update_col_infop, proto_tree *tree);

/**
 * @brief Get the PDU number. PDUs are numbered from zero within a stream.
 * @param frag A fragment within the PDU.
 * @return The PDU number.
 */
extern uint32_t stream_get_pdu_no( const stream_pdu_fragment_t *frag);

/**
 * @brief Initializes stream-related data structures and reassembly tables.
 */
void stream_init( void );

/**
 * @brief Cleans up stream-related data structures and reassembly tables.
 */
void stream_cleanup( void );
