//===================================================== file = timeget2.c =====
//=  A client program to do threaded GETs from a Web server                   =
//=   - Times the GET response                                                =
//=============================================================================
//=  Notes:                                                                   =
//=    1) This program is for Winsock only.                                   =
//=    2) This program hardwires the IP address into IP_ADDR and hardwires    =
//=       the GET request string into GET_STRING.                             =
//=    3) NUM_GET is the number of serial GETs to do                          =
//=---------------------------------------------------------------------------=
//=  Output from an execution:                                                =
//=                                                                           =
//=   --------------------------------------------- timeget2.c -----          =
//=     Number of parallel GETs = 100                                         =
//=     Target IP address       = 131.247.2.16                                =
//=     GET string              = GET /1m.dat HTTP/1.0                        =
//=                                                                           =
//=                                                                           =
//=     Elapsed time            = 4406.000 millisec                           =
//=   ---------------------------------------------------------------         =
//=---------------------------------------------------------------------------=
//=  Build: bcc32 timeget2.c                                                  =
//=---------------------------------------------------------------------------=
//=  Execute: timeget2                                                        =
//=---------------------------------------------------------------------------=
//=  History:  KJC (10/02/02) - Genesis (from httpget3.c)                     =
//=============================================================================

//----- Include files ---------------------------------------------------------
#include <stdio.h>          // Needed for printf()
#include <stdlib.h>         // Needed for exit()
#include <string.h>         // Needed for strcpy() and strlen()
#include <windows.h>        // Needed for all Winsock stuff
#include <sys\timeb.h>      // Needed for ftime() and timeb structure
#include <process.h>        // Needed for _beginthread() and _endthread()

//----- Defines ---------------------------------------------------------------
#define  BUF_SIZE            4096     // Buffer size
#define  PORT_NUM              80     // Web servers are at port 80
#define  IP_ADDR    "131.247.2.16"    // IP address of web server
#define  GET_STRING "GET /1m.dat HTTP/1.0\n\n"  // GET string
#define  NUM_GET              100     // Number of GETs to do

//----- Globals ---------------------------------------------------------------
int Count;                            // Global thread counter
int Num;                              // Number of threads completed

//----- Function prototypes -------------------------------------------------
void do_get(void *in_arg);            // Thread function to do a GET

//===== Main program ==========================================================
void main(void)
{
  WORD wVersionRequested = MAKEWORD(1,1);    // Stuff for WSA functions
  WSADATA wsaData;                           // Stuff for WSA functions
  struct               timeb start, stop;    // Start and stop times structures
  double               elapsed;              // Elapsed time in seconds
  int                  retcode;              // Return code
  int                  i;                    // Loop counter

  // This stuff initializes winsock
  WSAStartup(wVersionRequested, &wsaData);

  // Output a banner
  printf("--------------------------------------------- timeget2.c -----\n");
  printf("  Number of parallel GETs = %d \n", NUM_GET);
  printf("  Target IP address       = %s \n", IP_ADDR);
  printf("  GET string              = %s \n", GET_STRING);

  // Start timing
  ftime(&start);

  // Do NUM_GET GETs
  Count = Num = 0;
  for (i=0; i<NUM_GET; i++)
  {
    Count++;
    if (_beginthread(do_get, 4096, (void *)i) < 0)
    {
      printf("ERROR - Unable to create thread \n");
      exit(1);
    }
  }

  // Wait for all threads to finish
  while(Count);

  // Stop timing and compute elapsed time
  ftime(&stop);
  elapsed=((double) stop.time + ((double) stop.millitm * 0.001)) -
          ((double) start.time + ((double) start.millitm * 0.001));

  // Output elapsed time
  printf("  Elapsed time            = %7.3f millisec \n", 1000.0 * elapsed);
  printf("---------------------------------------------------------------\n");

  // Clean-up WSA stuff
  WSACleanup();
}

//===========================================================================
//=  Thread function to do a get                                            =
//===========================================================================
void do_get(void *in_arg)
{
  unsigned int         server_s;             // Server socket descriptor
  struct sockaddr_in   server_addr;          // Server Internet address
  char                 out_buf[BUF_SIZE];    // Output buffer for GET request
  char                 in_buf[BUF_SIZE];     // Input buffer for response
  int                  retcode;              // Return code
  int                  i;                    // Loop counter

  // Create a socket
  server_s = socket(AF_INET, SOCK_STREAM, 0);
  if (server_s < 0)
  {
    Count--;
    printf("*** ERROR - socket() failed (%d) \n", WSAGetLastError());
    _endthread();
    exit(1);
  }

  // Fill-in the Web server socket's address information
  server_addr.sin_family = AF_INET;                 // Address family to use
  server_addr.sin_port = htons(PORT_NUM);           // Port num to use
  server_addr.sin_addr.s_addr = inet_addr(IP_ADDR); // IP address to use

  // Do a connect (connect() blocks)
  retcode = connect(server_s, (struct sockaddr *)&server_addr,
                    sizeof(server_addr));
  if (retcode != 0)
  {
    Count--;
    printf("*** ERROR - connect() failed (%d) \n", WSAGetLastError());
    _endthread();
    exit(1);
  }

  // Send a GET to the Web server
  strcpy(out_buf, GET_STRING);
  send(server_s, out_buf, strlen(out_buf), 0);

  // Receive from the Web server
  //  - The return code from recv() is the number of bytes received
  retcode = recv(server_s, in_buf, BUF_SIZE, 0);
  while ((retcode > 0) || (retcode == -1))
  {
    if (retcode == -1)
    {
      Count--;
      printf("*** ERROR - recv() failed (%d) \n", WSAGetLastError());
      _endthread();
      exit(1);
    }
    retcode = recv(server_s, in_buf, BUF_SIZE, 0);
  }

  // Decrement for a completed thread
  Count--;

  // Output GET finished (comment this out for better performance)
  // printf("  GET finished -- %d \n", Num++);

  // Close all open sockets and end the thread
  closesocket(server_s);
  _endthread();
}

