/*
** Command & Conquer Renegade(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see .
*/
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Bandwidth Tester *
* *
* $Archive:: /Commando/Code/BandTest/BandTest.cpp $*
* *
* $Author:: Tom_s $*
* *
* $Modtime:: 3/04/02 5:50p $*
* *
* $Revision:: 17 $*
* *
* *
*---------------------------------------------------------------------------------------------*
* *
* *
*---------------------------------------------------------------------------------------------*
* *
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#define WIN32_LEAN_AND_MEAN
#include
#include
#pragma warning(disable:4201)
#include
#pragma warning(default:4201)
#include
#include
#include
#include
#include
#include "BandTest.h"
#include "..\combat\specialbuilds.h"
// warning C4711: function 'xxx' selected for automatic inline expansion
#pragma warning(disable:4711)
/***********************************************************************************************
** Data structures
*/
#pragma pack(4)
/*
** IP header definition.
*/
typedef struct tIPHeaderType {
unsigned char Length : 4; // length of the header
unsigned char Version : 4; // Version of IP (must be 4 for IP4)
unsigned char TOS; // Type of service (usually 0)
unsigned short PacketLen; // total length of the packet
unsigned short ID; // unique identifier
unsigned short Flags; // flags
unsigned char TTL; // Time to live
unsigned char Protocol; // protocol (TCP, UDP etc)
unsigned short Checksum; // IP checksum
unsigned int SourceIP; // IP this packet came from
unsigned int DestIP; // IP this packet is going to
} IPHeaderType;
/*
** ICMP packet header. Sits after the IP header when used.
*/
typedef struct tICMPHeaderType {
char Type;
char Code;
unsigned short Checksum;
unsigned short ID;
unsigned short Sequence;
} ICMPHeaderType;
/*
** UDP header. Sits after the IP header when used.
*/
typedef struct tUDPHeaderType {
unsigned short SourcePort;
unsigned short DestPort;
unsigned short Length;
unsigned short Checksum;
} UDPHeaderType;
/***********************************************************************************************
** Defines
*/
/*
** Total size of ICMP echo packet. 20 + 8
*/
#define ICMP_ECHO_SIZE 28
/*
** ICMP message numbers.
*/
#define ICMP_ECHO_REPLY 0
#define ICMP_ECHO 8
#define ICMP_TIME_EXCEEDED 11
/*
** IP protocol numbers.
*/
#define PROTOCOL_ICMP 1
#define PROTOCOL_UDP 17
/*
** Timer.
*/
#ifndef TIMER_SECOND
#define TIMER_SECOND 1000
#endif //TIMER_SECOND
/***********************************************************************************************
** Global data.
*/
/*
** Sockets.
*/
SOCKET RawSocket = INVALID_SOCKET;
SOCKET ICMPRawSocket = INVALID_SOCKET;
/*
** Registry.
*/
static HKEY RegistryKey;
//static char BandTestRegistryLocation[64] = {"Software\\Westwood\\Renegade\\BandTest\\"};
#if defined(FREEDEDICATEDSERVER)
static char BandTestRegistryLocation[64] = {"Software\\Westwood\\RenegadeFDS\\BandTest\\"};
#elif defined(MULTIPLAYERDEMO)
static char BandTestRegistryLocation[64] = {"Software\\Westwood\\RenegadeMPDemo\\BandTest\\"};
#elif defined(BETACLIENT)
static char BandTestRegistryLocation[64] = {"Software\\Westwood\\RenegadeBeta\\BandTest\\"};
#else
static char BandTestRegistryLocation[64] = {"Software\\Westwood\\Renegade\\BandTest\\"};
#endif
static char RegistryPath[1024];
/*
** Packet loss.
*/
int PingsSent = 0;
int PingsLost = 0;
/*
** Connection quality.
*/
int NumConsistentPings = 0;
int NumPingsCheckedForConsistency = 0;
/*
** State.
*/
bool StatsValid = false;
#ifdef _DEBUG
HANDLE DebugFile = INVALID_HANDLE_VALUE;
char DebugFileName[256];
#endif //_DEBUG
/***********************************************************************************************
** Function prototypes.
*/
static bool Open_Raw_Sockets(int &failure_code);
static void Close_Raw_Sockets(void);
static bool Send_Ping(char *payload, int payload_size, SOCKET socket, struct sockaddr *address, int sequence_id);
static bool Get_Ping_Response(SOCKET socket, int &seq_id, struct sockaddr *address, unsigned long validate_addr, unsigned long &my_address);
static unsigned short Get_IP_Checksum(unsigned short *buffer, int size);
static bool Send_Raw_UDP(char *payload, int payload_size, SOCKET socket, struct sockaddr *address, unsigned short source_port, unsigned short dest_port);
static unsigned long Upstream_Detect(unsigned long server_ip, unsigned long my_ip, int &failure_code, unsigned long &downstream, BandtestSettingsStruct *settings);
static int Ping_Host(unsigned long host_ip, unsigned long my_ip, int times, int payload_size, unsigned long *ping_times, unsigned long timeout);
static float Average_Ping(int num_pings, unsigned long *ping_times, bool ignore_low_high);
static float Lowest_Ping(int num_pings, unsigned long *ping_times);
static int Get_Path_To_Server(unsigned long *path, unsigned long my_ip, unsigned long server_ip);
static void Ping_Profile(SOCKADDR_IN *router_addr, unsigned long my_ip);
static bool Set_Registry_Int(const char *name, int value);
static int Get_Registry_Int(const char *name, int def_value);
static bool Open_Registry(void);
static void Close_Registry(void);
#ifdef _DEBUG
void DebugString (char const * string, ...);
char * Addr_As_String2(struct sockaddr_in *addr);
char * Addr_As_String(unsigned char *addr);
#else //_DEBUG
#define DebugString
//_forceinline void DebugString(char const *, ...) {};
//inline char * Addr_As_String(sockaddr_in *) {};
inline char * Addr_As_String(unsigned char *) {return NULL;};
inline char * Addr_As_String2(struct sockaddr_in *){return NULL;};
#endif //_DEBUG
/*
** Default settings.
*/
BandtestSettingsStruct DefaultSettings = {
0, //AlwaysICMP
0, //TTLScatter
50, //FastPingPackets
20, //SlowPingPackets
15, //FastPingThreshold
0, //PingProfile
};
/***********************************************************************************************
** Your actual Code. No, really.
*/
/***********************************************************************************************
* DllMain -- Dll entry point. Not used for much *
* *
* *
* *
* INPUT: Nothing *
* *
* OUTPUT: Nothing *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 10/3/2001 11:20AM ST : Created *
*=============================================================================================*/
bool APIENTRY DllMain(HANDLE, DWORD, void *)
{
return(true);
}
/***********************************************************************************************
* Detect_Upstream_Bandwidth -- Try and figure out what our upstream bandwidth is *
* *
* *
* *
* INPUT: IP address of server to use as destination IP in tests.Server receives no packets *
* My IP. *
* Number of times to retry on error *
* (out) Extended error code *
* *
* OUTPUT: Bandwidth in bits per second. 0 = couldn't detect. 0xffffffff means **BIG** *
* *
* WARNINGS: All IPs in host order *
* *
* *
* HISTORY: *
* 10/3/2001 11:21AM ST : Created *
*=============================================================================================*/
BANDTEST_API unsigned long Detect_Bandwidth(unsigned long server_ip, unsigned long my_ip, int retries, int &failure_code, unsigned long &downstream, unsigned long api_version, BandtestSettingsStruct *settings, char *regpath)
{
if (api_version != BANDTEST_API_VERSION) {
return(BANDTEST_WRONG_API_VERSION);
}
if (regpath == NULL) {
strcpy(RegistryPath, BandTestRegistryLocation);
} else {
strcpy(RegistryPath, regpath);
}
if (!Open_Registry()) {
failure_code = BANDTEST_UNKNOWN_ERROR;
return(0);
}
timeBeginPeriod(1);
PingsSent = 0;
PingsLost = 0;
NumConsistentPings = 0;
NumPingsCheckedForConsistency = 0;
StatsValid = false;
int tried = 0;
int bps = 0;
if (settings == NULL) {
settings = &DefaultSettings;
}
while (tried < retries + 1) {
tried++;
bps = Upstream_Detect(server_ip, my_ip, failure_code, downstream, settings);
if (bps != 0) {
StatsValid = true;
if (PingsSent) {
DebugString("Packet loss: %d percent\n", (100 * PingsLost) / PingsSent);
Set_Registry_Int("PingLoss", (100 * PingsLost) / PingsSent);
if (NumPingsCheckedForConsistency) {
DebugString("Connection quality: %d percent\n", (100 * NumConsistentPings) / NumPingsCheckedForConsistency);
Set_Registry_Int("Quality", (100 * NumConsistentPings) / NumPingsCheckedForConsistency);
}
}
break;
}
/*
** Error. See what the error code tells us.
*/
switch (failure_code) {
/*
** Fatal errors.
*/
case BANDTEST_NO_WINSOCK2:
case BANDTEST_NO_RAW_SOCKET_PERMISSION:
case BANDTEST_NO_RAW_SOCKET_CREATE:
case BANDTEST_NO_UDP_SOCKET_BIND:
tried = retries + 1;
break;
/*
** Erros where retrying might help.
*/
case BANDTEST_NO_TTL_SET:
case BANDTEST_NO_PING_RESPONSE:
case BANDTEST_NO_FINAL_PING_TIME:
case BANDTEST_NO_EXTERNAL_ROUTER:
case BANDTEST_NO_IP_DETECT:
break;
/*
** Errors we should never get.
*/
case BANDTEST_OK:
case BANDTEST_UNKNOWN_ERROR:
case BANDTEST_BAD_PARAM:
default:
DebugString("Failed with error code %d\n", failure_code);
//assert(false);
break;
}
if (tried < retries + 1) {
DebugString("Retry %d\n", tried);
}
}
timeEndPeriod(1);
Close_Registry();
return(bps);
}
/***********************************************************************************************
* Upstream_Detect-- Try and figure out what our upstream bandwidth is *
* *
* *
* *
* INPUT: IP address of server to use as destination IP in tests.Server receives no packets *
* My IP. *
* (out) Extended error code *
* *
* OUTPUT: Bandwidth in bits per second. 0 = couldn't detect. 0xffffffff means **BIG** *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 10/3/2001 11:21AM ST : Created *
*=============================================================================================*/
unsigned long Upstream_Detect(unsigned long server_ip, unsigned long my_ip, int &failure_code, unsigned long &downstream, BandtestSettingsStruct *settings)
{
struct sockaddr_in host_address;
struct sockaddr_in address;
char temp_buffer[640];
int seq_id;
int router_ttl = 0;
struct sockaddr_in router_addr;
unsigned short source_port = 1230;
int ttl;
unsigned short packet_sequencer = 0;
float average_ping = 0.0f;
//float lowest_ping = 0.0f;
unsigned long ping_dest_address = 0;
unsigned long path_to_server[256];
int hops_to_server = 0;
unsigned long upstream_bandwidth;
unsigned long ping_times[100];
unsigned long performance_timer = timeGetTime();
unsigned long detect_start_time = performance_timer;
int i;
/*
** Fill the temp buffer with garbage so it doesn't compress so well on modems.
*/
srand(timeGetTime());
for (int b=0 ; b 2500) {
DebugString("Failed to get response to IP detect ping\n");
failure_code = BANDTEST_NO_IP_DETECT;
Close_Raw_Sockets();
return(0);
}
};
/*
** See if the router is on the same network as me.
*/
if (seq_id == 50) {
my_ip = ping_dest_address;
#ifdef _DEBUG
ping_dest_address = htonl(my_ip);
DebugString("Detected my IP as %s\n", Addr_As_String((unsigned char*)&ping_dest_address));
#endif //_DEBUG
} else {
DebugString("Unexpected response to IP detect ping\n");
failure_code = BANDTEST_NO_IP_DETECT;
Close_Raw_Sockets();
return(0);
}
DebugString("Took %d ms to discover my IP address\n", timeGetTime() - performance_timer);
}
/*
** Get the path to the server.
**
*/
performance_timer = timeGetTime();
hops_to_server = Get_Path_To_Server(&path_to_server[0], my_ip, server_ip);
DebugString("Took %d ms to find path to server\n", timeGetTime() - performance_timer);
if (hops_to_server == 0) {
DebugString("Failed to get path to server\n");
failure_code = BANDTEST_NO_EXTERNAL_ROUTER;
Close_Raw_Sockets();
return(0);
}
/*
** Dump out the whole path to the server.
*/
#ifdef _DEBUG
DebugString("Found path to server...\n");
for (i=0 ; i 3) {
first_router = 2;
}
for (i=first_router ; i 100) {
num_pings = 6;
}
}
pings = Ping_Host(path_to_server[i], my_ip, num_pings, 0, ping_times, timeout);
if (pings) {
//lowest_ping = Lowest_Ping(pings, ping_times);
average_ping = Average_Ping(pings, ping_times, true);
//DebugString("Lowest ping time to external router is %.2f ms\n", lowest_ping);
DebugString("Average ping time to external router is %.2f ms\n", average_ping);
DebugString("Took %d ms to find average ping\n", timeGetTime() - performance_timer);
performance_timer = timeGetTime();
break;
} else {
DebugString("Failed to ping external router\n");
failure_code = BANDTEST_NO_PING_RESPONSE;
Close_Raw_Sockets();
return(0);
}
}
}
}
if (router_ttl == 0) {
DebugString("Failed to find external router\n");
failure_code = BANDTEST_NO_EXTERNAL_ROUTER;
Close_Raw_Sockets();
return(0);
}
assert(router_ttl != 0);
/*
** If the ping time is low, it's *probably* a high bandwidth connection so we can get a more accurate test by sending more
** packets without taking tooooo long.
*/
int num_udp_packets = settings->SlowPingPackets;
unsigned long timeout = 8*TIMER_SECOND;
if (average_ping < (float)(settings->FastPingThreshold)) {
num_udp_packets = settings->FastPingPackets;
timeout = 4*TIMER_SECOND;
}
/*
** Set the UDP TTL to the next router down the list after the one we just pinged.
*/
SOCKET test_socket = RawSocket;
if (settings->AlwaysICMP) {
test_socket = ICMPRawSocket;
}
ttl = router_ttl + 1;
int result = setsockopt(test_socket, IPPROTO_IP, IP_TTL, (char*)&ttl, sizeof(ttl));
if (result == SOCKET_ERROR) {
DebugString("setsockopt failed to set IP_TTL = %d on test socket - error code %d\n", ttl, WSAGetLastError());
failure_code = BANDTEST_NO_TTL_SET;
Close_Raw_Sockets();
return(0);
}
/*
** Make the UDP socket buffer a bit bigger. Not really important...
*/
int socket_transmit_buffer_size = 128000;
result = setsockopt(test_socket, SOL_SOCKET, SO_RCVBUF, (char*)&socket_transmit_buffer_size, 4);
if (result == SOCKET_ERROR) {
DebugString("setsockopt failed to set SO_RECVBUF with error code %d\n", WSAGetLastError());
}
/*
** Make a note of the current time so we can see how long this whole process takes.
*/
unsigned long start_time = timeGetTime();
int base_ttl = ttl;
int max_ttl = hops_to_server - 1;
if (max_ttl < base_ttl) {
max_ttl = base_ttl;
}
performance_timer = timeGetTime();
/*
** Send a shitload of UDP packets to the next router down the list after the one we just pinged.
*/
DebugString("Sending %d 500 byte UDP packets\n", num_udp_packets);
for (i=0 ; iTTLScatter) {
ttl++;
if (ttl > max_ttl) {
ttl = base_ttl;
}
int result = setsockopt(test_socket, IPPROTO_IP, IP_TTL, (char*)&ttl, sizeof(ttl));
if (result == SOCKET_ERROR) {
DebugString("setsockopt failed to set IP_TTL = %d on test socket - error code %d\n", ttl, WSAGetLastError());
failure_code = BANDTEST_NO_TTL_SET;
}
}
/*
** We have to fill the packet with different garbage every time we send it otherwise a modem will be able to
** do delta compression on the packets.
*/
for (int b=0 ; bAlwaysICMP) {
Send_Ping(temp_buffer, 466, ICMPRawSocket, (struct sockaddr *) &host_address, 0);
} else {
Send_Raw_UDP(temp_buffer, 466, RawSocket, (struct sockaddr *) &host_address, 1234, 4321);
}
}
DebugString("Took %d ms to send bulk packets\n", timeGetTime() - performance_timer);
performance_timer = timeGetTime();
/*
** Set the TTL to max on the ICMP socket. This shouldn't be needed but I'm doing it just in case there are any bugs in
** windoze that might confuse TTL settings between sockets.
*/
ttl = 255;
result = setsockopt(ICMPRawSocket, IPPROTO_IP, IP_TTL, (char*)&ttl, sizeof(ttl));
if (result == SOCKET_ERROR) {
DebugString("setsockopt failed to set IP_TTL = %d - error code %d\n", ttl, WSAGetLastError());
}
/*
** Now see what the ping time to the router is. Since there are n UDP packets ahead of this ping before it goes out, the
** ping time will include the time taken to send the UDP packets.
*/
unsigned long new_router_ping_time = 0xffffffff;
packet_sequencer = 5;
unsigned long second_start_time = timeGetTime();
float total_time = 0.0f;
/*
** Send a couple of pings to reduce the possibility of packet loss being a factor.
*/
Send_Ping((char*)temp_buffer, 0, ICMPRawSocket, (struct sockaddr *) &router_addr, packet_sequencer);
Send_Ping((char*)temp_buffer, 0, ICMPRawSocket, (struct sockaddr *) &router_addr, packet_sequencer + 1);
seq_id = -1;
while (seq_id != packet_sequencer && seq_id != packet_sequencer+1) {
Get_Ping_Response(ICMPRawSocket, seq_id, (struct sockaddr *) &address, 0, ping_dest_address);
if (timeGetTime() - second_start_time > timeout) {
break;
}
};
if (seq_id == packet_sequencer || seq_id == packet_sequencer + 1) {
unsigned long time_now = timeGetTime();
new_router_ping_time = time_now - second_start_time;
total_time = (float)(time_now - start_time);
DebugString("Ping time to external router is now %d ms\n", new_router_ping_time);
DebugString("Total time to send %d bytes plus send and receive ping is %d ms\n", num_udp_packets * 500, total_time);
} else {
DebugString("Failed to get final ping response in %d seconds\n", timeout / 1000);
failure_code = BANDTEST_NO_FINAL_PING_TIME;
Close_Raw_Sockets();
return(0);
}
if (new_router_ping_time == 0xffffffff) {
DebugString("Failed to get final ping response\n");
failure_code = BANDTEST_NO_FINAL_PING_TIME;
return(0);
} else {
total_time -= average_ping;
/*
** Work out the bandwidth.
** Approx bps up = ((10000 + 28) * 8) / (time2 - time1).
*/
if (((unsigned long) total_time) == 0 || (total_time > ((float)0x10000000))) {
DebugString("Upstream bandwidth is huge :-)\n");
failure_code = BANDTEST_OK;
upstream_bandwidth = 0xffffffff;
} else {
unsigned long bw = (((num_udp_packets * 500) * 8) * 1000) / (unsigned long)total_time;
if (bw > 100000) {
float floater = (float)bw / 1024;
DebugString("Upstream bandwidth to external router is %.1f kilobits per second\n", floater);
} else {
DebugString("Upstream bandwidth to external router is %d bits per second\n", bw);
}
failure_code = BANDTEST_OK;
upstream_bandwidth = bw;
//return(bw);
}
}
DebugString("Took %d ms to get new ping time\n", timeGetTime() - performance_timer);
/*
** If the bandwidth in the registry is close to what we just calculated then use the old downstream calculation from the
** registry.
*/
unsigned long downstream_bandwidth = upstream_bandwidth;
int old_band = Get_Registry_Int("Up", 0);
unsigned long diff = abs(upstream_bandwidth - old_band);
bool calc_down = true;
if (diff < upstream_bandwidth / 10) {
downstream_bandwidth = Get_Registry_Int("Down", upstream_bandwidth);
if (downstream_bandwidth) {
calc_down = false;
}
}
/*
** Store the calculated bandwidth into the registry.
*/
Set_Registry_Int("Up", upstream_bandwidth);
/*
**
** Well, I suppose, since we are here, we might as well have a stab at downstream bandwidth too.
**
**
** Try sending max size pings to our friendly router and subtracting how long we think the upstream should have taken
** from the average ping time. Assume the routers latency is 0 (which of course it isn't).
*/
bool method_one = false;
//float average_time_exceeded = 0.0f;
performance_timer = timeGetTime();
if (calc_down && upstream_bandwidth < 576 * 1000 && upstream_bandwidth > 8) {
int new_ping_timeout = max((int)(average_ping * 5), 200);
#if (0)
if (upstream_bandwidth > 80000) {
method_one = true;
}
if (method_one) {
DebugString("Detecting downstream bandwidth - method 1\n");
ttl = router_ttl + 1;
int result = setsockopt(RawSocket, IPPROTO_IP, IP_TTL, (char*)&ttl, sizeof(ttl));
if (result == SOCKET_ERROR) {
DebugString("setsockopt failed to set IP_TTL = %d on test socket - error code %d\n", ttl, WSAGetLastError());
failure_code = BANDTEST_NO_TTL_SET;
Close_Raw_Sockets();
return(0);
}
/*
** First we had better wait for all those time exceeded packets to come back.
*/
seq_id = -1;
start_time = timeGetTime();
unsigned long last_icmp_in_time = start_time;
for (;;) {
Get_Ping_Response(ICMPRawSocket, seq_id, (struct sockaddr *) &address, ntohl(host_address.sin_addr.s_addr), ping_dest_address);
if (seq_id != -1) {
seq_id = -1;
last_icmp_in_time = timeGetTime();
}
if (timeGetTime() - start_time > 3*TIMER_SECOND) {
break;
}
if (timeGetTime() - last_icmp_in_time > TIMER_SECOND / 2) {
break;
}
}
/*
** Send a shitload of UDP packets to the next router down the list after the one we just pinged.
** Wait for a response for each packet before sending the next.
*/
num_udp_packets = 50;
DebugString("Sending %d 500 byte UDP packets\n", num_udp_packets);
int num_pings = 0;
for (i=0 ; i (unsigned long)new_ping_timeout) {
break;
}
}
}
/*
** This is the average time taken to get the TIME EXCEEDED message back.
*/
DebugString("Quickest time exceeded came in after %.2f ms\n", Lowest_Ping(num_pings, ping_times));
average_time_exceeded = Average_Ping(num_pings, ping_times, true);
DebugString("Average time exceeded came in after %.2f ms\n", average_time_exceeded);
}
#endif //(0)
DebugString("Detecting downstream bandwidth - method 2\n");
/*
** First we had better wait for all those time exceeded packets to come back.
*/
seq_id = -1;
start_time = timeGetTime();
unsigned long last_icmp_in_time = start_time;
for (;;) {
Get_Ping_Response(ICMPRawSocket, seq_id, (struct sockaddr *) &address, ntohl(host_address.sin_addr.s_addr), ping_dest_address);
if (seq_id != -1) {
seq_id = -1;
last_icmp_in_time = timeGetTime();
}
if (timeGetTime() - start_time > 3*TIMER_SECOND) {
break;
}
if (timeGetTime() - last_icmp_in_time > TIMER_SECOND / 2) {
break;
}
}
//int new_ping_timeout = max((int)(average_ping * 5), 200);
float old_average_ping = average_ping;
//float old_lowest_ping = lowest_ping;
average_ping = 0.0f;
/*
** Set the TTL back to max.
*/
int new_ttl = 255;
int result = setsockopt(ICMPRawSocket, IPPROTO_IP, IP_TTL, (char*)&new_ttl, sizeof(new_ttl));
if (result == SOCKET_ERROR) {
DebugString("setsockopt failed to set IP_TTL = %d - error code %d\n", new_ttl, WSAGetLastError());
failure_code = BANDTEST_NO_TTL_SET;
Close_Raw_Sockets();
return(upstream_bandwidth);
}
/*
** Ping the router once to get a ballpark trip time.
*/
int pings = Ping_Host(ntohl(router_addr.sin_addr.s_addr), my_ip, 1, 540, ping_times, new_ping_timeout);
if (pings == 0) {
pings = Ping_Host(ntohl(router_addr.sin_addr.s_addr), my_ip, 1, 540, ping_times, 2 * TIMER_SECOND);
if (pings == 0) {
pings = Ping_Host(ntohl(router_addr.sin_addr.s_addr), my_ip, 1, 540, ping_times, 2 * TIMER_SECOND);
}
}
if (pings) {
/*
** Do more pings if the ping time is low. User a smaller timeout too.
*/
int num_pings = 15;
unsigned long timeout = ping_times[0] * 3;
if (ping_times[0] < 100) {
num_pings = 50;
timeout = 200;
} else {
if (ping_times[0] > 250) {
num_pings = 6;
}
}
if (method_one) {
num_pings = 50;
}
DebugString("Sending large pings\n");
pings = Ping_Host(ntohl(router_addr.sin_addr.s_addr), my_ip, num_pings, 540, ping_times, timeout);
if (pings) {
//lowest_ping = Lowest_Ping(pings, ping_times);
DebugString("Quickest ping came in after %.2f ms\n", Lowest_Ping(num_pings, ping_times));
average_ping = Average_Ping(pings, ping_times, true);
//DebugString("Lowest ping time to external router is now %.2f ms\n", lowest_ping);
DebugString("Average ping time to external router is now %.2f ms\n", average_ping);
} else {
DebugString("Failed to ping external router\n");
failure_code = BANDTEST_NO_PING_RESPONSE;
Close_Raw_Sockets();
return(upstream_bandwidth);
}
/*
** Just to make sure we can never get a divide by 0.
*/
if (upstream_bandwidth / 8 == 0) {
upstream_bandwidth = 56000;
}
float time_upstream = (1000.0f * 540.0f) / ((float)(upstream_bandwidth / 8));
DebugString("Time upstream is %.1f ms\n", time_upstream);
float time_downstream = (float)((average_ping - time_upstream) - old_average_ping);
/*
** 576 bytes took 'time_downstream' ms to come downstream.
*/
if (time_downstream > 0.0) {
float dbw = ((1000.0f / time_downstream) * 4320.0f); // 540*8 = 4320
//downstream_bandwidth = ((1000.0f / time_downstream) * 576 * 8);
downstream_bandwidth = (int)dbw;
}
DebugString("Took %d ms to calculate downstream bandwidth\n", timeGetTime() - performance_timer);
Set_Registry_Int("Down", downstream_bandwidth);
}
}
if (settings->PingProfile) {
Ping_Profile(&router_addr, my_ip);
}
Close_Raw_Sockets();
if (downstream_bandwidth > 100000) {
float floater = (float)downstream_bandwidth / 1024;
DebugString("Downstream bandwidth from external router is %.1f kilobits per second\n", floater);
} else {
DebugString("Downstream bandwidth from external router is %d bits per second\n", downstream_bandwidth);
}
/*
** Method 1 just uses the difference between then time exceeded pings and the echo pings.
*/
#if (0)
if (method_one) {
float time_down = average_ping - average_time_exceeded;
if (time_down > 0) {
float bps_down = (1000.0f / time_down) * (float)(540);
bps_down = bps_down * 8.0f;
if (bps_down > 100000) {
float floater = (float)bps_down / 1024;
DebugString("Downstream bandwidth from external router by alt method is %.1f kilobits per second\n", floater);
} else {
DebugString("Downstream bandwidth from external router by alt method is %f bits per second\n", bps_down);
}
}
}
#endif //(0)
/*
** Assume down is at least as much as up.
*/
if (downstream_bandwidth < upstream_bandwidth) {
downstream_bandwidth = upstream_bandwidth;
}
downstream = downstream_bandwidth;
DebugString("Total time to detect bandwidth = %d ms\n", timeGetTime() - detect_start_time);
failure_code = BANDTEST_OK;
return(upstream_bandwidth);
}
void Ping_Profile(SOCKADDR_IN *router_addr, unsigned long my_ip)
{
float ping_averages[1000];
unsigned long ping_times[100];
char temp_buffer[128];
char temp_graph[30][80];
static char _ping_graph[30][80] = {
" ms| \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" Ping | \n",
" Time | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" ms| \n",
"________|_______________________________________________________\n",
" 0 Payload Size 540\n",
" \n",
" \n",
};
DebugString("Profiling ping responses\n");
memcpy(temp_graph, _ping_graph, sizeof(temp_graph));
/*
** Set the TTL back to max.
*/
int new_ttl = 255;
int result = setsockopt(ICMPRawSocket, IPPROTO_IP, IP_TTL, (char*)&new_ttl, sizeof(new_ttl));
if (result == SOCKET_ERROR) {
DebugString("setsockopt failed to set IP_TTL = %d - error code %d\n", new_ttl, WSAGetLastError());
}
int ping_number = 0;
for (int packet_size = 0 ; packet_size < 541 ; packet_size += 10) {
/*
** Ping the router once to get a ballpark trip time.
*/
int pings = Ping_Host(ntohl(router_addr->sin_addr.s_addr), my_ip, 1, packet_size, ping_times, 1000);
if (pings == 0) {
pings = Ping_Host(ntohl(router_addr->sin_addr.s_addr), my_ip, 1, packet_size, ping_times, 2 * TIMER_SECOND);
if (pings == 0) {
pings = Ping_Host(ntohl(router_addr->sin_addr.s_addr), my_ip, 1, packet_size, ping_times, 2 * TIMER_SECOND);
}
}
if (pings) {
/*
** Do more pings if the ping time is low. User a smaller timeout too.
*/
int num_pings = 15;
unsigned long timeout = ping_times[0] * 3;
if (ping_times[0] < 100) {
num_pings = 30;
timeout = 200;
} else {
if (ping_times[0] > 250) {
num_pings = 6;
}
}
DebugString("Sending %d byte pings\n", packet_size);
pings = Ping_Host(ntohl(router_addr->sin_addr.s_addr), my_ip, num_pings, packet_size, ping_times, timeout);
if (pings) {
float average_ping = Average_Ping(pings, ping_times, true);
DebugString("Average ping time to external router is now %.2f ms\n", average_ping);
ping_averages[ping_number] = average_ping;
} else {
DebugString("Failed to ping external router\n");
ping_averages[ping_number] = 0.0;
}
}
ping_number++;
}
/*
** Scale the ping graph.
*/
float min_ping = 10000.0f;
float max_ping = -1.0f;
for (int i=0 ; i 1500) {
DebugString("Failed to get any response to ping with TTL = %d\n", ttl);
break;
}
};
if (seq_id != -1) {
unsigned long long_router_addr = ntohl(address.sin_addr.s_addr);
path[hops_to_server++] = long_router_addr;
/*
** See if this router is the target. If so, we are at the end of the path.
*/
if (long_router_addr == server_ip || seq_id == packet_sequencer) {
break;
}
}
packet_sequencer++;
}
/*
** If we got a good path then store it in the registry.
*/
if (hops_to_server > 0 && path[hops_to_server - 1] == server_ip) {
Set_Registry_Int("MyIP", my_ip);
Set_Registry_Int("ServerIP", server_ip);
Set_Registry_Int("PathLength", hops_to_server);
Set_Registry_Int("PathValid", (int)timeGetTime());
for (int i=0 ; i timeout) {
DebugString("Failed to get response to reference ping %d\n", i);
PingsLost++;
break;
}
};
/*
** Check the time now and record it as a ping time.
*/
if (seq_id == _packet_sequencer) {
unsigned long router_ping_time = timeGetTime() - start_time;
DebugString("Ping time %d to external router %s is %d ms\n", num_pings, Addr_As_String2(&host_addr), router_ping_time);
ping_times[num_pings++] = router_ping_time;
}
_packet_sequencer++;
}
/*
** Try and get a measure of how far off center some of the pings are.
*/
if (num_pings > 5) {
NumPingsCheckedForConsistency += num_pings;
unsigned long *ping_copies = (unsigned long*) _alloca(num_pings * 4);
memcpy(ping_copies, ping_times, num_pings * 4);
float average_ping = Average_Ping(num_pings, ping_copies, true);
float error_permit = 0.25f;
if (average_ping < 100.0f) {
error_permit = 0.35f;
}
if (average_ping < 30.0f) {
error_permit = 0.5f;
}
for (int p=0 ; p 2) {
Sort_Pings(num_pings, ping_times);
memmove((char*)ping_times, ((char*)ping_times) + 4, 4 * (num_pings - 2));
num_pings -= 2;
}
float average_ping = 0.0;
for (int i=0 ; i 5) {
float filter_percent = 0.25f;
if (average_ping < 10.0) {
filter_percent = 0.30f;
}
float new_average = 0;
int num_considered = 0;
for (int i=0 ; i 3) {
average_ping = new_average / (float) num_considered;
}
}
return(average_ping);
}
/***********************************************************************************************
* Lowest_Ping -- Get the lowest ping time from a list of pings. *
* *
* *
* *
* INPUT: Number of pings *
* Ptr to ping times array *
* *
* OUTPUT: Nothing *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 10/9/2001 5:03PM ST : Created *
*=============================================================================================*/
float Lowest_Ping(int num_pings, unsigned long *ping_times)
{
float lowest_ping = 1000000.0;
for (int i=0 ; i= 1024);
assert(dest_port >= 1024);
assert(address != NULL);
if (address == NULL) {
return(false);
}
if (payload_size > 550) {
return(false);
}
/*
** Build the header on the stack for convenience.
*/
unsigned char packetbuf[1024];
UDPHeaderType *header = (UDPHeaderType*) packetbuf;
/*
** Fill in the header fields.
*/
header->SourcePort = source_port;
header->DestPort = htons(dest_port);
header->Length = (unsigned short) (sizeof(UDPHeaderType) + payload_size);
header->Checksum = 0;
/*
** Copy the payload into place.
*/
char *payload_ptr = ((char*)header) + sizeof(UDPHeaderType);
memcpy(payload_ptr, payload, payload_size);
/*
** Fix up the UDP header checksum.
*/
int packet_size = payload_size + sizeof(*header);
header->Checksum = Get_IP_Checksum((unsigned short *)header, packet_size);
/*
** Send it.
*/
((struct sockaddr_in*)address)->sin_port = htons(dest_port);
int result = sendto(socket, (char*)header, packet_size, 0, address, sizeof(*address));
if (result == SOCKET_ERROR) {
DebugString("Send_Raw_UDP - sendto failed with error code %d\n", WSAGetLastError());
return(false);
}
if (result != packet_size) {
return(false);
}
return(true);
}
/***********************************************************************************************
* Send_Ping -- Use raw ICMP socket to send a ping message. *
* *
* *
* *
* INPUT: Ptr to buffer to copy packet payload from *
* Size of packet payload *
* Socket to use *
* Address to ping *
* *
* OUTPUT: True if ping sent OK *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 10/3/2001 11:51AM ST : Created *
*=============================================================================================*/
bool Send_Ping(char *payload, int payload_size, SOCKET socket, struct sockaddr *address, int sequence_id)
{
//DebugString("Send ping. payload=%08X, size=%d, socket=%d, address=%s, seq_id=%d\n", payload, payload_size, socket, Addr_As_String2((struct sockaddr_in *)address), sequence_id);
/*
** Asserts.
*/
assert(payload_size < 550);
assert(socket != INVALID_SOCKET);
assert(address != NULL);
if (address == NULL) {
return(false);
}
if (payload_size > 550) {
return(false);
}
/*
** Build the header on the stack for convenience.
*/
unsigned char packetbuf[1024];
ICMPHeaderType *header = (ICMPHeaderType*) packetbuf;
/*
** Set up the ICMP header fields.
*/
header->Type = ICMP_ECHO;
header->Code = 0;
header->ID = (unsigned short) (GetCurrentProcessId() & 0xffff);
header->Checksum = 0;
header->Sequence = (unsigned short) sequence_id;
/*
** Copy the payload into position.
*/
char *payload_ptr = ((char*)header) + sizeof(ICMPHeaderType);
memcpy(payload_ptr, payload, payload_size);
/*
** Fix up the checksum in the ICMP header.
*/
int packet_size = payload_size + sizeof(*header);
header->Checksum = Get_IP_Checksum((unsigned short *)header, packet_size);
/*
** Send it.
*/
//DebugString("sendto\n");
int result = sendto(socket, (char*)header, packet_size, 0, address, sizeof(*address));
//DebugString("returned from sendto\n");
if (result == SOCKET_ERROR) {
DebugString("sendto failed with error code %d\n", WSAGetLastError());
return(false);
}
if (result != packet_size) {
return(false);
}
return(true);
}
/***********************************************************************************************
* Get_Ping_Response -- Wait for an ICMP echo reply or time exceeded message *
* *
* *
* *
* INPUT: Socket *
* Packet sequence id to look for *
* (out) Ptr to buffer to put sender address in *
* Address to use to validate pings (i.e. address ping was sent to) *
* (out) My address - filled in on ping responses *
* *
* OUTPUT: True if we got a ping response *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 10/3/2001 12:57PM ST : Created *
*=============================================================================================*/
bool Get_Ping_Response(SOCKET socket, int &seq_id, struct sockaddr *address, unsigned long validate_address, unsigned long &my_address)
{
struct sockaddr_in addr;
int addr_len;
char recv_buffer[1024];
unsigned long bytes;
int result = ioctlsocket(socket, FIONREAD, &bytes);
/*
** Result of 0 is success.
*/
if (result != 0) {
Sleep(0);
return(false);
} else {
/*
** If there is outstanding data, 'bytes' will contain the size of the next queued datagram.
*/
if (bytes == 0) {
Sleep(0);
return(false);
} else {
/*
** Call recvfrom function to get the outstanding packet.
*/
addr_len = sizeof(addr);
result = recvfrom(socket, recv_buffer, sizeof(recv_buffer), 0, (LPSOCKADDR)&addr, &addr_len);
if (result == SOCKET_ERROR) {
DebugString("recvfrom failed with error code %d\n", WSAGetLastError());
return(false);
}
//DebugString("Get_Ping_Response - received packet %d bytes long\n", result);
//DebugString("Get_Ping_Response - recvfrom %s\n", Addr_As_String2(&addr));
if (result < (sizeof(IPHeaderType) + sizeof(ICMPHeaderType))) {
DebugString("Get_Ping_Response - packet header too small\n");
return(false);
}
/*
** Decode the ping response. We get the IP header and all.
*/
IPHeaderType *ip_header = (IPHeaderType*) recv_buffer;
/*
** Get the header length. Length specified in the header is in longs so multiply it by 4 to get bytes.
*/
int ip_header_size = ip_header->Length * 4;
if (result < (ip_header_size + (int)sizeof(ICMPHeaderType))) {
DebugString("Get_Ping_Response - packet header reported size too big\n");
return(false);
}
if (ip_header->Protocol == PROTOCOL_ICMP) {
//DebugString("Protocol is ICMP\n");
/*
** Figure out where the ICMP header is.
*/
//IPHeaderType *ip_header = (IPHeaderType*) recv_buffer;
ICMPHeaderType *icmp_header = (ICMPHeaderType*) (recv_buffer + ip_header_size);
my_address = ntohl(ip_header->DestIP);
switch (icmp_header->Type) {
/*
** An echo reply is basically a ping response.
*/
case ICMP_ECHO_REPLY:
//DebugString("Type is ICMP_ECHO_REPLY\n");
if (icmp_header->ID == (unsigned short)(GetCurrentProcessId() & 0xffff)) {
memcpy(address, &addr, addr_len);
seq_id = icmp_header->Sequence;
return(true);
}
break;
/*
** A time exceeded is sent when a router discards a packet due to a TTL of 0.
*/
case ICMP_TIME_EXCEEDED:
//DebugString("Type is ICMP_TIME_EXCEEDED\n");
{
/*
** Find the packets original IP header. ICMP_TIME_EXCEEDED is 8 bytes followed by a copy of the original IP
** header followed by the original ICMP header followed by 64 bits of the original payload. Phew. (the original
** payload seems to be frequently lost).
*/
IPHeaderType *original_ip_header = (IPHeaderType*)(((char*)icmp_header) + 8);
if (ntohl(original_ip_header->DestIP) == validate_address) {
DebugString("Received ICMP_TIME_EXCEEDED from %s\n", Addr_As_String((unsigned char*)&ip_header->SourceIP));
memcpy(address, &addr, addr_len);
seq_id = 100000;
return(true);
}
}
break;
default:
DebugString("Type is %d\n", icmp_header->Type);
break;
}
} else {
DebugString("Protocol is %d\n", ip_header->Protocol);
}
}
}
return(false);
}
/***********************************************************************************************
* Open_Raw_Sockets -- Initialize winsock and create the raw sockets we need *
* *
* *
* *
* INPUT: Nothing *
* *
* OUTPUT: Nothing *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 10/3/2001 11:31AM ST : Created *
*=============================================================================================*/
bool Open_Raw_Sockets(int &failure_code)
{
WSADATA wsa_data;
bool use_group = false; //true;
/*
** We need Winsocl 2 for raw sockets.
*/
if (WSAStartup(MAKEWORD(2,1), &wsa_data) != 0) {
DebugString("WSAStartup failed: error code %d\n", GetLastError());
failure_code = BANDTEST_NO_WINSOCK2;
return(false);
}
/*
** Create a socket for UDP packets.
*/
if (use_group) {
RawSocket = WSASocket(AF_INET, SOCK_RAW, IPPROTO_UDP, NULL, SG_UNCONSTRAINED_GROUP, 0);
if (RawSocket == INVALID_SOCKET) {
DebugString("Unable to create raw UDP socket with SG_UNCONSTRAINED_GROUP - error code \n", WSAGetLastError());
use_group = false;
}
}
if (!use_group) {
RawSocket = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
}
if (RawSocket == INVALID_SOCKET) {
DebugString("Unable to create raw UDP socket - error code \n", WSAGetLastError());
WSACleanup();
if (WSAGetLastError() == WSAEACCES) {
failure_code = BANDTEST_NO_RAW_SOCKET_PERMISSION;
} else {
failure_code = BANDTEST_NO_RAW_SOCKET_CREATE;
}
return(false);
}
/*
** Get the group number.
*/
unsigned long group = 0;
int length = 4;
if (use_group) {
if (getsockopt (RawSocket, SOL_SOCKET, SO_GROUP_ID, (char*)&group, &length) == SOCKET_ERROR) {
DebugString("Unable to get group for raw socket - error code \n", WSAGetLastError());
use_group = false;
}
}
/*
** Create a socket for ICMP packets.
*/
if (use_group) {
ICMPRawSocket = WSASocket(AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, group, 0);
} else {
ICMPRawSocket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
}
if (ICMPRawSocket == INVALID_SOCKET) {
DebugString("Unable to create raw ICMP socket - error code \n", WSAGetLastError());
closesocket(RawSocket);
WSACleanup();
if (WSAGetLastError() == WSAEACCES) {
failure_code = BANDTEST_NO_RAW_SOCKET_PERMISSION;
} else {
failure_code = BANDTEST_NO_RAW_SOCKET_CREATE;
}
return(false);
}
/*
** Set the priority for the sockets.
*/
//unsigned long priority;
//getsockopt (RawSocket, SOL_SOCKET, SO_GROUP_PRIORITY, (char*)&priority, &length);
//getsockopt (ICMPRawSocket, SOL_SOCKET, SO_GROUP_PRIORITY, (char*)&priority, &length);
unsigned long new_priority = 50;
int result = setsockopt(RawSocket, SOL_SOCKET, SO_GROUP_PRIORITY, (char*)&new_priority, sizeof(new_priority));
if (result != 0) {
DebugString("Unable to set priority on UDP socket - error code %d\n", WSAGetLastError());
}
new_priority = 1;
result = setsockopt(ICMPRawSocket, SOL_SOCKET, SO_GROUP_PRIORITY, (char*)&new_priority, sizeof(new_priority));
if (result != 0) {
DebugString("Unable to set priority on ICMP socket - error code %d\n", WSAGetLastError());
}
return(true);
}
/***********************************************************************************************
* Close_Raw_Sockets -- Initialize winsock and create the raw sockets we need *
* *
* *
* *
* INPUT: Nothing *
* *
* OUTPUT: Nothing *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 10/3/2001 11:31AM ST : Created *
*=============================================================================================*/
void Close_Raw_Sockets(void)
{
if (RawSocket != INVALID_SOCKET) {
closesocket(RawSocket);
}
if (RawSocket != INVALID_SOCKET) {
closesocket(ICMPRawSocket);
}
WSACleanup();
}
/***********************************************************************************************
* Get_IP_Checksum -- Create a checksum value for an IP packets *
* *
* *
* *
* INPUT: Buffer *
* Buffer size *
* *
* OUTPUT: Checksum *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 10/3/2001 11:44AM ST : Created *
*=============================================================================================*/
unsigned short Get_IP_Checksum(unsigned short *buffer, int size)
{
unsigned long checksum = 0;
int new_size = size;
unsigned short *bufptr = buffer;
while(new_size >1) {
checksum += *bufptr++;
new_size -= sizeof(unsigned short);
}
if (new_size) {
checksum += *(unsigned char*) bufptr;
}
checksum = (checksum >> 16) + (checksum & 0xffff);
checksum += (checksum >> 16);
checksum = ~checksum;
return ((unsigned short) checksum);
}
bool Set_Registry_Int(const char *name, int value)
{
int result = RegSetValueEx(RegistryKey, name, 0, REG_DWORD, (unsigned char*)&value, sizeof(value));
return((result == ERROR_SUCCESS) ? true : false);
}
int Get_Registry_Int(const char *name, int def_value)
{
unsigned long type;
unsigned long data;
unsigned long data_size = sizeof(data);
if (RegQueryValueEx(RegistryKey, name, NULL, &type, (unsigned char*)&data, &data_size) == ERROR_SUCCESS) {
return(data);
}
return(def_value);
}
bool Open_Registry(void)
{
HKEY key;
unsigned long disposition;
long result = RegCreateKeyEx(HKEY_LOCAL_MACHINE, RegistryPath, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &key, &disposition);
if (result == ERROR_SUCCESS) {
RegistryKey = key;
return(true);
}
return(false);
}
void Close_Registry(void)
{
RegCloseKey(RegistryKey);
}
#ifdef _DEBUG
/***********************************************************************************************
* DebugString -- Debug output *
* *
* *
* *
* INPUT: Printf format *
* *
* OUTPUT: Nothing *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 10/3/2001 11:36AM ST : Created *
*=============================================================================================*/
void DebugString (char const * string, ...)
{
static char buffer[1024];
static char filebuf[1024];
static char path_to_exe[512];
static char drive[_MAX_DRIVE];
static char dir[_MAX_DIR];
va_list va;
strcpy(buffer, "BandTest: ");
va_start(va, string);
vsprintf(&buffer[10], string, va);
va_end(va);
DWORD actual;
if (DebugFile == INVALID_HANDLE_VALUE) {
GetModuleFileName (GetModuleHandle(NULL), &path_to_exe[0], 512);
_splitpath(path_to_exe, drive, dir, NULL, NULL);
_makepath(DebugFileName, drive, dir, "bandtest", "txt");
DebugFile = CreateFile(DebugFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
} else {
DebugFile = CreateFile(DebugFileName, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
}
OutputDebugString (buffer);
if (DebugFile != INVALID_HANDLE_VALUE) {
SetFilePointer (DebugFile, 0, NULL, FILE_END);
char *srcbuf = buffer;
char *destbuf = filebuf;
char c;
while (*srcbuf != 0) {
c = *srcbuf++;
if (c == '\n') {
*destbuf++ = '\r';
}
*destbuf++ = c;
}
*destbuf = 0;
WriteFile(DebugFile, filebuf, strlen(filebuf), &actual, NULL);
CloseHandle (DebugFile);
}
}
/***********************************************************************************************
* Addr_As_String -- Get a human readable internet address *
* *
* *
* *
* INPUT: Address ptr *
* *
* OUTPUT: String representation *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 8/31/2001 3:48PM ST : Created *
*=============================================================================================*/
char * Addr_As_String2(struct sockaddr_in *addr)
{
static char _string[128];
sprintf(_string, "%d.%d.%d.%d ; %d", (int)(addr->sin_addr.S_un.S_un_b.s_b1),
(int)(addr->sin_addr.S_un.S_un_b.s_b2),
(int)(addr->sin_addr.S_un.S_un_b.s_b3),
(int)(addr->sin_addr.S_un.S_un_b.s_b4),
(int)(addr->sin_port));
return(_string);
}
/***********************************************************************************************
* Addr_As_String -- Get a human readable internet address *
* *
* *
* *
* INPUT: Address ptr *
* *
* OUTPUT: String representation *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 8/31/2001 3:48PM ST : Created *
*=============================================================================================*/
char * Addr_As_String(unsigned char *addr)
{
static char _string[128];
sprintf(_string, "%d.%d.%d.%d", (int)(addr[0]), (int)(addr[1]), (int)(addr[2]), (int)(addr[3]));
return(_string);
}
#endif //_DEBUG
#if (0)
/*
** Try to find a router with a different address class than ours. Start at TTL = 1 and increase until we find what we
** are looking for.
*/
ttl = 1;
hops_to_server = 0;
found_whole_path = false;
do {
performance_timer = timeGetTime();
router_ttl = 0;
for (ttl ; ttl < 100 ; ttl++) {
memcpy(&address, &host_address, sizeof(address));
/*
** Set the TTL.
*/
int result = setsockopt(ICMPRawSocket, IPPROTO_IP, IP_TTL, (char*)&ttl, sizeof(ttl));
if (result == SOCKET_ERROR) {
DebugString("setsockopt failed to set IP_TTL = %d - error code %d\n", ttl, WSAGetLastError());
failure_code = BANDTEST_NO_TTL_SET;
Close_Raw_Sockets();
return(0);
}
unsigned long start_time = timeGetTime();
/*
** Send a ping with the previously set TTL.
*/
DebugString("Sending ping with TTL = %d\n", ttl);
Send_Ping(temp_buffer, 0, ICMPRawSocket, (struct sockaddr *) &address, packet_sequencer);
/*
** Wait for a ping response.
*/
seq_id = -1;
while (seq_id == -1) {
Get_Ping_Response(ICMPRawSocket, seq_id, (struct sockaddr *) &address, ntohl(host_address.sin_addr.s_addr), ping_dest_address);
if (timeGetTime() - start_time > 5000) {
DebugString("Failed to get response to ping with TTL = %d\n", ttl);
break;
//failure_code = BANDTEST_NO_PING_RESPONSE;
//Close_Raw_Sockets();
//return(0);
}
};
if (seq_id != -1) {
unsigned long long_router_addr = ntohl(address.sin_addr.s_addr);
if (!found_whole_path) {
path_to_server[hops_to_server++] = long_router_addr;
}
/*
** See if this router is the target. If so, we are at the end of the path.
*/
if (long_router_addr == server_ip || seq_id == packet_sequencer) {
/*
** We better have found an external router by now...
*/
assert(router_ttl != 0);
found_whole_path = true;
break;
}
/*
** See if the router is on the same network as me.
*/
if (router_ttl == 0 && (long_router_addr & 0xffff0000) != (my_ip & 0xffff0000)) {
memcpy(&router_addr, &address, sizeof(router_addr));
router_ttl = ttl;
DebugString("Found external router at %s - ttl = %d\n", Addr_As_String((unsigned char*)&address.sin_addr.s_addr), router_ttl);
if (found_whole_path || settings->TTLScatter == 0) {
break;
}
}
}
packet_sequencer++;
}
//if (router_ttl == 0) {
// DebugString("Failed to find external router\n");
// failure_code = BANDTEST_NO_EXTERNAL_ROUTER;
// Close_Raw_Sockets();
// return(0);
//}
//assert(router_ttl != 0);
if (router_ttl == 0) {
continue;
}
DebugString("Took %d ms to find external router\n", timeGetTime() - performance_timer);
performance_timer = timeGetTime();
average_ping = 0;
/*
** Set the TTL back to max.
*/
int new_ttl = 255;
int result = setsockopt(ICMPRawSocket, IPPROTO_IP, IP_TTL, (char*)&new_ttl, sizeof(new_ttl));
if (result == SOCKET_ERROR) {
DebugString("setsockopt failed to set IP_TTL = %d - error code %d\n", new_ttl, WSAGetLastError());
failure_code = BANDTEST_NO_TTL_SET;
Close_Raw_Sockets();
return(0);
}
/*
** Ping the router directly to get a reference round trip time.
** Try 3 pings and take an average.
*/
packet_sequencer = 0;
memset(ping_times, 0xff, sizeof(ping_times));
num_pings = 0;
for (i=0 ; i<3 ; i++) {
unsigned long start_time = timeGetTime();
Send_Ping((char*)temp_buffer, 0, ICMPRawSocket, (struct sockaddr *) &router_addr, packet_sequencer);
seq_id = -1;
while (seq_id != packet_sequencer) {
Get_Ping_Response(ICMPRawSocket, seq_id, (struct sockaddr *) &address, ntohl(host_address.sin_addr.s_addr), ping_dest_address);
if (timeGetTime() - start_time > 2000) {
DebugString("Failed to get response to reference ping %d\n", i);
failure_code = BANDTEST_NO_PING_RESPONSE;
break;
//Close_Raw_Sockets();
//return(0);
}
};
//assert(seq_id == packet_sequencer);
//assert(seq_id < 3);
if (seq_id == packet_sequencer) {
unsigned long router_ping_time = timeGetTime() - start_time;
DebugString("Ping time %d to external router %s is %d ms\n", num_pings, Addr_As_String2(&router_addr), router_ping_time);
ping_times[num_pings++] = router_ping_time;
}
packet_sequencer++;
}
//assert(num_pings == 3);
average_ping = 0;
if (num_pings > 0) {
for (int p=0 ; p