// Filename: datagramTCPHeader.cxx
// Created by:  drose (08Feb00)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license.  You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////

#include "datagramTCPHeader.h"
#include "netDatagram.h"
#include "datagramIterator.h"
#include "config_net.h"

#include "pnotify.h"

////////////////////////////////////////////////////////////////////
//     Function: DatagramTCPHeader::Constructor
//       Access: Public
//  Description: This constructor creates a header based on an
//               already-constructed NetDatagram.
////////////////////////////////////////////////////////////////////
DatagramTCPHeader::
DatagramTCPHeader(const NetDatagram &datagram, int header_size) {
  const string &str = datagram.get_message();
  switch (header_size) {
  case 0:
    break;

  case datagram_tcp16_header_size:
    {
      PRUint16 size = str.length();
      nassertv(size == str.length());
      _header.add_uint16(size);
    }
    break;

  case datagram_tcp32_header_size:
    {
      PRUint32 size = str.length();
      nassertv(size == str.length());
      _header.add_uint32(size);
    }
    break;

  default:
    nassertv(false);
  }

  nassertv((int)_header.get_length() == header_size);
}

////////////////////////////////////////////////////////////////////
//     Function: DatagramTCPHeader::Constructor
//       Access: Public
//  Description: This constructor decodes a header from a block of
//               data of length datagram_tcp_header_size, presumably
//               just read from a socket.
////////////////////////////////////////////////////////////////////
DatagramTCPHeader::
DatagramTCPHeader(const void *data, int header_size) : 
  _header(data, header_size) 
{
}

////////////////////////////////////////////////////////////////////
//     Function: DatagramTCPHeader::get_datagram_size
//       Access: Public
//  Description: Returns the number of bytes in the associated
//               datagram.
////////////////////////////////////////////////////////////////////
int DatagramTCPHeader::
get_datagram_size(int header_size) const {
  DatagramIterator di(_header);
  switch (header_size) {
  case 0:
    return 0;

  case datagram_tcp16_header_size:
    return di.get_uint16();

  case datagram_tcp32_header_size:
    return di.get_uint32();
  }

  return -1;
}

////////////////////////////////////////////////////////////////////
//     Function: DatagramTCPHeader::verify_datagram
//       Access: Public
//  Description: Verifies that the indicated datagram has the
//               appropriate length.  Returns true if it matches,
//               false otherwise.
////////////////////////////////////////////////////////////////////
bool DatagramTCPHeader::
verify_datagram(const NetDatagram &datagram, int header_size) const {
  if (header_size == 0) {
    // No way to validate without a header, so everything is valid.
    return true;
  }

  const string &str = datagram.get_message();
  int actual_size = str.length();
  int expected_size = get_datagram_size(header_size);
  if (actual_size == expected_size) {
    return true;
  }

  if (net_cat.is_debug()) {
    net_cat.debug()
      << "Invalid datagram!  Size is " << actual_size
      << " bytes, header reports " << expected_size << "\n";

    // We write the hex dump into a ostringstream first, to guarantee
    // an atomic write to the output stream in case we're threaded.

    ostringstream hex;
    datagram.dump_hex(hex);
    hex << "\n";
    net_cat.debug() << hex.str();
  }

  return false;
}
