/*
 * floodconn.c
 * Steve Shah (sshah@planetoid.org)
 * 
 * See floodconn.README for more information.
 *
 * Ignore the forking thing for now... One day I'll finish it.
 *
 */

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/param.h>
#include <sys/uio.h>
#include <netinet/in.h>
#include <unistd.h>

#include <sys/ipc.h>
#include <sys/shm.h>

#include <sys/resource.h>
#include <sys/file.h>
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>

#include <string.h>
#include <errno.h>

#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <time.h>

#define MAX_FD 32768

#define HTTP_GET "GET / HTTP/1.1\n\rHost: 10.10.10.10\n\r\n\r"

int main (int argc, char *argv[])
{
    struct sockaddr_in mysock;
    struct protoent *tcp;
    int port;
    int socket_out[MAX_FD];
    int maxconns;
    int curconn;
    int proc_count;
    int mypid;
    int http_get_len;
    int seconds;
    time_t time_start, time_end, time_check;
    char buf[1024];
    int total_conns;
    int read_success, write_success;
    int len;
    int bytes_read, bytes_written;
    int parent_pid;

    if (argc < 6) {
	printf ("usage: %s ip port maxconns proc-count seconds\n", argv[0]);
	exit(0);
    }

    port = atoi(argv[2]);
    maxconns = atoi(argv[3]);
    proc_count = atoi(argv[4]);
    seconds = atoi(argv[5]);
    
    http_get_len = strlen(HTTP_GET);

    if (maxconns > MAX_FD) {
        printf ("Max conns is limited to %d\n", MAX_FD);
        exit(0);
    }

    parent_pid = getpid();
    mypid = getpid();
/*
    printf ("Parent pid: %d\n", parent_pid);

    for (i = 0; i < proc_count; i++) {
	mypid = fork();
	if (mypid) {
	    printf ("Starting process %d\n", mypid);
	    break;
	}
    }
*/

    tcp = getprotobyname("tcp");

    bzero((char *)&mysock, sizeof(mysock));
    mysock.sin_family = PF_INET;
    mysock.sin_port = htons(port);
    mysock.sin_addr.s_addr = inet_addr(argv[1]);

/*    maxconns = maxconns / proc_count;
 */


    time_start = time(NULL);
    time_check = time_start;
    total_conns = 0;
    bytes_read = 0;
    bytes_written = 0;
    do {
	
	for (curconn = 0; curconn < maxconns; curconn++) {
	    
	    socket_out[curconn] = socket (PF_INET, SOCK_STREAM, tcp->p_proto);
	    if (socket_out[curconn] == -1) {
		perror ("Cannot socket");
		exit(0);
	    }
	    
	    if (connect (socket_out[curconn],(struct sockaddr*)&mysock,
			 sizeof(struct sockaddr)) == -1) {
		perror ("Cannot connect");
		exit(0);
	    }
	    
	    total_conns++;
	    
	}
	
	for (curconn = 0; curconn < maxconns; curconn++) {
	 
	    len = write (socket_out[curconn], HTTP_GET, http_get_len);
	    if (len == http_get_len) {
		write_success++;
		bytes_written += len;
	    }
	
	}

	for (curconn = 0; curconn < maxconns; curconn++) {
	    
	    while ((len = read (socket_out[curconn], buf, 1024)) > 0) {
		bytes_read += len;
	    }

	    if (len != 0) {
		read_success++;
	    }
	}

	for (curconn = 0; curconn < maxconns; curconn++) {
	    
	    close (socket_out[curconn]);
    
	}

	time_end = time(NULL);
	if (time_end > time_check) {
	    printf (".");
	    fflush(stdout);
	    time_check = time_end;
	}

    } while ((time_end - time_start) < seconds);

    printf ("\n");
    printf ("[%05d] Time start:        %s", mypid, ctime(&time_start));
    printf ("[%05d] Time end:          %s", mypid, ctime(&time_end));
    printf ("[%05d] Connections:       %d\n", mypid, total_conns);
    printf ("[%05d] Bytes written:     %d\n", mypid, bytes_written);
    printf ("[%05d] Bytes read:        %d\n", mypid, bytes_read);

    return 0;
}




