test_ucast_spocket.cpp

Go to the documentation of this file.
00001 /*
00002 *  Name   : test_ucast_spocket
00003 *  Author : Chris Koeritz
00004 *  Purpose: This is the "main" program for our sockets tester.  It parses command
00005 *  line parameters and starts up the tester class.
00006 **
00007 * Copyright (c) 2001-$now By Author.  This program is free software; you can  *
00008 * redistribute it and/or modify it under the terms of the GNU General Public  *
00009 * License as published by the Free Software Foundation; either version 2 of   *
00010 * the License or (at your option) any later version.  This is online at:      *
00011 *     http://www.fsf.org/copyleft/gpl.html                                    *
00012 * Please send any updates to: fred@gruntose.com                               *
00013 */
00014 
00015 #include "bcast_spocketer.h"
00016 
00017 #include <application/hoople_main.h>
00018 #include <basis/byte_array.h>
00019 #include <basis/astring.h>
00020 #include <loggers/program_wide_logger.h>
00021 #include <processes/launch_process.h>
00022 #include <structures/static_memory_gremlin.h>
00023 #include <sockets/internet_address.h>
00024 #include <timely/time_control.h>
00025 #include <unit_test/unit_base.h>
00026 
00027 #include <stdio.h>
00028 #include <string.h>
00029 
00030 using namespace application;
00031 using namespace basis;
00032 using namespace loggers;
00033 using namespace mathematics;
00034 using namespace processes;
00035 using namespace sockets;
00036 using namespace structures;
00037 using namespace textual;
00038 using namespace timely;
00039 using namespace unit_test;
00040 
00041 #define LOG(to_print) EMERGENCY_LOG(program_wide_logger().get(), astring(to_print))
00042 
00043 const int INITIAL_DELAY = 1;  // number of seconds before starting sends.
00044 
00045 typedef abyte ip_address_holder[4];
00046 
00047 class test_ucast_spocket : public virtual application_shell, public virtual unit_base
00048 {
00049 public:
00050   test_ucast_spocket() {}
00051   DEFINE_CLASS_NAME("test_ucast_spocket");
00052   virtual int execute();
00053 
00054   bool parse_address(const astring &input, ip_address_holder &ip_address);
00055 };
00056 
00057 //hmmm: extract this to function in sockets.
00058 bool test_ucast_spocket::parse_address(const astring &input, ip_address_holder &ip_address)
00059 {
00060   int index = 0;  // current storage position in our array.
00061   int current_byte = 0;
00062   const char *last_period = 0;  // helps check for non-empty numbers.
00063   bool got_digit = false;
00064   for (const char *address = input.s(); *address; address++) {
00065     if ( (*address <= '9') && (*address >= '0') ) {
00066       current_byte *= 10;  // shift over.
00067       current_byte += *address - '0';  // add in current character.
00068       got_digit = true;
00069     } else if (*address == '.') {
00070       got_digit = false;
00071       if (last_period + 1 == address) {
00072         LOG("The IP address entry has an empty digit.  Exiting.");
00073         return false;
00074       }
00075       last_period = address;  // set our last period location.
00076       if (current_byte > 255) {
00077         LOG("The IP address entry has an illegal abyte.  Exiting.");
00078         return false;
00079       }
00080       ip_address[index] = abyte(current_byte);  // store current byte.
00081       current_byte = 0;  // reset.
00082       index++;  // next place in array.
00083       if (index > 3) break;
00084         // stop if there are too many periods, but keep accumulated address.
00085     } else {
00086       LOG("The IP address entry has illegal characters.  Exiting.");
00087       return false;
00088     }
00089   }
00090   // catch the case where we ran out of chars before adding the last byte.
00091   if ( (index == 3) && got_digit) {
00092     if (current_byte > 255) {
00093       LOG("The IP address entry has an illegal abyte.  Exiting.");
00094       return false;
00095     }
00096     ip_address[index] = current_byte;
00097   } else if (index < 4) {
00098     LOG("The IP address entry is too short.  Exiting.");
00099     return false;
00100   }
00101   return true;
00102 }
00103 
00104 int test_ucast_spocket::execute()
00105 {
00106 //this preamble with command line parsing is identical to bcast version,
00107 //and will be very close to regular spocket version.
00108 //get it extracted to a helper class for use by all three.
00109   FUNCDEF("execute");
00110   ip_address_holder ip_address;  // accumulates the source address.
00111   ip_address_holder dest_addr;  // where to send stuff to.
00112   int rcv_port = 0;
00113   int send_port = 0;
00114   int send_size = 0;
00115   int send_count = 0;
00116 
00117   const char *DEFAULT_HOST = "127.0.0.1";
00118   const int DEFAULT_PORT = 12342;
00119   const int DEFAULT_SEND_SIZE = 1008;
00120   const int DEFAULT_SEND_COUNT = 10;
00121 
00122   if (_global_argc < 7) {
00123     if (_global_argc > 1) {
00124       LOG("\
00125 This program takes six command line arguments to begin operation.\n\
00126 These arguments (in order) are:\n\
00127 \tIP address for src\tIn the form w.x.y.z\n\
00128 \tIP address for dest\tIn the form w.x.y.z\n\
00129 \tReceive Port number\tAs a short integer\n\
00130 \tSending Port number\tAs a short integer\n\
00131 \tSend size\t\tThe size of the data to exchange.\n\
00132 \tSend count\t\tThe number of \"packets\" to exchange.\n\
00133 Note: it is expected that the testers have equal send sizes; this\n\
00134 allows the receiver to know when it's gotten all the data that's\n\
00135 expected during a cycle.");
00136       return 1;  // bail if they provided anything; otherwise we test.
00137     } else {
00138       parse_address(DEFAULT_HOST, ip_address);
00139       parse_address(DEFAULT_HOST, dest_addr);
00140       rcv_port = DEFAULT_PORT;
00141       send_port = DEFAULT_PORT + 1;
00142       send_size = DEFAULT_SEND_SIZE;
00143       send_count = DEFAULT_SEND_COUNT;
00144     }
00145   }
00146 
00147   // only parse the parameters if we got enough from the user; otherwise we accept our
00148   // defaults to do a simple test run.
00149   if (_global_argc >= 7) {
00150 
00151     if (!parse_address(_global_argv[1], ip_address)) {
00152       LOG("failed to parse source address.");
00153       return 9283;
00154     }
00155 
00156     LOG(a_sprintf("\tParsed a source of: \"%d.%d.%d.%d\".",
00157         (int)ip_address[0], (int)ip_address[1], (int)ip_address[2],
00158         (int)ip_address[3]));
00159 
00160     if (!parse_address(_global_argv[2], dest_addr)) {
00161       LOG("failed to parse dest address.");
00162       return 9283;
00163     }
00164 
00165     LOG(a_sprintf("\tParsed a destination of: \"%d.%d.%d.%d\".",
00166         (int)dest_addr[0], (int)dest_addr[1], (int)dest_addr[2],
00167         (int)dest_addr[3]));
00168 
00169     // parse the third parameter: the port.
00170     if (sscanf(_global_argv[3], "%d", &rcv_port) < 1) {
00171       LOG("The port entry is malformed.  Exiting.");
00172       return 3;
00173     }
00174     LOG(a_sprintf("\tGot a receive port of %d.", rcv_port));
00175 
00176     // parse the fourth parameter: the port.
00177     if (sscanf(_global_argv[4], "%d", &send_port) < 1) {
00178       LOG("The port entry is malformed.  Exiting.");
00179       return 3;
00180     }
00181     LOG(a_sprintf("\tGot a send port of %d.", send_port));
00182 
00183     // parse the fifth parameter: the size of the sends.
00184     if (sscanf(_global_argv[5], "%d", &send_size) < 1) {
00185       LOG("The send size entry is malformed.  Exiting.");
00186       return 5;
00187     }
00188     LOG(a_sprintf("\tGot a send size of %d.", send_size));
00189 
00190     // parse the sixth parameter: the number of sends.
00191     if (sscanf(_global_argv[6], "%d", &send_count) < 1) {
00192       LOG("The send count entry is malformed.  Exiting.");
00193       return 5;
00194     }
00195     LOG(a_sprintf("\tGot a send count of %d.", send_count));
00196   }
00197 
00198   if (_global_argc == 1) {
00199     // launch a paired duplicate of our test so we can chat.
00200     launch_process zingit;
00201     un_int kidnum;
00202     un_int result = zingit.run(_global_argv[0],
00203         astring(DEFAULT_HOST) + " " +  DEFAULT_HOST + " "
00204         /* we have reversed the send and receive ports. */
00205         + a_sprintf("%d", DEFAULT_PORT + 1) + " " + a_sprintf("%d", DEFAULT_PORT)
00206         + " " + a_sprintf("%d", DEFAULT_SEND_SIZE) + " " + a_sprintf("%d", DEFAULT_SEND_COUNT),
00207         launch_process::RETURN_IMMEDIATELY, kidnum);
00208     ASSERT_EQUAL(result, 0, "launching paired process should start successfully");
00209   }
00210 
00211   // package our parameters in a form the tester likes.
00212   internet_address to_pass(byte_array(4, ip_address), "", rcv_port);
00213   internet_address dest(byte_array(4, dest_addr), "", send_port);
00214 
00215   // now, construct our tester object.
00216   broadcast_spocket_tester tester(to_pass, true);
00217 
00218   // choose the appropriate action based on our role.
00219   bool outcome = tester.connect();
00220   if (!outcome) {
00221     LOG(astring("Failed to connect on the tester."));
00222     return 10;
00223   }
00224 
00225   LOG(a_sprintf("you now have %d seconds; get other side ready.",
00226       INITIAL_DELAY));
00227   time_control::sleep_ms(INITIAL_DELAY * SECOND_ms);
00228   LOG("starting test");
00229 
00230   // so, we're connected.  try sending the test packages out.
00231   testing_statistics stats;  // to be filled by the tester.
00232   outcome = tester.perform_test(dest, send_size, send_count * 2, stats);
00233     // multiply send_count since we count each side as one.
00234   if (!outcome) {
00235     LOG("Failed out of send_data; maybe other side terminated.");
00236   }
00237 
00238   stats.total_runs /= 2;  // cut down to the real number of tests.
00239 
00240   if (!stats.total_runs)
00241     stats.total_runs = 1;
00242 
00243   // now report on the stats that we get from the data sending.
00244   LOG(a_sprintf("Report for %d completed test cycles.", stats.total_runs));
00245   LOG("");
00246   LOG("\t\tsend stats\t\treceive stats");
00247   LOG("\t\t----------\t\t-------------");
00248   LOG(a_sprintf("bytes\t\t%d\t\t\t%d", stats.bytes_sent,
00249       stats.bytes_received));
00250   LOG(a_sprintf("time\t\t%d\t\t\t%d", stats.send_time, stats.receive_time));
00251   LOG(a_sprintf("avg. bytes\t%d\t\t\t%d", stats.bytes_sent
00252       / stats.total_runs / 2, stats.bytes_received / stats.total_runs / 2));
00253   LOG("");
00254   LOG(a_sprintf("round trip time: %d ms", stats.round_trip_time));
00255 //hmmm: use the bandwidth measurer object!!!
00256   double bandwidth = double(stats.bytes_sent + stats.bytes_received)
00257       / stats.round_trip_time / 1024.0 * 1000.0;
00258   LOG(a_sprintf("bandwidth overall: %f K/s", bandwidth));
00259 
00260   if (_global_argc == 1) return final_report();
00261   else return 0;  // no unit test report for non-top-level process
00262 }
00263 
00264 HOOPLE_MAIN(test_ucast_spocket, );
00265 
Generated on Sat Jan 28 04:22:55 2012 for hoople2 project by  doxygen 1.6.3