/*
 *   tcpcli           a very simple TCP client for benchmarking
 *   Copyright (c)    2006 Michal Trojnara <Michal.Trojnara@mobi-com.net>
 *                    All Rights Reserved
 *
 *   Version:         1.00
 *   Date:            2006.12.17
 *
 *   Author:          Michal Trojnara  <Michal.Trojnara@mobi-com.net>
 *
 *   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 <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h>
#include <time.h>

#define NUM_THREADS	1
#define NUM_RETRIES 10000

int port_number=50000;
int false=0, true=1;

void connection(void) {
    struct sockaddr_in addr;
    int fd, rc;
    char c;

    fd=socket(AF_INET, SOCK_STREAM, 0);
    memset(&addr, 0, sizeof(addr));
    addr.sin_family=AF_INET;
    addr.sin_addr.s_addr=htonl(INADDR_LOOPBACK);
    addr.sin_port=htons(port_number);
    rc=connect(fd, (struct sockaddr *)&addr, sizeof(addr));
    if(rc) {    /* error */
        close(fd);
        perror("connect");
        // printf("Thread finished: error\n");
        pthread_exit(&true);
    }
    rc=read(fd, &c, 1); /* read a single byte */
    close(fd);
    if(rc==1)   /* ok */
        return;
    if(rc)      /* error */
        perror("read");
    else        /* eof */
        fprintf(stderr, "read: Unexpected close\n");
    // printf("Thread finished: error\n");
    pthread_exit(&true);
}

void *thread_proc(void *arg) {
    int i;

    // printf("Thread started\n");
    for(i=0; i<NUM_RETRIES; ++i)
        connection();
    // printf("Thread finished: success\n");
    pthread_exit(&false);
}

void fatal(int rc, char *str) {
    if(!rc)
        return;
    fprintf(stderr, "ERROR: %s returned %d\n", str, rc);
    exit(true);
}

int main(int argc, char *argv[]) {
     pthread_t thread[NUM_THREADS];
     pthread_attr_t attr;
     int t, retval=0;
     void *status;
     struct timeval tv1, tv2;
     double diff;

     printf("Benchmarking %d connection(s) by %d thread(s)\n",
         NUM_RETRIES*NUM_THREADS, NUM_THREADS);
     gettimeofday(&tv1, NULL);

     /* create the threads */
     pthread_attr_init(&attr);
     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
     for(t=0; t<NUM_THREADS; ++t)
        fatal(pthread_create(&thread[t], &attr, thread_proc, NULL),
            "pthread_create");
     pthread_attr_destroy(&attr);

     /* join the threads */
     for(t=0; t<NUM_THREADS; ++t) {
        fatal(pthread_join(thread[t], &status),
            "pthread_join");
        retval|=*(int *)status;
     }
     gettimeofday(&tv2, NULL);
     diff=tv2.tv_sec-tv1.tv_sec+(tv2.tv_usec-tv1.tv_usec)/1000000.0;

     if(retval) {
        printf("Bechmark done: error\n");
     } else {
        printf("Bechmark done: success\n");
        printf("%.2f seconds, %.2f connections/second\n",
            diff, NUM_RETRIES*NUM_THREADS/diff);
     }
     return retval;
}

/* end of tcpcli.c file */
