bcast_spocketer.cpp

Go to the documentation of this file.
00001 /*****************************************************************************\
00002 *                                                                             *
00003 *  Name   : broadcast_spocket_tester                                          *
00004 *  Author : Chris Koeritz                                                     *
00005 *                                                                             *
00006 *******************************************************************************
00007 * Copyright (c) 2000-$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 <basis/byte_array.h>
00018 #include <basis/chaos.h>
00019 #include <basis/function.h>
00020 #include <basis/istring.h>
00021 #include <basis/log_base.h>
00022 #include <basis/portable.h>
00023 #include <mechanisms/time_stamp.h>
00024 #include <sockets/address.h>
00025 #include <sockets/raw_socket.h>
00026 #include <sockets/spocket.h>
00027 #include <sockets/tcpip_definitions.h>
00028 #include <sockets/tcpip_stack.h>
00029 
00030 #include <errno.h>
00031 
00032 const int MAXIMUM_WINSOCK_MTU = 1500;
00033   // the largest chunk of bytes we can receive at once.
00034 
00035 const int MAXIMUM_TRANSFER_WAIT = 40 * SECOND_ms;
00036   // the longest amount of time we wait in trying to receive data.
00037 
00038 static byte receive_buffer[MAXIMUM_WINSOCK_MTU + 1];
00039   // used for dumping received data into.
00040 
00041 #define LOG(s) program_wide_logger().log(s)
00042 
00043 //#define DEBUG_SPOCKET_TESTER
00044   // uncomment for noisy version.
00045 
00046 broadcast_spocket_tester::broadcast_spocket_tester
00047     (const internet_address &where, bool unicast)
00048 : _where(new internet_address(where)),
00049   _stack(new tcpip_stack),
00050   _socket(NIL),
00051   _raw(new raw_socket),
00052   _ucast(unicast)
00053 {
00054 }
00055 
00056 broadcast_spocket_tester::~broadcast_spocket_tester()
00057 {
00058   WHACK(_socket);
00059   WHACK(_stack);
00060   WHACK(_where);
00061   WHACK(_raw);
00062 }
00063 
00064 bool broadcast_spocket_tester::connect()
00065 {
00066   spocket::sock_types type = spocket::BROADCAST;
00067   if (_ucast) type = spocket::UNICAST;
00068   if (!_socket) {
00069     _socket = new spocket(*_where, type);
00070   }
00071   outcome ret = _socket->connect();
00072   return ret == spocket::OKAY;
00073 }
00074 
00075 bool broadcast_spocket_tester::do_a_send(const internet_address &where_to,
00076     byte *buffer, int size, testing_statistics &stats)
00077 {
00078   time_stamp start_time;
00079   int len_sent;
00080   time_stamp when_to_leave(MAXIMUM_TRANSFER_WAIT);
00081   outcome worked;
00082 
00083 #ifdef DEBUG_SPOCKET_TESTER
00084   LOG(isprintf("into do a send with %d bytes", size));
00085 #endif
00086 
00087   while (time_stamp() < when_to_leave) {
00088     worked = _socket->send_to(where_to, buffer, size, len_sent);
00089     if (worked == spocket::NONE_READY) {
00090       portable::sleep_ms(20);
00091       continue;
00092     } else if (worked == spocket::PARTIAL) {
00093 //danger danger if we get wrong info.
00094       buffer += len_sent;
00095       size -= len_sent;
00096       portable::sleep_ms(20);
00097       continue;
00098     } else break;
00099   }
00100 #ifdef DEBUG_SPOCKET_TESTER
00101   LOG("got out of loop");
00102 #endif
00103 
00104   stats.send_time += int(time_stamp().value() - start_time.value());
00105 
00106   if ( (worked != spocket::OKAY) || !len_sent) {
00107     LOG("No data went out on the socket.");
00108     return false;
00109   }
00110   if (len_sent != size) {
00111     LOG(isprintf("The full chunk didn't get sent out: %d bytes instead of %d",
00112         len_sent, size));
00113 //more bad news.  what do we do about getting the rest out?
00114     return false;
00115   }
00116   stats.bytes_sent += len_sent;
00117 
00118   time_stamp end_time;
00119 //  int time_taken = int(end_time.value() - start_time.value());
00120 
00121   return true;
00122 }
00123 
00124 bool broadcast_spocket_tester::do_a_receive(int size_expected,
00125     testing_statistics &stats)
00126 {
00127   time_stamp start_time;
00128 
00129 #ifdef DEBUG_SPOCKET_TESTER
00130   LOG("into do a rcv");
00131 #endif
00132 
00133   time_stamp when_to_leave(MAXIMUM_TRANSFER_WAIT);
00134   int full_length = 0;
00135   while ( (full_length < size_expected) && (time_stamp() < when_to_leave) ) {
00136     time_stamp start_of_receive;
00137     int len = MAXIMUM_WINSOCK_MTU;
00138     internet_address where_from;
00139     outcome ret = _socket->receive_from(receive_buffer, len, where_from);
00141     if (ret != spocket::OKAY) {
00142       if (ret == spocket::NONE_READY) {
00143         portable::sleep_ms(20);
00144         continue;
00145       } else break;
00146     }
00147     // reset our time if we've gotten good data.
00148     if (ret == spocket::OKAY)
00149       when_to_leave.reset(MAXIMUM_TRANSFER_WAIT);
00150 
00151     int receive_duration = int(time_stamp().value()
00152         - start_of_receive.value());
00153     stats.receive_time += receive_duration;
00154 
00155 #ifdef DEBUG_SPOCKET_TESTER
00156     LOG(isprintf("did recv, len=%d", len));
00157 #endif
00158 
00159     if (!len) {
00160       LOG("Our socket has been disconnected.");
00161       return false;
00162     } else if (len < 0) {
00163       if (errno == SOCK_EWOULDBLOCK) continue;  // no data.
00164       LOG(istring("The receive failed with an error ")
00165           + portable::system_error_text(errno));
00166       return false;
00167     }
00168     full_length += len;
00169     stats.bytes_received += len;
00170   }
00171 
00172   if (full_length != size_expected)
00173     LOG(isprintf("Did not get the full size expected (wanted %d and "
00174         "got %d bytes).", size_expected, full_length));
00175 
00176   return true;
00177 }
00178 
00179 bool broadcast_spocket_tester::perform_test(const internet_address &dest,
00180     int size, int count, testing_statistics &stats)
00181 {
00182 #ifdef DEBUG_SPOCKET_TESTER
00183   LOG("into perf test");
00184 #endif
00185 
00186   // the statics are used to generate our random buffer for sending.
00187   static byte garbage_buffer[MAXIMUM_WINSOCK_MTU + 1];
00188   static bool garbage_initialized = false;
00189   chaos randomizer;
00190 
00191   // if our static buffer full of random stuff was never initialized, we do
00192   // so now.  this supports efficiently re-using the tester if desired.
00193   if (!garbage_initialized) {
00194     // note the less than or equal; we know we have one more byte to fill.
00195     for (int i = 0; i <= MAXIMUM_WINSOCK_MTU; i++)
00196       garbage_buffer[i] = randomizer.inclusive(0, 255);
00197     garbage_initialized = true;
00198   }
00199 
00200   // reset the statistical package.
00201   stats.total_runs = 0;
00202   stats.send_time = 0;
00203   stats.receive_time = 0;
00204   stats.bytes_sent = 0;
00205   stats.bytes_received = 0;
00206 
00207   // check that they aren't trying to do too big of a send.
00208   if (size > MAXIMUM_WINSOCK_MTU) {
00209     LOG("The size is over our limit.  To fix this, edit the "
00210         "send_data function.");
00211     return false;
00212   }
00213 
00214   // check that our socket is usable.
00215   if (!_socket) {
00216     LOG("One cannot send data on an uninitialized tester!");
00217     return false;
00218   }
00219 
00220   int runs_completed = 0;
00221     // counts up how many times we've done our test cycle.
00222 
00223   while (runs_completed < count) {
00224 #ifdef DEBUG_SPOCKET_TESTER
00225     LOG(isprintf("iter %d", runs_completed));
00226 #endif
00227     // we're doing the client side routine here.
00228     time_stamp trip_start;
00229 #ifdef DEBUG_SPOCKET_TESTER
00230     LOG("client about to send");
00231 #endif
00232     if (!do_a_send(dest, garbage_buffer, size, stats)) {
00233       LOG("We failed on a send.  Now quitting.");
00234       return false;
00235     }
00236 #ifdef DEBUG_SPOCKET_TESTER
00237     LOG("client about to rcv");
00238 #endif
00239     if (!do_a_receive(size, stats)) {
00240       LOG("We failed on a receive.  Now quitting.");
00241       return false;
00242     }
00243     stats.round_trip_time += int(time_stamp().value() - trip_start.value());
00244 
00245     runs_completed++;  // finished a run.
00246     stats.total_runs++;  // count it in the overall stats too.
00247     if ( !(runs_completed % 10) )
00248       LOG(isprintf("Completed test #%d.", runs_completed));
00249   }
00250 
00251   return true;
00252 }
00253 

Generated on Fri Aug 29 04:29:09 2008 for HOOPLE Libraries by  doxygen 1.5.1