//===========================================================================
// @(#) $Name: arts++-1-1-a12 $
// @(#) $Id: ArtsHeader.cc,v 1.3 2004/04/21 23:51:32 kkeys Exp $
//===========================================================================
//  Copyright Notice
//
//  By accessing this software, arts++, you are duly informed
//  of and agree to be bound by the conditions described below in this
//  notice:
//
//  This software product, arts++, is developed by Daniel W. McRobb, and
//  copyrighted(C) 1998 by the University of California, San Diego
//  (UCSD), with all rights reserved.  UCSD administers the CAIDA grant,
//  NCR-9711092, under which part of this code was developed.
//
//  There is no charge for arts++ software.  You can redistribute it
//  and/or modify it under the terms of the GNU Lesser General Public
//  License, Version 2.1, February 1999, which is incorporated by
//  reference herein.
//
//  arts++ is distributed WITHOUT ANY WARRANTY, IMPLIED OR EXPRESS, OF
//  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE or that the use
//  of it will not infringe on any third party's intellectual
//  property rights.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with arts++.  Copies can also be obtained from:
//
//    http://www.gnu.org/copyleft/lesser.html
//
//  or by writing to:
//
//  Free Software Foundation, Inc.
//  59 Temple Place, Suite 330
//  Boston, MA 02111-1307
//  USA
//
//  Or contact:
//
//    info@caida.org
//===========================================================================

extern "C" {
#include <sys/types.h>
#include <netinet/in.h>
#include <stdio.h>
}

#include <string>

#include "ArtsHeader.hh"
#include "ArtsPrimitive.hh"

typedef struct {
  uint32_t     identifier;
  const char  *name;
} ArtsIdToName_t;

static const ArtsIdToName_t ArtsObjectNames[] = {
  { artsC_OBJECT_AS_MATRIX,        "AS_matrix" },
  { artsC_OBJECT_PORT,             "port_table" },
  { artsC_OBJECT_PORT_MATRIX,      "port_matrix" },
  { artsC_OBJECT_PROTO,            "protocol_table" },
  { artsC_OBJECT_TOS,              "TOS_table" },
  { artsC_OBJECT_NET,              "net_matrix" },
  { artsC_OBJECT_IP_PATH,          "IP_path" },
  { artsC_OBJECT_SELECTED_PORT,    "selected_port_table" },
  { artsC_OBJECT_INTERFACE_MATRIX, "interface_matrix" },
  { artsC_OBJECT_NEXT_HOP,         "IP_nexthop_table" },
  { artsC_OBJECT_BGP4,             "BGP4_table" },
  { artsC_OBJECT_RTT_TIME_SERIES,  "RTT_time_series" },
  { 0x0, NULL }
};

static const std::string rcsid = "@(#) $Name: arts++-1-1-a12 $ $Id: ArtsHeader.cc,v 1.3 2004/04/21 23:51:32 kkeys Exp $";

//-------------------------------------------------------------------------
//                         ArtsHeader::ArtsHeader()                        
//.........................................................................
//                                                                         
//-------------------------------------------------------------------------
ArtsHeader::ArtsHeader()
{
  #ifndef NDEBUG
    ++_numObjects;
  #endif
  
  this->_magic = artsC_MAGIC;
  this->_identifier = 0;
  this->_flags = 0;
  this->_version = 0;
  this->_numAttributes = 0;
  this->_attrLength = 0;
  this->_dataLength = 0;
}

//-------------------------------------------------------------------------
//                        ArtsHeader::~ArtsHeader()                        
//.........................................................................
//                                                                         
//-------------------------------------------------------------------------
ArtsHeader::~ArtsHeader()
{
  #ifndef NDEBUG
    --_numObjects;
  #endif
}

//-------------------------------------------------------------------------
//             const char * ArtsHeader::IdentifierName() const
//-------------------------------------------------------------------------
const char * ArtsHeader::IdentifierName() const
{
  const ArtsIdToName_t  *idToNamePtr;
  static char            hexname[16];
  
  for (idToNamePtr = &(ArtsObjectNames[0]); idToNamePtr->identifier != 0;
       idToNamePtr++) {
    if (idToNamePtr->identifier == this->_identifier) {
      return(idToNamePtr->name);
    }
  }

  memset(hexname,0,16);
  sprintf(hexname,"%#x",this->_identifier);
  return(hexname);
}

//------------------------------------------------------------------------
//            std::ostream& ArtsHeader::write(std::ostream& os) const
//------------------------------------------------------------------------
std::ostream& ArtsHeader::write(std::ostream& os) const
{
  uint16_t  uShortDatum;
  uint32_t  uIntDatum, idAndVersion;
  
  uShortDatum = htons(this->_magic);
  os.write((char*)&uShortDatum,sizeof(uShortDatum));

  idAndVersion = (this->_identifier << 4) | this->_version;
  uIntDatum = htonl(idAndVersion);
  os.write((char*)&uIntDatum,sizeof(uIntDatum));
  
  uIntDatum = htonl(this->_flags);
  os.write((char*)&uIntDatum,sizeof(uIntDatum));
  
  uShortDatum = htons(this->_numAttributes);
  os.write((char*)&uShortDatum,sizeof(uShortDatum));
  
  uIntDatum = htonl(this->_attrLength);
  os.write((char*)&uIntDatum,sizeof(uIntDatum));
  
  uIntDatum = htonl(this->_dataLength);
  os.write((char*)&uIntDatum,sizeof(uIntDatum));

  return(os);
}

//-------------------------------------------------------------------------
//                   int ArtsHeader::write(int fd) const                   
//.........................................................................
//                                                                         
//-------------------------------------------------------------------------
int ArtsHeader::write(int fd) const
{
  uint16_t  uShortDatum;
  uint32_t  uIntDatum, idAndVersion;
  int       rc;
  int       bytesWritten = 0;
  
  uShortDatum = htons(this->_magic);
  rc = g_ArtsLibInternal_Primitive.FdWrite(fd,&uShortDatum,
                                           sizeof(uShortDatum));
  if (rc < (int)sizeof(uShortDatum)) {
    return(-1);
  }
  bytesWritten += rc;

  idAndVersion = (this->_identifier << 4) | this->_version;
  uIntDatum = htonl(idAndVersion);
  rc = g_ArtsLibInternal_Primitive.FdWrite(fd,&uIntDatum,sizeof(uIntDatum));
  if (rc < (int)sizeof(uIntDatum)) {
    return(-1);
  }
  bytesWritten += rc;
  
  uIntDatum = htonl(this->_flags);
  rc = g_ArtsLibInternal_Primitive.FdWrite(fd,&uIntDatum,sizeof(uIntDatum));
  if (rc < (int)sizeof(uIntDatum)) {
    return(-1);
  }
  bytesWritten += rc;
  
  uShortDatum = htons(this->_numAttributes);
  rc = g_ArtsLibInternal_Primitive.FdWrite(fd,&uShortDatum,
                                           sizeof(uShortDatum));
  if (rc < (int)sizeof(uShortDatum)) {
    return(-1);
  }
  bytesWritten += rc;
  
  uIntDatum = htonl(this->_attrLength);
  rc = g_ArtsLibInternal_Primitive.FdWrite(fd,&uIntDatum,sizeof(uIntDatum));
  if (rc < (int)sizeof(uIntDatum)) {
    return(-1);
  }
  bytesWritten += rc;
  
  uIntDatum = htonl(this->_dataLength);
  rc = g_ArtsLibInternal_Primitive.FdWrite(fd,&uIntDatum,sizeof(uIntDatum));
  if (rc < (int)sizeof(uIntDatum)) {
    return(-1);
  }
  bytesWritten += rc;

  return(bytesWritten);
}

//------------------------------------------------------------------------
//             std::istream& ArtsHeader::read(std::istream& is)
//------------------------------------------------------------------------
std::istream& ArtsHeader::read(std::istream& is)
{
  uint16_t  uShortDatum;
  uint32_t  uIntDatum;
  uint32_t  idAndVersion;
  
  is.read((char*)&uShortDatum,sizeof(uShortDatum));
  if (is.eof())
    return(is);
  
  this->_magic = ntohs(uShortDatum);

  is.read((char*)&uIntDatum,sizeof(uIntDatum));
  if (is.eof())
    return(is);
  
  idAndVersion = ntohl(uIntDatum);
  this->_identifier = idAndVersion >> 4;
  this->_version    = idAndVersion & 0x0f;

  is.read((char*)&uIntDatum,sizeof(uIntDatum));
  if (is.eof())
    return(is);  
  this->_flags = ntohl(uIntDatum);

  is.read((char*)&uShortDatum,sizeof(uShortDatum));
  if (is.eof())
    return(is);
  this->_numAttributes = ntohs(uShortDatum);

  is.read((char*)&uIntDatum,sizeof(uIntDatum));
  if (is.eof())
    return(is);
  this->_attrLength = ntohl(uIntDatum);

  is.read((char*)&uIntDatum,sizeof(uIntDatum));
  if (is.eof())
    return(is);
  this->_dataLength = ntohl(uIntDatum);

  return(is);
}

//-------------------------------------------------------------------------
//                       int ArtsHeader::read(int fd)                      
//.........................................................................
//                                                                         
//-------------------------------------------------------------------------
int ArtsHeader::read(int fd)
{
  int       rc;
  int       bytesRead = 0;
  uint16_t  uShortDatum;
  uint32_t  uIntDatum;
  uint32_t  idAndVersion;
  
  rc = g_ArtsLibInternal_Primitive.FdRead(fd,&uShortDatum,
                                          sizeof(uShortDatum));
  if (rc <= 0)
    return(rc);
  bytesRead += rc;
  this->_magic = ntohs(uShortDatum);

  g_ArtsLibInternal_Primitive.FdRead(fd,&uIntDatum,sizeof(uIntDatum));
  if (rc <= 0)
    return(rc);
  bytesRead += rc;
  
  idAndVersion = ntohl(uIntDatum);
  this->_identifier = idAndVersion >> 4;
  this->_version    = idAndVersion & 0x0f;

  g_ArtsLibInternal_Primitive.FdRead(fd,&uIntDatum,sizeof(uIntDatum));
  if (rc <= 0)
    return(rc);
  bytesRead += rc;
  this->_flags = ntohl(uIntDatum);

  g_ArtsLibInternal_Primitive.FdRead(fd,&uShortDatum,sizeof(uShortDatum));
  if (rc <= 0)
    return(rc);
  bytesRead += rc;
  this->_numAttributes = ntohs(uShortDatum);

  g_ArtsLibInternal_Primitive.FdRead(fd,&uIntDatum,sizeof(uIntDatum));
  if (rc <= 0)
    return(rc);
  bytesRead += rc;
  this->_attrLength = ntohl(uIntDatum);

  g_ArtsLibInternal_Primitive.FdRead(fd,&uIntDatum,sizeof(uIntDatum));
  if (rc <= 0)
    return(rc);
  bytesRead += rc;
  this->_dataLength = ntohl(uIntDatum);

  return(bytesRead);
}

//-------------------------------------------------------------------------
//   ArtsHeader & ArtsHeader::operator = (const ArtsHeader & artsHeader)   
//.........................................................................
//                                                                         
//-------------------------------------------------------------------------
ArtsHeader & ArtsHeader::operator = (const ArtsHeader & artsHeader)
{
  this->_magic = artsHeader.Magic();
  this->_identifier = artsHeader.Identifier();
  this->_version = artsHeader.Version();
  this->_flags = artsHeader.Flags();
  this->_numAttributes = artsHeader.NumAttributes();
  this->_attrLength = artsHeader.AttrLength();
  this->_dataLength = artsHeader.DataLength();
  return(*this);
}

//------------------------------------------------------------------------
//   std::ostream& operator << (std::ostream& os, const ArtsHeader & artsHeader)
//------------------------------------------------------------------------
std::ostream& operator << (std::ostream& os, const ArtsHeader & artsHeader)
{
  using namespace std;

  os << "HEADER" << setiosflags(ios::showbase) << endl;
  os << "\tmagic: " << dec << artsHeader.Magic()
     << " (" << hex << artsHeader.Magic() << ")" << endl;
  os << "\tidentifier: " << dec << artsHeader.Identifier()
     << " (" << hex << artsHeader.Identifier() << ")" << endl;
  os << "\tversion: " << dec << (int)artsHeader.Version()
     << " (" << hex << (int)artsHeader.Version() << ")" << endl;
  os << "\tflags: " << dec << artsHeader.Flags()
     << " (" << hex << artsHeader.Flags() << ")" << endl;
  os << "\tnum_attributes: " << dec << artsHeader.NumAttributes()
     << " (" << hex << artsHeader.NumAttributes() << ")" << endl;
  os << "\tattr_length: " << dec << artsHeader.AttrLength()
     << " (" << hex << artsHeader.AttrLength() << ")" << endl;
  os << "\tdata_length: " << dec << artsHeader.DataLength()
     << " (" << hex << artsHeader.DataLength() << ")" << dec << endl;

  return(os);
}

uint32_t ArtsHeader::_numObjects = 0;
