text: /*
   * Reassembly.h
   *
   *  Created on: May 2, 2013
   *      Author: root
   */
  
  #ifndef REASSEMBLY_H_
  #define REASSEMBLY_H_
  
  #include "xtreme/common/timestamp.h"
  #ifdef COMMON_IP_ADDRESS
    #include "xtreme/common/ipaddress.h"
  #else
    #include "xtreme/common/internal/TcpEngine/Ip_addr.h"
  #endif
  
  #include <list>
  #include <boost/unordered_map.hpp>
  
  namespace xtreme {
  namespace TcpEngine {
  
  /* only in fd_head: packet is defragmented */
  #define FD_DEFRAGMENTED     0x0001
  
  /* there are overlapping fragments */
  #define FD_OVERLAP      0x0002
  
  /* overlapping fragments contain different data */
  #define FD_OVERLAPCONFLICT  0x0004
  
  /* more than one fragment which indicates end-of data */
  #define FD_MULTIPLETAILS    0x0008
  
  /* fragment contains data past the end of the datagram */
  #define FD_TOOLONGFRAGMENT  0x0010
  
  /* fragment data not alloc'ed, fd->data pointing to fd_head->data+fd->offset */
  #define FD_NOT_MALLOCED         0x0020
  
  /* this flag is used to request fragment_add to continue the reassembly process */
  #define FD_PARTIAL_REASSEMBLY   0x0040
  
  /* fragment offset is indicated by sequence number and not byte offset
   into the defragmented packet */
  #define FD_BLOCKSEQUENCE        0x0100
  
  /* if REASSEMBLE_FLAGS_CHECK_DATA_PRESENT is set, and the first fragment is
   * incomplete, this flag is set in the flags word on the fd_head returned.
   *
   * It's all a fudge to preserve historical behaviour.
   */
  #define FD_DATA_NOT_PRESENT 0x0200
  
  /* This flag is set in (only) fd_head to denote that datalen has been set to a valid value.
   * It's implied by FD_DEFRAGMENTED (we must know the total length of the
   * datagram if we have defragmented it...)
   */
  #define FD_DATALEN_SET      0x0400
  
  #define DESEGMENT_ONE_MORE_SEGMENT 0x0fffffff
  #define DESEGMENT_UNTIL_FIN        0xfffffffe
  
  /**
   * section of about tcp reassembely,
   * pdu detail info
   */
  struct TCP_multi_pdu {
    uint32_t seq_;
    uint32_t next_pdu_;
    uint64_t first_frame_;
    Timestamp last_frame_time_;
    uint32_t flags_;
    #define MSP_FLAGS_REASSEMBLE_ENTIRE_SEGMENT 0x00000001
  
    TCP_multi_pdu()
        : seq_(0),
          next_pdu_(0),
          first_frame_(0),
          last_frame_time_(0),
          flags_(0) {
    }
  };
  
  /*
   *
   */
  typedef TCP_multi_pdu * TCP_multi_pdu_ptr;
  typedef std::list<TCP_multi_pdu_ptr> TCP_multi_pdu_ptr_list;
  
  /**
   * less and equal than
   */
  struct LE_of_TCP_multi_pdu_ptr {
    bool operator()(const TCP_multi_pdu_ptr & first, const TCP_multi_pdu_ptr & second) {
      if (first->seq_ <= second->seq_)
        return true;
      return false;
    }
    bool operator()(const TCP_multi_pdu_ptr & first, uint32_t sn) const {
      if (first->seq_ <= sn)
        return true;
      return false;
    }
    bool operator()(uint32_t sn, const TCP_multi_pdu_ptr & first) const {
      if (sn <= first->seq_)
        return true;
      return false;
    }
  };
  
  /*
   * find the pdu element by frame number
   */
  TCP_multi_pdu_ptr find_multi_pdu_le(TCP_multi_pdu_ptr_list & list, uint32_t sn);
  
  struct Fragment_data {
    Fragment_data * next_;
    uint32_t offset_;
    uint32_t len_;
    uint32_t datalen_;
    uint32_t reaseembled_in_;
    uint32_t flags_;
    uint32_t frame_;          // the frame number, the TCPEngine has to maintan this since frameevent has no such thing.
    Fragment_data()
        : next_(0),
          offset_(0),
          len_(0),
          datalen_(0),
          reaseembled_in_(0),
          flags_(0),
          frame_(0) {
    }
  };
  
  typedef Fragment_data * Fragment_data_ptr;
  struct Fragment_data_key {
  #ifdef COMMON_IP_ADDRESS
    /**
     * the source ip;
     */
    IPAddress src_ip_;
  
    /**
     * the destination ip
     */
    IPAddress dest_ip_;
  #else
    /**
     * the source ip;
     */
    Ip_addr src_ip_;
  
    /**
     * the destination ip
     */
    Ip_addr dest_ip_;
  #endif
    /*
     * should be the frame ID, identification number from IP header;
     */
    uint64_t frame_id_;
  
    bool operator==(const Fragment_data_key & fd1) {
      return (fd1.frame_id_ == this->frame_id_) && (fd1.src_ip_ == this->src_ip_) && (fd1.dest_ip_ == this->dest_ip_);
    }
    Fragment_data_key()
    :src_ip_((uint32_t)0),dest_ip_((uint32_t)0),frame_id_(0){}
  };
  
  /*
   * not reply on the intrusive_ptr bcoz of performance.
   */
  typedef Fragment_data_key * Fragment_data_key_ptr;
  
  /**
   * hash function for the comparaion based on the src:port and dst:port, and the frame Id;
   */
  struct Fragment_data_Hash {
    size_t operator()(const Fragment_data_key_ptr & sp) const;
  };
  
  /*
   * used in the hash-map find, equal function desclaration.
   */
  struct Fragment_data_Equal {
    bool operator()(const Fragment_data_key_ptr & sp1, const Fragment_data_key_ptr & sp2) const;
  };
  /*
   * container for the Fragment pdus
   * key: ipendpoint, and frame number
   * value: fragment detail information.eg. the length, datalenth, and flag, reassemblem in frame id
   * which can be used in esimate the impacted TCP KPIs.
   */
  typedef boost::unordered_map<Fragment_data_key_ptr, Fragment_data_ptr, Fragment_data_Hash, Fragment_data_Equal> Fragment_Data_Hash_Table;
  
  /*
   * put partial flag into element in container of hash-table.
   */
  void fragment_set_partial_reassembly(Fragment_data_key & key, Fragment_Data_Hash_Table & fragment_table);
  
  /*
   *
   */
  Fragment_data * fragment_add_common(uint64_t frame_num, const int offset, Fragment_data_key & key,
                                      Fragment_Data_Hash_Table & fragment_table, const uint32_t frag_offset,
                                      const uint32_t frag_data_len, const bool more_frags, const bool visited,
                                      const bool check_already_added = true);
  
  bool fragment_add_work(Fragment_data *fd_head, const uint64_t frame_num, const int offset, const uint32_t frag_offset,
                         const uint32_t frag_data_len, const bool more_frags);
  }
  }
  
  #endif /* REASSEMBLY_H_ */
  