/*
 *========================================================================
 * $Id: net.c 88 2004-09-28 22:49:38Z rgb $
 *
 * See copyright in copyright.h and the accompanying file COPYING
 *========================================================================
 */

#include <wulfware/libwulf.h>
 /* id buffer */
static char idbuf[K];
static unsigned long seconds,useconds;

/*
 * <net> tag init and update (same thing)
 */
void init_net(Host *hostptr)
{

 int i,j;
 /* 
  * current timestamp and delta (to microsecond resolution) 
  */
 double timestamp, delta_time, delta_value, new_value;
 unsigned long new_uvalue;
 unsigned long long new_ulvalue;

 if((verbose == D_ALL) || (verbose == D_VALUES)){
   fprintf(OUTFP,"D_VALUES: Starting init_net() on %s.  Use -v %d to focus.\n",hostptr->hostname,D_VALUES);
 }

 /* 
  * net - tv_sec and tv_usec timestamps.
  */
 /* <net tv_sec=?> */
 if(xtract_attribute(UNSIGNED_LONG,&seconds,value_xpath[NETDEV],
                      "tv_sec",hostptr->xp_doc) > 1){
   fprintf(OUTFP,"fill_values() Warning: %s not unique content tag.\n",
         value_xpath[NETDEV]);
 }
 if((verbose == D_ALL) || (verbose == D_VALUES)){
   fprintf(OUTFP,"D_VALUES: seconds = %d\n",seconds);
 }
 hostptr->val.netdev_tv_sec = seconds;

 /* <net tv_usec=?> */
 if(xtract_attribute(UNSIGNED_LONG,&useconds,value_xpath[NETDEV],
                      "tv_usec",hostptr->xp_doc) > 1){
   fprintf(OUTFP,"fill_values() Warning: %s not unique content tag.\n",
         value_xpath[NETDEV]);
 }
 if((verbose == D_ALL) || (verbose == D_VALUES)){
   fprintf(OUTFP,"D_VALUES: useconds = %d\n",useconds);
 }
 hostptr->val.netdev_tv_usec = useconds;
 if((verbose == D_ALL) || (verbose == D_VALUES)){
   fprintf(OUTFP,"D_VALUES: netdev_tv_sec = %ul netdev_tv_usec = %ul\n",hostptr->val.netdev_tv_sec,hostptr->val.netdev_tv_usec);
 }
 timestamp = (double) seconds + 1.e-6*useconds;
 if((verbose == D_ALL) || (verbose == D_VALUES)){
   fprintf(OUTFP,"D_VALUES: netdev_tv_sec = %d netdev_tv_usec = %d\n",hostptr->val.netdev_tv_sec,hostptr->val.netdev_tv_usec);
   fprintf(OUTFP,"D_VALUES: netdev_time = %.6f\n",timestamp);
 }


 /*
  * Count the network interfaces on this host
  */
 hostptr->val.num_interfaces = xtract(COUNT,NULL,value_xpath[INTERFACE],hostptr->xp_doc);
 if((verbose == D_ALL) || (verbose == D_VALUES)){
   fprintf(OUTFP,"D_VALUES: Found %d network interfaces on %s (plus 1 for total stats)\n",hostptr->val.num_interfaces,hostptr->hostname);
   fprintf(OUTFP,"D_VALUES: Each needs %d bytes\n",sizeof(Interface));
 }
 /*
  * Allocate memory for the interface data in hostptr->val.interface
  */
 hostptr->val.interface = (Interface *) ( malloc( (size_t) ( (hostptr->val.num_interfaces+1)*sizeof(Interface) ) ) );
 if((verbose == D_ALL) || (verbose == D_VALUES)){
   fprintf(OUTFP,"D_VALUES: Need %d bytes per interface\n",sizeof(Interface));
   fprintf(OUTFP,"D_VALUES: Malloc'd %d bytes in interface struct vector\n",(hostptr->val.num_interfaces+1)*sizeof(Interface));
   fprintf(OUTFP,"D_VALUES: base address is %x\n",hostptr->val.interface);
 }
 /*
  * Displace by one (to save room for a total network struct)
  */
 hostptr->val.interface++;
 if((verbose == D_ALL) || (verbose == D_VALUES)){
   fprintf(OUTFP,"D_VALUES: displaced base address is now %x\n",hostptr->val.interface);
   fprintf(OUTFP,"D_VALUES: address of interface[-1] is %x\n",&hostptr->val.interface[-1]);
 }

 /*
  * Now we fill in  /proc/net/dev derived values 
  */
 /* Do all network interfaces */
 for(j=0;j<hostptr->val.num_interfaces;j++){
     
   /* Get devtype attribute for interface */
   sprintf(idbuf,"%s[@id=\"%d\"]",value_xpath[INTERFACE],j);
   if(xtract_attribute(STRING,&hostptr->val.interface[j].devtype,idbuf,
                      "devtype",hostptr->xp_doc) > 1){
     fprintf(stderr,"init_net() Warning: %s not unique content tag on %s.\n",
         idbuf,hostptr->hostname);
   }
   if((verbose == D_ALL) || (verbose == D_VALUES)){
     fprintf(OUTFP,"D_VALUES: interface devtype = %s\n",hostptr->val.interface[j].devtype);
   }

   /* Get devid attribute for interface */
   sprintf(idbuf,"%s[@id=\"%d\"]",value_xpath[INTERFACE],j);
   if(xtract_attribute(STRING,&hostptr->val.interface[j].devid,idbuf,
                      "devid",hostptr->xp_doc) > 1){
     fprintf(stderr,"init_net() Warning: %s not unique content tag on %s.\n",
           idbuf,hostptr->hostname);
   }
   if((verbose == D_ALL) || (verbose == D_VALUES)){
     fprintf(OUTFP,"D_VALUES: interface devid = %s\n",hostptr->val.interface[j].devid);
   }

   /* interface host */
   sprintf(idbuf,"%s[@id=\"%d\"]/host",value_xpath[INTERFACE],j);
   if( xtract(STRING,&hostptr->val.interface[j].host,idbuf,hostptr->xp_doc) > 1 ){
     fprintf(stderr,"init_net() Warning: %s not unique content tag on %s.\n",
         idbuf,hostptr->hostname);
   }
   if((verbose == D_ALL) || (verbose == D_VALUES)){
     fprintf(OUTFP,"D_VALUES: interface hostname  = %s\n",hostptr->val.interface[j].host);
   }

   /* interface ip */
   sprintf(idbuf,"%s[@id=\"%d\"]/ip",value_xpath[INTERFACE],j);
   if( xtract(STRING,&hostptr->val.interface[j].ip,idbuf,hostptr->xp_doc) > 1 ){
     fprintf(stderr,"init_net() Warning: %s not unique content tag on %s.\n",
         idbuf,hostptr->hostname);
   }
   if((verbose == D_ALL) || (verbose == D_VALUES)){
     fprintf(OUTFP,"D_VALUES: interface ip  = %s\n",hostptr->val.interface[j].ip);
   }

   /* rx_bytes */
   sprintf(idbuf,"%s[@id=\"%d\"]/receive/bytes",value_xpath[INTERFACE],j);
   if( xtract(UNSIGNED_LONG_LONG,&new_uvalue,idbuf,hostptr->xp_doc) > 1 ){
     fprintf(stderr,"init_net() Warning: %s not unique content tag on %s.\n",
         idbuf,hostptr->hostname);
   }
   hostptr->val.interface[j].rx_bytes = new_uvalue;
   if((verbose == D_ALL) || (verbose == D_VALUES)){
     fprintf(OUTFP,"D_VALUES: interface[%d].rx_bytes = %lu\n",j,hostptr->val.interface[j].rx_bytes);
   }

   /* rx_packets */
   sprintf(idbuf,"%s[@id=\"%d\"]/receive/packets",value_xpath[INTERFACE],j);
   if( xtract(UNSIGNED_LONG_LONG,&new_uvalue,idbuf,hostptr->xp_doc) > 1 ){
     fprintf(stderr,"init_net() Warning: %s not unique content tag on %s.\n",
         idbuf,hostptr->hostname);
   }
   hostptr->val.interface[j].rx_packets = new_uvalue;
   if((verbose == D_ALL) || (verbose == D_VALUES)){
     fprintf(OUTFP,"D_VALUES: interface[%d].rx_packets = %lu\n",j,hostptr->val.interface[j].rx_packets);
   }

   /* rx_errs */
   sprintf(idbuf,"%s[@id=\"%d\"]/receive/errs",value_xpath[INTERFACE],j);
   if( xtract(UNSIGNED_LONG_LONG,&new_uvalue,idbuf,hostptr->xp_doc) > 1 ){
     fprintf(stderr,"init_net() Warning: %s not unique content tag on %s.\n",
         idbuf,hostptr->hostname);
   }
   hostptr->val.interface[j].rx_errs = new_uvalue;
   if((verbose == D_ALL) || (verbose == D_VALUES)){
     fprintf(OUTFP,"D_VALUES: interface[%d].rx_errs = %lu\n",j,hostptr->val.interface[j].rx_errs);
   }

   /* tx_bytes */
   sprintf(idbuf,"%s[@id=\"%d\"]/transmit/bytes",value_xpath[INTERFACE],j);
   if( xtract(UNSIGNED_LONG_LONG,&new_uvalue,idbuf,hostptr->xp_doc) > 1 ){
     fprintf(stderr,"init_net() Warning: %s not unique content tag on %s.\n",
         idbuf,hostptr->hostname);
   }
   hostptr->val.interface[j].tx_bytes = new_uvalue;
   if((verbose == D_ALL) || (verbose == D_VALUES)){
     fprintf(OUTFP,"D_VALUES: interface[%d].tx_bytes = %lu\n",j,hostptr->val.interface[j].tx_bytes);
   }

   /* tx_packets */
   sprintf(idbuf,"%s[@id=\"%d\"]/transmit/packets",value_xpath[INTERFACE],j);
   if( xtract(UNSIGNED_LONG_LONG,&new_uvalue,idbuf,hostptr->xp_doc) > 1 ){
     fprintf(stderr,"init_net() Warning: %s not unique content tag on %s.\n",
         idbuf,hostptr->hostname);
   }
   hostptr->val.interface[j].tx_packets = new_uvalue;
   if((verbose == D_ALL) || (verbose == D_VALUES)){
     fprintf(OUTFP,"D_VALUES: interface[%d].tx_packets = %lu\n",j,hostptr->val.interface[j].tx_packets);
   }

   /* tx_errs */
   sprintf(idbuf,"%s[@id=\"%d\"]/transmit/errs",value_xpath[INTERFACE],j);
   if( xtract(UNSIGNED_LONG_LONG,&new_uvalue,idbuf,hostptr->xp_doc) > 1 ){
     fprintf(stderr,"init_net() Warning: %s not unique content tag on %s.\n",
         idbuf,hostptr->hostname);
   }
   hostptr->val.interface[j].tx_errs = new_uvalue;
   if((verbose == D_ALL) || (verbose == D_VALUES)){
     fprintf(OUTFP,"D_VALUES: interface[%d].tx_errs = %lu\n",j,hostptr->val.interface[j].tx_errs);
   }

 }

}


void update_net(Host *hostptr)
{

 int i,j;
 /* 
  * current timestamp and delta (to microsecond resolution) 
  */
 double timestamp, delta_time, delta_value, new_value;
 unsigned long delta_sec,delta_usec;
 unsigned long seconds,useconds;
 unsigned long new_uvalue;

 if((verbose == D_ALL) || (verbose == D_VALUES)){
   fprintf(OUTFP,"D_VALUES: Starting update_net() on %s.  Use -v %d to focus.\n",hostptr->hostname,D_VALUES);
   
 }

     /* 
      * netdev - tv_sec and tv_usec timestamps (for rates) just like above.
      */

 /* 
  * net - tv_sec and tv_usec timestamps AND conversion into deltas
  * so reasonably accurate rates can be formed.
  */
 /* <net tv_sec=?> */
 if(xtract_attribute(UNSIGNED_LONG,&seconds,value_xpath[NETDEV],
                      "tv_sec",hostptr->xp_doc) > 1){
   fprintf(OUTFP,"fill_values() Warning: %s not unique content tag.\n",
         value_xpath[NETDEV]);
 }
 if((verbose == D_ALL) || (verbose == D_VALUES)){
   fprintf(OUTFP,"D_VALUES: old seconds = %ld\n",hostptr->val.netdev_tv_sec);
   fprintf(OUTFP,"D_VALUES: new seconds = %ld\n",seconds);
 }

 /* <net tv_usec=?> */
 if(xtract_attribute(UNSIGNED_LONG,&useconds,value_xpath[NETDEV],
                      "tv_usec",hostptr->xp_doc) > 1){
   fprintf(OUTFP,"fill_values() Warning: %s not unique content tag.\n",
         value_xpath[NETDEV]);
 }
 if((verbose == D_ALL) || (verbose == D_VALUES)){
   fprintf(OUTFP,"D_VALUES: old useconds = %ld\n",hostptr->val.netdev_tv_usec);
   fprintf(OUTFP,"D_VALUES: new useconds = %ld\n",useconds);
 }

 /* 
  * There is a small chance that delta_time is negative - if the clock
  * is reset between cycles, for example - and it COULD be zero.  We
  * fix whatever garbage we might find here which will affect only one
  * cycle anyway.  Note that since seconds and useconds are unsigned
  * long, the following MUST be done with the 1.0* or casts or the
  * arithmetic won't come out at all right when a subtraction of two
  * unsigned int's turns out negative.
  */
 delta_time = 1.0*seconds - 1.0*hostptr->val.netdev_tv_sec + 1.e-6*useconds - 1.e-6*hostptr->val.netdev_tv_usec;
 if(delta_time <= 0.0) delta_time = 1.e-8;	/* avoid divergence */
 timestamp = (double) seconds + 1.e-6*useconds;

 hostptr->val.netdev_tv_sec = seconds;
 hostptr->val.netdev_tv_usec = useconds;

 if((verbose == D_ALL) || (verbose == D_VALUES)){
   fprintf(OUTFP,"D_VALUES: netdev_tv_sec = %lu netdev_tv_usec = %ul\n",hostptr->val.netdev_tv_sec,hostptr->val.netdev_tv_usec);
   fprintf(OUTFP,"D_VALUES: netdev_time = %.6f\n",timestamp);
   fprintf(OUTFP,"D_VALUES: delta_time = %.6f\n",delta_time);
 }

 /*   
  * Form rates for all network interfaces, form totals as well in -1 slot.
  */
 hostptr->val.interface[-1].rx_bytes_rate = 0;
 hostptr->val.interface[-1].rx_packets_rate = 0;
 hostptr->val.interface[-1].rx_errs_rate = 0;
 hostptr->val.interface[-1].tx_bytes_rate = 0;
 hostptr->val.interface[-1].tx_packets_rate = 0;
 hostptr->val.interface[-1].tx_errs_rate = 0;
 for(j=0;j<hostptr->val.num_interfaces;j++){
   if((verbose == D_ALL) || (verbose == D_VALUES)){
     fprintf(OUTFP,"D_VALUES: About to fill host %s val.interface[%d].\n",hostptr->hostname,j);
   }

   /* rx_bytes */
   sprintf(idbuf,"%s[@id=\"%d\"]/receive/bytes",value_xpath[INTERFACE],j);
   if(xtract(UNSIGNED_LONG_LONG,&new_uvalue,idbuf,hostptr->xp_doc) > 1){
     fprintf(OUTFP,"fill_values() Warning: %s not unique content tag on %s.\n",
         idbuf,hostptr->hostname);
   }
   delta_value = (new_uvalue - hostptr->val.interface[j].rx_bytes);
   hostptr->val.interface[j].rx_bytes_rate = delta_value/delta_time;
   hostptr->val.interface[j].rx_bytes = new_uvalue;
   if((verbose == D_ALL) || (verbose == D_VALUES)){
     fprintf(OUTFP,"D_VALUES: interface[%d].rx_bytes = %lu, rate = %f\n",j,hostptr->val.interface[j].rx_bytes,hostptr->val.interface[j].rx_bytes_rate);
   }

   /* rx_packets */
   sprintf(idbuf,"%s[@id=\"%d\"]/receive/packets",value_xpath[INTERFACE],j);
   if(xtract(UNSIGNED_LONG_LONG,&new_uvalue,idbuf,hostptr->xp_doc) > 1){
     fprintf(OUTFP,"fill_values() Warning: %s not unique content tag on %s.\n",
         idbuf,hostptr->hostname);
   }
   delta_value = (new_uvalue - hostptr->val.interface[j].rx_packets);
   hostptr->val.interface[j].rx_packets_rate = delta_value/delta_time;
   hostptr->val.interface[j].rx_packets = new_uvalue;
   if((verbose == D_ALL) || (verbose == D_VALUES)){
     fprintf(OUTFP,"D_VALUES: interface[%d].rx_packets = %lu, rate = %f\n",j,hostptr->val.interface[j].rx_packets,hostptr->val.interface[j].rx_packets_rate);
   }

   /* rx_errs */
   sprintf(idbuf,"%s[@id=\"%d\"]/receive/errs",value_xpath[INTERFACE],j);
   if(xtract(UNSIGNED_LONG_LONG,&new_uvalue,idbuf,hostptr->xp_doc) > 1){
     fprintf(OUTFP,"fill_values() Warning: %s not unique content tag on %s.\n",
         idbuf,hostptr->hostname);
   }
   delta_value = (new_uvalue - hostptr->val.interface[j].rx_errs);
   hostptr->val.interface[j].rx_errs_rate = delta_value/delta_time;
   hostptr->val.interface[j].rx_errs = new_uvalue;
   if((verbose == D_ALL) || (verbose == D_VALUES)){
     fprintf(OUTFP,"D_VALUES: interface[%d].rx_errs = %lu, rate = %f\n",j,hostptr->val.interface[j].rx_errs,hostptr->val.interface[j].rx_errs_rate);
   }
      
   /* tx_bytes */
   sprintf(idbuf,"%s[@id=\"%d\"]/transmit/bytes",value_xpath[INTERFACE],j);
   if(xtract(UNSIGNED_LONG_LONG,&new_uvalue,idbuf,hostptr->xp_doc) > 1){
     fprintf(OUTFP,"fill_values() Warning: %s not unique content tag on %s.\n",
         idbuf,hostptr->hostname);
   }
   delta_value = (new_uvalue - hostptr->val.interface[j].tx_bytes);
   hostptr->val.interface[j].tx_bytes_rate = delta_value/delta_time;
   hostptr->val.interface[j].tx_bytes = new_uvalue;
   if((verbose == D_ALL) || (verbose == D_VALUES)){
     fprintf(OUTFP,"D_VALUES: interface[%d].tx_bytes = %lu, rate = %f\n",j,hostptr->val.interface[j].tx_bytes,hostptr->val.interface[j].tx_bytes_rate);
   }
      
   /* tx_packets */
   sprintf(idbuf,"%s[@id=\"%d\"]/transmit/packets",value_xpath[INTERFACE],j);
   if(xtract(UNSIGNED_LONG_LONG,&new_uvalue,idbuf,hostptr->xp_doc) > 1){
     fprintf(OUTFP,"fill_values() Warning: %s not unique content tag on %s.\n",
         idbuf,hostptr->hostname);
   }
   delta_value = (new_uvalue - hostptr->val.interface[j].tx_packets);
   hostptr->val.interface[j].tx_packets_rate = delta_value/delta_time;
   hostptr->val.interface[j].tx_packets = new_uvalue;
   if((verbose == D_ALL) || (verbose == D_VALUES)){
     fprintf(OUTFP,"D_VALUES: interface[%d].tx_packets = %lu, rate = %f\n",j,hostptr->val.interface[j].tx_packets,hostptr->val.interface[j].tx_packets_rate);
   }
      
   /* tx_errs */
   sprintf(idbuf,"%s[@id=\"%d\"]/transmit/errs",value_xpath[INTERFACE],j);
   if(xtract(UNSIGNED_LONG_LONG,&new_uvalue,idbuf,hostptr->xp_doc) > 1){
     fprintf(OUTFP,"fill_values() Warning: %s not unique content tag on %s.\n",
         idbuf,hostptr->hostname);
   }
   delta_value = (new_uvalue - hostptr->val.interface[j].tx_errs);
   hostptr->val.interface[j].tx_errs_rate = delta_value/delta_time;
   hostptr->val.interface[j].tx_errs = new_uvalue;
   if((verbose == D_ALL) || (verbose == D_VALUES)){
     fprintf(OUTFP,"D_VALUES: interface[%d].tx_errs = %lu, rate = %f\n",j,hostptr->val.interface[j].tx_errs,hostptr->val.interface[j].tx_errs_rate);
   }

   /* increment val.interface for total rates */
   hostptr->val.interface[-1].rx_bytes_rate += hostptr->val.interface[j].rx_bytes_rate;
   hostptr->val.interface[-1].rx_packets_rate += hostptr->val.interface[j].rx_packets_rate;
   hostptr->val.interface[-1].rx_errs_rate += hostptr->val.interface[j].rx_errs_rate;
   hostptr->val.interface[-1].tx_bytes_rate += hostptr->val.interface[j].tx_bytes_rate;
   hostptr->val.interface[-1].tx_packets_rate += hostptr->val.interface[j].tx_packets_rate;
   hostptr->val.interface[-1].tx_errs_rate += hostptr->val.interface[j].tx_errs_rate;
      
 }

 /* 
  * <net><sockstat> values (bundled in with <net>)
  */
 /* <tcp><inuse> */
 if(xtract(LONG,&hostptr->val.tcp_inuse,value_xpath[TCP_INUSE],hostptr->xp_doc) > 1){
   fprintf(OUTFP,"fill_values() Warning: %s not unique content tag on %s.\n",
       value_xpath[SWAP_FREE],hostptr->hostname);
 }
 if((verbose == D_ALL) || (verbose == D_VALUES)){
   fprintf(OUTFP,"D_VALUES: tcp_inuse = %d\n",hostptr->val.tcp_inuse);
 }

}
