#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/ioctl.h>
#include <sys/param.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include "ips.h"

#ifndef HOSTNAMELEN
#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN 64
#endif
#define HOSTNAMELEN MAXHOSTNAMELEN
#endif

/** This code based on some code published on August 16th 2000
 * on comp.unix.programming, and evidently placed in the public
 * domain.
 *
 * This code is probably not terribly portable but seems fine on
 * Linux.
 **/
Vector<Interface*> *ips()
{
  char   hostbuf[HOSTNAMELEN];
  int      fd;
  int    pppflag, bcstflag;
  struct ifreq    *ifr;
  struct ifconf   ifc;
  struct ifreq    buf[30];  /* arbitrarily large enough */
  struct hostent  *hp;

  fd=-1;

  Vector<Interface*> *ifaces=new Vector<Interface*>();

  /* look up this machine */    
  if (gethostname(hostbuf, sizeof hostbuf)) {
    perror("gethostname");
    return ifaces;
    //    exit(EXIT_FAILURE);
  }

  /* get hostent struct for this host */
  if (NULL == (hp = gethostbyname(hostbuf))) {
    fprintf(stderr, "%s hostname", hostbuf);
    herror(" lookup");
    //    exit(EXIT_FAILURE);
    return ifaces;
  }

  /* open a socket */
  if (0 > (fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP))) {
      perror("socket");
      //      exit(EXIT_FAILURE);
      return ifaces;
  }

  ifc.ifc_len = sizeof (buf);
  ifc.ifc_req = buf;

  /* get configuration of interfaces */
  if (ioctl(fd, SIOCGIFCONF, &ifc)) {
    perror("ioctl SIOCFIFCONF");
    return ifaces;
    //    exit(EXIT_FAILURE);
  }
  
  /* step through interfaces */
  ifr = ifc.ifc_req;
  while ((char *) ifr < (char *) ifc.ifc_req + ifc.ifc_len) {
    struct in_addr *inadr;

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

    /* get flag data for this interface */
    if (ioctl(fd, SIOCGIFFLAGS, ifr)) {
      break;
    }

    if ((ifr->ifr_flags & (IFF_UP | IFF_LOOPBACK)) != IFF_UP) {
      ++ifr;
      continue;  /* not up or loopback a interface, skip it */
    }

    /* keep track of whether it is a ppp interface or not */
    pppflag  = ifr->ifr_flags & IFF_POINTOPOINT;
    bcstflag = ifr->ifr_flags & IFF_BROADCAST;

    Interface *iface=new Interface();

    //    printf("\ndevice:       %s\n", ifr->ifr_name);
    iface->ifname=strdup(ifr->ifr_name);

    inadr = (struct in_addr *) 
      &((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;

    //    printf("IP addr:      %s\n",  inet_ntoa(*inadr));
    iface->ip=strdup(inet_ntoa(*inadr));

    ifaces->add(iface);

    ++ifr;
  }

  if (fd!=-1)
    close(fd);

  return ifaces;
}


