spocket_tester.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "spocket_tester.h"
00016
00017 #include <basis/byte_array.h>
00018 #include <basis/functions.h>
00019 #include <basis/astring.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
00031 #include <errno.h>
00032
00033
00034 using namespace basis;
00035
00036 using namespace loggers;
00037 using namespace mathematics;
00038 using namespace sockets;
00039 using namespace structures;
00040 using namespace textual;
00041 using namespace timely;
00042
00043
00044 #define LOG(to_print) EMERGENCY_LOG(program_wide_logger().get(), astring(to_print))
00045
00046 const int MAXIMUM_WINSOCK_MTU = 100000;
00047
00048
00049 const int MAXIMUM_TRANSFER_WAIT = 40 * SECOND_ms;
00050
00051
00052 static abyte receive_buffer[MAXIMUM_WINSOCK_MTU + 1];
00053
00054
00055 const int PAUSE_TIME = 200;
00056
00057
00058
00059
00060
00061 spocket_tester::spocket_tester(const internet_address &where)
00062 : _where(new internet_address(where)),
00063 _stack(new tcpip_stack),
00064 _socket(NIL),
00065 _root_server(NIL),
00066 _raw(new raw_socket)
00067 {
00068 }
00069
00070 spocket_tester::~spocket_tester()
00071 {
00072 WHACK(_socket);
00073 WHACK(_root_server);
00074 WHACK(_stack);
00075 WHACK(_where);
00076 WHACK(_raw);
00077 }
00078
00079 bool spocket_tester::connect()
00080 {
00081 if (!_socket) {
00082 _socket = new spocket(*_where);
00083 }
00084 outcome ret = spocket::NO_CONNECTION;
00085 while (true) {
00086 ret = _socket->connect();
00087 if (ret == spocket::OKAY) break;
00088 if (ret != spocket::NO_CONNECTION) break;
00089 time_control::sleep_ms(100);
00090 }
00091 return ret == spocket::OKAY;
00092 }
00093
00094 bool spocket_tester::accept(bool wait)
00095 {
00096 if (!_root_server) {
00097 _root_server = new spocket(*_where);
00098 }
00099 if (_socket) {
00100 LOG("already have a socket for accept!");
00101 return true;
00102 }
00103 outcome ret = spocket::NO_CONNECTION;
00104 while (true) {
00105 ret = _root_server->accept(_socket, false);
00106 if (ret == spocket::OKAY) break;
00107 if (ret != spocket::NO_CONNECTION) break;
00108 if (!wait) return true;
00109 time_control::sleep_ms(100);
00110 }
00111 return ret == spocket::OKAY;
00112 }
00113
00114 bool spocket_tester::do_a_send(abyte *buffer, int size,
00115 testing_statistics &stats)
00116 {
00117 time_stamp start_time;
00118 int len_sent;
00119 time_stamp when_to_leave(MAXIMUM_TRANSFER_WAIT);
00120 outcome worked;
00121
00122 #ifdef DEBUG_SPOCKET_TESTER
00123 LOG("into do a send");
00124 #endif
00125
00126 while (time_stamp() < when_to_leave) {
00127 worked = _socket->send(buffer, size, len_sent);
00128 if (worked == spocket::NONE_READY) {
00130 _socket->await_writable(PAUSE_TIME);
00131 continue;
00132 } else if (worked == spocket::PARTIAL) {
00133
00134 buffer += len_sent;
00135 size -= len_sent;
00136 stats.bytes_sent += len_sent;
00138 _socket->await_writable(PAUSE_TIME);
00139 continue;
00140 } else break;
00141 }
00142 #ifdef DEBUG_SPOCKET_TESTER
00143 LOG("got out of loop");
00144 #endif
00145
00146 stats.send_time += int(time_stamp().value() - start_time.value());
00147 stats.bytes_sent += len_sent;
00148
00149 if ( (worked != spocket::OKAY) && (worked != spocket::PARTIAL) ) {
00150 LOG(astring("No data went out on the socket: ")
00151 + spocket::outcome_name(worked));
00152 return false;
00153 }
00154 if (len_sent != size) {
00155 LOG(a_sprintf("partial send on socket, %d bytes instead of %d, recurse.",
00156 len_sent, size));
00157 return do_a_send(buffer + len_sent, size - len_sent, stats);
00158 }
00159
00160 time_stamp end_time;
00161
00162
00163 return true;
00164 }
00165
00166 bool spocket_tester::do_a_receive(int size_expected, testing_statistics &stats)
00167 {
00168 time_stamp start_time;
00169
00170 #ifdef DEBUG_SPOCKET_TESTER
00171 LOG("into do a rcv");
00172 #endif
00173
00174 time_stamp when_to_leave(MAXIMUM_TRANSFER_WAIT);
00175 int full_length = 0;
00176 while ( (full_length < size_expected) && (time_stamp() < when_to_leave) ) {
00177 time_stamp start_of_receive;
00178 int len = MAXIMUM_WINSOCK_MTU;
00179 outcome ret = _socket->receive(receive_buffer, len);
00180 if (ret != spocket::OKAY) {
00181 if (ret == spocket::NONE_READY) {
00182 if (len != 0) LOG(a_sprintf("supposedly nothing was received (%d bytes)", len));
00184 _socket->await_readable(PAUSE_TIME);
00185 continue;
00186 } else break;
00187 }
00188
00189 if (ret == spocket::OKAY)
00190 when_to_leave.reset(MAXIMUM_TRANSFER_WAIT);
00191
00192 int receive_duration = int(time_stamp().value()
00193 - start_of_receive.value());
00194 stats.receive_time += receive_duration;
00195
00196 #ifdef DEBUG_SPOCKET_TESTER
00197 LOG(a_sprintf("did recv, len=%d", len));
00198 #endif
00199
00200 if (!len) {
00201 LOG("Our socket has been disconnected.");
00202 return false;
00203 } else if (len < 0) {
00204 if (errno == SOCK_EWOULDBLOCK) continue;
00205 LOG(astring("The receive failed with an error ")
00206 + critical_events::system_error_text(errno));
00207 return false;
00208 }
00209 full_length += len;
00210 stats.bytes_received += len;
00211 }
00212
00213 if (full_length != size_expected)
00214 LOG(a_sprintf("Did not get the full size expected (wanted %d and "
00215 "got %d bytes).", size_expected, full_length));
00216
00217 return true;
00218 }
00219
00220 bool spocket_tester::perform_test(int size, int count,
00221 testing_statistics &stats)
00222 {
00223 #ifdef DEBUG_SPOCKET_TESTER
00224 LOG("into perf test");
00225 #endif
00226
00227
00228 static abyte garbage_buffer[MAXIMUM_WINSOCK_MTU + 1];
00229 static bool garbage_initialized = false;
00230 chaos randomizer;
00231
00232
00233
00234 if (!garbage_initialized) {
00235 LOG("initializing random send buffer.");
00236
00237 for (int i = 0; i <= MAXIMUM_WINSOCK_MTU; i++)
00238 garbage_buffer[i] = randomizer.inclusive(0, 255);
00239 garbage_initialized = true;
00240 LOG("random send buffer initialized.");
00241 }
00242
00243
00244 stats.total_runs = 0;
00245 stats.send_time = 0;
00246 stats.receive_time = 0;
00247 stats.bytes_sent = 0;
00248 stats.bytes_received = 0;
00249
00250
00251 if (size > MAXIMUM_WINSOCK_MTU) {
00252 LOG("The size is over our limit. To fix this, edit the "
00253 "send_data function.");
00254 return false;
00255 }
00256
00257
00258 if (!_socket) {
00259 LOG("One cannot send data on an uninitialized tester!");
00260 return false;
00261 }
00262
00263 int runs_completed = 0;
00264
00265
00266 while (runs_completed < count) {
00267 #ifdef DEBUG_SPOCKET_TESTER
00268 LOG(a_sprintf("iter %d", runs_completed));
00269 #endif
00270 if (_socket->client()) {
00271
00272 time_stamp trip_start;
00273 #ifdef DEBUG_SPOCKET_TESTER
00274 LOG("client about to send");
00275 #endif
00276 if (!do_a_send(garbage_buffer, size, stats)) {
00277 LOG("We failed on a send. Now quitting.");
00278 return false;
00279 }
00280 #ifdef DEBUG_SPOCKET_TESTER
00281 LOG("client about to rcv");
00282 #endif
00283 if (!do_a_receive(size, stats)) {
00284 LOG("We failed on a receive. Now quitting.");
00285 return false;
00286 }
00287 stats.round_trip_time += int(time_stamp().value() - trip_start.value());
00288 } else {
00289
00290 time_stamp trip_start;
00291 #ifdef DEBUG_SPOCKET_TESTER
00292 LOG("server about to rcv");
00293 #endif
00294 if (!do_a_receive(size, stats)) {
00295 LOG("We failed on a receive. Now quitting.");
00296 return false;
00297 }
00298 #ifdef DEBUG_SPOCKET_TESTER
00299 LOG("server about to send");
00300 #endif
00301 if (!do_a_send(garbage_buffer, size, stats)) {
00302 LOG("We failed on a send. Now quitting.");
00303 return false;
00304 }
00305 stats.round_trip_time += int(time_stamp().value() - trip_start.value());
00306 }
00307
00308 runs_completed++;
00309 stats.total_runs++;
00310 if ( !(runs_completed % 10) )
00311 LOG(a_sprintf("Completed test #%d.", runs_completed));
00312 }
00313
00314 return true;
00315 }
00316