This is the mail archive of the ecos-discuss@sourceware.cygnus.com mailing list for the eCos project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

tcp_sink/source/echo byte ordering



Hi,

The three network programs tcp_echo, tcp_sink, and tcp_source
will only inter-operate if all three hosts have the same byte
order.  Adding a few htonl() and ntohl() macros when
manipulating the "params" struct fixes things.

Attached are my fixed sources for the three.  (I also fixed
some gcc warnings in source/sink).  

Next time I'll send patches instead of entire files, but it's
Monday, I don't have the original source tree around, and I
have to leave right now and go waste my lunch hour to renew my
driver's license...

-- 
Grant Edwards
grante@visi.com
//==========================================================================
//
//      tests/tcp_source.c
//
//      Simple TCP throughput test - source component
//      * CAUTION: host, i.e. non eCos, only *
//
//==========================================================================
//####COPYRIGHTBEGIN####
//                                                                          
// -------------------------------------------                              
// The contents of this file are subject to the Red Hat eCos Public License 
// Version 1.1 (the "License"); you may not use this file except in         
// compliance with the License.  You may obtain a copy of the License at    
// http://www.redhat.com/                                                   
//                                                                          
// Software distributed under the License is distributed on an "AS IS"      
// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the 
// License for the specific language governing rights and limitations under 
// the License.                                                             
//                                                                          
// The Original Code is eCos - Embedded Configurable Operating System,      
// released September 30, 1998.                                             
//                                                                          
// The Initial Developer of the Original Code is Red Hat.                   
// Portions created by Red Hat are                                          
// Copyright (C) 1998, 1999, 2000 Red Hat, Inc.                             
// All Rights Reserved.                                                     
// -------------------------------------------                              
//                                                                          
//####COPYRIGHTEND####
//####BSDCOPYRIGHTBEGIN####
//
// -------------------------------------------
//
// Portions of this software may have been derived from OpenBSD or other sources,
// and are covered by the appropriate copyright disclaimers included herein.
//
// -------------------------------------------
//
//####BSDCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s):    gthomas
// Contributors: gthomas
// Date:         2000-01-10
// Purpose:      
// Description:  This is the middle part of a three part test.  The idea is
//   to test the throughput of box in a configuration like this:
//
//      +------+   port   +----+     port    +----+
//      |SOURCE|=========>|ECHO|============>|SINK|
//      +------+   9990   +----+     9991    +----+
// 
//
//####DESCRIPTIONEND####
//
//==========================================================================

// Network throughput test code

#undef _KERNEL
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>

#include <sys/param.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/errno.h>
#include <sys/time.h>

#include <net/if.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <net/route.h>

#include <netdb.h>

#define SOURCE_PORT 9990
#define SINK_PORT   9991

struct test_params {
    long nbufs;
    long bufsize;
    long load;
};

struct test_status {
    long ok;
};

#define NUM_BUF 1024
#define MAX_BUF 8192
static unsigned char data_buf[MAX_BUF];

void
pexit(char *s)
{
    perror(s);
    exit(1);
}

void
show_results(struct timeval *start, struct timeval *end, 
             int nbufs, int buflen)
{
    struct timeval tot_time;
    long tot_bytes = nbufs * buflen;
    double real_time, thru;
    timersub(end, start, &tot_time);
    printf("SOURCE complete - %d bufs of %d bytes in %ld.%02ld seconds",
           nbufs, buflen, 
           tot_time.tv_sec, tot_time.tv_usec / 10000);
    real_time = tot_time.tv_sec + ((tot_time.tv_usec / 10000) * .01);
    // Compute bytes / second (rounded up)
    thru = tot_bytes / real_time;
    // Convert to Mb / second
    printf(" - %.2f KB/S", thru / 1024.0);
    printf(" - %.4f Mbit/S (M = 10^6)", thru * 8.0 / 1000000.0);
    printf("\n");
}

int
do_read(int s, unsigned char *buf, int len)
{
    int total, slen, rlen;
    total = 0;
    rlen = len;
    while (total < len) {
        slen = read(s, buf, rlen);
        if (slen != rlen) {
            if (slen < 0) {
                printf("Error after reading %d bytes\n", total);
                return -1;
            }
            rlen -= slen;
            buf += slen;
        }
        total += slen;
    }
    return total;
}

int
do_write(int s, unsigned char *buf, int len)
{
    int total, slen, rlen;
    total = 0;
    rlen = len;
    while (total < len) {
        slen = write(s, buf, rlen);
        if (slen != rlen) {
            if (slen < 0) {
                printf("Error after writing %d bytes\n", total);
                return -1;
            }
            rlen -= slen;
            buf += slen;
        }
        total += slen;
    }
    return total;
}

static void
source_test(char *echo_node, int load)
{
    int s_source;
    struct sockaddr_in slave, local;
    int one = 1;
    int len;
    struct hostent *host;
    struct test_params params;
    struct test_params nparams;
    struct test_status status;
    struct test_status nstatus;
    struct timeval start_time, end_time;
    int i;

    printf("Start TCP test - SOURCE mode to %s\n", echo_node);

    host = gethostbyname(echo_node);
    if (host == (struct hostent *)NULL) {
        pexit("gethostbyname");
    }

    memset(&slave, 0, sizeof(slave));
    slave.sin_family = AF_INET;
    slave.sin_port = htons(SOURCE_PORT);
    memcpy(&slave.sin_addr.s_addr, host->h_addr, host->h_length);

    s_source = socket(AF_INET, SOCK_STREAM, 0);
    if (s_source < 0) {
        pexit("stream socket");
    }
    memset(&local, 0, sizeof(local));
    local.sin_family = AF_INET;
    local.sin_port = INADDR_ANY;
    local.sin_addr.s_addr = INADDR_ANY;
    if(bind(s_source, (struct sockaddr *) &local, sizeof(local)) < 0) {
        pexit("bind /source/ error");
    }
    if (setsockopt(s_source, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) {
        pexit("setsockopt /source/ SO_REUSEADDR");
    }

    if (connect(s_source, (struct sockaddr *)&slave, sizeof(slave)) < 0) { 
        pexit("Can't connect to target");
    }

    params.nbufs = NUM_BUF;
    params.bufsize = MAX_BUF;
    params.load = load;
   
    nparams.nbufs = htonl(params.nbufs);
    nparams.bufsize = htonl(params.bufsize);
    nparams.load = htonl(params.load);
   
    if ( do_write(s_source, (unsigned char *)&nparams, sizeof(nparams))
                  != sizeof(params)) {
        pexit("Can't send initialization parameters");
    }
    if (do_read(s_source, (unsigned char *)&nstatus, sizeof(nstatus))
                  != sizeof(status)) {
        pexit("Can't get status from 'echo' client");
    }

    status.ok = ntohl(nstatus.ok);
   
    // Actual test
    gettimeofday(&start_time, 0);
    for (i = 0;  i < params.nbufs;  i++) {
        if ((len = do_write(s_source, data_buf, params.bufsize)) != params.bufsize) {
            printf("Error writing buffer #%d:", i+1);
            if (len < 0) {
                perror("can't write data");
            } else {
                printf(" short data, only wrote %d bytes\n", len);
            }
        }
    }
    gettimeofday(&end_time, 0);
    show_results(&start_time, &end_time, params.nbufs, params.bufsize);
}

int
main(int argc, char *argv[])
{
    int load = 0;
    if (argc > 2) {
        load = atoi(argv[2]);
    }
    source_test(argv[1], load);
   return 0;
}
//==========================================================================
//
//      tests/tcp_sink.c
//
//      Simple TCP throughput test - sink component
//      * CAUTION: host, i.e. non eCos, only *
//
//==========================================================================
//####COPYRIGHTBEGIN####
//                                                                          
// -------------------------------------------                              
// The contents of this file are subject to the Red Hat eCos Public License 
// Version 1.1 (the "License"); you may not use this file except in         
// compliance with the License.  You may obtain a copy of the License at    
// http://www.redhat.com/                                                   
//                                                                          
// Software distributed under the License is distributed on an "AS IS"      
// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the 
// License for the specific language governing rights and limitations under 
// the License.                                                             
//                                                                          
// The Original Code is eCos - Embedded Configurable Operating System,      
// released September 30, 1998.                                             
//                                                                          
// The Initial Developer of the Original Code is Red Hat.                   
// Portions created by Red Hat are                                          
// Copyright (C) 1998, 1999, 2000 Red Hat, Inc.                             
// All Rights Reserved.                                                     
// -------------------------------------------                              
//                                                                          
//####COPYRIGHTEND####
//####BSDCOPYRIGHTBEGIN####
//
// -------------------------------------------
//
// Portions of this software may have been derived from OpenBSD or other sources,
// and are covered by the appropriate copyright disclaimers included herein.
//
// -------------------------------------------
//
//####BSDCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s):    gthomas
// Contributors: gthomas
// Date:         2000-01-10
// Purpose:      
// Description:  This is the middle part of a three part test.  The idea is
//   to test the throughput of box in a configuration like this:
//
//      +------+   port   +----+     port    +----+
//      |SOURCE|=========>|ECHO|============>|SINK|
//      +------+   9990   +----+     9991    +----+
// 
//
//####DESCRIPTIONEND####
//
//==========================================================================

// Network throughput test code

#undef _KERNEL
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>

#include <sys/param.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/errno.h>
#include <sys/time.h>

#include <net/if.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <net/route.h>

#include <netdb.h>

#define SOURCE_PORT 9990
#define SINK_PORT   9991

struct test_params {
    long nbufs;
    long bufsize;
    long load;
};

struct test_status {
    long ok;
};

#define NUM_BUF 128
#define MAX_BUF 32 * 8192
static unsigned char data_buf[MAX_BUF];

void
pexit(char *s)
{
    perror(s);
    exit(1);
}

void
show_results(struct timeval *start, struct timeval *end, 
             int nbufs, int buflen)
{
    struct timeval tot_time;
    long tot_bytes = nbufs * buflen;
    double real_time, thru;
    timersub(end, start, &tot_time);
    printf("SINK complete - %d bufs of %d bytes in %ld.%02ld seconds",
           nbufs, buflen, 
           tot_time.tv_sec, tot_time.tv_usec / 10000);
    real_time = tot_time.tv_sec + ((tot_time.tv_usec / 10000) * .01);
    // Compute bytes / second (rounded up)
    thru = tot_bytes / real_time;
    // Convert to Mb / second
    printf(" - %.2f KB/S", thru / 1024.0);
    printf(" - %.4f Mbit/S (M = 10^6)", thru * 8.0 / 1000000.0);
    printf("\n");
}

int
do_read(int s, unsigned char *buf, int len)
{
    int total, slen, rlen;
    total = 0;
    rlen = len;
    while (total < len) {
        slen = read(s, buf, rlen);
        if (slen != rlen) {
            if (slen < 0) {
                printf("Error after reading %d bytes\n", total);
                return -1;
            }
            rlen -= slen;
            buf += slen;
        }
        total += slen;
    }
    return total;
}

int
do_write(int s, unsigned char *buf, int len)
{
    int total, slen, rlen;
    total = 0;
    rlen = len;
    while (total < len) {
        slen = write(s, buf, rlen);
        if (slen != rlen) {
            if (slen < 0) {
                printf("Error after writing %d bytes\n", total);
                return -1;
            }
            rlen -= slen;
            buf += slen;
        }
        total += slen;
    }
    return total;
}

static void
sink_test(char *echo_node)
{
    int s_sink;
    struct sockaddr_in slave, local;
    int one = 1;
    int len;
    struct hostent *host;
    struct test_params params, nparams;
    struct test_status status, nstatus;
    struct timeval start_time, end_time;
    int i;

    printf("Start TCP test - SINK mode to %s\n", echo_node);

    host = gethostbyname(echo_node);
    if (host == (struct hostent *)NULL) {
        pexit("gethostbyname");
    }

    memset(&slave, 0, sizeof(slave));
    slave.sin_family = AF_INET;
    slave.sin_port = htons(SINK_PORT);
    memcpy(&slave.sin_addr.s_addr, host->h_addr, host->h_length);

    s_sink = socket(AF_INET, SOCK_STREAM, 0);
    if (s_sink < 0) {
        pexit("stream socket");
    }
    memset(&local, 0, sizeof(local));
    local.sin_family = AF_INET;
    local.sin_port = INADDR_ANY;
    local.sin_addr.s_addr = INADDR_ANY;
    if(bind(s_sink, (struct sockaddr *) &local, sizeof(local)) < 0) {
        pexit("bind /sink/ error");
    }
    if (setsockopt(s_sink, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) {
        pexit("setsockopt /sink/ SO_REUSEADDR");
    }

    if (connect(s_sink, (struct sockaddr *)&slave, sizeof(slave)) < 0) { 
        pexit("Can't connect to target");
    }

    // Get testing paramters from middleman
    if (do_read(s_sink, (unsigned char *)&nparams, sizeof(nparams))
                  != sizeof(nparams)) {
        pexit("Can't read initialization parameters");
    }
   
    params.nbufs = ntohl(nparams.nbufs);
    params.bufsize = ntohl(nparams.bufsize);
    params.load = ntohl(nparams.load);
     
    printf("Using %ld buffers of %ld bytes each\n", params.nbufs, params.bufsize);

    // Actual test
    gettimeofday(&start_time, 0);
    for (i = 0;  i < params.nbufs;  i++) {
        if ((len = do_read(s_sink, data_buf, params.bufsize)) != params.bufsize) {
            printf("Error reading buffer #%d:", i+1);
            if (len < 0) {
                perror("can't read data");
            } else {
                printf(" short data, only read %d bytes\n", len);
            }
        }
    }
    gettimeofday(&end_time, 0);
    show_results(&start_time, &end_time, params.nbufs, params.bufsize);

    // Tell the middleman
   
    nstatus.ok = htonl(status.ok);
   
    if (do_write(s_sink, (unsigned char *)&nstatus, sizeof(nstatus))
                        != sizeof(nstatus)) {
        pexit("Can't send ACK to 'echo' host");
    }
}

int
main(int argc, char *argv[])
{
    sink_test(argv[1]);
    return 0;
}
//==========================================================================
//
//      tests/tcp_echo.c
//
//      Simple TCP throughput test - echo component
//
//==========================================================================
//####COPYRIGHTBEGIN####
//                                                                          
// -------------------------------------------                              
// The contents of this file are subject to the Red Hat eCos Public License 
// Version 1.1 (the "License"); you may not use this file except in         
// compliance with the License.  You may obtain a copy of the License at    
// http://www.redhat.com/                                                   
//                                                                          
// Software distributed under the License is distributed on an "AS IS"      
// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the 
// License for the specific language governing rights and limitations under 
// the License.                                                             
//                                                                          
// The Original Code is eCos - Embedded Configurable Operating System,      
// released September 30, 1998.                                             
//                                                                          
// The Initial Developer of the Original Code is Red Hat.                   
// Portions created by Red Hat are                                          
// Copyright (C) 1998, 1999, 2000 Red Hat, Inc.                             
// All Rights Reserved.                                                     
// -------------------------------------------                              
//                                                                          
//####COPYRIGHTEND####
//####BSDCOPYRIGHTBEGIN####
//
// -------------------------------------------
//
// Portions of this software may have been derived from OpenBSD or other sources,
// and are covered by the appropriate copyright disclaimers included herein.
//
// -------------------------------------------
//
//####BSDCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s):    gthomas
// Contributors: gthomas
// Date:         2000-01-10
// Purpose:      
// Description:  This is the middle part of a three part test.  The idea is
//   to test the throughput of box in a configuration like this:
//
//      +------+   port   +----+     port    +----+
//      |SOURCE|=========>|ECHO|============>|SINK|
//      +------+   9990   +----+     9991    +----+
// 
//
//####DESCRIPTIONEND####
//
//==========================================================================

// Network throughput test code

#include <network.h>

#define SOURCE_PORT 9990
#define SINK_PORT   9991

#define MAX_BUF 8192
static unsigned char data_buf[MAX_BUF];

struct test_params {
    long nbufs;
    long bufsize;
    long load;
};

struct test_status {
    long ok;
};

#define STACK_SIZE CYGNUM_HAL_STACK_SIZE_TYPICAL
static char stack[STACK_SIZE];
static cyg_thread thread_data;
static cyg_handle_t thread_handle;

// Background load stuff
#define NUM_LOAD_THREADS         10 // Get 10% granularity
#define IDLE_THREAD_PRIORITY     CYGPKG_NET_THREAD_PRIORITY+3
#define LOAD_THREAD_PRIORITY     CYGPKG_NET_THREAD_PRIORITY-1
#define MAIN_THREAD_PRIORITY     CYGPKG_NET_THREAD_PRIORITY-2
#define DESIRED_BACKGROUND_LOAD  50 // Should be accurate enough over range
static char         idle_thread_stack[STACK_SIZE];
static cyg_thread   idle_thread_data;
static cyg_handle_t idle_thread_handle;
static cyg_sem_t    idle_thread_sem;
volatile static long long    idle_thread_count;
static char         load_thread_stack[NUM_LOAD_THREADS][STACK_SIZE];
static cyg_thread   load_thread_data[NUM_LOAD_THREADS];
static cyg_handle_t load_thread_handle[NUM_LOAD_THREADS];
static cyg_sem_t    load_thread_sem[NUM_LOAD_THREADS];
static long         load_thread_level;
static void calibrate_load(int load);
static void start_load(int load);
static void do_some_random_computation(int p,int id);
#define abs(n) ((n) < 0 ? -(n) : (n))

static long long no_load_idle_count_1_second;

void
cyg_test_exit(void)
{
    diag_printf("... Done\n");
    while (1) ;
}

void
pexit(char *s)
{
    perror(s);
    cyg_test_exit();
}

int
do_read(int s, void *_buf, int len)
{
    int total, slen, rlen;
    unsigned char *buf = (unsigned char *)_buf;
    total = 0;
    rlen = len;
    while (total < len) {
        slen = read(s, buf, rlen);
        if (slen != rlen) {
            if (slen < 0) {
                diag_printf("Error after reading %d bytes\n", total);
                return -1;
            }
            rlen -= slen;
            buf += slen;
        }
        total += slen;
    }
    return total;
}

int
do_write(int s, void *_buf, int len)
{
    int total, slen, rlen;
    unsigned char *buf = (unsigned char *)_buf;
    total = 0;
    rlen = len;
    while (total < len) {
        slen = write(s, buf, rlen);
        if (slen != rlen) {
            if (slen < 0) {
                diag_printf("Error after writing %d bytes\n", total);
                return -1;
            }
            rlen -= slen;
            buf += slen;
        }
        total += slen;
    }
    return total;
}

//
// This function is called to calibrate the "background load" which can be
// applied during testing.  It will be called before any commands from the
// host are managed.
//
static void
calibrate_load(int desired_load)
{
    long long no_load_idle, load_idle;
    int percent_load;
    int prev_load_level = 0;
    int delta = 0;
    // Compute the "no load" idle value
    idle_thread_count = 0;
    cyg_semaphore_post(&idle_thread_sem);  // Start idle thread
    cyg_thread_delay(1*100);               // Pause for one second
    cyg_semaphore_wait(&idle_thread_sem);  // Stop idle thread
    no_load_idle = idle_thread_count;
    diag_printf("No load = %d\n", (int)idle_thread_count);
    load_thread_level = 100; // IF using the array access load instead of the FP one
    while (true) {
        start_load(desired_load);              // Start up a given load
        idle_thread_count = 0;
        cyg_semaphore_post(&idle_thread_sem);  // Start idle thread
        cyg_thread_delay(1*100);               // Pause for one second
        cyg_semaphore_wait(&idle_thread_sem);  // Stop idle thread
        load_idle = idle_thread_count;
        start_load(0);                         // Shut down background load
        percent_load = 100 - ((load_idle * 100) / no_load_idle);
        diag_printf("Load[%d] = %d => %d%%\n", load_thread_level, 
                    (int)idle_thread_count, percent_load);
        if (abs(desired_load-percent_load) <= 2) break;
        delta = abs(load_thread_level - prev_load_level);
        prev_load_level = load_thread_level;
        if (percent_load < desired_load) {
            load_thread_level *= 2;
        } else {
            load_thread_level -= delta / 2;
        }
    }
    // Now we are within a few percent of the target; scale the load
    // factor to get a better fit, and test it, print the answer.
    load_thread_level *= desired_load;
    load_thread_level += percent_load/2;
    load_thread_level /= percent_load;
    start_load(desired_load);              // Start up a given load
    idle_thread_count = 0;
    cyg_semaphore_post(&idle_thread_sem);  // Start idle thread
    cyg_thread_delay(1*100);               // Pause for one second
    cyg_semaphore_wait(&idle_thread_sem);  // Stop idle thread
    load_idle = idle_thread_count;
    start_load(0);                         // Shut down background load
    percent_load = 100 - ((load_idle * 100) / no_load_idle);
    diag_printf("Final load[%d] = %d => %d%%\n", load_thread_level, 
                (int)idle_thread_count, percent_load);
    no_load_idle_count_1_second = no_load_idle;
}

//
// This function is called to set up a load level of 'load' percent (given
// as a whole number, e.g. start_load(20) would mean initiate a background
// load of 20%, leaving the cpu 80% idle).
//
static void
start_load(int load)
{
    static int prev_load = 0;
    int i;
    if (load == 0) {
        diag_printf("Set no background load\n");
        if (prev_load == 0) return;  // Nothing out there to stop
        for (i = 0;  i < prev_load * NUM_LOAD_THREADS/100;  i++) {
            cyg_semaphore_wait(&load_thread_sem[i]);
        }
        prev_load = 0;
    } else {
        diag_printf("Set background load = %d%% starting %d threads\n",
                    load, load * NUM_LOAD_THREADS/100 );
        for (i = 0;  i < load * NUM_LOAD_THREADS/100;  i++) {
            cyg_semaphore_post(&load_thread_sem[i]);
        }
        prev_load = load;
    }
}

//
// These thread(s) do some amount of "background" computing.  This is used
// to simulate a given load level.  They need to be run at a higher priority 
// than the network code itself.
//
// Like the "idle" thread, they run as long as their "switch" (aka semaphore)
// is enabled.
//
void
net_load(cyg_addrword_t who)
{
    int i;
    while (true) {
        cyg_semaphore_wait(&load_thread_sem[who]);
        for (i = 0;  i < load_thread_level;  i++) {
            do_some_random_computation(i,who);
        }
        cyg_thread_delay(1);  // Wait until the next 'tick'
        cyg_semaphore_post(&load_thread_sem[who]);
    }
}

//
// Some arbitrary computation, designed to use up the CPU and cause associated
// cache "thrash" behaviour - part of background load modelling.
//
static void
do_some_random_computation(int p,int id)
{
    // Just something that might be "hard"
#if 0
    {
        volatile double x;
        x = ((p * 10) * 3.14159) / 180.0;  // radians
    }
#endif
#if 1
    {
        static int footle[0x10001];
        static int counter = 0;
        register int i;

        i = (p << 8) + id + counter++;
        i &= 0xffff;
        footle[ i+1 ] += footle[ i ] + 1;
    }
#endif
}

//
// This thread does nothing but count.  It will be allowed to count
// as long as the semaphore is "free".  
//
void
net_idle(cyg_addrword_t param)
{
    while (true) {
        cyg_semaphore_wait(&idle_thread_sem);
        idle_thread_count++;
        cyg_semaphore_post(&idle_thread_sem);
    }
}

static void
echo_test(cyg_addrword_t p)
{
    int s_source, s_sink, e_source, e_sink;
    struct sockaddr_in e_source_addr, e_sink_addr, local;
    int one = 1;
    fd_set in_fds;
    int i, num, len;
    struct test_params params,nparams;
    struct test_status status,nstatus;

    cyg_tick_count_t starttime, stoptime;

    s_source = socket(AF_INET, SOCK_STREAM, 0);
    if (s_source < 0) {
        pexit("stream socket");
    }
    memset(&local, 0, sizeof(local));
    local.sin_family = AF_INET;
    local.sin_len = sizeof(local);
    local.sin_port = ntohs(SOURCE_PORT);
    local.sin_addr.s_addr = INADDR_ANY;
    if(bind(s_source, (struct sockaddr *) &local, sizeof(local)) < 0) {
        pexit("bind /source/ error");
    }
    if (setsockopt(s_source, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) {
        pexit("setsockopt /source/ SO_REUSEADDR");
    }
    if (setsockopt(s_source, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one))) {
        pexit("setsockopt /source/ SO_REUSEPORT");
    }
    listen(s_source, SOMAXCONN);

    s_sink = socket(AF_INET, SOCK_STREAM, 0);
    if (s_sink < 0) {
        pexit("stream socket");
    }
    memset(&local, 0, sizeof(local));
    local.sin_family = AF_INET;
    local.sin_len = sizeof(local);
    local.sin_port = ntohs(SINK_PORT);
    local.sin_addr.s_addr = INADDR_ANY;
    if(bind(s_sink, (struct sockaddr *) &local, sizeof(local)) < 0) {
        pexit("bind /sink/ error");
    }
    if (setsockopt(s_sink, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) {
        pexit("setsockopt /sink/ SO_REUSEADDR");
    }
    if (setsockopt(s_sink, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one))) {
        pexit("setsockopt /sink/ SO_REUSEPORT");
    }
    listen(s_sink, SOMAXCONN);

    e_source = 0;  e_sink = 0;
    while (true) {
        // Wait for a connection on either of the ports
        FD_ZERO(&in_fds);
        FD_SET(s_source, &in_fds);
        FD_SET(s_sink, &in_fds);
        num = select(max(s_sink,s_source)+1, &in_fds, 0, 0, 0);
        if (FD_ISSET(s_source, &in_fds)) {
            len = sizeof(e_source_addr);
            if ((e_source = accept(s_source, (struct sockaddr *)&e_source_addr, &len)) < 0) {
                pexit("accept /source/");
            }
            diag_printf("SOURCE connection from %s:%d\n", 
                        inet_ntoa(e_source_addr.sin_addr), ntohs(e_source_addr.sin_port));
        }
        if (FD_ISSET(s_sink, &in_fds)) {
            len = sizeof(e_sink_addr);
            if ((e_sink = accept(s_sink, (struct sockaddr *)&e_sink_addr, &len)) < 0) {
                pexit("accept /sink/");
            }
            diag_printf("SINK connection from %s:%d\n", 
                        inet_ntoa(e_sink_addr.sin_addr), ntohs(e_sink_addr.sin_port));
        }
        // Continue with test once a connection is established in both directions
        if ((e_source != 0) && (e_sink != 0)) {
            break;
        }
    }

    // Wait for "source" to tell us the testing paramters
    if (do_read(e_source, &nparams, sizeof(nparams)) != sizeof(nparams)) {
        pexit("Can't read initialization parameters");
    }
  
    params.nbufs = ntohl(nparams.nbufs);
    params.bufsize = ntohl(nparams.bufsize);
    params.load = ntohl(nparams.load);
  
    diag_printf("Using %d buffers of %d bytes each, %d%% background load\n", 
                params.nbufs, params.bufsize, params.load);

    // Tell the sink what the parameters are
    if (do_write(e_sink, &nparams, sizeof(nparams)) != sizeof(nparams)) {
        pexit("Can't write initialization parameters");
    }
  
    nstatus.ok = htonl(status.ok);
  
    // Tell the "source" to start - we're all connected and ready to go!
    if (do_write(e_source, &nstatus, sizeof(nstatus)) != sizeof(nstatus)) {
        pexit("Can't send ACK to 'source' host");
    }

    idle_thread_count = 0;
    cyg_semaphore_post(&idle_thread_sem);  // Start idle thread
    starttime = cyg_current_time();
    start_load(params.load);

    // Echo the data from the source to the sink hosts
    for (i = 0;  i < params.nbufs;  i++) {
        if ((len = do_read(e_source, data_buf, params.bufsize)) != params.bufsize) {
            diag_printf("Can't read buf #%d: ", i+1);
            if (len < 0) {
                perror("I/O error");
            } else {
                diag_printf("short read - only %d bytes\n", len);
            }
        }
        if ((len = do_write(e_sink, data_buf, params.bufsize)) != params.bufsize) {
            diag_printf("Can't write buf #%d: ", i+1);
            if (len < 0) {
                perror("I/O error");
            } else {
                diag_printf("short write - only %d bytes\n", len);
            }
        }
    }

    // Wait for the data to drain and the "sink" to tell us all is OK.
    if (do_read(e_sink, &status, sizeof(status)) != sizeof(status)) {
        pexit("Can't receive ACK from 'sink' host");
    }

    start_load(0);
    cyg_semaphore_wait(&idle_thread_sem);  // Stop idle thread
    stoptime = cyg_current_time();
    stoptime -= starttime; // time taken in cS
    // expected idle loops in that time period for an idle system:
    starttime = no_load_idle_count_1_second * stoptime / 100;
    diag_printf( "%d ticks elapsed, %d kloops predicted for an idle system\n",
                 (int)stoptime, (int)(starttime/1000) );
    diag_printf( "actual kloops %d, CPU was %d%% idle during transfer\n",
                 (int)(idle_thread_count/1000),
                 (int)(idle_thread_count * 100 / starttime) );
}

void
net_test(cyg_addrword_t param)
{
    diag_printf("Start TCP test - ECHO mode\n");
    init_all_network_interfaces();
    calibrate_load(DESIRED_BACKGROUND_LOAD);
    echo_test(param);
    cyg_test_exit();
}

void
cyg_start(void)
{
    int i;
    // Create a main thread which actually runs the test
    cyg_thread_create(MAIN_THREAD_PRIORITY, // Priority
                      net_test,             // entry
                      0,                    // entry parameter
                      "Network test",       // Name
                      &stack[0],            // Stack
                      STACK_SIZE,           // Size
                      &thread_handle,       // Handle
                      &thread_data          // Thread data structure
            );
    cyg_thread_resume(thread_handle);  // Start it
    // Create the idle thread environment
    cyg_semaphore_init(&idle_thread_sem, 0);
    cyg_thread_create(IDLE_THREAD_PRIORITY,     // Priority
                      net_idle,                 // entry
                      0,                        // entry parameter
                      "Network idle",           // Name
                      &idle_thread_stack[0],    // Stack
                      STACK_SIZE,               // Size
                      &idle_thread_handle,      // Handle
                      &idle_thread_data         // Thread data structure
            );
    cyg_thread_resume(idle_thread_handle);      // Start it
    // Create the load threads and their environment(s)
    for (i = 0;  i < NUM_LOAD_THREADS;  i++) {
        cyg_semaphore_init(&load_thread_sem[i], 0);
        cyg_thread_create(LOAD_THREAD_PRIORITY,     // Priority
                          net_load,                 // entry
                          i,                        // entry parameter
                          "Background load",        // Name
                          &load_thread_stack[i][0], // Stack
                          STACK_SIZE,               // Size
                          &load_thread_handle[i],   // Handle
                          &load_thread_data[i]      // Thread data structure
            );
        cyg_thread_resume(load_thread_handle[i]);   // Start it
    }
    cyg_scheduler_start();
}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]