//===========================================================================
//  $Name: cflowd-2-1-b1 $
//  $Id: CflowdServer.cc,v 1.13 1999/10/15 18:52:03 dwm Exp $
//===========================================================================
//  CAIDA Copyright Notice
//
//  By accessing this software, cflowd++, you are duly informed
//  of and agree to be bound by the conditions described below in this
//  notice:
//
//  This software product, cflowd++, 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 cflowd software. You can redistribute it
//  and/or modify it under the terms of the GNU General Public License,
//  v.  2 dated June 1991 which is incorporated by reference herein.
//  cflowd 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 GPL along with cflowd.
//  Copies can also be obtained from:
//
//    http://www.gnu.org/copyleft/gpl.html
//
//  or by writing to:
//
//    University of California, San Diego
//
//    SDSC/CAIDA
//    9500 Gilman Dr., MS-0505
//    La Jolla, CA 92093 - 0505  USA
//
//  Or contact:
//
//    info@caida.org
//===========================================================================
extern "C" {
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <netdb.h>
#include <syslog.h>
#include <assert.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/param.h>
}

#include <fstream.h>
#include <strstream.h>
#include <string>

#include "CflowdServer.hh"
#include "CflowdCisco.hh"

static const string rcsid = "@(#) $Name: cflowd-2-1-b1 $ $Id: CflowdServer.cc,v 1.13 1999/10/15 18:52:03 dwm Exp $";

#ifndef INADDR_NONE
#define INADDR_NONE 0xffffffff
#endif

//-------------------------------------------------------------------------
//                       CflowdServer::CflowdServer()                      
//.........................................................................
//  
//-------------------------------------------------------------------------
CflowdServer::CflowdServer()
{
  this->_sockFd = -1;
  memset(&(this->_sockAddr),0,sizeof(this->_sockAddr));
  this->_sockAddr.sin_family = AF_INET;
  this->_nextPollTime = time((time_t *)NULL);
  this->_pollInterval = 300;
}

//-------------------------------------------------------------------------
//                      CflowdServer::~CflowdServer()                      
//.........................................................................
//  
//-------------------------------------------------------------------------
CflowdServer::~CflowdServer()
{
  if (this->_sockFd >= 0) {
    close(this->_sockFd);
    this->_sockFd = -1;
  }
}

//-------------------------------------------------------------------------
//                       bool CflowdServer::Connect()                      
//.........................................................................
//  
//-------------------------------------------------------------------------
bool CflowdServer::Connect()
{
  this->_sockFd = socket(AF_INET,SOCK_STREAM,0);
  if (this->_sockFd < 0) {
    syslog(LOG_ERR,"[E] socket(AF_INET,SOCK_STREAM,0) failed: %m {%s:%d}",
           __FILE__,__LINE__);
    return(false);
  }
  if (connect(this->_sockFd,(struct sockaddr *)&(this->_sockAddr),
              sizeof(this->_sockAddr)) < 0) {
    syslog(LOG_ERR,
           "[E] connect(%d,%p,%d) (host %s port %d) failed: %m {%s:%d}",
           this->_sockFd,&(this->_sockAddr),sizeof(this->_sockAddr),
           this->HostName().c_str(),this->Port(),__FILE__,__LINE__);
    close(this->_sockFd);
    this->_sockFd = -1;
    return(false);
  }

  syslog(LOG_INFO,"[I] connected to %s:%d",this->HostName().c_str(),
         this->Port());

  int on = 1;
  if (setsockopt(this->_sockFd,SOL_SOCKET,SO_KEEPALIVE,
                 (char *)&on,sizeof(on)) < 0) {
    syslog(LOG_WARNING,
           "[W] setsockopt(%d,SOL_SOCKET,SO_KEEPALIVE,%p,%d) failed:"
           " %m {%s:%d}",this->_sockFd,&on,sizeof(on),__FILE__,__LINE__);
  }
  
  return(true);
}

//-------------------------------------------------------------------------
//                     void CflowdServer::Disconnect()                     
//.........................................................................
//  
//-------------------------------------------------------------------------
void CflowdServer::Disconnect()
{
  close(this->_sockFd);
  return;
}

//-------------------------------------------------------------------------
//  bool                                  
//  CflowdCiscoInterfaceMatrixToArtsFile(const CflowdCisco & cflowdCisco, 
//                                       ofstream & outStream) 
//.........................................................................
//  
//-------------------------------------------------------------------------
bool
CflowdCiscoInterfaceMatrixToArtsFile(const CflowdCisco & cflowdCisco,
                                     ofstream & outStream)
{
  CflowdCiscoFlowInterfaceMap::const_iterator  intfIter;
  bool rc = true;

  assert(cflowdCisco.TableIndex() & CflowdCisco::k_cflowdInterfaceMatrixMask);
  
  for (intfIter = cflowdCisco.Interfaces().begin();
       intfIter != cflowdCisco.Interfaces().end(); intfIter++) {
    ArtsInterfaceMatrix       artsIntfMatrix;
    ArtsInterfaceMatrixEntry  artsIntfEntry;

    artsIntfMatrix.AddHostAttribute(cflowdCisco.IpAddress());
    artsIntfMatrix.AddPeriodAttribute(cflowdCisco.LastCleared(),
                                      cflowdCisco.LastUpdated());
    artsIntfMatrix.AddIfIndexAttribute((*intfIter).first);
    if ((*intfIter).second.IpAddr() != INADDR_NONE) {
      artsIntfMatrix.AddIfIpAddrAttribute((*intfIter).second.IpAddr());
    }
    if ((*intfIter).second.IfDescr().length() > 0) {
      artsIntfMatrix.AddIfDescrAttribute((*intfIter).second.IfDescr());
    }
    artsIntfMatrix.InterfaceEntries().reserve((*intfIter).second.InterfaceMatrix().size());
    CflowdInterfaceMatrix::const_iterator  cfdIntfMatrixIter;
    for (cfdIntfMatrixIter = (*intfIter).second.InterfaceMatrix().begin();
         cfdIntfMatrixIter != (*intfIter).second.InterfaceMatrix().end();
         cfdIntfMatrixIter++) {
      artsIntfEntry.Src((*cfdIntfMatrixIter).first.Src());
      artsIntfEntry.Dst((*cfdIntfMatrixIter).first.Dst());
      artsIntfEntry.Pkts((*cfdIntfMatrixIter).second.Pkts());
      artsIntfEntry.Bytes((*cfdIntfMatrixIter).second.Bytes());
      artsIntfMatrix.TotalPkts(artsIntfMatrix.TotalPkts() +
                               artsIntfEntry.Pkts());
      artsIntfMatrix.TotalBytes(artsIntfMatrix.TotalBytes() +
                                artsIntfEntry.Bytes());
      artsIntfMatrix.InterfaceEntries().push_back(artsIntfEntry);
    }
    artsIntfMatrix.write(outStream);
    if (! outStream) {
      syslog(LOG_ERR,"[E] artsIntfMatrix.write(outStream) failed. {%s:%d}",
             __FILE__,__LINE__);
      rc = false;
      break;
    }
  }
  return(rc);
}

//-------------------------------------------------------------------------
//   bool                                  
//   CflowdCiscoNextHopTableToArtsFile(const CflowdCisco & cflowdCisco, 
//                                     ofstream & outStream) 
//.........................................................................
//  
//-------------------------------------------------------------------------
bool
CflowdCiscoNextHopTableToArtsFile(const CflowdCisco & cflowdCisco,
                                  ofstream & outStream)
{
  CflowdCiscoFlowInterfaceMap::const_iterator  intfIter;
  bool rc = true;

  assert(cflowdCisco.TableIndex() & CflowdCisco::k_cflowdNextHopTableMask);
  
  for (intfIter = cflowdCisco.Interfaces().begin();
       intfIter != cflowdCisco.Interfaces().end(); intfIter++) {
    ArtsNextHopTable       artsNextHopTable;
    ArtsNextHopTableEntry  artsNextHopEntry;
    artsNextHopTable.AddHostAttribute(cflowdCisco.IpAddress());
    artsNextHopTable.AddPeriodAttribute(cflowdCisco.LastCleared(),
                                        cflowdCisco.LastUpdated());
    artsNextHopTable.AddIfIndexAttribute((*intfIter).first);
    if ((*intfIter).second.IpAddr() != INADDR_NONE) {
      artsNextHopTable.AddIfIpAddrAttribute((*intfIter).second.IpAddr());
    }
    if ((*intfIter).second.IfDescr().length() > 0) {
      artsNextHopTable.AddIfDescrAttribute((*intfIter).second.IfDescr());
    }
    artsNextHopTable.NextHopEntries().reserve((*intfIter).second.InterfaceMatrix().size());
    CflowdNextHopTable::const_iterator  cfdNextHopTableIter;
    for (cfdNextHopTableIter = (*intfIter).second.NextHopTable().begin();
         cfdNextHopTableIter != (*intfIter).second.NextHopTable().end();
         cfdNextHopTableIter++) {
      artsNextHopEntry.IpAddr((*cfdNextHopTableIter).first);
      artsNextHopEntry.Pkts((*cfdNextHopTableIter).second.Pkts());
      artsNextHopEntry.Bytes((*cfdNextHopTableIter).second.Bytes());
      artsNextHopTable.TotalPkts(artsNextHopTable.TotalPkts() +
                                 artsNextHopEntry.Pkts());
      artsNextHopTable.TotalBytes(artsNextHopTable.TotalBytes() +
                                  artsNextHopEntry.Bytes());
      artsNextHopTable.NextHopEntries().push_back(artsNextHopEntry);
    }
    artsNextHopTable.write(outStream);
    if (! outStream) {
      syslog(LOG_ERR,
             "[E] artsNextHopTable.write(outStream) failed. {%s:%d}",
             __FILE__,__LINE__);
      rc = false;
      break;
    }
  }
  return(rc);
}

//-------------------------------------------------------------------------
//   bool                                  
//   CflowdCiscoProtocolTableToArtsFile(const CflowdCisco & cflowdCisco, 
//                                      ofstream & outStream) 
//.........................................................................
//  
//-------------------------------------------------------------------------
bool
CflowdCiscoProtocolTableToArtsFile(const CflowdCisco & cflowdCisco,
                                   ofstream & outStream)
{
  CflowdCiscoFlowInterfaceMap::const_iterator  intfIter;
  bool rc = true;

  assert(cflowdCisco.TableIndex() & CflowdCisco::k_cflowdProtocolTableMask);
  
  for (intfIter = cflowdCisco.Interfaces().begin();
       intfIter != cflowdCisco.Interfaces().end(); intfIter++) {
    ArtsProtocolTable        protocolTable;
    ArtsProtocolTableEntry   protoEntry;
    
    protocolTable.AddHostAttribute(cflowdCisco.IpAddress());
    protocolTable.AddPeriodAttribute(cflowdCisco.LastCleared(),
                                     cflowdCisco.LastUpdated());
    protocolTable.AddIfIndexAttribute((*intfIter).first);
    if ((*intfIter).second.IpAddr() != INADDR_NONE) {
      protocolTable.AddIfIpAddrAttribute((*intfIter).second.IpAddr());
    }
    if ((*intfIter).second.IfDescr().length() > 0) {
      protocolTable.AddIfDescrAttribute((*intfIter).second.IfDescr());
    }
    protocolTable.ProtocolEntries().reserve((*intfIter).second.ProtocolTable().size());
    
    CflowdProtocolTable::const_iterator  protoIter;
    
    for (protoIter = (*intfIter).second.ProtocolTable().begin();
         protoIter != (*intfIter).second.ProtocolTable().end();
         protoIter++) {
      protoEntry.ProtocolNumber((*protoIter).first);
      protoEntry.Pkts((*protoIter).second.Pkts());
      protoEntry.Bytes((*protoIter).second.Bytes());
      protocolTable.TotalPkts(protocolTable.TotalPkts() + protoEntry.Pkts());
      protocolTable.TotalBytes(protocolTable.TotalBytes() +
                               protoEntry.Bytes());
      protocolTable.ProtocolEntries().push_back(protoEntry);
    }
    protocolTable.write(outStream);
    if (! outStream) {
      syslog(LOG_ERR,
             "[E] protocolTable.write(outStream) failed. {%s:%d}",
             __FILE__,__LINE__);
      rc = false;
      break;
    }
  }
  return(rc);
}

bool
CflowdCiscoTosTableToArtsFile(const CflowdCisco & cflowdCisco,
                                   ofstream & outStream)
{
  CflowdCiscoFlowInterfaceMap::const_iterator  intfIter;
  bool rc = true;

  assert(cflowdCisco.TableIndex() & CflowdCisco::k_cflowdTosTableMask);
  
  for (intfIter = cflowdCisco.Interfaces().begin();
       intfIter != cflowdCisco.Interfaces().end(); intfIter++) {
    ArtsTosTable        tosTable;
    ArtsTosTableEntry   tosEntry;
    
    tosTable.AddHostAttribute(cflowdCisco.IpAddress());
    tosTable.AddPeriodAttribute(cflowdCisco.LastCleared(),
                                     cflowdCisco.LastUpdated());
    tosTable.AddIfIndexAttribute((*intfIter).first);
    if ((*intfIter).second.IpAddr() != INADDR_NONE) {
      tosTable.AddIfIpAddrAttribute((*intfIter).second.IpAddr());
    }
    if ((*intfIter).second.IfDescr().length() > 0) {
      tosTable.AddIfDescrAttribute((*intfIter).second.IfDescr());
    }
    tosTable.TosEntries().reserve((*intfIter).second.TosTable().size());
    
    CflowdTosTable::const_iterator  tosIter;
    
    for (tosIter = (*intfIter).second.TosTable().begin();
         tosIter != (*intfIter).second.TosTable().end();
         tosIter++) {
      tosEntry.TosNumber((*tosIter).first);
      tosEntry.Pkts((*tosIter).second.Pkts());
      tosEntry.Bytes((*tosIter).second.Bytes());
      tosTable.TotalPkts(tosTable.TotalPkts() + tosEntry.Pkts());
      tosTable.TotalBytes(tosTable.TotalBytes() + tosEntry.Bytes());
      tosTable.TosEntries().push_back(tosEntry);
    }
    tosTable.write(outStream);
    if (! outStream) {
      syslog(LOG_ERR,
             "[E] tosTable.write(outStream) failed. {%s:%d}",
             __FILE__,__LINE__);
      rc = false;
      break;
    }
  }
  return(rc);
}

//-------------------------------------------------------------------------
//   bool                                  
//   CflowdCiscoPortMatrixToArtsFile(const CflowdCisco & cflowdCisco, 
//                                   ofstream & outStream) 
//.........................................................................
//  
//-------------------------------------------------------------------------
bool
CflowdCiscoPortMatrixToArtsFile(const CflowdCisco & cflowdCisco,
                                ofstream & outStream)
{
  CflowdCiscoFlowInterfaceMap::const_iterator  intfIter;
  bool rc = true;

  assert(cflowdCisco.TableIndex() & CflowdCisco::k_cflowdPortMatrixMask);
  
  for (intfIter = cflowdCisco.Interfaces().begin();
       intfIter != cflowdCisco.Interfaces().end(); intfIter++) {
    ArtsPortMatrix        portMatrix;
    ArtsPortMatrixEntry   portMatrixEntry;
    
    portMatrix.AddHostAttribute(cflowdCisco.IpAddress());
    portMatrix.AddPeriodAttribute(cflowdCisco.LastCleared(),
                                  cflowdCisco.LastUpdated());
    portMatrix.AddIfIndexAttribute((*intfIter).first);
    if ((*intfIter).second.IpAddr() != INADDR_NONE) {
      portMatrix.AddIfIpAddrAttribute((*intfIter).second.IpAddr());
    }
    if ((*intfIter).second.IfDescr().length() > 0) {
      portMatrix.AddIfDescrAttribute((*intfIter).second.IfDescr());
    }
    portMatrix.PortEntries().reserve((*intfIter).second.PortMatrix().size());
    
    CflowdPortMatrix::const_iterator  portmIter;
    
    for (portmIter = (*intfIter).second.PortMatrix().begin();
         portmIter != (*intfIter).second.PortMatrix().end(); portmIter++) {
      portMatrixEntry.Src((*portmIter).first.Src());
      portMatrixEntry.Dst((*portmIter).first.Dst());
      portMatrixEntry.Pkts((*portmIter).second.Pkts());
      portMatrixEntry.Bytes((*portmIter).second.Bytes());
      portMatrix.TotalPkts(portMatrix.TotalPkts() + portMatrixEntry.Pkts());
      portMatrix.TotalBytes(portMatrix.TotalBytes() +
                            portMatrixEntry.Bytes());
      portMatrix.PortEntries().push_back(portMatrixEntry);
    }
    portMatrix.write(outStream);
    if (! outStream) {
      syslog(LOG_ERR,
             "[E] portMatrix.write(outStream) failed. {%s:%d}",
             __FILE__,__LINE__);
      rc = false;
      break;
    }
  }
  return(rc);
}

//-------------------------------------------------------------------------
//   bool                                  
//   CflowdCiscoAsMatrixToArtsFile(const CflowdCisco & cflowdCisco, 
//                                 ofstream & outStream) 
//.........................................................................
//  
//-------------------------------------------------------------------------
bool
CflowdCiscoAsMatrixToArtsFile(const CflowdCisco & cflowdCisco,
                              ofstream & outStream)
{
  CflowdCiscoFlowInterfaceMap::const_iterator  intfIter;
  bool rc = true;

  assert(cflowdCisco.TableIndex() & CflowdCisco::k_cflowdAsMatrixMask);
  
  for (intfIter = cflowdCisco.Interfaces().begin();
       intfIter != cflowdCisco.Interfaces().end(); intfIter++) {
    ArtsAsMatrix        asMatrix;
    ArtsAsMatrixEntry   asMatrixEntry;
    
    asMatrix.AddHostAttribute(cflowdCisco.IpAddress());
    asMatrix.AddPeriodAttribute(cflowdCisco.LastCleared(),
                                cflowdCisco.LastUpdated());
    asMatrix.AddIfIndexAttribute((*intfIter).first);
    if ((*intfIter).second.IpAddr() != INADDR_NONE) {
      asMatrix.AddIfIpAddrAttribute((*intfIter).second.IpAddr());
    }
    if ((*intfIter).second.IfDescr().length() > 0) {
      asMatrix.AddIfDescrAttribute((*intfIter).second.IfDescr());
    }
    asMatrix.AsEntries().reserve((*intfIter).second.AsMatrix().size());
    
    CflowdAsMatrix::const_iterator  asmIter;
    
    for (asmIter = (*intfIter).second.AsMatrix().begin();
         asmIter != (*intfIter).second.AsMatrix().end(); asmIter++) {
      asMatrixEntry.Src((*asmIter).first.Src());
      asMatrixEntry.Dst((*asmIter).first.Dst());
      asMatrixEntry.Pkts((*asmIter).second.Pkts());
      asMatrixEntry.Bytes((*asmIter).second.Bytes());
      asMatrix.TotalPkts(asMatrix.TotalPkts() + asMatrixEntry.Pkts());
      asMatrix.TotalBytes(asMatrix.TotalBytes() +
                          asMatrixEntry.Bytes());
      asMatrix.AsEntries().push_back(asMatrixEntry);
    }
    asMatrix.write(outStream);
    if (! outStream) {
      syslog(LOG_ERR,
             "[E] asMatrix.write(outStream) failed. {%s:%d}",
             __FILE__,__LINE__);
      rc = false;
      break;
    }
  }
  return(rc);
}

//-------------------------------------------------------------------------
//    bool                                  
//    CflowdCiscoNetMatrixToArtsFile(const CflowdCisco & cflowdCisco, 
//                                   ofstream & outStream) 
//.........................................................................
//  
//-------------------------------------------------------------------------
bool
CflowdCiscoNetMatrixToArtsFile(const CflowdCisco & cflowdCisco,
                               ofstream & outStream)
{
  CflowdCiscoFlowInterfaceMap::const_iterator  intfIter;
  bool rc = true;

  assert(cflowdCisco.TableIndex() & CflowdCisco::k_cflowdNetMatrixMask);
  
  for (intfIter = cflowdCisco.Interfaces().begin();
       intfIter != cflowdCisco.Interfaces().end(); intfIter++) {
    ArtsNetMatrix        netMatrix;
    ArtsNetMatrixEntry   netMatrixEntry;
    
    netMatrix.AddHostAttribute(cflowdCisco.IpAddress());
    netMatrix.AddPeriodAttribute(cflowdCisco.LastCleared(),
                                 cflowdCisco.LastUpdated());
    netMatrix.AddIfIndexAttribute((*intfIter).first);
    if ((*intfIter).second.IpAddr() != INADDR_NONE) {
      netMatrix.AddIfIpAddrAttribute((*intfIter).second.IpAddr());
    }
    if ((*intfIter).second.IfDescr().length() > 0) {
      netMatrix.AddIfDescrAttribute((*intfIter).second.IfDescr());
    }
    netMatrix.NetEntries().reserve((*intfIter).second.NetMatrix().size());
    
    CflowdNetMatrix::const_iterator  netmIter;
    
    for (netmIter = (*intfIter).second.NetMatrix().begin();
         netmIter != (*intfIter).second.NetMatrix().end(); netmIter++) {
      netMatrixEntry.Src((*netmIter).first.Src());
      netMatrixEntry.SrcMaskLen((*netmIter).first.SrcMaskLen());
      netMatrixEntry.Dst((*netmIter).first.Dst());
      netMatrixEntry.DstMaskLen((*netmIter).first.DstMaskLen());
      netMatrixEntry.Pkts((*netmIter).second.Pkts());
      netMatrixEntry.Bytes((*netmIter).second.Bytes());
      netMatrix.TotalPkts(netMatrix.TotalPkts() + netMatrixEntry.Pkts());
      netMatrix.TotalBytes(netMatrix.TotalBytes() +
                           netMatrixEntry.Bytes());
      netMatrix.NetEntries().push_back(netMatrixEntry);
    }
    netMatrix.write(outStream);
    if (! outStream) {
      syslog(LOG_ERR,
             "[E] netMatrix.write(outStream) failed. {%s:%d}",
             __FILE__,__LINE__);
      rc = false;
      break;
    }
  }
  return(rc);
}

//-------------------------------------------------------------------------
//     bool CflowdCiscoDataToArtsFile(const string & dirname,         
//                                    const string & fileprefix,      
//                                    const CflowdCisco & cflowdCisco) 
//.........................................................................
//  
//-------------------------------------------------------------------------
bool CflowdCiscoDataToArtsFile(const string & dirname,
                               const string & fileprefix,
                               const CflowdCisco & cflowdCisco)
{
  ArtsNetMatrix                                 netMatrix;
  ArtsAsMatrix                                  asMatrix;
  CflowdCiscoFlowInterfaceMap::const_iterator   intfIter;
  bool                                          rc = true;
  ostrstream                                    outdirname, outfilename;
  time_t                                        now = time((time_t *)NULL);
  struct tm                                    *tmGmtNow = gmtime(&now);
  struct in_addr                                addrIn;
  
  addrIn.s_addr = cflowdCisco.IpAddress();
  outdirname << dirname << "/" << inet_ntoa(addrIn) << ends;
  
  struct stat statbuf;
  
  if (stat(outdirname.str(),&statbuf) < 0) {
    if (mkdir(outdirname.str(),0755) < 0) {
      syslog(LOG_ERR,"[E] mkdir(\"%s\",0755) failed: %m {%s:%d}",
             outdirname.str(),__FILE__,__LINE__);
      return(false);
    }
  }
  outfilename << outdirname.str() << "/" << fileprefix << "."
              << setfill('0')
              << setw(4) << tmGmtNow->tm_year + 1900
              << setw(2) << tmGmtNow->tm_mon + 1
              << setw(2) << tmGmtNow->tm_mday
              << ends;
  outdirname.freeze(0);
  
  ofstream *outStream = new ofstream(outfilename.str(),ios::app);
  
  if (!outStream || !(*outStream)) {
    syslog(LOG_ERR,"[E] new ofstream(%s,ios::app) failed: %m {%s:%d}",
           outfilename.str(),__FILE__,__LINE__);
    outfilename.freeze(0);
    return(false);
  }
  outfilename.freeze(0);
  
  //  interface matrix
  if (cflowdCisco.TableIndex() & CflowdCisco::k_cflowdInterfaceMatrixMask) {
    if (! CflowdCiscoInterfaceMatrixToArtsFile(cflowdCisco,*outStream)) {
      rc = false;
      goto _CflowdCiscoDataToArtsFile_done;
    }
  }

  //  nexthop table
  if (cflowdCisco.TableIndex() & CflowdCisco::k_cflowdNextHopTableMask) {
    if (! CflowdCiscoNextHopTableToArtsFile(cflowdCisco,*outStream)) {
      rc = false;
      goto _CflowdCiscoDataToArtsFile_done;
    }
  }

  //  protocol table
  if (cflowdCisco.TableIndex() & CflowdCisco::k_cflowdProtocolTableMask) {
    if (! CflowdCiscoProtocolTableToArtsFile(cflowdCisco,*outStream)) {
      rc = false;
      goto _CflowdCiscoDataToArtsFile_done;
    }
  }
  
  //  TOS table
  if (cflowdCisco.TableIndex() & CflowdCisco::k_cflowdTosTableMask) {
    if (! CflowdCiscoTosTableToArtsFile(cflowdCisco,*outStream)) {
      rc = false;
      goto _CflowdCiscoDataToArtsFile_done;
    }
  }
  
  //  port matrix
  if (cflowdCisco.TableIndex() & CflowdCisco::k_cflowdPortMatrixMask) {
    if (! CflowdCiscoPortMatrixToArtsFile(cflowdCisco,*outStream)) {
      rc = false;
      goto _CflowdCiscoDataToArtsFile_done;
    }
  }
  
  //  AS matrix
  if (cflowdCisco.TableIndex() & CflowdCisco::k_cflowdAsMatrixMask) {
    if (! CflowdCiscoAsMatrixToArtsFile(cflowdCisco,*outStream)) {
      rc = false;
      goto _CflowdCiscoDataToArtsFile_done;
    }
  }
  
  //  net matrix
  if (cflowdCisco.TableIndex() & CflowdCisco::k_cflowdNetMatrixMask) {
    if (! CflowdCiscoNetMatrixToArtsFile(cflowdCisco,*outStream)) {
      rc = false;
    }
  }
    
  _CflowdCiscoDataToArtsFile_done:
  
  outStream->close();
  delete(outStream);
  return(rc);
}

//-------------------------------------------------------------------------
//            bool CflowdServer::GetData(const string & dirname,           
//                                       const string & fileprefix,        
//                                       Signal & sigAlrm)                 
//.........................................................................
//  
//-------------------------------------------------------------------------
bool CflowdServer::GetData(const string & dirname,
                           const string & fileprefix,
                           Signal & sigAlrm)
{
  int    rc;
  int    bytesRead = 0;
  bool   retVal = false;

  // set the next time we'll poll
  this->_nextPollTime = this->_nextPollTime + this->_pollInterval;

  // connect
  if (! this->Connect())
    return(false);
  
  uint32_t             numCiscos;
  uint32_t             ciscoNum;
  ipv4addr_t           ciscoIp;

  //  get the number of ciscos for which data is available
  if ((rc = g_CfdArtsPrimitive.ReadUint32(this->_sockFd,numCiscos,
                                          sizeof(numCiscos))) <
      sizeof(numCiscos)) {
    syslog(LOG_ERR,"[E] read(%d,%p,%d) failed: %m {%s:%d}",
           this->_sockFd,&numCiscos,sizeof(numCiscos),__FILE__,__LINE__);
    this->Disconnect();
    return(false);
  }
  bytesRead += rc;

  if (numCiscos < 1) {
    syslog(LOG_ERR,"[E] %s has no data {%s:%d}",
           this->HostName().c_str(),__FILE__,__LINE__);
    return(false);
  }
  
  if (numCiscos == 1) {
    syslog(LOG_INFO,"[I] %s has data for %d router.",
           this->HostName().c_str(),numCiscos);
  }
  else {
    syslog(LOG_INFO,"[I] %s has data for %d routers.",
           this->HostName().c_str(),numCiscos);
  }
  
  // get data for all ciscos
  for (ciscoNum = 0; ciscoNum < numCiscos; ciscoNum++) {
    CflowdCisco     cflowdCisco;
    struct in_addr  addrIn;
    
    if ((rc = cflowdCisco.read(this->_sockFd)) < 0) {
      syslog(LOG_ERR,"[E] cflowdCisco.read(%d) failed {%s:%d}",
             this->_sockFd,__FILE__,__LINE__);
      this->Disconnect();
      return(false);
    }
    sigAlrm.Block();
    addrIn.s_addr = cflowdCisco.IpAddress();
    syslog(LOG_INFO,"[I] got data for router %s from %s",
           inet_ntoa(addrIn),this->_hostName.c_str());
    // write data for the cisco to the Arts output file
    if (! CflowdCiscoDataToArtsFile(dirname,fileprefix,cflowdCisco)) {
      syslog(LOG_ERR,"[E] failed to write data for %s {%s:%d}",
             inet_ntoa(addrIn),__FILE__,__LINE__);
    }
    else {
      syslog(LOG_INFO,"[I] wrote data for router %s",inet_ntoa(addrIn));
      retVal = true;
    }
    sigAlrm.Unblock();
  }
  this->Disconnect();
  return(retVal);
}

//-------------------------------------------------------------------------
//              const string & CflowdServer::HostName() const              
//.........................................................................
//  
//-------------------------------------------------------------------------
const string & CflowdServer::HostName() const
{
  return(this->_hostName);
}

//-------------------------------------------------------------------------
//      const string & CflowdServer::HostName(const string & hostname)
//.........................................................................
//  
//-------------------------------------------------------------------------
const string & CflowdServer::HostName(const string & hostname)
{
  struct hostent  *hostEntry;
  
  if (inet_addr(hostname.c_str()) == INADDR_NONE) {
    // wasn't a valid IP address
    hostEntry = gethostbyname(hostname.c_str());
    if (!hostEntry) {
      // unknown host
      syslog(LOG_ERR,"[E] bad hostname for CflowdServer: %s {%s:%d}",
             hostname.c_str(),__FILE__,__LINE__);
      return(this->_hostName);
    }
    else {
      memcpy(&(this->_sockAddr.sin_addr.s_addr),
             hostEntry->h_addr_list[0],
             sizeof(this->_sockAddr.sin_addr.s_addr));
    }
  }
  else {
    // use the IP address
    this->_sockAddr.sin_addr.s_addr = inet_addr(hostname.c_str());
  }
  
  this->_hostName = hostname;
  return(this->_hostName);
}

//-------------------------------------------------------------------------
//                unsigned short CflowdServer::Port() const                
//.........................................................................
//  
//-------------------------------------------------------------------------
unsigned short CflowdServer::Port() const
{
  return(ntohs(this->_sockAddr.sin_port));
}

//-------------------------------------------------------------------------
//          unsigned short CflowdServer::Port(unsigned short port)         
//.........................................................................
//  
//-------------------------------------------------------------------------
unsigned short CflowdServer::Port(unsigned short port)
{
  this->_sockAddr.sin_port = htons(port);
  return(this->_sockAddr.sin_port);
}

//-------------------------------------------------------------------------
//                time_t CflowdServer::NextPollTime() const                
//.........................................................................
//  
//-------------------------------------------------------------------------
time_t CflowdServer::NextPollTime() const
{
  return(this->_nextPollTime);
}

//-------------------------------------------------------------------------
//          time_t CflowdServer::NextPollTime(time_t nextPollTime)         
//.........................................................................
//  
//-------------------------------------------------------------------------
time_t CflowdServer::NextPollTime(time_t nextPollTime)
{
  this->_nextPollTime = nextPollTime;
  return(this->_nextPollTime);
}

//-------------------------------------------------------------------------
//                time_t CflowdServer::PollInterval() const                
//.........................................................................
//  
//-------------------------------------------------------------------------
time_t CflowdServer::PollInterval() const
{
  return(this->_pollInterval);
}

//-------------------------------------------------------------------------
//          time_t CflowdServer::PollInterval(time_t pollInterval)         
//.........................................................................
//  
//-------------------------------------------------------------------------
time_t CflowdServer::PollInterval(time_t pollInterval)
{
  this->_pollInterval = pollInterval;
  return(this->_pollInterval);
}
