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