/******************************************************** 
 * 
 * File:           receiveUDP.c
 *
 * P.N.:            
 * 
 * Rel.:           1.0.0 
 *
  * Product:        UDP Latency test for loop controls 
 *
 * Property:       UNINA - All rights reserved 
 *
 * Author:         Fabio Garufi 
 * 
 * Creation Date:  March 16, 2005 
 *
 * Description: 
 * 	Receives bounched packets and analyses time delay.
 * 
 * Revisions History: 
 *
 *
 ********************************************************/

/*@****************************************************** 
 *	INCLUDE SECTION
 ********************************************************/
#include <file.h>
#include <sys/types.h>
#include <fcntl.h>
#ifdef LINUX
#include <linux/socket.h>
#else
#include <socket.h>
#endif
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <errno.h>
#include<net/if.h>
#include <sys/time.h>
#define NUM_CAR 4096
#define PORT  12345
#include <math.h>

#ifdef LYNXOS

#endif //LYNXOS


int read_timeo(int fd, int usec);
unsigned int tvsub(struct timeval *, 
                   struct timeval *);

		   
typedef struct
{
	int id;
	struct timeval timev;
} data_t;

/*@******************************************************
 * Function: main 
 * 
 * Description: 
 * 
 * INPUT: 
 * 
 * OUTPUT: 
 *
 * RETURN VALUE: 
 * 
 ********************************************************/ 
int main(argc, argv)
int argc;
char **argv;
{
  int s, fd;
  char str_in[NUM_CAR];
  char str_out[NUM_CAR];
  unsigned int dest_ip_addr;
  struct sockaddr_in loc_addr;
  struct sockaddr src_addr;
  struct sockaddr sockname;
  struct hostent * loc_host;
  data_t data_old, data_new;
  data_t *pdata;
  int i,j;
  int namelen;
  int num_car_letti;
  int  val;
  struct ifreq testioctl;
  u_short port;
  struct timeval timeo;
  int thresh;
  int packets;
  int lost=0;
  int over=0;
  float avg,  sigma, sigma2;
  unsigned int delta, sum,  max;
  float avg2,sum2;
  struct timeval now;
  int *dels;

  max= 0; sum= 0; sum2= 0 ;
  
  if(argc <4)
    {
      printf("usage %s <local_IP> <packet Nr.> <thresh> [<port>]\n", argv[0]);
      return -1;
    }
  
  packets = atoi(argv[2]);
  thresh = atoi(argv[3]);
  
  if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
	perror("ubeam: socket call failed: ");
	exit(1);
  } /* end if */

 loc_host = gethostbyname(argv[1]);
  //loc_host = gethostbyaddr(argv[1], strlen(argv[1]), AF_INET);
  if (loc_host == (struct hostent *)NULL) {
    perror("ubeam: error in gethostbyname: ");
    exit(1);
  } /* end if */
  
  loc_addr.sin_family = AF_INET;
/*********************************************/
  if(argc == 5)
    port = (u_short)atoi(argv[4]);
  else
    port = PORT;

  loc_addr.sin_port = htons(port+1);
  loc_addr.sin_addr.s_addr = INADDR_ANY;
/*********************************************/
  if (bind(s, (struct sockaddr*)&loc_addr, sizeof(struct sockaddr_in)) < 0) {
    printf("errno = %d \n", errno);
	perror("ubeam: bind failed: ");
	exit(1);
  } /* end if */
	dels = (int *)calloc(packets, sizeof(int));
  while (i<packets) {
        namelen = sizeof(struct sockaddr);
	memcpy((data_t *)&data_old,(data_t *)&data_new, sizeof(data_t));
        if ((num_car_letti = recvfrom(s, str_in, NUM_CAR, 
                                      0, &src_addr, &namelen)) == -1) {
	    perror("ubeam: recvfrom failed: ");
	    exit(1);
        }
	gettimeofday(&now, NULL);
	pdata = (data_t *)str_in;
	memcpy((data_t *)&data_new, pdata, sizeof(data_t));
	if(pdata->id != (data_old.id +1))
		 lost++;
	else if((delta=tvsub(&now,&data_new.timev )) > thresh)
	{
//		printf("id %d delta = %d\n",data_new.id, delta);
		(delta > max) ? (max = delta) : (max);
		over++;
		dels[i]=delta;
	}
	else
	{	
		(delta > max) ? (max = delta) : (max);
		sum+=delta; 
		sum2 += (delta*delta);
		dels[i]=delta;
	}
	i++;
	      
 
  } /* end for */

  close(s);

  /* Elaborate and print statistics */
   avg = (float)sum/(float)packets;
   avg2 = sum2/(float)packets;
   sigma2 = avg2 - (float)avg*avg; 
   sigma = sqrt(sigma2);
    printf("Lost packets...............%d\n", lost);
    printf("Packets over threshold.....%d\n", over);
    printf("Max delay..................%d\n", max);
    printf("Average delay..............%f\n", avg);
    printf("RMS delay..................%f\n", sigma);
    
    /* Save measured delays into file */
    /*
    fd = open("./dels", O_CREAT|O_RDWR, 0777);
    for (i = 0; i<packets; i++)
    {
    	if(write(fd,(int *)&dels[i], sizeof(int))<0)
		perror("write");
     }
    close(fd);
    */
    free(dels);
} /* end of main */

int read_timeo(int fd, int usec)
{
  fd_set rset;
  struct timeval timeo;
  FD_ZERO(&rset);
  FD_SET(fd, &rset);
  
  timeo.tv_sec=0;
  timeo.tv_usec=usec;

  return(select(fd+1, &rset, NULL, NULL, &timeo));
} 

unsigned int tvsub(struct timeval * t1, 
                   struct timeval * t0)
{
  unsigned int res;
  unsigned int aux;
  
  aux = t1->tv_sec - t0->tv_sec;
  if (aux > 0) {
  /* res = (aux - 1) * 1000000 + t1->tv_usec + 1000000 - t0->tv_usec; */
    res = aux * 1000000 + t1->tv_usec - t0->tv_usec;
  }
  else {
    res = t1->tv_usec - t0->tv_usec;
  } /* end if */	
  
  return(res);              
} /* end of tvsub */
