/*
 * NFS-test routines
 * $Header: nfs.c,v 2.1 93/04/13 21:46:10 jraja Exp $
 * $Log:	nfs.c,v $
 * Revision 2.1  93/04/13  21:46:10  21:46:10  jraja (Jarno Tapio Rajahalme)
 * Made this compile with the newest API.
 * 
 * Revision 2.0  93/03/20  17:31:45  17:31:45  ppessi (Pekka Pessi)
 * initial netlib version..
 * 
 * Revision 1.10  93/03/19  14:45:10  14:45:10  puhuri (Markus Peuhkuri)
 * Add modifications made by too and ppessi.
 * 
 * Revision 1.9  93/03/17  21:24:02  21:24:02  puhuri (Markus Peuhkuri)
 * Add checksum test
 * 
 * Revision 1.8  93/03/16  19:14:01  19:14:01  too (Tomi Ollila)
 * code fixes
 * 
 * Revision 1.7  93/03/16  10:42:33  10:42:33  puhuri (Markus Peuhkuri)
 * Added AmiTCP stuff.
 * 
 * Revision 1.6  93/03/15  18:59:37  18:59:37  puhuri (Markus Peuhkuri)
 * Comment fix
 * 
 */

/*
 * A testing software for UDP-ping-pong
 * Client sends a UDP-datagram to server, which responds with
 * same datagram. At server end there is a time control: 
 * if server does not respond in NFSTIMEOUT (30) seconds
 * one of packets is asumed to disapperad and another packet is sent.
 * After
 */

#ifdef AMIGA
#if __SASC
#include <proto/socket.h>
#elif __GNUC__
#include <inline/socket.h>
#else
#include <clib/socket_protos.h>
#endif
#endif /* AMIGA */

#ifdef __STDC__
#include <stdlib.h>
#endif

#include <stdio.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>

#include <sys/time.h>

#include <netinet/in.h>

#include "qwriter.h"
#include <string.h>		/* after qwriter.h */

int nfs_server(char *host, UWORD port1, int bufsiz, int length, int chk)
{
  int sid_s;
  struct sockaddr who;
  long adrlen = sizeof(who);
  int rounds=0;
  u16 *buf, sum;


  int r,s;
  if((sid_s=open_server(NULL, port1, SOCK_DGRAM))<0) /* We listen this */
    return(FAIL);
  
  if(buf=(u16 *)malloc(max(bufsiz, length))){	/* Allocate buffer */
    *buf=length;
    for(;;){
      if((r=recvfrom(sid_s, (char *)buf, bufsiz, 0, &who, &adrlen)) < 0)
	preturn("nfs-server: read");
      if(*buf == 0)
	break;
      if(chk)
	if(ntohs(*(buf+1)) != 
	   (sum = pppfcs(PPPINITFCS, (unsigned char *)(buf+2), ntohs(*buf))))
	  fprintf(stderr,"Checksum error in nfs-server: "
		  "should be %ld, is %ld\n"
		  "Error in recieved packet %ld\n",ntohs(*(buf+1)),
		  sum, rounds+1);
      *buf=htons(length);
      if(chk)
	*(buf+1) = htons(pppfcs(PPPINITFCS, (unsigned char *)(buf+2), length));
      if((s=sendto(sid_s, (char *)buf, length, 0, &who, adrlen)) < 0)
	preturn("nfs-server: write");
      DP(("r=%ld s=%ld len=%ld buf=%ld\n",r,s,length, bufsiz));
      rounds++;
    }
    CloseSocket(sid_s);
    printf("%ld times send packet\n",rounds);
    free(buf);
  }
  return(OK);
}

int nfs_client(char *host, UWORD port1, int rounds, int length, 
	       int bufsiz, double tval, int chk)
{
  int sid_c, i;
  u16 *buf, sum;
  struct timeval tv, tv1, tv2;
  double timediff;
  int fail = 0;
  fd_set reades;

  int r,s;

  if((sid_c = open_client(host, port1, SOCK_DGRAM)) < 0) /* We send there */
    return(FAIL);

  if(buf=(u16 *)malloc(max(bufsiz, length))){	/* Allocate junk-buffer */
    tv.tv_sec=(int)tval;tv.tv_usec=(int)((tval-tv.tv_sec)*1E6);
    gettimeofday(&tv1,NULL);
    for(i=0;i<rounds ;i++){
      do {
	*buf=htons(length);
	if(chk)
	  *(buf+1) = 
	    htons(pppfcs(PPPINITFCS, (unsigned char *)(buf+2), length));
	if((s = send(sid_c, (char *)buf, length, 0))<0)
	  preturn("nfs-client: send");
	FD_ZERO(&reades);
	FD_SET(sid_c, &reades);
      } while (select(sid_c + 1, &reades, NULL, NULL, &tv) == 0 && ++fail);
      if((r = recv(sid_c, (char *)buf, bufsiz, 0)) < 0)
	preturn("nfs-client: recv");
      if(chk)
	if(ntohs(*(buf+1)) != 
	   (sum = pppfcs(PPPINITFCS, (unsigned char *)(buf+2), ntohs(*buf))))
	  fprintf(stderr,"Checksum error in nfs-server: "
		  "should be %ld, is %ld\n"
		  "Error in recieved packet %ld\n",ntohs(*(buf+1)),
		  sum, rounds+1);
      DP(("s=%ld r=%ld i=%ld fail=%ld\n",s,r,i,fail));
    }
    *buf=0;
    if((s = send(sid_c, (char *)buf, length, 0)) < 0)
      preturn("nfs-client: write");
    
    gettimeofday(&tv2,NULL);
    free(buf);
  }
  CloseSocket(sid_c);

  timediff = (double)(tv2.tv_sec-tv1.tv_sec)+
    ((double)(tv2.tv_usec-tv1.tv_usec))/1E6;
  printf("Send %ld (%ld retransmissions), got %ld packets \n",i+fail,fail,i);
  printf("Total time used: %8.4lf seconds (%lg bytes/s)\n",
	 timediff,(i * (length + r)) / timediff);
  printf("Real time used: %8.4lf seconds (%lg bytes/s)\n",
	 timediff - (tval * fail),
	 (i * (length + r)) / (timediff - (tval * fail)));
  printf("Round-trip time: %8.4lf ms (total), %8.4lf ms (real)\n",
	 1000 * timediff / i, 1000 * (timediff - tval * fail) / i);
  return(OK);
}
