bcast_spocketer.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "bcast_spocketer.h"
00016
00017 #include <basis/astring.h>
00018 #include <basis/byte_array.h>
00019 #include <basis/functions.h>
00020 #include <loggers/critical_events.h>
00021 #include <loggers/program_wide_logger.h>
00022 #include <mathematics/chaos.h>
00023 #include <sockets/internet_address.h>
00024 #include <sockets/raw_socket.h>
00025 #include <sockets/spocket.h>
00026 #include <sockets/tcpip_definitions.h>
00027 #include <sockets/tcpip_stack.h>
00028 #include <timely/time_control.h>
00029 #include <timely/time_stamp.h>
00030 #include <unit_test/unit_base.h>
00031
00032 #include <errno.h>
00033
00034
00035 using namespace basis;
00036
00037 using namespace loggers;
00038 using namespace mathematics;
00039 using namespace sockets;
00040 using namespace structures;
00041
00042 using namespace timely;
00043 using namespace unit_test;
00044
00045 #define LOG(to_print) EMERGENCY_LOG(program_wide_logger().get(), astring(to_print))
00046
00047 const int MAXIMUM_WINSOCK_MTU = 1500;
00048
00049
00050 const int MAXIMUM_TRANSFER_WAIT = 40 * SECOND_ms;
00051
00052
00053 static abyte receive_buffer[MAXIMUM_WINSOCK_MTU + 1];
00054
00055
00056
00057
00058
00059 broadcast_spocket_tester::broadcast_spocket_tester
00060 (const internet_address &where, bool unicast)
00061 : _where(new internet_address(where)),
00062 _stack(new tcpip_stack),
00063 _socket(NIL),
00064 _raw(new raw_socket),
00065 _ucast(unicast)
00066 {
00067 }
00068
00069 broadcast_spocket_tester::~broadcast_spocket_tester()
00070 {
00071 WHACK(_socket);
00072 WHACK(_stack);
00073 WHACK(_where);
00074 WHACK(_raw);
00075 }
00076
00077 bool broadcast_spocket_tester::connect()
00078 {
00079 spocket::sock_types type = spocket::BROADCAST;
00080 if (_ucast) type = spocket::UNICAST;
00081 if (!_socket) {
00082 _socket = new spocket(*_where, type);
00083 }
00084 outcome ret = _socket->connect();
00085 return ret == spocket::OKAY;
00086 }
00087
00088 bool broadcast_spocket_tester::do_a_send(const internet_address &where_to,
00089 abyte *buffer, int size, testing_statistics &stats)
00090 {
00091 time_stamp start_time;
00092 int len_sent;
00093 time_stamp when_to_leave(MAXIMUM_TRANSFER_WAIT);
00094 outcome worked;
00095
00096 #ifdef DEBUG_SPOCKET_TESTER
00097 LOG(a_sprintf("into do a send with %d bytes", size));
00098 #endif
00099
00100 while (time_stamp() < when_to_leave) {
00101 worked = _socket->send_to(where_to, buffer, size, len_sent);
00102 if (worked == spocket::NONE_READY) {
00103 time_control::sleep_ms(20);
00104 continue;
00105 } else if (worked == spocket::PARTIAL) {
00106
00107 buffer += len_sent;
00108 size -= len_sent;
00109 time_control::sleep_ms(20);
00110 continue;
00111 } else break;
00112 }
00113 #ifdef DEBUG_SPOCKET_TESTER
00114 LOG("got out of loop");
00115 #endif
00116
00117 stats.send_time += int(time_stamp().value() - start_time.value());
00118
00119 if ( (worked != spocket::OKAY) || !len_sent) {
00120 LOG("No data went out on the socket.");
00121 return false;
00122 }
00123 if (len_sent != size) {
00124 LOG(a_sprintf("The full chunk didn't get sent out: %d bytes instead of %d",
00125 len_sent, size));
00126
00127 return false;
00128 }
00129 stats.bytes_sent += len_sent;
00130
00131 time_stamp end_time;
00132
00133
00134 return true;
00135 }
00136
00137 bool broadcast_spocket_tester::do_a_receive(int size_expected,
00138 testing_statistics &stats)
00139 {
00140 time_stamp start_time;
00141
00142 #ifdef DEBUG_SPOCKET_TESTER
00143 LOG("into do a rcv");
00144 #endif
00145
00146 time_stamp when_to_leave(MAXIMUM_TRANSFER_WAIT);
00147 int full_length = 0;
00148 while ( (full_length < size_expected) && (time_stamp() < when_to_leave) ) {
00149 time_stamp start_of_receive;
00150 int len = MAXIMUM_WINSOCK_MTU;
00151 internet_address where_from;
00152 outcome ret = _socket->receive_from(receive_buffer, len, where_from);
00154 if (ret != spocket::OKAY) {
00155 if (ret == spocket::NONE_READY) {
00156 time_control::sleep_ms(20);
00157 continue;
00158 } else break;
00159 }
00160
00161 if (ret == spocket::OKAY)
00162 when_to_leave.reset(MAXIMUM_TRANSFER_WAIT);
00163
00164 int receive_duration = int(time_stamp().value()
00165 - start_of_receive.value());
00166 stats.receive_time += receive_duration;
00167
00168 #ifdef DEBUG_SPOCKET_TESTER
00169 LOG(a_sprintf("did recv, len=%d", len));
00170 #endif
00171
00172 if (!len) {
00173 LOG("Our socket has been disconnected.");
00174 return false;
00175 } else if (len < 0) {
00176 if (errno == SOCK_EWOULDBLOCK) continue;
00177 LOG(astring("The receive failed with an error ")
00178 + critical_events::system_error_text(errno));
00179 return false;
00180 }
00181 full_length += len;
00182 stats.bytes_received += len;
00183 }
00184
00185 if (full_length != size_expected)
00186 LOG(a_sprintf("Did not get the full size expected (wanted %d and "
00187 "got %d bytes).", size_expected, full_length));
00188
00189 return true;
00190 }
00191
00192 bool broadcast_spocket_tester::perform_test(const internet_address &dest,
00193 int size, int count, testing_statistics &stats)
00194 {
00195 #ifdef DEBUG_SPOCKET_TESTER
00196 LOG("into perf test");
00197 #endif
00198
00199
00200 static abyte garbage_buffer[MAXIMUM_WINSOCK_MTU + 1];
00201 static bool garbage_initialized = false;
00202 chaos randomizer;
00203
00204
00205
00206 if (!garbage_initialized) {
00207
00208 for (int i = 0; i <= MAXIMUM_WINSOCK_MTU; i++)
00209 garbage_buffer[i] = randomizer.inclusive(0, 255);
00210 garbage_initialized = true;
00211 }
00212
00213
00214 stats.total_runs = 0;
00215 stats.send_time = 0;
00216 stats.receive_time = 0;
00217 stats.bytes_sent = 0;
00218 stats.bytes_received = 0;
00219
00220
00221 if (size > MAXIMUM_WINSOCK_MTU) {
00222 LOG("The size is over our limit. To fix this, edit the "
00223 "send_data function.");
00224 return false;
00225 }
00226
00227
00228 if (!_socket) {
00229 LOG("One cannot send data on an uninitialized tester!");
00230 return false;
00231 }
00232
00233 int runs_completed = 0;
00234
00235
00236 while (runs_completed < count) {
00237 #ifdef DEBUG_SPOCKET_TESTER
00238 LOG(a_sprintf("iter %d", runs_completed));
00239 #endif
00240
00241 time_stamp trip_start;
00242 #ifdef DEBUG_SPOCKET_TESTER
00243 LOG("client about to send");
00244 #endif
00245 if (!do_a_send(dest, garbage_buffer, size, stats)) {
00246 LOG("We failed on a send. Now quitting.");
00247 return false;
00248 }
00249 #ifdef DEBUG_SPOCKET_TESTER
00250 LOG("client about to rcv");
00251 #endif
00252 if (!do_a_receive(size, stats)) {
00253 LOG("We failed on a receive. Now quitting.");
00254 return false;
00255 }
00256 stats.round_trip_time += int(time_stamp().value() - trip_start.value());
00257
00258 runs_completed++;
00259 stats.total_runs++;
00260 if ( !(runs_completed % 10) )
00261 LOG(a_sprintf("Completed test #%d.", runs_completed));
00262 }
00263
00264 return true;
00265 }
00266