//===========================================================================
//  $Name: cflowd-2-1-b1 $
//  $Id: CflowdRawFlowClientList.cc,v 1.8 1999/08/19 01:52:14 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 "aclocal.h"
}

#include <string>

#include "CflowdRawFlowClientList.hh"

static const string rcsid = "@(#) $Name: cflowd-2-1-b1 $ $Id: CflowdRawFlowClientList.cc,v 1.8 1999/08/19 01:52:14 dwm Exp $";

//-------------------------------------------------------------------------
//            CflowdRawFlowClientList::CflowdRawFlowClientList()           
//.........................................................................
//  
//-------------------------------------------------------------------------
CflowdRawFlowClientList::CflowdRawFlowClientList()
{
  this->_maxFd = -1;
  FD_ZERO(&_fdSet);
}

//-------------------------------------------------------------------------
//           CflowdRawFlowClientList::~CflowdRawFlowClientList()           
//.........................................................................
//  
//-------------------------------------------------------------------------
CflowdRawFlowClientList::~CflowdRawFlowClientList()
{
  this->CloseAll();
}

//-------------------------------------------------------------------------
//                 void CflowdRawFlowClientList::CloseAll()                
//.........................................................................
//  
//-------------------------------------------------------------------------
void CflowdRawFlowClientList::CloseAll()
{
  CflowdRawFlowClientList::iterator  clientIter;

  for (clientIter = (*this).begin(); clientIter != (*this).end();
       clientIter++) {
    close((*clientIter).fd);
  }
  return;
}

//-------------------------------------------------------------------------
//  void
//  CflowdRawFlowClientList::Close(iterator & client)
//.........................................................................
//  
//-------------------------------------------------------------------------
void
CflowdRawFlowClientList::Close(iterator & client)
{
  ::close((*client).fd);
  FD_CLR((*client).fd,&(this->_fdSet));
  (*client).fd = -1;
  (*this).erase(client++);

  if (client != (*this).end())
    client--;
  
  return;
}

//-------------------------------------------------------------------------
//                  void CflowdRawFlowClientList::Clear()                  
//.........................................................................
//  
//-------------------------------------------------------------------------
void CflowdRawFlowClientList::Clear()
{
  this->CloseAll();
  (*this).erase((*this).begin(),(*this).end());

  return;
}

//-------------------------------------------------------------------------
//                fd_set & CflowdRawFlowClientList::FdSet()
//.........................................................................
//  
//-------------------------------------------------------------------------
fd_set & CflowdRawFlowClientList::FdSet()
{
  return(this->_fdSet);
}

//-------------------------------------------------------------------------
//                int CflowdRawFlowClientList::MaxFd() const               
//.........................................................................
//  
//-------------------------------------------------------------------------
int CflowdRawFlowClientList::MaxFd() const
{
  return(this->_maxFd);
}


//-------------------------------------------------------------------------
//               int CflowdRawFlowClientList::Accept(int fd)               
//.........................................................................
//  
//-------------------------------------------------------------------------
int CflowdRawFlowClientList::Accept(int fd)
{
  int                  newSockFd = -1;
  CflowdRawFlowClient  newClient;
  struct sockaddr_un   clientSockAddr;
  socklen_t            clientSockAddrLen = sizeof(clientSockAddr);
    
  newSockFd = accept(fd,(struct sockaddr *)&clientSockAddr,&clientSockAddrLen);
  if (newSockFd < 0) {
    syslog(LOG_ERR,"[E] accept(%d,%p,%p) failed: %m {%s:%d}",
           fd,&clientSockAddr,&clientSockAddrLen,__FILE__,__LINE__);
    return(-1);
  }
  else {
    syslog(LOG_INFO,"[I] raw flow client connected.");
  }
  
  newClient.fd = newSockFd;
  (*this).push_front(newClient);
  
  FD_SET(newSockFd,&(this->_fdSet));

  if (newSockFd > this->_maxFd) {
    this->_maxFd = newSockFd;
  }

  #ifdef SO_SNDBUF
    int    sendqsize = 524288;
    int    prevsendqsize = 1048576;
    int    tryval, diff;

    while (setsockopt(newSockFd,SOL_SOCKET,SO_SNDBUF,(char *)&sendqsize,
                      sizeof(sendqsize)) != 0) {
      prevsendqsize = sendqsize;
      sendqsize = sendqsize >> 1;
    }
    
    while ((diff = prevsendqsize - sendqsize) > 1024) {
      tryval = sendqsize + diff/2;
      if (!setsockopt(newSockFd,SOL_SOCKET,SO_SNDBUF,(char *)&tryval,
                      sizeof(tryval)))
        sendqsize = tryval;
      else
        prevsendqsize = tryval;
    }

    if (setsockopt(newSockFd,SOL_SOCKET,SO_SNDBUF,(char *)&sendqsize,
                   sizeof(sendqsize)) == 0) {
      syslog(LOG_INFO,
             "[I] set send queue to %d bytes for fd %d",
             sendqsize,newSockFd);
    }
    else {
      syslog(LOG_ERR,
             "[E] setsockopt(%d,SOL_SOCKET,SO_SNDBUF,%d,%d) failed: %m "
             "{%s:%d}",
             __FILE__,__LINE__,newSockFd,sendqsize,sizeof(sendqsize));
    }
  #endif  // SO_SNDBUF

  return(newSockFd);
}
