/*
 * DetectIP.cpp
 *
 *  Created on: 2008-11-15
 *      Author: root
 */
#include  <sys/types.h>
#include  <sys/socket.h>
#include  <netinet/in.h>
#include  <netdb.h>
#include <net/if.h>
#include <linux/sockios.h>
#include <sys/ioctl.h>
#include <net/if_arp.h>
#include  <arpa/inet.h>

#include <libsesdata.h>
#include "DetectIP.h"
using namespace LibSESData;

DetectIP::DetectIP() {
	GetHostIPList(m_IPList);
}

DetectIP::~DetectIP() {
	m_IPList.clear();
}
bool DetectIP::PollingIP()
{
	std::vector< HostInfo_t > IPList;
	GetHostIPList(IPList);
	bool isIPChanged = isIPListChanged(IPList);
	if ( true == isIPChanged )
	{
		m_IPList.clear();
		for(unsigned int i = 0; i < IPList.size(); i++)
		{
			m_IPList.push_back(IPList[i]);
		}
		//m_IPList = IPList;
	}
	return isIPChanged;
}
bool DetectIP::isIPListChanged(std::vector<HostInfo_t>& IPList)
{
	if ( IPList.size() == 0 )
	{
		return false;
	}
	if(IPList.size() != m_IPList.size())
	{
//		int i = IPList.size();
//		int j = m_IPList.size();
//		CSESLog::WriteLine("TSD DetectIP::isIPListChanged>>IP list Size is not equal");
//		char   numStr[6];
//		bzero(numStr,6);
//		snprintf(numStr,5,"%d",i);
//		CSESLog::WriteLine("new list is");
//		CSESLog::WriteLine(numStr);
//		bzero(numStr,6);
//		snprintf(numStr,5,"%d",j);
//		CSESLog::WriteLine("old list is");
//		CSESLog::WriteLine(numStr);
		return true;
	}
	for(unsigned int i = 0; i < IPList.size(); i++)
	{
		bool isFound = false;
		for(unsigned int j = 0; j < m_IPList.size(); j++)
		{
			if ( 0 == ((m_IPList[j]).netcardname).compare((IPList[i]).netcardname) )
			{
				isFound = true;
				if ( 0 != ((m_IPList[j]).IP).compare((IPList[i]).IP) )
				{
					return true;
				}
			}
		}
		if ( false == isFound )
		{
			return true;
		}
	}
	return false;
}
/*void DetectIP::GetHostIPList(std::vector<HostInfo_t>& IPList)
{
    int s;
    struct ifconf conf;
    struct ifreq *ifr;
    char buff[BUFSIZ];
    int num;
    int i;

    s = socket(PF_INET, SOCK_DGRAM, 0);
    conf.ifc_len = BUFSIZ;
    conf.ifc_buf = buff;

    ioctl(s, SIOCGIFCONF, &conf);
    num = conf.ifc_len / sizeof(struct ifreq);
    ifr = conf.ifc_req;
    for(i=0;i < num;i++)
    {
            struct sockaddr_in *sin = (struct sockaddr_in *)(&ifr->ifr_addr);

            ioctl(s, SIOCGIFFLAGS, ifr);
            if(((ifr->ifr_flags & IFF_LOOPBACK) == 0) && (ifr->ifr_flags & IFF_UP))
            {
            	HostInfo_t hi;
            	hi.IP = inet_ntoa(sin->sin_addr);
            	hi.netcardname = ifr->ifr_name;
            	IPList.push_back(hi);
            }
            ifr++;
    }
}*/
#define inaddrr(x) (*(struct in_addr *) &ifr->x[sizeof sa.sin_port])
#define IFRSIZE   ((int)(size * sizeof (struct ifreq)))

void DetectIP::GetHostIPList(std::vector<HostInfo_t>& IPList)
{
	  //unsigned char      *u;
	  int                sockfd, size  = 1;
	  struct ifreq       *ifr;
	  struct ifconf      ifc;
	  struct sockaddr_in sa;

	  if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP))) {
	   //fprintf(stderr, "Cannot open socket.\n");
		  CSESLog::WriteLine("TSD DetectIP::GetHostIPList>>Cannot open socket.",CSESLog::ERROR);
		  return;
	  }

	  ifc.ifc_len = IFRSIZE;
	  ifc.ifc_req = NULL;

	  do {
	    ++size;
	    /* realloc buffer size until no overflow occurs  */
	    if (NULL == (ifc.ifc_req = (ifreq*)realloc(ifc.ifc_req, IFRSIZE))) {
			  CSESLog::WriteLine("TSD DetectIP::GetHostIPList>>Out of memory.",CSESLog::ERROR);
			  return;
//	      fprintf(stderr, "Out of memory.\n");
//	      exit(EXIT_FAILURE);
	    }
	    ifc.ifc_len = IFRSIZE;
	    if (ioctl(sockfd, SIOCGIFCONF, &ifc)) {
			  CSESLog::WriteLine("TSD DetectIP::GetHostIPList>>ioctl SIOCFIFCONF failed.",CSESLog::ERROR);
			  return;
//	      perror("ioctl SIOCFIFCONF");
//	      exit(EXIT_FAILURE);
	    }
	  } while  (IFRSIZE <= ifc.ifc_len);

	  ifr = ifc.ifc_req;
	  for (;(char *) ifr < (char *) ifc.ifc_req + ifc.ifc_len; ++ifr) {

	    if (ifr->ifr_addr.sa_data == (ifr+1)->ifr_addr.sa_data) {
	      continue;  /* duplicate, skip it */
	    }

	    if (ioctl(sockfd, SIOCGIFFLAGS, ifr)) {
	      continue;  /* failed to get flags, skip it */
	    }

	   // printf("Interface:  %s\n", ifr->ifr_name);
	    //printf("IP Address: %s\n", inet_ntoa(inaddrr(ifr_addr.sa_data)));
    	HostInfo_t hi;
    	hi.IP = inet_ntoa(inaddrr(ifr_addr.sa_data));
    	hi.netcardname = ifr->ifr_name;
    	IPList.push_back(hi);

	    /*
	      This won't work on HP-UX 10.20 as there's no SIOCGIFHWADDR ioctl. You'll
	      need to use DLPI or the NETSTAT ioctl on /dev/lan0, etc (and you'll need
	      to be root to use the NETSTAT ioctl. Also this is deprecated and doesn't
	      work on 11.00).

	      On Digital Unix you can use the SIOCRPHYSADDR ioctl according to an old
	      utility I have. Also on SGI I think you need to use a raw socket, e.g. s
	      = socket(PF_RAW, SOCK_RAW, RAWPROTO_SNOOP)

	      Dave

	      From: David Peter <dave.peter@eu.citrix.com>
	     */

/*	    if (0 == ioctl(sockfd, SIOCGIFHWADDR, ifr)) {

	       Select which  hardware types to process.
	       *
	       *    See list in system include file included from
	       *    /usr/include/net/if_arp.h  (For example, on
	       *    Linux see file /usr/include/linux/if_arp.h to
	       *    get the list.)

	      switch (ifr->ifr_hwaddr.sa_family) {
	      default:
	 printf("\n");
	 continue;
	      case  ARPHRD_NETROM:  case  ARPHRD_ETHER:  case  ARPHRD_PPP:
	      case  ARPHRD_EETHER:  case  ARPHRD_IEEE802: break;
	      }

	      u = (unsigned char *) &ifr->ifr_addr.sa_data;

	      if (u[0] + u[1] + u[2] + u[3] + u[4] + u[5]) {
	        printf("HW Address: %2.2x.%2.2x.%2.2x.%2.2x.%2.2x.%2.2x\n",
	      u[0], u[1], u[2], u[3], u[4], u[5]);
	      }
	    }

	    if (0 == ioctl(sockfd, SIOCGIFNETMASK, ifr) &&
	 strcmp("255.255.255.255", inet_ntoa(inaddrr(ifr_addr.sa_data)))) {
	      printf("Netmask:    %s\n", inet_ntoa(inaddrr(ifr_addr.sa_data)));
	    }

	    if (ifr->ifr_flags & IFF_BROADCAST) {
	      if (0 == ioctl(sockfd, SIOCGIFBRDADDR, ifr) &&
	   strcmp("0.0.0.0", inet_ntoa(inaddrr(ifr_addr.sa_data)))) {
	        printf("Broadcast:  %s\n", inet_ntoa(inaddrr(ifr_addr.sa_data)));
	      }
	    }

	    if (0 == ioctl(sockfd, SIOCGIFMTU, ifr)) {
	      printf("MTU:        %u\n",  ifr->ifr_mtu);
	    }

	    if (0 == ioctl(sockfd, SIOCGIFMETRIC, ifr)) {
	      printf("Metric:     %u\n",  ifr->ifr_metric);
	    } printf("\n");
	    */
	  }

	  close(sockfd);
}
