//===========================================================================
//  $Name: arts++-1-1-a12 $
//  $Id: ArtsNetMatrixEntry.cc,v 1.2 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 <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
}

#include <string>

#include "ArtsNetMatrixEntry.hh"
#include "ArtsPrimitive.hh"

using namespace std;

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

//-------------------------------------------------------------------------
//                  ArtsNetMatrixEntry::ArtsNetMatrixEntry()                 
//.........................................................................
//                                                                         
//-------------------------------------------------------------------------
ArtsNetMatrixEntry::ArtsNetMatrixEntry()
{
  #ifndef NDEBUG
    ++ArtsNetMatrixEntry::_numObjects;
  #endif
}

//----------------------------------------------------------------------------
//        ArtsNetMatrixEntry::
//        ArtsNetMatrixEntry(const ArtsNetMatrixEntry & netmEntry) 
//............................................................................
//  
//----------------------------------------------------------------------------
ArtsNetMatrixEntry::ArtsNetMatrixEntry(const ArtsNetMatrixEntry & netmEntry)
{
  this->_descriptor = netmEntry._descriptor;
  this->_src        = netmEntry._src;
  this->_dst        = netmEntry._dst;
  this->_pkts       = netmEntry._pkts;
  this->_bytes      = netmEntry._bytes;

  #ifndef NDEBUG
    ++ArtsNetMatrixEntry::_numObjects;
  #endif
}

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

//-------------------------------------------------------------------------
//            uint8_t ArtsNetMatrixEntry::SrcMaskLen() const
//.........................................................................
//  
//-------------------------------------------------------------------------
uint8_t ArtsNetMatrixEntry::SrcMaskLen() const
{
  return(((this->_descriptor >> 5) & 0x1f) + 1);
}

//-------------------------------------------------------------------------
//         uint8_t ArtsNetMatrixEntry::SrcMaskLen(uint8_t maskLen)
//.........................................................................
//  
//-------------------------------------------------------------------------
uint8_t ArtsNetMatrixEntry::SrcMaskLen(uint8_t maskLen)
{
  this->_descriptor = (this->_descriptor & 0xfc1f) |
                      ((uint16_t)(maskLen - 1) << 5);
  return(maskLen);
}

//-------------------------------------------------------------------------
//              uint8_t ArtsNetMatrixEntry::DstMaskLen() const
//.........................................................................
//  
//-------------------------------------------------------------------------
uint8_t ArtsNetMatrixEntry::DstMaskLen() const
{
  return((this->_descriptor & 0x1f) + 1);
}

//-------------------------------------------------------------------------
//        uint8_t ArtsNetMatrixEntry::DstMaskLen(uint8_t maskLen)
//.........................................................................
//  
//-------------------------------------------------------------------------
uint8_t ArtsNetMatrixEntry::DstMaskLen(uint8_t maskLen)
{
  this->_descriptor = (this->_descriptor & 0xffe0) | (uint16_t)(maskLen - 1);
  return((this->_descriptor & 0x1f) + 1);
}

//-------------------------------------------------------------------------
//             uint64_t ArtsNetMatrixEntry::Pkts(uint64_t pkts)
//.........................................................................
//  
//-------------------------------------------------------------------------
uint64_t ArtsNetMatrixEntry::Pkts(uint64_t pkts)
{
  this->_pkts = pkts;
  if (pkts > (uint64_t)0xffffffff) {
    this->_descriptor = (this->_descriptor & 0xe3ff) | (0x0007 << 10);
  } else if (pkts > (uint64_t)0xffff) {
    this->_descriptor = (this->_descriptor & 0xe3ff) | (0x0003 << 10);
  } else if (pkts > (uint64_t)0xff) {
    this->_descriptor = (this->_descriptor & 0xe3ff) | (0x0001 << 10);
  } else {
    this->_descriptor = (this->_descriptor & 0xe3ff);
  }
  return(this->_pkts);
}

//-------------------------------------------------------------------------
//            uint64_t ArtsNetMatrixEntry::Bytes(uint64_t bytes)
//.........................................................................
//  
//-------------------------------------------------------------------------
uint64_t ArtsNetMatrixEntry::Bytes(uint64_t bytes)
{
  this->_bytes = bytes;
  if (bytes > (uint64_t)0xffffffff) {
    this->_descriptor = (this->_descriptor & 0x1fff) | (0x0007 << 13);
  } else if (bytes > (uint64_t)0xffff) {
    this->_descriptor = (this->_descriptor & 0x1fff) | (0x0003 << 13);
  } else if (bytes > (uint64_t)0xff) {
    this->_descriptor = (this->_descriptor & 0x1fff) | (0x0001 << 13);
  } else {
    this->_descriptor = (this->_descriptor & 0x1fff);
  }
  return(this->_bytes);
}

//-------------------------------------------------------------------------
//    uint32_t ArtsNetMatrixEntry::Length(uint8_t version) const
//.........................................................................
//                                                                         
//-------------------------------------------------------------------------
uint32_t ArtsNetMatrixEntry::Length(uint8_t version) const
{
  uint32_t   length;

  length = sizeof(this->_descriptor);
  length += (this->SrcMaskLen() + 7) / 8;
  length += (this->DstMaskLen() + 7) / 8;
  length += ((this->_descriptor >> 10) & 0x07) + 1;
  length += (this->_descriptor >> 13) + 1;
  return(length);
}

//-------------------------------------------------------------------------
//   istream& ArtsNetMatrixEntry::read(istream& is, uint8_t version)
//.........................................................................
//                                                                         
//-------------------------------------------------------------------------
istream& ArtsNetMatrixEntry::read(istream& is, uint8_t version)
{
  uint8_t        bytesize,
                 pktsize,
                 srcsize,
                 srcmasklen,
                 dstsize,
                 dstmasklen;
  
  is.read((char*)&this->_descriptor,sizeof(this->_descriptor));
  this->_descriptor = ntohs(this->_descriptor);
  
  srcmasklen = ((this->_descriptor >> 5) & 0x1f) + 1;
  srcsize = (srcmasklen + 7) / 8;

  dstmasklen = (this->_descriptor & 0x1f) + 1;
  dstsize = (dstmasklen + 7) / 8;

  pktsize  = ((this->_descriptor >> 10) & 0x07) + 1;
  bytesize = (this->_descriptor >> 13) + 1;

  g_ArtsLibInternal_Primitive.ReadIpv4Network(is,this->_src,srcsize);
  g_ArtsLibInternal_Primitive.ReadIpv4Network(is,this->_dst,dstsize);
  g_ArtsLibInternal_Primitive.ReadUint64(is,this->_pkts,pktsize);
  g_ArtsLibInternal_Primitive.ReadUint64(is,this->_bytes,bytesize);

  return(is);
}

//-------------------------------------------------------------------------
//         int ArtsNetMatrixEntry::read(int fd, uint8_t version)
//.........................................................................
//                                                                         
//-------------------------------------------------------------------------
int ArtsNetMatrixEntry::read(int fd, uint8_t version)
{
  uint8_t        bytesize,
                 pktsize,
                 srcsize,
                 dstsize,
                 srcmasklen,
                 dstmasklen;
  int            rc;
  int            bytesRead = 0;
  
  rc = g_ArtsLibInternal_Primitive.FdRead(fd,&this->_descriptor,
                                          sizeof(this->_descriptor));
  if (rc != sizeof(this->_descriptor)) {
    return(-1);
  }
  this->_descriptor = ntohs(this->_descriptor);
  
  bytesRead += rc;

  srcmasklen = ((this->_descriptor >> 5) & 0x1f) + 1;
  srcsize = (srcmasklen + 7) / 8;

  dstmasklen = (this->_descriptor & 0x1f) + 1;
  dstsize = (dstmasklen + 7) / 8;

  pktsize  = ((this->_descriptor >> 10) & 0x07) + 1;
  bytesize = (this->_descriptor >> 13) + 1;

  rc = g_ArtsLibInternal_Primitive.ReadIpv4Network(fd,this->_src,srcsize);
  if (rc != srcsize) {
    return(-1);
  }
  bytesRead += rc;
  
  rc = g_ArtsLibInternal_Primitive.ReadIpv4Network(fd,this->_dst,dstsize);
  if (rc != dstsize) {
    return(-1);
  }
  bytesRead += rc;
  
  rc = g_ArtsLibInternal_Primitive.ReadUint64(fd,this->_pkts,pktsize);
  if (rc != pktsize) {
    return(-1);
  }
  bytesRead += rc;
  
  rc = g_ArtsLibInternal_Primitive.ReadUint64(fd,this->_bytes,bytesize);
  if (rc != bytesize) {
    return(-1);
  }
  bytesRead += rc;

  return(bytesRead);
}

//-------------------------------------------------------------------------
// ostream& ArtsNetMatrixEntry::write(ostream& os, uint8_t version) const
//.........................................................................
//                                                                         
//-------------------------------------------------------------------------
ostream & ArtsNetMatrixEntry::write(ostream & os, uint8_t version) const
{
  uint8_t        bytesize,
                 pktsize,
                 srcsize,
                 dstsize,
                 srcmasklen,
                 dstmasklen;
  uint16_t       tmpDescriptor;

  tmpDescriptor = htons(this->_descriptor);
  os.write((char*)&tmpDescriptor,sizeof(tmpDescriptor));

  srcmasklen = ((this->_descriptor >> 5) & 0x1f) + 1;
  srcsize = (srcmasklen + 7) / 8;

  dstmasklen = (this->_descriptor & 0x1f) + 1;
  dstsize = (dstmasklen + 7) / 8;

  pktsize  = ((this->_descriptor >> 10) & 0x07) + 1;
  bytesize = (this->_descriptor >> 13) + 1;

  g_ArtsLibInternal_Primitive.WriteIpv4Network(os,this->_src,srcsize);
  g_ArtsLibInternal_Primitive.WriteIpv4Network(os,this->_dst,dstsize);
  g_ArtsLibInternal_Primitive.WriteUint64(os,this->_pkts,pktsize);
  g_ArtsLibInternal_Primitive.WriteUint64(os,this->_bytes,bytesize);

  return(os);
}

//-------------------------------------------------------------------------
//     int ArtsNetMatrixEntry::write(int fd, uint8_t version) const
//.........................................................................
//                                                                         
//-------------------------------------------------------------------------
int ArtsNetMatrixEntry::write(int fd, uint8_t version) const
{
  uint8_t        bytesize,
                 pktsize,
                 srcsize,
                 dstsize,
                 srcmasklen,
                 dstmasklen;
  int            rc;
  int            bytesWritten = 0;
  uint16_t       tmpDescriptor;

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

  srcmasklen = ((this->_descriptor >> 5) & 0x1f) + 1;
  srcsize = (srcmasklen + 7) / 8;

  dstmasklen = (this->_descriptor & 0x1f) + 1;
  dstsize = (dstmasklen + 7) / 8;

  pktsize  = ((this->_descriptor >> 10) & 0x07) + 1;
  bytesize = (this->_descriptor >> 13) + 1;

  rc = g_ArtsLibInternal_Primitive.WriteIpv4Network(fd,this->_src,srcsize);
  if (rc != srcsize) {
    return(-1);
  }
  bytesWritten += rc;
  
  rc = g_ArtsLibInternal_Primitive.WriteIpv4Network(fd,this->_dst,dstsize);
  if (rc != dstsize) {
    return(-1);
  }
  bytesWritten += rc;
  
  rc = g_ArtsLibInternal_Primitive.WriteUint64(fd,this->_pkts,pktsize);
  if (rc != pktsize) {
    return(-1);
  }
  bytesWritten += rc;
  
  rc = g_ArtsLibInternal_Primitive.WriteUint64(fd,this->_bytes,bytesize);
  if (rc != bytesize) {
    return(-1);
  }
  bytesWritten += rc;

  return(bytesWritten);
}

//-------------------------------------------------------------------------
//   ostream & operator << (ostream& os,                   
//                          const ArtsNetMatrixEntry & artsNetMatrixEntry) 
//.........................................................................
//                                                                         
//-------------------------------------------------------------------------
ostream & operator << (ostream& os,
                       const ArtsNetMatrixEntry & artsNetMatrixEntry)
{
  struct in_addr   inAddr;
  
  os << "\tNET MATRIX ENTRY" << endl;
  os << "\t\tdescriptor: 0x"
     << hex << (int)artsNetMatrixEntry.Descriptor() << dec << endl;
  inAddr.s_addr = artsNetMatrixEntry.Src();
  os << "\t\tsrc: " << inet_ntoa(inAddr) << "/"
     << (int)artsNetMatrixEntry.SrcMaskLen() << endl;
  inAddr.s_addr = artsNetMatrixEntry.Dst();
  os << "\t\tdst: " << inet_ntoa(inAddr) << "/"
     << (int)artsNetMatrixEntry.DstMaskLen() << endl;
  os << "\t\tpkts: " << artsNetMatrixEntry.Pkts() << endl;
  os << "\t\tbytes: " << artsNetMatrixEntry.Bytes() << endl;

  return(os);
}

//---------------------------------------------------------------------------
//        bool ArtsNetMatrixEntryGreaterBytes::
//        operator () (const ArtsNetMatrixEntry & netEntry1,
//                     const ArtsNetMatrixEntry & netEntry2) const
//...........................................................................
//
//---------------------------------------------------------------------------
bool ArtsNetMatrixEntryGreaterBytes::
operator () (const ArtsNetMatrixEntry & netEntry1,
             const ArtsNetMatrixEntry & netEntry2) const
{
  return(netEntry1.Bytes() > netEntry2.Bytes());
}

//---------------------------------------------------------------------------
//        bool ArtsNetMatrixEntryGreaterPkts::
//        operator () (const ArtsNetMatrixEntry & netEntry1,
//                     const ArtsNetMatrixEntry & netEntry2) const
//...........................................................................
//
//---------------------------------------------------------------------------
bool ArtsNetMatrixEntryGreaterPkts::
operator () (const ArtsNetMatrixEntry & netEntry1,
             const ArtsNetMatrixEntry & netEntry2) const
{
  return(netEntry1.Pkts() > netEntry2.Pkts());
}

uint32_t ArtsNetMatrixEntry::_numObjects = 0;
