/*
 * A testing software for TCP-ping-pong
 */

/*
 * Telnet routines
 * $Header: telnet.c,v 2.3 93/04/20 18:48:32 puhuri Exp $
 * $Log:	telnet.c,v $
 * Revision 2.3  93/04/20  18:48:32  18:48:32  puhuri (Markus Peuhkuri)
 * Errors in debug printing
 * 
 * Revision 2.2  93/04/19  04:40:30  04:40:30  ppessi (Pekka Pessi)
 * Optimizations with socket options
 * 
 * Revision 2.1  93/04/13  21:46:14  21:46:14  jraja (Jarno Tapio Rajahalme)
 * Made this compile with the newest API.
 * 
 * Revision 2.0  93/03/20  17:31:50  17:31:50  ppessi (Pekka Pessi)
 * initial netlib version..
 * 
 * Revision 1.9  93/03/19  16:48:21  16:48:21  puhuri (Markus Peuhkuri)
 * Add possibility to make non-uniform distribution of length of
 * replied data in telnet-server.
 * 
 * Revision 1.8  93/03/17  21:24:07  21:24:07  puhuri (Markus Peuhkuri)
 * Add checksum test
 * 
 * Revision 1.7  93/03/16  19:15:04  19:15:04  too (Tomi Ollila)
 * code fixes
 * 
 * Revision 1.6  93/03/16  10:42:47  10:42:47  puhuri (Markus Peuhkuri)
 * Added AmiTCP stuff.
 * 
 * Revision 1.5  93/03/15  18:59:52  18:59:52  puhuri (Markus Peuhkuri)
 * Comment fix
 * 
 */

#include <sys/types.h>

#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 <stdio.h>
#include "qwriter.h"
#include <string.h>

static u16 givernd(int *dtable);
static int lg2(int i);

static int lg2(int i)
{
  int j;

  for(j = 0; (1 << j) <= i; j++)
    ;
  return (j-1);
}

static u16 givernd(int *dtable)
{
  int i, len = 0, rnd = rand(), lg;

  lg = lg2(dtable[0]);
  for(i = 0; lg > i; i++)
    len = len * 2 + ((rnd & (1 << i)) ? 2 : 1);

  DP(("len=%ld i=%ld rnd=%04lx lg=%ld dtable[?]=%ld\n",len,i,rnd,lg, len - (1 << lg) +2));
  return max(((rnd >> i) % dtable[len - (1 << lg) +2]), 4);
}

int telnet_server(UWORD port1, int *dtable, int chk)
{
  int sid_c,t;
  int len=0;
  u16 *buf, wlen;

  int d;

  printf("dtable=%ld max=%ld ",dtable[0],dtable[dtable[0]]);
  if((sid_c = open_server(NULL, port1, SOCK_STREAM))<0)
    return(FAIL);
  /* Allocate 32 kilos for send buffer */
  d = 32*1024;
  setsockopt(sid_c, SOL_SOCKET, SO_SNDBUF, (char *)&d, sizeof d);
  
  if(buf = (u16 *)malloc(dtable[dtable[0]])){	/* Allocate buffer */
    while((d = recv(sid_c, (char *)buf, 1, 0)) >= 0 && *(char *)buf != '\0'){
      wlen = givernd(dtable);
      DP(("r=%ld s=%ld ",(long)d,(long)wlen));
      *buf = htons(wlen);
      if(chk)			/* Calculate checkum */
	*(buf+1) = htons(pppfcs(PPPINITFCS, (unsigned char *)(buf+2), 
				wlen-2*sizeof(u16)));
      if((t = send(sid_c, (char *)buf, wlen, 0)) != wlen){
	preturn("telnet-server: send");
	break;
      }
      len += t;
      DP(("st=%ld len=%ld\n",t,len));
    }
    if(d<0)
      perror("telnet-server: recv");
    CloseSocket(sid_c);
    printf("%ld writen\n",len);
    free(buf);
  }
  return(OK);
}

int telnet_client(char *host, UWORD port1, int rounds, int bufsiz, int chk)
{
  int sid_s;
  int i,total,t, t2;
  u16 *buf, sum;
  struct timeval tv1,tv2;
  double timediff;
  unsigned int inlen;

  int s,r;

  if((sid_s=open_client(host, port1, SOCK_STREAM))<0)
    return(FAIL);
  /* Allocate 32 kilos for receive buffer */
  s = 32*1024;
  setsockopt(sid_s, SOL_SOCKET, SO_RCVBUF, (char *)&s, sizeof s);

  if (buf = (u16 *)malloc(bufsiz)){	/* Allocate junk-buffer */
    gettimeofday(&tv1, NULL);
    for (i = total = 0;
	 i < rounds && (*(char *)buf = 'a')
	 && (s = send(sid_s, (char *)buf, 1, 0)) > 0;
	 i++, total += inlen) {
      if ((r = recv(sid_s, (char *)buf, 2*sizeof(u16), 0))<=0 ||
	  ((inlen = ntohs(*buf)) == 0 || 
	   (inlen > bufsiz)))
	{
	  fprintf(stderr, "Requested read: %ld, Size of buffer=%ld\n",
		  inlen, bufsiz);
	  preturn("telnet-client: read");
	  break;
	}
      DP(("s=%ld r=%ld inlen=%ld",s,r,inlen));

      for(t = 2* sizeof(u16);t < inlen; t += t2)
	if((t2 = recv(sid_s, ((char *)(buf))+t, inlen-t, 0)) < 0){
	  DP((" t2=%ld\n",t2));
	  preturn("telnet-client: recv");
	} else
	  DP((" t2=%ld",t2));

      DP((" t=%ld total=%ld",t,total));
      if(chk)			/* Calculate checkum */
	if(ntohs(*(buf+1)) != 
	   (sum = pppfcs(PPPINITFCS, (unsigned char *)(buf+2), 
			 t-2*sizeof(u16))))
	  fprintf(stderr,"Checksum error in telnet-client: "
		  "should be %ld, is %ld\n"
		  "Error in recieved bytes %ld-%ld\n",ntohs(*(buf+1)),
		  sum, total-t, total);
      DP(((chk)?" sum=%ld psum=%ld\n":"\n",sum,ntohs(*(buf+1))));
    }
    *buf=0;
    if (send(sid_s, (char *)buf, 1, 0) <= 0)
      preturn("telnet-clent: send (last)");
    free(buf);
  }

  gettimeofday(&tv2, NULL);
  CloseSocket(sid_s);

  timediff=(double)(tv2.tv_sec-tv1.tv_sec)+((double)(tv2.tv_usec-tv1.tv_usec))/1E6;
  printf("Send %ld chars, got %ld chars\n",i,total);
  printf("Time used: %8.4lf seconds (%lg bytes/s)\n",timediff,(i+total)/timediff);
  printf("Avarage round-trip delay: %lg ms\n",timediff/i*1E3);
  return(OK);
}
