netstress/0000755€_=êŸ00000240000000000012606606506012122 5ustar dialoutnetstress/Releasenotes0000644€_=êŸ00000240000000273512374732555014513 0ustar dialout------------------------------------------------------------------------------ Release: netstress_1.2.0 Date: Aug 19, 2014 Notes: * Migrated source code from CVS to GIT * Enhanced Makefile to build binary files and packages in their own subdir * Added creation of debian packages * Added creation of binary tar packages * Fixed bug where 32bit systems would not sync with 64bit systems due to consistant data sizes on disparate cpu's - Changed type "unsigned long long" to uint64_t - Changed type "unsigned long" to uint32_t * Fixed unreported bug where master closed or overwrote the 1st slaves pid when a death of child event was received for a 2nd or Nth slave process died. * Added slave identity to output providing the ability to keep slave associated messages separate. Uses index into array of slave data (children) and optional [NAME] argument for -s|--slave and -m|--master flags. * Fixed getopt so --host requires an argument. * Added "-c|--ctime = Report current time (default reports elapsed time)" * Fixed to actually report the elapsed time when we say we will * Removed TBD file (will be maintained using sourceforge environment) * Removed Changelog file (seemed to be a duplicate of Releasenotes) ------------------------------------------------------------------------------ Release: netstress_1.01.00 Date: Nov 2, 2007 Notes: First public release ------------------------------------------------------------------------------ netstress/.cvsignore0000644€_=êŸ00000240000000005412374230460014113 0ustar dialout*.swp *.o netstress pkgdir netstress_*.deb netstress/.gitignore0000644€_=êŸ00000240000000011412374230460014100 0ustar dialoutnetstress netstress.o .#* *.swp ~* pkgdir *.o i386 i686 amd64 x86_64 *.tgz netstress/tar-excludes0000644€_=êŸ00000240000000010612374230460014434 0ustar dialoutCVS .#* *.swp ~* pkgdir *.o i386 i686 amd64 x86_64 *.tgz *.deb *.rpm netstress/netstress.c0000644€_=êŸ00000240000016133112374665221014326 0ustar dialout/***************************************************************************** * File: netstress.c * Desc: Networking stress utility *****************************************************************************/ /***************************************************************************** * Copyright (c) 2005, Avocent Corp. * Written by Jim Gleason - July 5, 2005 * Copyright (c) 2006/2007, Helius, Inc. * Enhanced by Jim Gleason - 2006 .. May 2007 ****************************************************************************** * * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of its copyright holders nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *****************************************************************************/ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* Define the min & max packet size (min == packet_number & seed & length) */ #define KB (1024) #define LHEADER_SIZE (3) #define HEADER_SIZE (LHEADER_SIZE*sizeof(uint32_t)) #define MAX_PACKET_SIZE (4*KB) #define LMAX_PACKET_SIZE (MAX_PACKET_SIZE / sizeof(uint32_t)) #define DEFAULT_PORT 5678 #define DEFAULT_REPORT_EVERY_N_SECONDS 5 #define DEFAULT_BENCHMARK_EVERY_N_REPORTS 3 #define DAYS_IN_SECONDS (24*60*60) #define HOURS_IN_SECONDS (60*60) #define MINUTES_IN_SECONDS (60) /*** Global Variables *******************************************************/ int verbosity = 0; /* 0 = no_verbosity, 1...n = verbosity_level */ int debug = 0; /* 0 = no_debug, 1...n = debug_level */ int debugging_receive_loop = 0; int debugging_transmit_loop = 0; /****************************************************************************/ #define MAX_SLAVES 32 // NOTE: We limit the length of the childs connectionName and identity here // because it doesn't make sense to print a name so long that we lose // reference to the actual message or data. // NOTE: The identity is a combination of the connection ID & name #define MAX_CONNECTIONNAME 32 #define MAX_IDENTITY (MAX_CONNECTIONNAME+4) typedef struct children_t { pid_t tx_pid; pid_t rx_pid; // The connectionID is really just the index (passed from master to slave) int32_t connectionID; // The connectionName is optional (passed from slave to master) char connectionName[MAX_CONNECTIONNAME]; char identity[MAX_IDENTITY]; } children_t; typedef struct context_t { char *progname; /* Program name */ int master; /* 1 = master, 0 = slave */ char *host; /* Hostname or IP Address to use */ int port; /* Port number to use */ uint32_t seed; /* Random number seed */ time_t connect_time; /* Actual connect time */ int report_using_current_time; /* Default = 0 = Report elapsed time */ int report_every_n_seconds; /* Default = 5 */ int benchmark_every_n_reports; /* Default = 3 */ int benchmark_in_bytes_per_second; /* 0 = bits, 1 = bytes */ unsigned char measure; /* m=1000000|k=1000|b=1 */ float f_measure; /* Benchmark divider */ char s_measure[64]; /* Benchmark divider in string format */ int master_write_slave_read_test; /* default is 1 (enabled) */ int master_read_slave_write_test; /* default is 1 (enabled) */ struct hostent *hostent; int socket_fd; /* Socket file descriptor returned from socket() */ struct sockaddr_in this_sockaddr; /* Our socket address information */ struct sockaddr_in that_sockaddr; /* Their socket address information */ pid_t pid; children_t children[MAX_SLAVES]; // NOTE: The connectionName is optional // The context->connectionName is the name of the master char connectionName[MAX_CONNECTIONNAME]; /* * Provide a fixed random buffer (we pre-fill this) * This buffer is used UNLESS real_random is set. * When this buffer is used, we convert the seed to * an offset into this buffer. */ int real_random; /* Default = 0 */ unsigned char randomTxBuffer[(MAX_PACKET_SIZE+sizeof(long)) * 2]; unsigned char randomRxBuffer[(MAX_PACKET_SIZE+sizeof(long)) * 2]; /* * Run "Fast" as we can - Don't check the data! * NOTE: This overrides real_random! */ int fast; /* Default = 0 */ } context_t; context_t *global_context = NULL; /****************************************************************************/ extern int errno; /****************************************************************************/ /* "seconds_counter" needs to be shared amongst all processes */ #if (1) # define MY_SHM_KEY 0xDEADBEEF #else # define MY_SHM_KEY IPC_PRIVATE #endif static int ShmID; struct shmid_ds Myshmid_ds; static uint32_t *seconds_counter = NULL; #define seconds_counter_SIZE sizeof(uint32_t) /****************************************************************************/ int main( int argc, char *argv[], char *envv[]); static int parse_options( int argc, char *argv[], char *envv[], context_t *context); static void give_usage( context_t *context); static children_t *which_child(context_t *context, pid_t pid); static char *SIGstring(int sig); static void watch_for_DEATH_OF_PARENT(void); static void DEATH_OF_PARENT_handler( int sig); static void DEATH_OF_CHILD_handler( int sig); static void SIGALRM_handler( int sig); //static void generic_SIG_handler( // int sig); static int handshakeConnectionInformation( context_t *context, int socket_fd, children_t *child); static int netstress_master( context_t *context); static int netstress_slave( context_t *context); static char *time_stamp(context_t *context); static char *elapsed_time_stamp(context_t *context); static char *current_time_stamp(context_t *context); static char *transfer_speed( context_t *context, time_t total_time, uint64_t total_byte_count, time_t delta_time, uint32_t delta_byte_count); static void receive_loop( context_t *context, int socket_fd, char *identity); static void transmit_loop( context_t *context, int socket_fd, char *identity); /***************************************************************************** * Func: Vprintf * Desc: This is basically printf with a leading argument that is a debug level. * This also prepends a "DEBUG: " string * If debug is >= this debug level the printf will be performed. *****************************************************************************/ void Vprintf(int verbosity_lvl, const char *format, ...) { if (verbosity >= verbosity_lvl) { //pid_t pid = getpid(); va_list ap; va_start(ap, format); //printf("VERBOSE(%d): ", pid); vprintf(format, ap); va_end(ap); } return; } /* Vprintf */ /***************************************************************************** * Func: Dprintf * Desc: This is basically printf with a leading argument that is a debug level. * This also prepends a "DEBUG: " string * If debug is >= this debug level the printf will be performed. *****************************************************************************/ void Dprintf(int dbg_lvl, const char *format, ...) { if (debug >= dbg_lvl) { pid_t pid = getpid(); va_list ap; va_start(ap, format); printf("DEBUG(%d): ", pid); vprintf(format, ap); va_end(ap); } return; } /* Dprintf */ void setChildIdentity(children_t *child) { // NOTE: The length of the child identity is limited // because it doesn't make sense to print a name so // long we lose reference to the actual message or data. if (child->connectionName[0] == '\0') { sprintf(child->identity, "%d", child->connectionID); } else { sprintf(child->identity, "%d=%s", child->connectionID, child->connectionName); } return; } /* setChildIdentity */ /***************************************************************************** * Func: main * Desc: Main controlling function *****************************************************************************/ int main( int argc, char *argv[], char *envv[]) { context_t _context; context_t *context = &_context; //int sts; char *cp; char *buff; int buff_size; int i; global_context = context; /* Initialize the context structure */ memset(context, 0, sizeof(context_t)); context->seed = (uint32_t)time(NULL); context->port = DEFAULT_PORT; context->report_using_current_time = 0; /* 0 = Report elapsed time */ context->report_every_n_seconds = DEFAULT_REPORT_EVERY_N_SECONDS; context->benchmark_every_n_reports = DEFAULT_BENCHMARK_EVERY_N_REPORTS; context->benchmark_in_bytes_per_second = 0; /* 0=bits, 1=bytes */ context->measure = 'm'; /* m=1000000|k=1000|b=1 */ context->master_write_slave_read_test = 1; /* default is 1 (enabled) */ context->master_read_slave_write_test = 1; /* default is 1 (enabled) */ context->real_random = 0; /* default is 0 (disabled) */ context->fast = 0; /* default is 0 (disabled) */ context->pid = getpid(); for (i = 0; i < MAX_SLAVES; i++) { // Let container know its own index (ID) context->children[i].connectionID=i; } /* Get the program name while Striping off any associated path */ cp = rindex(argv[0],'/'); if (cp) { cp++; context->progname = cp; } else { context->progname = argv[0]; } parse_options(argc, argv, envv, context); if (context->fast) { context->real_random = 0; /* Can't do "Fast" and real_random */ printf("WARNING: Data validataion checks have been disabled\n"); } /* Determine some stuff based on the options */ buff = &context->s_measure[0]; buff_size = sizeof(context->s_measure); if (context->measure == 'm') { context->f_measure = 1000000.0; *buff = 'm'; buff++; buff_size--; } else if (context->measure == 'k') { context->f_measure = 1000.0; *buff = 'k'; buff++; buff_size--; } else /* (context->measure == 'b') */ { context->f_measure = 1.0; } if (context->benchmark_in_bytes_per_second) { snprintf(buff, buff_size, "%s", "bytes"); } else { snprintf(buff, buff_size, "%s", "bits"); context->f_measure /= 8.0; } #ifdef NOT_YET sts = setpriority(PRIO_PROCESS, 0, context->priority); if (sts < 0) { printf("ERROR: Unable to set priority to %d\n", context->priority); printf("errno = %d = \"%s\"\n", errno, strerror(errno)); } #endif /* NOT_YET */ Dprintf(1, "%s %s Host=%s Port=%d Seed=%lu\n", context->progname, context->master?"Master":"Slave", context->host, context->port, context->seed); /* Setup shared memory */ /* Setup "seconds_counter" as shared memory for all processes */ ShmID = shmget(MY_SHM_KEY, seconds_counter_SIZE, 0600 | IPC_CREAT); if (ShmID != -1) { /* Attach to the shared memory */ seconds_counter = shmat(ShmID, 0, SHM_W); if (seconds_counter) { *seconds_counter = 0L; /* Catch and handle death of child processes */ (void) signal(SIGCHLD, &DEATH_OF_CHILD_handler); /* Catch and handle an alarm every 1 second */ (void) signal(SIGALRM, &SIGALRM_handler); (void) alarm(1); // (void) signal(SIGHUP, &generic_SIG_handler); // = 1 // (void) signal(SIGINT, &generic_SIG_handler); // = 2 = ^C // (void) signal(SIGQUIT, &generic_SIG_handler); // = 3 // (void) signal(SIGABRT, &generic_SIG_handler); // = 6 // (void) signal(SIGKILL, &generic_SIG_handler); // = 9 // (void) signal(SIGTERM, &generic_SIG_handler); // = 15 = kill default // (void) signal(SIGSTOP, &generic_SIG_handler); // = 19 /* Farm off and do the real work */ if (context->master) { /*sts =*/ netstress_master(context); } else { /*sts =*/ netstress_slave(context); } } /* Remove shared memory */ shmctl(ShmID, IPC_RMID, &Myshmid_ds); seconds_counter = NULL; } exit(0); return(0); } /* main() */ /***************************************************************************** * Func: parse_options * Desc: Parse the command line options *****************************************************************************/ static int parse_options( int argc, char *argv[], char *envv[], context_t *context) { int retval = 0; /* Success */ int c = -1; int optind = 0; int master_set = 0; int slave_set = 0; /***** For short_options *****/ /* () --> no arg */ /* (:) --> arg is required */ /* (::) --> arg is optional */ static char short_options[] = "m::s::h:p:S:cn:N:bMKBwrRfvd?"; /***** For long_options *****/ /* ARG1 = NAME */ /* ARG2 = Has_Arg --> 0=no, 1=required, 2=optional */ /* FLAG = How results are returned for long option (see man page) */ /* VAL = Value to return if long option specified if FLAG == 0 */ static struct option long_options[] = { {"master", 2, 0, 'm'}, {"slave", 2, 0, 's'}, {"host", 1, 0, 'h'}, {"port", 1, 0, 'p'}, {"seed", 1, 0, 'S'}, {"ctime", 0, 0, 'c'}, {"nsec", 1, 0, 'n'}, {"nrep", 1, 0, 'N'}, {"bytes", 0, 0, 'b'}, {"mps", 0, 0, 'M'}, {"kps", 0, 0, 'K'}, {"bps", 0, 0, 'B'}, {"mwo", 0, 0, 'w'}, {"mro", 0, 0, 'r'}, {"realrandom", 0, 0, 'R'}, {"fast", 0, 0, 'f'}, {"verbosity", 0, 0, 'v'}, {"debug", 0, 0, 'd'}, {"help", 0, 0, '?'}, {0, 0, 0, 0} }; for ( ; ; ) { c = getopt_long(argc, argv, short_options, long_options, &optind); /* The following needs checked outside of switch so break work right */ if (c < 0) { break; /* Done with options, get out of loop */ } /* See what options we were passed */ switch (c) { case 'm': /* Master */ master_set = 1; context->master = 1; /* 1 = master, 0 = slave */ // Note: context was already initialized to zeroes if ((optarg != NULL) && (*optarg != '\0')) { strncpy(context->connectionName, optarg, sizeof(context->connectionName)-1); } break; case 's': /* Slave */ slave_set = 1; context->master = 0; /* 1 = master, 0 = slave */ // Note: context was already initialized to zeroes if ((optarg != NULL) && (*optarg != '\0')) { // NOTE: In slave mode, we always use the first child... strncpy(context->children[0].connectionName, optarg, sizeof(context->children[0].connectionName)-1); } break; case 'h': /* Host or IP Address */ context->host = optarg; break; case 'p': /* Port */ context->port = atoi(optarg); break; case 'S': /* Seed */ context->seed = atol(optarg); break; case 'c': /* Report using current time */ context->report_using_current_time = 1; break; case 'n': /* Report every nnn seconds */ context->report_every_n_seconds = atol(optarg); break; case 'N': /* Benchmark every nnn reports */ context->benchmark_every_n_reports = atol(optarg); break; case 'b': /* bytes/sec (default is bits/sec) */ context->benchmark_in_bytes_per_second = 1; /* 0=bits, 1=bytes */ break; case 'M': /* mbytes/sec or mbits/sec */ context->measure = 'm'; break; case 'K': /* kbytes/sec or kbits/sec */ context->measure = 'k'; break; case 'B': /* bytes/sec or bits/sec */ context->measure = 'b'; break; case 'w': /* Only test master write / slave read */ context->master_write_slave_read_test = 1; context->master_read_slave_write_test = 0; break; case 'r': /* Only test master read / slave write */ context->master_write_slave_read_test = 0; context->master_read_slave_write_test = 1; break; case 'R': /* Real-Random */ context->real_random = 1; break; case 'f': /* Fast (don't check data) */ context->fast = 1; break; case 'v': /* Verbosity */ verbosity++; /* 0 = no_verbosity, 1...n = verbosity_level */ break; case 'd': /* Debug */ debug++; /* 0 = no_debug, 1...n = debug_level */ break; case '?': /* Help */ default: give_usage(context); /* NOTE: give_usage() doesn't return */ break; } } if (((master_set == 0) && (slave_set == 0)) || ((master_set == 1) && (slave_set == 1))) { printf("\n"); printf("ERROR: Either \"Master\" or \"Slave\" must be set\n"); give_usage(context); /* NOTE: give_usage() doesn't return */ } if (context->master == 0) { if (context->host == NULL) { printf("\n"); printf("ERROR: \"Slave\" mode requires a HOST to be specified\n"); give_usage(context); /* NOTE: give_usage() doesn't return */ } } return(retval); } /* parse_options() */ /***************************************************************************** * Func: give_usage * Desc: Give the command line usage (help) * NOTE: This function does NOT return. *****************************************************************************/ static void give_usage( context_t *context) { printf("\n"); printf("Usage: %s -m[NAME] | --master=[NAME] [OPTIONS]\n", context->progname); printf(" --- or ---\n"); printf("Usage: %s -s[NAME] | --slave=[NAME] -hHOST|--host=HOST [OPTIONS]\n", context->progname); printf(" --- or ---\n"); printf("Usage: %s --help|-?\n", context->progname); printf("\n"); printf("%s is designed to stress/benchmark a network device or\n", context->progname); printf("connection. Two or more sessions are required to use this utility.\n"); printf("One must specify \"--master\" while the others specify \"--slave\".\n"); printf("\n"); printf("Benchmark timings are given independently for read and write\n"); printf("transactions. Benchmark times are reported in xxx/yyy format\n"); printf("where xxx is the total transfer speed and yyy is the transfer\n"); printf("speed for transfers since it was last reported.\n"); printf("\n"); printf(" OPTIONS:\n"); printf(" -m[NAME]|--master[=NAME] = This instance is the master\n"); printf(" -s[NAME]|--slave[=NAME] = This instance is the slave\n"); printf(" -h|--host nnn.nnn.nnn.nnn = Use this host or IP address\n"); printf(" -p|--port nnn = Use this port (default=%d)\n", DEFAULT_PORT); printf(" --seed|-S nnn = Use this random number seed (master only)\n"); printf(" -c|--ctime = Report current time (default reports elapsed time)\n"); printf(" -n|--nsec nnn = Report every nnn seconds (default=%d)\n", DEFAULT_REPORT_EVERY_N_SECONDS); printf(" -N|--nrep nnn = Benchmark every nnn reports (default=%d)\n", DEFAULT_BENCHMARK_EVERY_N_REPORTS); printf(" -b|--bytes = Benchmark using bytes (default is bits)\n"); printf(" -M|--mps = Benchmark using mbytes/sec or mbits/sec (default)\n"); printf(" -K|--kps = Benchmark using kbytes/sec or kbits/sec\n"); printf(" -B|--bps = Benchmark using bytes/sec or bits/sec\n"); printf(" -w|--mwo = Only test master write / slave read\n"); printf(" -r|--mro = Only test master read / slave write\n"); printf(" -R|--realrandom = Do real random test (not psuedo random)\n"); printf(" -f|--fast = Run Fast (no checking, no real_random)\n"); printf(" -v|--verbosity = Enable verbosity (multiples increase level)\n"); printf(" -d|--debug = Enable debugging (multiples increase level)\n"); printf(" -?|--help = Give this information\n"); printf("\n"); exit(-1); } /* give_usage() */ /***************************************************************************** * Func: which_child * Desc: The funtion used to determine which children are asssociated with a pid *****************************************************************************/ static children_t *which_child(context_t *context, pid_t pid) { children_t *child = NULL; int i; if (pid > 0) { for (i = 0; i < MAX_SLAVES; i++) { if ((context->children[i].tx_pid == pid) || (context->children[i].rx_pid == pid)) { child = &(context->children[i]); break; } } } return(child); } /* which_child() */ /***************************************************************************** * Func: SIGstring * Desc: Return a string of the signal specified. *****************************************************************************/ static char *SIGstring(int sig) { char *str; static char *SIGstrings[] = { "1 SIGHUP", "2 SIGINT", "3 SIGQUIT", "4 SIGILL", "5 SIGTRAP", "6 SIGABRT", "7 SIGBUS", "8 SIGFPE", "9 SIGKILL", "10 SIGUSR1", "11 SIGSEGV", "12 SIGUSR2", "13 SIGPIPE", "14 SIGALRM", "15 SIGTERM", "16 SIGSTKFLT", "17 SIGCHLD", "18 SIGCONT", "19 SIGSTOP", "20 SIGTSTP", "21 SIGTTIN", "22 SIGTTOU", "23 SIGURG", "24 SIGXCPU", "25 SIGXFSZ", "26 SIGVTALRM", "27 SIGPROF", "28 SIGWINCH", "29 SIGIO", "30 SIGPWR", "31 SIGSYS", "34 SIGRTMIN", "35 SIGRTMIN+1", "36 SIGRTMIN+2", "37 SIGRTMIN+3", "38 SIGRTMIN+4", "39 SIGRTMIN+5", "40 SIGRTMIN+6", "41 SIGRTMIN+7", "42 SIGRTMIN+8", "43 SIGRTMIN+9", "44 SIGRTMIN+10", "45 SIGRTMIN+11", "46 SIGRTMIN+12", "47 SIGRTMIN+13", "48 SIGRTMIN+14", "49 SIGRTMIN+15", "50 SIGRTMAX-14", "51 SIGRTMAX-13", "52 SIGRTMAX-12", "53 SIGRTMAX-11", "54 SIGRTMAX-10", "55 SIGRTMAX-9", "56 SIGRTMAX-8", "57 SIGRTMAX-7", "58 SIGRTMAX-6", "59 SIGRTMAX-5", "60 SIGRTMAX-4", "61 SIGRTMAX-3", "62 SIGRTMAX-2", "63 SIGRTMAX-1", "64 SIGRTMAX" }; if ((sig >= 1) && (sig <= 64)) { str = SIGstrings[sig-1]; } else { str = "Unknown"; } return(str); } /* SIGstring() */ #define SIGPARENT SIGUSR1 /***************************************************************************** * Func: watch_for_DEATH_OF_PARENT * Desc: Prepare to catch a signal indicating the death of our parent process * Cleanup and notify the user if one of our parent dies *****************************************************************************/ void watch_for_DEATH_OF_PARENT(void) { uint32_t junk = 0; uint32_t new_sig = SIGPARENT; int sts; sts = prctl(PR_SET_PDEATHSIG, new_sig, junk, junk, junk); Dprintf(1, "watch_for_DEATH_OF_PARENT: sts=%d, new_sig=%s\n", sts, SIGstring((int)new_sig)); return; } /* watch_for_DEATH_OF_PARENT() */ /***************************************************************************** * Func: DEATH_OF_PARENT_handler * Desc: The funtion used to catch death of a child signals * Cleanup and notify the user if one of our children dies * Rule: If our parent dies, we are to die. * and we attempt to kill our sibling (this last piece is extra I think) *****************************************************************************/ void DEATH_OF_PARENT_handler( int sig) { children_t *child; pid_t pid; if (sig == SIGPARENT) { /* Let the user know what happened */ printf("SIGNAL: %s: Our parent process died!\n", SIGstring(sig)); /* Determine what child we are so we can comment and cleanup */ pid = getpid(); child = which_child(global_context, pid); if (child) { if (child->tx_pid == pid) { printf("WARNING: ID=%s: TX process terminating\n", child->identity); child->tx_pid = 0; } else /* (child->rx_pid == pid) */ { printf("WARNING: ID=%s: RX process terminating\n", child->identity); child->rx_pid = 0; } } exit(0); } return; } /* DEATH_OF_PARENT_handler() */ /***************************************************************************** * Func: DEATH_OF_CHILD_handler * Desc: The funtion used to catch death of a child signals * Cleanup and notify the user if one of our children dies * Rule: If we are the master: Kill the associated RX or TX child. * Rule: If we are the slave: Kill all our children and die. *****************************************************************************/ void DEATH_OF_CHILD_handler( int sig) { pid_t pid; children_t *child = NULL; int i; if (sig == SIGCHLD) { int status; int terminating_signal = -1; int ret_value = -1; char *process_type = "A"; char *description = ""; /* Re-Enable the signal */ (void) signal(sig, DEATH_OF_CHILD_handler); /* Wait for the child to be cleaned up */ pid = waitpid (-1, &status, WNOHANG); /* Who died ? */ child = which_child(global_context, pid); if (child) { if (child->rx_pid == pid) { process_type = "RX"; } if (child->tx_pid == pid) { process_type = "TX"; } } /* Let the user know what happened */ if (WIFSIGNALED(status)) { terminating_signal = WTERMSIG(status); description = SIGstring(terminating_signal); } if (WIFEXITED(status)) { ret_value = WEXITSTATUS(status); description = strerror(status); } if (child) { printf("WARNING: ID=%s: %s child process died: pid=%d: sts=%d: sig=%d: ret=%d: %s!\n", child->identity, process_type, pid, status, terminating_signal, ret_value, description); } else { printf("WARNING: %s child process died: pid=%d: sts=%d: sig=%d: ret=%d: %s!\n", process_type, pid, status, terminating_signal, ret_value, description); } /* If a master: Kill our childs RX/TX sibling */ /* If a slave: Kill all our other children */ /* There should be only 1 set of children so the behavior is the same */ if (child) { if (child->tx_pid == pid) { // Kill RX sibling if (child->rx_pid > 0) { printf("WARNING: ID=%s: Terminating RX process\n", child->identity); kill(child->rx_pid, SIGTERM); child->rx_pid = 0; } } else /* (child->rx_pid == pid) */ { // Kill TX sibling if (child->tx_pid > 0) { printf("WARNING: ID=%s: Terminating TX process\n", child->identity); kill(child->tx_pid, SIGTERM); child->tx_pid = 0; } } } // Look for children where (only) one child has died. for (i = 0; i < MAX_SLAVES; i++) { for (i = 0; i < MAX_SLAVES; i++) { int alive_count = 0; if (global_context->children[i].rx_pid > 0) alive_count++; if (global_context->children[i].tx_pid > 0) alive_count++; if (alive_count == 1) { // Kill the remaining child. if (global_context->children[i].rx_pid > 0) { printf("WARNING: ID=%s: Terminating RX process\n", global_context->children[i].identity); kill(global_context->children[i].rx_pid, SIGTERM); global_context->children[i].rx_pid = 0; } if (global_context->children[i].tx_pid > 0) { printf("WARNING: ID=%s: Terminating TX process\n", global_context->children[i].identity); kill(global_context->children[i].tx_pid, SIGTERM); global_context->children[i].tx_pid = 0; } } } } // If slave: Check if all children have died. If so, die. if (global_context->master == 0) { for (i = 0; i < MAX_SLAVES; i++) { if ((global_context->children[i].rx_pid > 0) || (global_context->children[i].tx_pid > 0)) { break; } } if (i >= MAX_SLAVES) { printf("WARNING: Slave parent process terminating\n"); exit(0); } } } return; } /* DEATH_OF_CHILD_handler() */ /***************************************************************************** * Func: SIGALRM_handler * Desc: The funtion used to catch SIGALRM signals * Receive and handle an alarm every 1 second *****************************************************************************/ static void SIGALRM_handler(int sig) { if (sig == SIGALRM) { /* Re-Enable the signal and submit another alarm */ (void) signal(sig, SIGALRM_handler); (void) alarm(1); (*seconds_counter)++; //Dprintf(2, "SIGNAL: %s: %lu\n", SIGstring(sig), *seconds_counter); Vprintf(1, "%lu seconds\n", *seconds_counter); } return; } /* SIGALRM_handler() */ /***************************************************************************** * Func: generic_SIG_handler * Desc: The funtion used to catch generic signals *****************************************************************************/ //static void generic_SIG_handler(int sig) //{ // //DON'T//(void) signal(sig, generic_SIG_handler); // printf("SIGNAL: %s\n", SIGstring(sig)); // if ((sig == SIGINT) // || (sig == SIGTERM)) // { // // ^C // exit(0); // } // return; //} /* generic_SIG_handler() */ /***************************************************************************** * Func: fillRandomBuffer * Desc: Fill the TX or RX random buffer twice the size of MAX_PACKET_SIZE with * random numbers we can use instead of getting random numbers each time. * Basically we can randomly point into the first half of this data * as a starting point, and then use a random size of data no greater * than MAX_PACKET_SIZE. *****************************************************************************/ void fillRandomBuffer( context_t *context, char bufferID, /* "T"x or "R"x */ uint32_t seed) { static int tx_done_once = 0; static int rx_done_once = 0; int done_once = 0; int i; int llength; uint32_t *lbuffer = NULL; if ((bufferID == 'T') || (bufferID == 'T')) { /* Use TX BUffer */ lbuffer = (uint32_t *)context->randomTxBuffer; llength = sizeof(context->randomTxBuffer) / sizeof(uint32_t); done_once = tx_done_once; tx_done_once = 1; } else { /* Use RX BUffer */ lbuffer = (uint32_t *)context->randomRxBuffer; llength = sizeof(context->randomRxBuffer) / sizeof(uint32_t); done_once = rx_done_once; rx_done_once = 1; } if ( ! done_once) { Dprintf(1, "RANDOM: %c: %lu\n", bufferID, seed); srandom((unsigned int)seed); for (i = 0; i < llength; i++) { lbuffer[i] = random(); } } return; } /* fillRandomBuffer() */ /***************************************************************************** * Func: handshakeConnectionInformation * Desc: exchange the connectionID and connectionName * Desc: Send the Master's random seed against the Slave's *****************************************************************************/ static int handshakeConnectionInformation( context_t *context, int socket_fd, children_t *child) { int retval = 0; /* Success */ uint32_t checksum = 0; int i; if (context->master) { // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // NOTE: The sum here includes the connectionID and the sum of the name checksum = child->connectionID; // write(child->connectionID) (void) write(socket_fd, &child->connectionID, sizeof(child->connectionID)); // write(context->connectionName) (void) write(socket_fd, context->connectionName, sizeof(context->connectionName)); // write(sum(context->connectionName)) for (i = 0; i < sizeof(context->connectionName); i++) { checksum+=context->connectionName[i]; } (void) write(socket_fd, &checksum, sizeof(checksum)); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // read(child->connectionName) (void) read(socket_fd, child->connectionName, sizeof(child->connectionName)); // read(sum(child->connectionName)) (void) read(socket_fd, &checksum, sizeof(checksum)); //Test sum just read // NOTE: The sum here is the sum of the name only for (i = 0; i < sizeof(child->connectionName); i++) { checksum-=child->connectionName[i]; } if (checksum != 0) { printf("ERROR: connectionName sum mismatch\n"); printf("Connection aborted...\n"); retval = -1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - } else /* SLAVE */ { // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // read(child->connectionID) (void) read(socket_fd, &child->connectionID, sizeof(child->connectionID)); // read(context->connectionName) (void) read(socket_fd, context->connectionName, sizeof(context->connectionName)); // read(sum(context->connectionName)) (void) read(socket_fd, &checksum, sizeof(checksum)); //Test sum just read // NOTE: The sum here includes the connectionID and the sum of the name for (i = 0; i < sizeof(context->connectionName); i++) { checksum-=context->connectionName[i]; } if (checksum != child->connectionID) { printf("ERROR: connectionName sum mismatch\n"); printf("Connection aborted...\n"); retval = -1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // write(child->connectionName) (void) write(socket_fd, child->connectionName, sizeof(child->connectionName)); // write(sum(child->connectionName)) // NOTE: The sum here is the sum of the name only checksum = 0; for (i = 0; i < sizeof(child->connectionName); i++) { checksum+=child->connectionName[i]; } (void) write(socket_fd, &checksum, sizeof(checksum)); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - } setChildIdentity(child); return(retval); } /* handshakeConnectionInformation() */ /***************************************************************************** * Func: netstress_master * Desc: The master portion of the stressnet utility. *****************************************************************************/ static int netstress_master( context_t *context) { int retval = 0; /* Success */ int i; children_t *child = NULL; Dprintf(1, "%s(ENTER): %s\n", __FUNCTION__, context->master?"master":"Slave"); /* Open/Esstablish the socket connection(s) to the specified host */ context->socket_fd = socket(AF_INET, SOCK_STREAM, 0); if (context->socket_fd < 0) { retval = -1; /* Failure */ printf("ERROR: Unable to create socket %s:%d\n", context->host, context->port); printf("errno = %d = \"%s\"\n", errno, strerror(errno)); return(retval); } /* Initialize our socket information */ memset(&context->this_sockaddr, 0, sizeof(struct sockaddr_in)); context->this_sockaddr.sin_family = AF_INET; context->this_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY); context->this_sockaddr.sin_port = htons(context->port); retval = bind(context->socket_fd, (struct sockaddr *)&context->this_sockaddr, sizeof(struct sockaddr_in)); if (retval < 0) { printf("ERROR: Unable to bind to socket %s:%d\n", context->host, context->port); printf("errno = %d = \"%s\"\n", errno, strerror(errno)); return(retval); } retval = listen(context->socket_fd, 5); if (retval < 0) { printf("ERROR: Unable to listen to socket %s:%d\n", context->host, context->port); printf("errno = %d = \"%s\"\n", errno, strerror(errno)); return(retval); } for ( ; ; ) { // Find an unused set of pid's for the new child and point to them. // For the master side of this, we rotate through all entries. int newsocket_fd; /* Socket file descriptor returned from accept() */ child = NULL; for (i = 0; i < MAX_SLAVES; i++) { if (context->children[i].tx_pid <= 0) { child = &(context->children[i]); break; } } if (child == NULL) { sleep(1); continue; } newsocket_fd = accept(context->socket_fd, NULL, NULL); if (newsocket_fd >= 0) { /* We have someone trying to talk to us */ } else { printf("ERROR: Unable to accept a connecting socket %s:%d\n", context->host, context->port); printf("errno = %d = \"%s\"\n", errno, strerror(errno)); continue; } /* * ((( Master ))) * First handshake the connectionID and connectionName * so we can reference any output by its associated connection */ retval = handshakeConnectionInformation(context, newsocket_fd, child); if (retval < 0) { /* An error occurred ... Abort the connection */ /* A message has already been given */ close(newsocket_fd); continue; } /* Now fork a tx process and an rx process */ child->tx_pid = fork(); if (child->tx_pid == 0) { /* Child Process */ transmit_loop(context, newsocket_fd, child->identity); child->tx_pid = 0; /* Leave empty when done */ exit(0); } else { /* Parent Process */ if (child->tx_pid < 0) { printf("ERROR: Unable to fork a TX process\n"); printf("errno = %d = \"%s\"\n", errno, strerror(errno)); child->tx_pid = 0; /* Leave empty when done */ } } child->rx_pid = fork(); if (child->rx_pid == 0) { /* Child Process */ receive_loop(context, newsocket_fd, child->identity); child->rx_pid = 0; /* Leave empty when done */ exit(0); } else { /* Parent Process */ if (child->rx_pid < 0) { printf("ERROR: Unable to fork an RX process\n"); printf("errno = %d = \"%s\"\n", errno, strerror(errno)); printf("WARNING: ID=%s: Terminating TX process\n", child->identity); kill(child->tx_pid, SIGTERM); // = 15 = kill default child->tx_pid = 0; /* Leave empty when done */ child->rx_pid = 0; /* Leave empty when done */ } } } Dprintf(1, "%s(LEAVE): %s\n", __FUNCTION__, context->master?"master":"Slave"); return(retval); } /* netstress_master() */ /***************************************************************************** * Func: netstress_slave * Desc: The slave portion of the stressnet utility. *****************************************************************************/ static int netstress_slave( context_t *context) { int retval = 0; /* Success */ children_t *child = NULL; Dprintf(1, "%s(ENTER): %s\n", __FUNCTION__, context->master?"master":"Slave"); /* Open/Esstablish the socket connection(s) to the specified host */ if (context->host == NULL) { printf("ERROR: No hostname or IP was specified\n"); return(retval); } context->hostent = gethostbyname(context->host); if (context->hostent == NULL) { printf("ERROR: Invalid hostname or IP address specified: %s\n", context->host); printf("errno = %d = \"%s\"\n", errno, strerror(errno)); return(retval); } context->socket_fd = socket(AF_INET, SOCK_STREAM, 0); if (context->socket_fd < 0) { printf("ERROR: Unable to create socket\n"); printf("errno = %d = \"%s\"\n", errno, strerror(errno)); return(retval); } /* Initialize their socket address information */ memset(&context->that_sockaddr, 0, sizeof(struct sockaddr_in)); context->that_sockaddr.sin_family = context->hostent->h_addrtype; memcpy((char *)&context->that_sockaddr.sin_addr.s_addr, context->hostent->h_addr_list[0], context->hostent->h_length); context->that_sockaddr.sin_port = htons(context->port); /* Initialize our socket address information */ memset(&context->this_sockaddr, 0, sizeof(struct sockaddr_in)); context->this_sockaddr.sin_family = AF_INET; context->this_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY); context->this_sockaddr.sin_port = htons(0); retval = bind(context->socket_fd, (struct sockaddr *)&context->this_sockaddr, sizeof(struct sockaddr_in)); if (retval < 0) { printf("ERROR: Unable to bind to socket%s:%d\n", context->host, context->port); printf("errno = %d = \"%s\"\n", errno, strerror(errno)); return(retval); } retval = connect(context->socket_fd, (struct sockaddr *)&context->that_sockaddr, sizeof(struct sockaddr_in)); if (retval < 0) { printf("ERROR: Unable to connect to socket %s:%d\n", context->host, context->port); printf("errno = %d = \"%s\"\n", errno, strerror(errno)); return(retval); } // NOTE: In slave mode, we always use the first child... child = &(context->children[0]); /* * ((( Slave ))) * First handshake the connectionID and connectionName * so we can reference any output by its associated connection */ retval = handshakeConnectionInformation(context, context->socket_fd, child); if (retval < 0) { /* An error occurred ... Abort the connection */ /* A message has already been given */ return(retval); } if (child != NULL) { /* Now fork a tx process and an rx process */ child->tx_pid = fork(); if (child->tx_pid == 0) { /* Child Process */ transmit_loop(context, context->socket_fd, child->identity); child->tx_pid = 0; /* Leave empty when done */ printf("WARNING: Terminating Slave Parent process\n"); kill(context->pid, SIGTERM); context->pid = 0; exit(0); } else { /* Parent Process */ if (child->tx_pid < 0) { printf("ERROR: Unable to fork a TX process\n"); printf("errno = %d = \"%s\"\n", errno, strerror(errno)); child->tx_pid = 0; /* Leave empty when done */ } } child->rx_pid = fork(); if (child->rx_pid == 0) { /* Child Process */ receive_loop(context, context->socket_fd, child->identity); child->rx_pid = 0; /* Leave empty when done */ exit(0); } else { /* Parent Process */ if (child->rx_pid < 0) { printf("ERROR: Unable to fork an RX process\n"); printf("errno = %d = \"%s\"\n", errno, strerror(errno)); printf("WARNING: ID=%s: Terminating TX process\n", child->identity); kill(child->tx_pid, SIGTERM); // = 15 = kill default child->tx_pid = 0; /* Leave empty when done */ child->rx_pid = 0; /* Leave empty when done */ printf("WARNING: Terminating Slave Parent process\n"); kill(context->pid, SIGTERM); context->pid = 0; } } } for ( ; ; ) { sleep(1); } Dprintf(1, "%s(LEAVE): %s\n", __FUNCTION__, context->master?"master":"Slave"); return(retval); } /* netstress_slave() */ /***************************************************************************** * Func: time_stamp * Desc: Returns an ascii string representing either * the elapsed time or the current time * elapsed time example output: "0d 19h 32m 04s" * current time example output: "Mon Dec 14 19:32:04 2009" *****************************************************************************/ static char *time_stamp(context_t *context) { if (context->report_using_current_time == 0) { return(elapsed_time_stamp(context)); } else { return(current_time_stamp(context)); } } /* time_stamp() */ /***************************************************************************** * Func: elapsed_time_stamp * Desc: Returns an ascii string representing the elapsed time * example output: "0d 09h 32m 04s" *****************************************************************************/ static char *elapsed_time_stamp(context_t *context) { static char time_buffer[64]; time_t current_time; time_t elapsed_time; long days, hours, minutes, seconds; current_time = time(NULL); if (context->connect_time == 0L) { elapsed_time = 0; /* Not set yet - Assume times are the same */ } else { elapsed_time = current_time - context->connect_time; } days = elapsed_time / DAYS_IN_SECONDS; if ((days * DAYS_IN_SECONDS) > elapsed_time) days--; elapsed_time -= (days * DAYS_IN_SECONDS); hours = elapsed_time / HOURS_IN_SECONDS; if ((hours * HOURS_IN_SECONDS) > elapsed_time) hours--; elapsed_time -= (hours * HOURS_IN_SECONDS); minutes = elapsed_time / MINUTES_IN_SECONDS; if ((minutes * MINUTES_IN_SECONDS) > elapsed_time) minutes--; elapsed_time -= (minutes * MINUTES_IN_SECONDS); seconds = elapsed_time; sprintf(time_buffer, "%ldd %02ldh %02ldm %02lds", days, hours, minutes, seconds); return(time_buffer); } /* elapsed_time_stamp() */ /***************************************************************************** * Func: current_time_stamp * Desc: Returns an ascii string representing the current time * example output: "Mon Dec 14 19:32:04 2009" *****************************************************************************/ static char *current_time_stamp(context_t *context) { static char time_buffer[64]; time_t current_time; char *cp; current_time = time(NULL); strncpy(time_buffer, ctime(¤t_time), sizeof(time_buffer)); cp = strchr(time_buffer, '\n'); if (cp) { *cp = '\0'; } return(time_buffer); } /* current_time_stamp() */ /***************************************************************************** * Func: transfer_speed * Desc: return the transfer speed information in string format *****************************************************************************/ static char *transfer_speed( context_t *context, time_t total_time, uint64_t total_byte_count, time_t delta_time, uint32_t delta_byte_count) { static char speed_buffer[64]; speed_buffer[0] = '\0'; if (delta_time != 0L) { snprintf(speed_buffer, sizeof(speed_buffer), "%0.1f/%0.1f %s/sec", (((double)total_byte_count / (double)total_time) / context->f_measure), (((float)delta_byte_count / (float)delta_time) / context->f_measure), context->s_measure); } return(speed_buffer); } /* transfer_speed() */ /***************************************************************************** * Func: read_nBytes * Desc: Read an incoming data packet of nBytes2Read size * Returns: N < 0 == ERROR, N >= 0 == number of bytes read *****************************************************************************/ static long read_nBytes( context_t *context, int socket_fd, unsigned char *buffer, long nBytes2Read) { int total_nBytesRead = 0; int nBytesRead = 0; unsigned char *cp = buffer; for ( ; ; ) { nBytesRead = read(socket_fd, cp, (int)nBytes2Read); if (nBytesRead < 0) { if ((errno == EINTR) || (errno == EAGAIN)) { printf("WARNING: read interrupted, errno = %d = \"%s\"\n", errno, strerror(errno)); continue; } printf("ERROR: read failure, errno = %d = \"%s\"\n", errno, strerror(errno)); total_nBytesRead = nBytesRead; /* NOTE: nBytesRead < 0 == ERROR */ break; } else { total_nBytesRead += nBytesRead; cp += nBytesRead; nBytes2Read -= nBytesRead; if (nBytes2Read <= 0) { /* NOTE: nBytesRead >= 0 == number of bytes read */ break; } } } /* End of loop */ return((long)total_nBytesRead); } /* read_nBytes() */ /***************************************************************************** * Func: receive_loop * Desc: The receive (RX) loop *****************************************************************************/ static void receive_loop( context_t *context, int socket_fd, char *identity) { uint32_t loopcount = 0; unsigned char buffer[MAX_PACKET_SIZE+sizeof(long)]; uint32_t *lbuffer = (uint32_t *)buffer; uint32_t *lrbuffer = (uint32_t *)context->randomRxBuffer; uint32_t delta_byte_count = 0L; uint64_t total_byte_count = 0L; uint32_t our_last_seconds_counter = *seconds_counter; uint32_t our_seconds_counter = 0L; int our_report_count = 0; time_t start_time = 0L; /* * Allow the developer to pause to attach a debugger */ if (debugging_receive_loop) { int wait_here = 30; while(wait_here > 0) { wait_here--; sleep(1); } } /* * Don't do unwanted test */ if (((context->master == 1)&&(context->master_read_slave_write_test == 0)) || ((context->master == 0)&&(context->master_write_slave_read_test == 0))) { for ( ; ; ) { sleep(1); continue; } exit(0); return; } Dprintf(1, "%s(ENTER): %s\n", __FUNCTION__, context->master?"master":"Slave"); Dprintf(1, "%s(): %s: PPid:Pid=%d:%d\n", __FUNCTION__, context->master?"Master":"Slave", getppid(), getpid()); /* Catch and handle death of parent process */ (void) signal(SIGPARENT, &DEATH_OF_PARENT_handler); watch_for_DEATH_OF_PARENT(); printf("ID=%s: %s: %u read transactions\n", identity, time_stamp(context), loopcount); context->connect_time = time(NULL); start_time = context->connect_time; /* * Loop until we error out, detect data corruption, or quit */ for ( ; ; ) { static int initialized_randomRxBuffer = 0; uint32_t packet_number; uint32_t seed; long nBytes2Read; long nBytesRead; long nLongsRead; /* * Read an incoming header & buffer * [ packet_number:4 ] [ seed:4 ] [ length:4 ] */ nBytes2Read = HEADER_SIZE; nBytesRead = read_nBytes(context, socket_fd, buffer, nBytes2Read); if (nBytesRead < nBytes2Read) { /* * Read encountered an error * OR * Read did not get enough data for a valid header */ break; } /* * Extract the header information */ packet_number = lbuffer[0]; seed = lbuffer[1]; nBytes2Read = lbuffer[2]; Vprintf(2, "Read(N:%lu,S:%lu,L:%lu)\n", packet_number, seed, nBytes2Read); //printf("-"); /* * Fill a buffer twice the size of MAX_PACKET_SIZE with random * numbers we can use instead of getting random numbers each time. */ if ( ! initialized_randomRxBuffer) { initialized_randomRxBuffer++; fillRandomBuffer(context, 'R', seed); } /* * Read an incoming buffer * [ data:length ] */ nBytesRead = read_nBytes(context, socket_fd, buffer, nBytes2Read); if (nBytesRead < nBytes2Read) { /* * Read encountered an error * OR * Read did not get specified amount of data */ break; } nLongsRead = nBytesRead / sizeof(uint32_t); /* * Verify the data read */ if ( ! context->fast) { /* Use seed if using real_random, else use seed converted to an offset */ if (context->real_random) { int i; srandom((unsigned int)seed); for (i = 0; i < nLongsRead; i++) { uint32_t random_number = random(); if (lbuffer[i] != random_number) { printf("!!! READ: Data error @ %d !!!!!!!!!!!!!!!!!!!\n", i); break; } } } else { int offset = (seed%(uint32_t)(LMAX_PACKET_SIZE)) & (~3); Vprintf(2, "READ: %lu, %u: %lu:%lu\n", seed, (size_t)nBytesRead, lbuffer[0], lrbuffer[offset]); if (memcmp(buffer, &(lrbuffer[offset]), nBytesRead) != 0) { printf("!!! READ: Data error !!!!!!!!!!!!!!!!!!!\n"); break; } } } /* * Gather statistics */ loopcount++; delta_byte_count += (uint32_t)nBytesRead + (uint32_t)HEADER_SIZE; total_byte_count += (uint64_t)nBytesRead + (uint32_t)HEADER_SIZE; if (our_last_seconds_counter != *seconds_counter) { our_last_seconds_counter = *seconds_counter; our_seconds_counter++; //printf("Read second counter = %lu\n", our_seconds_counter); //printf("Read loop counter = %lu\n", loopcount); } /* * Report statistics */ if (our_seconds_counter >= context->report_every_n_seconds) { time_t current_time = 0L; time_t delta_time = 0L; time_t total_time = 0L; our_seconds_counter = 0L; our_report_count++; printf("ID=%s: %s: %u read transactions", identity, time_stamp(context), loopcount); if (our_report_count >= context->benchmark_every_n_reports) { our_report_count = 0; current_time = time(NULL); delta_time = current_time - start_time; total_time = current_time - context->connect_time; printf(" @ %s", transfer_speed(context, total_time, total_byte_count, delta_time, delta_byte_count)); start_time = current_time; delta_byte_count = 0L; } printf("\n"); } } /* End of outer loop */ Dprintf(1, "%s(LEAVE): %s\n", __FUNCTION__, context->master?"master":"Slave"); exit(0); return; } /* receive_loop() */ /***************************************************************************** * Func: write_nBytes * Desc: Write an outgoing data packet of nBytes2Write size * Returns: N < 0 == ERROR, N >= 0 == number of bytes written *****************************************************************************/ static long write_nBytes( context_t *context, int socket_fd, unsigned char *buffer, long nBytes2Write) { int total_nBytesWritten = 0; unsigned char *cp = buffer; for ( ; ; ) { long nBytesWritten = write(socket_fd, cp, (int)nBytes2Write); if (nBytesWritten < 0) { if ((errno == EINTR) || (errno == EAGAIN)) { printf("WARNING: write interrupted, errno = %d = \"%s\"\n", errno, strerror(errno)); continue; } printf("ERROR: write failure, errno = %d = \"%s\"\n", errno, strerror(errno)); total_nBytesWritten = nBytesWritten; /* NOTE: nBytesWritten < 0 == ERROR */ break; } else { total_nBytesWritten += nBytesWritten; cp += nBytesWritten; nBytes2Write -= nBytesWritten; if (nBytes2Write <= 0) { /* NOTE: nBytesWritten >= 0 == number of bytes written */ break; } } } /* End of loop */ return((long)total_nBytesWritten); } /* write_nBytes() */ /***************************************************************************** * Func: transmit_loop * Desc: The transmit (TX) loop *****************************************************************************/ static void transmit_loop( context_t *context, int socket_fd, char *identity) { uint32_t packet_number = 0; uint32_t loopcount = 0; unsigned char buffer[MAX_PACKET_SIZE+sizeof(long)+HEADER_SIZE]; uint32_t *lbuffer = (uint32_t *)buffer; uint32_t *lrbuffer = (uint32_t *)context->randomTxBuffer; uint32_t next_seed=0L; uint32_t delta_byte_count = 0L; uint64_t total_byte_count = 0L; uint32_t our_last_seconds_counter = *seconds_counter; uint32_t our_seconds_counter = 0L; int our_report_count = 0; time_t start_time = 0L; /* * Allow the developer to pause to attach a debugger */ if (debugging_transmit_loop) { int wait_here = 30; while(wait_here > 0) { wait_here--; sleep(1); } } /* * Don't do unwanted test */ if (((context->master == 1)&&(context->master_write_slave_read_test == 0)) || ((context->master == 0)&&(context->master_read_slave_write_test == 0))) { for ( ; ; ) { sleep(1); continue; } exit(0); return; } Dprintf(1, "%s(ENTER): %s\n", __FUNCTION__, context->master?"master":"Slave"); Dprintf(1, "%s(): %s: PPid:Pid=%d:%d\n", __FUNCTION__, context->master?"Master":"Slave", getppid(), getpid()); /* Catch and handle death of parent process */ (void) signal(SIGPARENT, &DEATH_OF_PARENT_handler); watch_for_DEATH_OF_PARENT(); /* * Fill a buffer twice the size of MAX_PACKET_SIZE with random * numbers we can use instead of getting random numbers each time. */ fillRandomBuffer(context, 'T', context->seed); /* Use seed if using real_random */ next_seed = context->seed; printf("ID=%s: %s: %u write transactions\n", identity, time_stamp(context), loopcount); context->connect_time = time(NULL); start_time = context->connect_time; /* * Loop until we error out, detect data corruption, or quit */ for ( ; ; ) { int nBytes2Write, total_nBytes2Write; int nBytesWritten; uint32_t seed; int offset; /* * Increment the packet number */ packet_number++; /* * Construct an outgoing header & buffer * [ packet_number:4 ] [ seed:4 ] [ length:4 ] * [ data:length ] */ /* * Fill in the header information */ seed = next_seed; offset = (seed%(uint32_t)(LMAX_PACKET_SIZE)) & (~3); next_seed = random(); nBytes2Write = random()%(uint32_t)(MAX_PACKET_SIZE-HEADER_SIZE); /* Ensure at least the seed & next length get sent */ lbuffer[0] = packet_number; /* Packet Number */ lbuffer[1] = seed; /* Seed */ lbuffer[2] = nBytes2Write; /* Data Length */ total_nBytes2Write = nBytes2Write + HEADER_SIZE; /* * Fill in the buffer */ if (context->real_random) { int i; long total_nLongs2Write = total_nBytes2Write / sizeof(uint32_t); srandom((unsigned int)seed); for (i = LHEADER_SIZE; i < total_nLongs2Write; i++) { uint32_t random_number = random(); lbuffer[i] = random_number; } } else { memcpy(&(lbuffer[LHEADER_SIZE]), &(lrbuffer[offset]), (size_t)nBytes2Write); Vprintf(3, "WRITE: %lu, %u: %lu:%lu\n", seed, (size_t)nBytes2Write, lbuffer[LHEADER_SIZE], lrbuffer[offset]); } Vprintf(3, "Writing(N:%lu,S:%lu,L:%lu)\n", packet_number, seed, nBytes2Write); //printf("+"); /* * Write an outgoing header & buffer * [packet_number:4] [ seed:4 ] [ next_length:4 ] [ data:length ] */ nBytesWritten = write_nBytes(context, socket_fd, buffer, total_nBytes2Write); if (nBytesWritten < total_nBytes2Write) { /* * Write encountered an error * OR * Write did not send all of the data */ break; /* Outer loop */ } /* * Gather statistics */ loopcount++; delta_byte_count += (uint32_t)nBytesWritten; total_byte_count += (uint64_t)nBytesWritten; if (our_last_seconds_counter != *seconds_counter) { our_last_seconds_counter = *seconds_counter; our_seconds_counter++; //printf("Write second counter = %lu\n", our_seconds_counter); //printf("Write loop counter = %lu\n", loopcount); } /* * Report statistics */ if (our_seconds_counter >= context->report_every_n_seconds) { time_t current_time = 0L; time_t delta_time = 0L; time_t total_time = 0L; our_seconds_counter = 0L; our_report_count++; printf("ID=%s: %s: %u write transactions", identity, time_stamp(context), loopcount); if (our_report_count >= context->benchmark_every_n_reports) { our_report_count = 0; current_time = time(NULL); delta_time = current_time - start_time; total_time = current_time - context->connect_time; printf(" @ %s", transfer_speed(context, total_time, total_byte_count, delta_time, delta_byte_count)); start_time = current_time; delta_byte_count = 0L; } printf("\n"); } } /* End of outer loop */ Dprintf(1, "%s(LEAVE): %s\n", __FUNCTION__, context->master?"master":"Slave"); exit(0); return; } /* transmit_loop() */ //----------------------------------------------------------------------------// // Emacs Editor Settings // // Local Variables: // indent-tabs-mode:t // End: //----------------------------------------------------------------------------// netstress/Makefile0000644€_=êŸ00000240000001050712374230460013557 0ustar dialout############################################################################## # Package: netstress Network Stress utility # File: Makefile.arch ############################################################################## CURDIR=$(shell basename $(shell pwd)) CFLAGS+=-O2 -Wall ${INC} #CFLAGS+=-g -Wall ${INC} BIN_DIR=/usr/sbin ### Currently have pkgdir/topdir nested to facilitate creating RPM's pkgdir=pkgdir topdir=${pkgdir}/topdir ############################################################################## ifeq (${ARCH},) ARCH:=$(shell arch) endif ifeq (${ARCH},i686) ARCH:=i386 endif ifeq (${ARCH},x86_64) ARCH:=amd64 endif ############################################################################## PKGname:=$(shell grep -e "[^[:space:]]" PKGname) PKGversion:=$(shell grep -e "[^[:space:]]" PKGversion) PKGarch:=${ARCH} ############################################################################## .PHONY: all all: ${ARCH}/netstress ############################################################################## ${ARCH}/netstress: ${ARCH}/netstress.o ${CC} ${CFLAGS} -o $@ $^ ############################################################################## ${ARCH}/%.o: %.c @mkdir -v -p ${ARCH} ${CC} ${CFLAGS} -c -o $@ $^ ############################################################################## .PHONY: bin_install bin_install: ${ARCH}/netstress @if [ -d "${pkgdir}" ]; then rm -fr ${pkgdir}; fi @mkdir -p --verbose ${topdir} @# @install -v -d -m 755 ${topdir}/${INSTALL_DIR} @install -v -d -m 755 ${topdir}/${BIN_DIR} @install -v -m 755 ${ARCH}/netstress ${topdir}/${BIN_DIR}/ ############################################################################## .PHONY: deb_install deb_install: ${MAKE} bin_install @# Place the debian package information/scripts in place @install -v -d -m 755 ${topdir}/DEBIAN @install -v -m 644 DEBIAN/control ${topdir}/DEBIAN/control @# @# Replace PKGname, PKGarch and PKGversion in the control file sed -i -e"s/^Package:.*/Package: ${PKGname}/g" \ -e"s/^Version:.*/Version: ${PKGversion}/g" \ -e"s/^Architecture:.*/Architecture: ${PKGarch}/g" \ ${topdir}/DEBIAN/control ############################################################################## .PHONY: rpm_install rpm_install: ${MAKE} bin_install @# Place the redhat package information/scripts in place @# TBD ############################################################################## DEB_PKG:="${ARCH}/${PKGname}_${PKGversion}_${PKGarch}.deb" .PHONY: deb debian deb: ${DEB_PKG} debian: ${DEB_PKG} ${DEB_PKG}: ${MAKE} deb_install @# Create the ${topdir}/DEBIAN/md5sums file @cd ${topdir}; \ find . ! -path \*/DEBIAN/\* -type f | xargs md5sum > DEBIAN/md5sums @# @# Create the actual .deb package dpkg-deb -b ${topdir} ${DEB_PKG} @ls -l ${DEB_PKG} ############################################################################## RPM_PKG:="${ARCH}/${PKGname}_${PKGversion}_${PKGarch}.rpm" .PHONY: rpm redhat rpm: ${DEB_PKG} redhat: ${DEB_PKG} ${RPM_PKG}: ${MAKE} rpm_install @# TBD ############################################################################## BINTAR_PKG:=${ARCH}/${PKGname}_${PKGversion}_${ARCH}.tgz .PHONY: bintar bintar: ${BINTAR_PKG} ${BINTAR_PKG}: ${MAKE} bin_install cd ${topdir}; \ tar -czv -f ../../$@ . ############################################################################## SRCTAR_PKG:=${PKGname}_${PKGversion}_src.tgz .PHONY: srctar srctar: ${SRCTAR_PKG} ${SRCTAR_PKG}: cd ..; \ tar -czv -X ${CURDIR}/tar-excludes -f ${CURDIR}/$@ ${CURDIR} ############################################################################## .PHONY: done done: echo "" @find . | grep -e"\.tgz$$" -e"\.deb$$" -e"\.rpm$$" | xargs ls -lh .PHONY: package package: ${MAKE} debian ${MAKE} redhat ${MAKE} bintar ${MAKE} srctar ${MAKE} done ############################################################################## .PHONY: clean clean: -@if [ -d "${ARCH}" ]; then rm -fr ${ARCH}; fi -@find . -mindepth 1 -maxdepth 1 -name "*.tgz" | xargs rm -f -@find . -mindepth 1 -maxdepth 1 -name "*.rpm" | xargs rm -f -@find . -mindepth 1 -maxdepth 1 -name "*.deb" | xargs rm -f -@rm -fr pkgdir .PHONY: cleanall cleanall: clean -@for THIS_ARCH in 1386 amd64; do \ if [ -d "$${THIS_ARCH}" ]; then rm -fr $${THIS_ARCH}; fi; \ done ############################################################################## netstress/PKGname0000644€_=êŸ00000240000000001212374230460013312 0ustar dialoutnetstress netstress/LICENSE0000644€_=êŸ00000240000000277112374230460013130 0ustar dialoutCopyright (c) 2005, Avocent Corp. Copyright (c) 2006/2007, Helius, Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of its copyright holders nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. netstress/PKGversion0000644€_=êŸ00000240000000000612374230460014062 0ustar dialout1.2.0