1 /*****************************************************************************\
3 * Name : spocket_tester *
4 * Author : Chris Koeritz *
6 *******************************************************************************
7 * Copyright (c) 2000-$now By Author. This program is free software; you can *
8 * redistribute it and/or modify it under the terms of the GNU General Public *
9 * License as published by the Free Software Foundation; either version 2 of *
10 * the License or (at your option) any later version. This is online at: *
11 * http://www.fsf.org/copyleft/gpl.html *
12 * Please send any updates to: fred@gruntose.com *
13 \*****************************************************************************/
15 #include "spocket_tester.h"
17 #include <basis/byte_array.h>
18 #include <basis/functions.h>
19 #include <basis/astring.h>
20 #include <loggers/critical_events.h>
21 #include <loggers/program_wide_logger.h>
22 #include <mathematics/chaos.h>
23 #include <sockets/internet_address.h>
24 #include <sockets/raw_socket.h>
25 #include <sockets/spocket.h>
26 #include <sockets/tcpip_definitions.h>
27 #include <sockets/tcpip_stack.h>
28 #include <timely/time_control.h>
29 #include <timely/time_stamp.h>
33 using namespace basis;
34 using namespace loggers;
35 using namespace mathematics;
36 using namespace sockets;
37 using namespace structures;
38 using namespace textual;
39 using namespace timely;
41 #define LOG(to_print) EMERGENCY_LOG(program_wide_logger().get(), astring(to_print))
43 const int MAXIMUM_WINSOCK_MTU = 100000;
44 // the largest chunk of bytes we will receive at one time.
46 const int MAXIMUM_TRANSFER_WAIT = 40 * SECOND_ms;
47 // the longest amount of time we wait in trying to receive data.
49 static abyte receive_buffer[MAXIMUM_WINSOCK_MTU + 1];
50 // used for dumping received data into.
52 const int PAUSE_TIME = 200;
53 // the snooze interval when we encounter socket underflow or overflow.
55 #define DEBUG_SPOCKET_TESTER
56 // uncomment for noisy version.
58 spocket_tester::spocket_tester(const internet_address &where)
59 : _where(new internet_address(where)),
60 _stack(new tcpip_stack),
67 spocket_tester::~spocket_tester()
76 bool spocket_tester::connect()
79 LOG("creating new client socket");
80 _socket = new spocket(*_where);
82 LOG(astring("connect socket info: ") + _socket->text_form());
83 outcome ret = spocket::NO_CONNECTION;
85 ret = _socket->connect();
86 if (ret == spocket::OKAY) break;
87 if (ret != spocket::NO_CONNECTION) break;
88 time_control::sleep_ms(100);
90 return ret == spocket::OKAY;
93 bool spocket_tester::accept(bool wait)
96 LOG("hey creating new root server socket");
97 _root_server = new spocket(*_where);
98 LOG("got past creating the root server socket");
99 LOG(astring("accept root server socket info: ") + _root_server->text_form());
102 LOG("already have a socket for accept!");
105 outcome ret = spocket::NO_CONNECTION;
106 LOG("int accepting loop on root server");
108 ret = _root_server->accept(_socket, false);
109 if (ret == spocket::OKAY) break;
110 if (ret != spocket::NO_CONNECTION) break;
111 if (!wait) return true; // we tried to accept at least once.
112 time_control::sleep_ms(100); // snooze to avoid slamming with accepts.
115 if (_socket != NIL) {
116 LOG(astring("accepted! socket info: ") + _socket->text_form());
118 return ret == spocket::OKAY;
121 bool spocket_tester::do_a_send(abyte *buffer, int size,
122 testing_statistics &stats)
124 time_stamp start_time;
126 time_stamp when_to_leave(MAXIMUM_TRANSFER_WAIT);
129 #ifdef DEBUG_SPOCKET_TESTER
130 LOG("into do a send");
133 while (time_stamp() < when_to_leave) {
134 worked = _socket->send(buffer, size, len_sent);
135 if (worked == spocket::NONE_READY) {
136 //// time_control::sleep_ms(PAUSE_TIME);
137 _socket->await_writable(PAUSE_TIME);
139 } else if (worked == spocket::PARTIAL) {
140 //danger danger if we get wrong info.
143 stats.bytes_sent += len_sent;
144 /// time_control::sleep_ms(PAUSE_TIME);
145 _socket->await_writable(PAUSE_TIME);
149 #ifdef DEBUG_SPOCKET_TESTER
150 LOG("got out of loop");
153 stats.send_time += int(time_stamp().value() - start_time.value());
154 stats.bytes_sent += len_sent;
156 if ( (worked != spocket::OKAY) && (worked != spocket::PARTIAL) ) {
157 LOG(astring("No data went out on the socket: ")
158 + spocket::outcome_name(worked));
161 if (len_sent != size) {
162 LOG(a_sprintf("partial send on socket, %d bytes instead of %d, recurse.",
164 return do_a_send(buffer + len_sent, size - len_sent, stats);
168 // int time_taken = int(end_time.value() - start_time.value());
173 bool spocket_tester::do_a_receive(int size_expected, testing_statistics &stats)
175 time_stamp start_time;
177 #ifdef DEBUG_SPOCKET_TESTER
178 LOG("into do a rcv");
181 time_stamp when_to_leave(MAXIMUM_TRANSFER_WAIT);
184 while ( (full_length < size_expected) && (time_stamp() < when_to_leave) ) {
186 time_stamp start_of_receive;
187 int len = MAXIMUM_WINSOCK_MTU;
190 LOG("WHAT? SOCKET IS NULL!!!");
192 ////time_control::sleep_ms(PAUSE_TIME);
194 LOG(astring("socket info: ") + _socket->text_form());
196 outcome ret = _socket->receive(receive_buffer, len);
198 if (ret != spocket::OKAY) {
199 if (ret == spocket::NONE_READY) {
200 if (len != 0) LOG(a_sprintf("supposedly nothing was received (%d bytes)", len));
201 /// time_control::sleep_ms(PAUSE_TIME);
202 _socket->await_readable(PAUSE_TIME);
206 // reset our time if we've gotten good data.
207 if (ret == spocket::OKAY)
208 when_to_leave.reset(MAXIMUM_TRANSFER_WAIT);
210 int receive_duration = int(time_stamp().value()
211 - start_of_receive.value());
212 stats.receive_time += receive_duration;
214 #ifdef DEBUG_SPOCKET_TESTER
215 LOG(a_sprintf("did recv, len=%d", len));
219 LOG("Our socket has been disconnected.");
221 } else if (len < 0) {
222 if (errno == SOCK_EWOULDBLOCK) continue; // no data.
223 LOG(astring("The receive failed with an error ")
224 + critical_events::system_error_text(errno));
228 stats.bytes_received += len;
231 if (full_length != size_expected)
232 LOG(a_sprintf("Did not get the full size expected (wanted %d and "
233 "got %d bytes).", size_expected, full_length));
238 bool spocket_tester::perform_test(int size, int count,
239 testing_statistics &stats)
241 #ifdef DEBUG_SPOCKET_TESTER
242 LOG("into perf test");
245 // the statics are used to generate our random buffer for sending.
246 static abyte garbage_buffer[MAXIMUM_WINSOCK_MTU + 1];
247 static bool garbage_initialized = false;
250 // if our static buffer full of random stuff was never initialized, we do
251 // so now. this supports efficiently re-using the tester if desired.
252 if (!garbage_initialized) {
253 LOG("initializing random send buffer.");
254 // note the less than or equal; we know we have one more byte to fill.
255 for (int i = 0; i <= MAXIMUM_WINSOCK_MTU; i++)
256 garbage_buffer[i] = randomizer.inclusive(0, 255);
257 garbage_initialized = true;
258 LOG("random send buffer initialized.");
261 // reset the statistical package.
262 stats.total_runs = 0;
264 stats.receive_time = 0;
265 stats.bytes_sent = 0;
266 stats.bytes_received = 0;
268 // check that they aren't trying to do too big of a send.
269 if (size > MAXIMUM_WINSOCK_MTU) {
270 LOG("The size is over our limit. To fix this, edit the "
271 "send_data function.");
275 // check that our socket is usable.
277 LOG("One cannot send data on an uninitialized tester!");
281 int runs_completed = 0;
282 // counts up how many times we've done our test cycle.
284 while (runs_completed < count) {
285 #ifdef DEBUG_SPOCKET_TESTER
286 LOG(a_sprintf("iter %d", runs_completed));
288 if (_socket->client()) {
289 // we're doing the client side routine here.
290 time_stamp trip_start;
291 #ifdef DEBUG_SPOCKET_TESTER
292 LOG("client about to send");
294 if (!do_a_send(garbage_buffer, size, stats)) {
295 LOG("We failed on a send. Now quitting.");
298 #ifdef DEBUG_SPOCKET_TESTER
299 LOG("client about to rcv");
301 if (!do_a_receive(size, stats)) {
302 LOG("We failed on a receive. Now quitting.");
305 stats.round_trip_time += int(time_stamp().value() - trip_start.value());
307 // we're doing the server side routine here.
308 time_stamp trip_start;
309 #ifdef DEBUG_SPOCKET_TESTER
310 LOG("server about to rcv");
312 if (!do_a_receive(size, stats)) {
313 LOG("We failed on a receive. Now quitting.");
316 #ifdef DEBUG_SPOCKET_TESTER
317 LOG("server about to send");
319 if (!do_a_send(garbage_buffer, size, stats)) {
320 LOG("We failed on a send. Now quitting.");
323 stats.round_trip_time += int(time_stamp().value() - trip_start.value());
326 runs_completed++; // finished a run.
327 stats.total_runs++; // count it in the overall stats too.
328 if ( !(runs_completed % 10) )
329 LOG(a_sprintf("Completed test #%d.", runs_completed));