//===========================================================================
// @(#) $Name: arts++-1-1-a12 $
// @(#) $Id: ArtsIpPathEntry.cc,v 1.5 2004/04/21 23:51:33 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 <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
}

#include <string>

#include "ArtsIpPathEntry.hh"
#include "ArtsPrimitive.hh"

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

//------------------------------------------------------------------------
//                 ArtsIpPathEntry::ArtsIpPathEntry()
//------------------------------------------------------------------------
ArtsIpPathEntry::ArtsIpPathEntry()
{
  this->Clear();

  #ifndef NDEBUG
    ++this->_numObjects;
  #endif
  
}

//------------------------------------------------------------------------
//  ArtsIpPathEntry::ArtsIpPathEntry(ipv4addr_t ipAddr, uint8_t hopNum)
//------------------------------------------------------------------------
ArtsIpPathEntry::ArtsIpPathEntry(ipv4addr_t ipAddr, uint8_t hopNum)
{
  this->_ipAddr = ipAddr;
  this->_hopNum = hopNum;

  #ifndef NDEBUG
    ++this->_numObjects;
  #endif
}

//-------------------------------------------------------------------------
//                   ArtsIpPathEntry::~ArtsIpPathEntry()                   
//.........................................................................
//                                                                         
//-------------------------------------------------------------------------
ArtsIpPathEntry::~ArtsIpPathEntry()
{
  #ifndef NDEBUG
    --this->_numObjects;
  #endif
}

//------------------------------------------------------------------------
//
//------------------------------------------------------------------------
ArtsIpPathEntry &
ArtsIpPathEntry::operator = (const ArtsIpPathEntry& artsIpPathEntry)
{
  this->_ipAddr = artsIpPathEntry._ipAddr;
  this->_hopNum = artsIpPathEntry._hopNum;
  _rtt = artsIpPathEntry._rtt;
  this->_numTries = artsIpPathEntry._numTries;
  
  return(*this);
}


std::istream& ArtsIpPathEntry::read(std::istream& is, uint8_t version,
				uint8_t flags)
{
  is.read((char*)&this->_hopNum,sizeof(this->_hopNum));
  if (! is)
    return(is);

  is.read((char*)&this->_ipAddr,sizeof(this->_ipAddr));
  if (! is)
    return(is);

  if (version >= 1) {
    // Version 1 always has iRTT.
    if (version == 1 || flags & k_rtt) {
      g_ArtsLibInternal_Primitive.ReadUint32(is, _rtt, sizeof(_rtt));
      if (! is)
	return(is);

      is.read((char*)&this->_numTries,sizeof(this->_numTries));
    }
  }
  
  return(is);
}

int ArtsIpPathEntry::read(int fd, uint8_t version, uint8_t flags)
{
  int rc;
  int bytesRead = 0;
  
  rc = g_ArtsLibInternal_Primitive.FdRead(fd,&this->_hopNum,
                                          sizeof(this->_hopNum));
  if (rc <= 0)
    return(rc);
  bytesRead += rc;
  rc = g_ArtsLibInternal_Primitive.FdRead(fd,&this->_ipAddr,
                                          sizeof(this->_ipAddr));
  if (rc <= 0)
    return(rc);
  bytesRead += rc;

  if (version >= 1) {
    // Version 1 always has iRTT.
    if (version == 1 || flags & k_rtt) {
      rc = g_ArtsLibInternal_Primitive.ReadUint32(fd, _rtt, sizeof(_rtt));
      if (rc <= 0) {
	return(rc);
      }
      bytesRead += rc;

      rc = g_ArtsLibInternal_Primitive.FdRead(fd,&this->_numTries,
					      sizeof(this->_numTries));
      if (rc <= 0) {
	return(rc);
      }
      bytesRead += rc;
    }
  }
  
  return(bytesRead);
}

std::ostream& ArtsIpPathEntry::write(std::ostream& os, uint8_t version,
				uint8_t flags) const
{
  os.write((char*)&this->_hopNum,sizeof(this->_hopNum));
  os.write((char*)&this->_ipAddr,sizeof(this->_ipAddr));

  if (version >= 1) {
    // Version 1 always has iRTT.
    if (version == 1 || flags & k_rtt) {
      g_ArtsLibInternal_Primitive.WriteUint32(os, _rtt, sizeof(_rtt));
      os.write((char*)&this->_numTries,sizeof(this->_numTries));
    }
  }

  return(os);
}

int ArtsIpPathEntry::write(int fd, uint8_t version, uint8_t flags) const
{
  int  rc;
  int  bytesWritten = 0;

  rc = g_ArtsLibInternal_Primitive.FdWrite(fd,&this->_hopNum,
                                           sizeof(this->_hopNum));
  if (rc != sizeof(this->_hopNum)) {
    return(-1);
  }
  bytesWritten += rc;

  rc = g_ArtsLibInternal_Primitive.FdWrite(fd,&this->_ipAddr,
                                           sizeof(this->_ipAddr));
  if (rc != sizeof(this->_ipAddr)) {
    return(-1);
  }
  bytesWritten += rc;

  if (version >= 1) {
    // Version 1 always has iRTT.
    if (version == 1 || flags & k_rtt) {
      rc = g_ArtsLibInternal_Primitive.WriteUint32(fd, _rtt, sizeof(_rtt));
      if (rc != 4) {
	return(-1);
      }
      bytesWritten += rc;

      rc = g_ArtsLibInternal_Primitive.FdWrite(fd,&this->_numTries,
					       sizeof(this->_numTries));
      if (rc != sizeof(this->_numTries)) {
	return(-1);
      }
      bytesWritten += rc;
    }
  }
  
  return(bytesWritten);
}

//------------------------------------------------------------------------
// std::ostream & operator << (std::ostream& os, const ArtsIpPathEntry & artsIpPathEntry)
//------------------------------------------------------------------------
std::ostream & operator << (std::ostream& os, const ArtsIpPathEntry & artsIpPathEntry)
{
  struct in_addr  inAddr;

  using namespace std;
  
  inAddr.s_addr = artsIpPathEntry.IpAddr();
  os << "\t\tHopNum: " << setiosflags(ios::left) << setw(3) << dec
     << (int)artsIpPathEntry.HopNum() << " IpAddr: "
     << setiosflags(ios::left) << setw(15) << inet_ntoa(inAddr) << " ("
     << hex << ntohl(inAddr.s_addr) << ")";

  if (artsIpPathEntry._rtt) {
    double rttMsecs = artsIpPathEntry._rtt / 1000.0;
    os << "  rtt: " << rttMsecs << " ms"
       << "  numTries: " << (int)artsIpPathEntry._numTries;
  }
  
  os << endl;
  return(os);
}

//----------------------------------------------------------------------------
//     void ArtsIpPathEntry::Clear() 
//............................................................................
//  
//----------------------------------------------------------------------------
void ArtsIpPathEntry::Clear()
{
  _rtt = 0;
  this->_ipAddr = 0;
  this->_hopNum = 0;
  this->_numTries = 0;

  return;
}

  
uint32_t ArtsIpPathEntry::_numObjects = 0;
