/**
   @file

   This program tests the low-level tcp-socket-stream library function.

*/

/*
  Copyright (c) Andreas Hofmeier
  (www.an-h.de, www.an-h.de.vu, www.lgut.uni-bremen.de/an-h/)
  
  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful, but
  WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/


#include <stdio.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <signal.h>
#include "../lib/libcomm.h"

/** Port on which the server is listening and the client trys to
    connect. */
#define PORT 1234
/** How much random bytes should be transfered? */
#define bufsize 8192
//#define bufsize 8

/** test0001sockts: see test0001sockts.c.
*/

main(int argc, char *argv[]) {
  // PID of the child process
  int fpid;

  printf("running %s...\n", argv[0]);
  if (!(fpid = fork())) {
    server_test_program(PORT);
  }

  client_test_program("127.0.0.1", PORT);
  client_test_program("localhost", PORT);
  client_test_program("lblacky", PORT);
  client_test_program("hofmeira.student.sbu.ac.uk", PORT);

  // kill server terst programm
  kill(fpid, 15);
  sleep(1);
  kill(fpid, 9);

  exit(0);
}


/** test0001sockts: see test0001sockts.c, Client Test Programm.

   The client test program generates a block of n*(bufsize) random
   bytes, sents theses bytes to the server, receive a block from
   server, invert it and compare it with generated block.

   BUGS: Receives only one block. If not all data ready and function
   resv() do noct block, data get lost. Test fails.

   @param server a string which contains the server name
   @param port an integer which specifies the port on the server
*/
client_test_program(char *server, int port) {
  // **************************************************************
  // *** Client Test Programm

  int i;

  // FD of socket
  int sock;

  char buf[bufsize], buf2[bufsize];

  printf("  Generating random numbers...\n");
  if (block_random(buf, bufsize) == NULL) {
    fail("cannot generate random numbers", 1);
  }
  
  // Connect to server
  printf("  Try server %s...", server);
  if ((sock = socket_connect(server, port)) < 0) {
    fail("Cannot connect.", 1);    
  }

  // send datablock to server
  send(sock, buf, bufsize, 0);

  // receive datablock from server
  recv(sock, buf2, bufsize, 0);

  close(sock);

  // invert the bits of the local datablock and
  // compare it with the result from the server
  // should be the same.
  for (i = 0; i < bufsize; i++) {
    if (~buf2[i] != buf[i]) {
      fail("some errors occure during the data transfer...");
    }
  }
  printf("OK.\n");
  sleep(1);
}


/** test0001sockts: see test0001sockts.c, Server Test Programm.

   The server test program binds a port and waits for connections. If
   someone connects it reads n*(bufsize) bytes, invert all bits of
   these bytes and send all back.

   BUGS: Receives only one block. If not all data ready and function
   resv() do noct block, data get lost. Test fails.

   @param port an integer which specifies the port to bind.
*/
server_test_program(int port) {
  // **************************************************************
  // *** Server Test Program

  // buffer for storing data.
  char buf[bufsize];

  // FD of socket which is bounded to the port
  int sockport;
  // FD of socket
  int sock;

  /* connector's address information */
  struct sockaddr_in their_addr;
  int sin_size;

    
  // Bind port
  printf("  binding port %d on localhost...", port);
  if ((sockport = socket_bind(port, 10)) < 0) {
    fail("Cannot bind port.", 1);
  }

  while (1) {
    // accept connection
    sin_size = sizeof(struct sockaddr_in);
    if ((sock = accept(sockport, (struct sockaddr *) &their_addr,
		       &sin_size)) != -1) {
      int i, size;
      char *pard = inet_ntoa(their_addr.sin_addr);
      fprintf(stdout, "  got connection from %s\n", pard);
      
      // receive datablock from client
      size = recv(sock, buf, bufsize, 0);
      // invert the bits of thh whole datablock
      for (i = 0; i < size; i++) {
	buf[i] = ~buf[i];
      }
      // send datablock to client
      send(sock, buf, size, 0);

      close(sock);
    }
  }
}  
