| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487 |
- /*
- ** 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 <http://www.gnu.org/licenses/>.
- */
- /***********************************************************************************************
- *** 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 <winsock2.h>
- #include <ws2tcpip.h>
- #pragma warning(disable:4201)
- #include <mmsystem.h>
- #pragma warning(default:4201)
- #include <malloc.h>
- #include <stdio.h>
- #include <conio.h>
- #include <stdlib.h>
- #include <assert.h>
- #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<sizeof(temp_buffer) ; b++) {
- temp_buffer[b] = (unsigned char) (rand() & 0xff);
- }
- /*
- ** Try to open the sockets we need.
- */
- if (!Open_Raw_Sockets(failure_code)) {
- return(0);
- }
- /*
- ** Bind the UDP socket to a port.
- */
- struct sockaddr_in temp_addr;
- temp_addr.sin_addr.s_addr = htonl(INADDR_ANY);
- temp_addr.sin_port = htons(source_port);
- temp_addr.sin_family = AF_INET;
- if (bind(RawSocket, (LPSOCKADDR) &temp_addr, sizeof(temp_addr)) == SOCKET_ERROR) {
- DebugString("bind failed with error code %d\n", WSAGetLastError());
- failure_code = BANDTEST_NO_UDP_SOCKET_BIND;
- Close_Raw_Sockets();
- return(0);
- }
- /*
- ** Bind the ICMP socket to our local address.
- */
- #if (0)
- temp_addr.sin_port = 0;
- if (bind(ICMPRawSocket, (LPSOCKADDR) &temp_addr, sizeof(temp_addr)) == SOCKET_ERROR) {
- DebugString("bind failed with error code %d\n", WSAGetLastError());
- failure_code = BANDTEST_NO_UDP_SOCKET_BIND;
- Close_Raw_Sockets();
- return(0);
- }
- #endif //(0)
- address.sin_addr.s_addr = htonl(server_ip);
- address.sin_port = 80; //www port number. We can use anything here.
- address.sin_family = AF_INET;
- memcpy(&host_address, &address, sizeof(host_address));
- /*
- ** If we don't know our own IP, ping someone we do know to find out.
- */
- if (my_ip == 0) {
- performance_timer = timeGetTime();
- DebugString("Detecting my IP\n");
- Send_Ping(temp_buffer, 0, ICMPRawSocket, (struct sockaddr *) &address, 50);
- /*
- ** Wait for a ping response.
- */
- unsigned long start_time = timeGetTime();
- 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 > 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<hops_to_server ; i++) {
- unsigned long temp = htonl(path_to_server[i]);
- DebugString(" %02d : %s\n", i, Addr_As_String((unsigned char*)(&temp)));
- }
- #endif //_DEBUG
- int first_router = 0;
- if (hops_to_server > 3) {
- first_router = 2;
- }
- for (i=first_router ; i<hops_to_server ; i++) {
- if ((path_to_server[i] & 0xffff0000) != (my_ip & 0xffff0000)) {
- /*
- ** Ping the router once to see if it responds.
- */
- int pings = Ping_Host(path_to_server[i], my_ip, 1, 0, ping_times, 2*TIMER_SECOND);
- if (pings == 0) {
- pings = Ping_Host(path_to_server[i], my_ip, 1, 0, ping_times, 2*TIMER_SECOND);
- }
- /*
- ** If it responded, this is our man, ping it some more to establish a reference ping average.
- */
- if (pings) {
- performance_timer = timeGetTime();
- router_ttl = i + 1;
- router_addr.sin_addr.s_addr = htonl(path_to_server[i]);
- router_addr.sin_port = 80;
- router_addr.sin_family = AF_INET;
- int num_pings = 15;
- unsigned long timeout = ping_times[0] * 3;
- if (ping_times[0] < 50) {
- num_pings = 50;
- timeout = 100;
- } else {
- if (ping_times[0] > 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 ; i<num_udp_packets ; i++) {
- /*
- ** Use a different TTL for each packet if requested.
- */
- if (settings->TTLScatter) {
- 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 ; b<sizeof(temp_buffer) ; b++) {
- temp_buffer[b] = (unsigned char) (rand() & 0xff);
- }
- if (settings->AlwaysICMP) {
- 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<num_udp_packets ; i++) {
- /*
- ** 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 ; b<sizeof(temp_buffer) ; b++) {
- temp_buffer[b] = (unsigned char) (rand() & 0xff);
- }
- start_time = timeGetTime();
- Send_Raw_UDP(temp_buffer, 540, RawSocket, (struct sockaddr *) &host_address, 1234, 4321);
- seq_id = -1;
- 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;
- unsigned long ping_time = timeGetTime() - start_time;
- ping_times[num_pings++] = ping_time;
- break;
- }
- if (timeGetTime() - start_time > (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<ping_number ; i++) {
- min_ping = min(min_ping, ping_averages[i]);
- max_ping = max(max_ping, ping_averages[i]);
- }
- sprintf(temp_buffer, "%3.1f", max_ping);
- strncpy(&temp_graph[0][0], temp_buffer, strlen(temp_buffer));
- sprintf(temp_buffer, "%3.1f", min_ping);
- strncpy(&temp_graph[25][0], temp_buffer, strlen(temp_buffer));
- float scale = 25.0f / (max_ping - min_ping);
- /*
- ** Draw the pings onto the graph.
- */
- for (i=0 ; i<ping_number ; i++) {
- float ping = ping_averages[i];
- int position = (int)((ping - min_ping) * scale);
- position = 25 - position;
- temp_graph[position][i+9] = '*';
- }
- /*
- ** Dump it out.
- */
- for (i=0 ; i<30 ; i++) {
- DebugString(temp_graph[i]);
- cprintf(temp_graph[i]);
- }
- }
- /***********************************************************************************************
- * Get_Path_To_Server -- Trace the route to the server *
- * *
- * *
- * *
- * INPUT: Ptr to array to receive path IPs *
- * My IP address *
- * Servers IP address *
- * *
- * OUTPUT: Number of hops in path *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 10/8/2001 2:07PM ST : Created *
- *=============================================================================================*/
- int Get_Path_To_Server(unsigned long *path, unsigned long my_ip, unsigned long server_ip)
- {
- char reg_name[128];
- int path_size = 0;
- struct sockaddr_in host_address;
- struct sockaddr_in address;
- char temp_buffer[640];
- int seq_id;
- unsigned long ping_dest_address = htonl(my_ip);
- /*
- ** See if the path in the registry looks valid.
- */
- int reg_my_ip = Get_Registry_Int("MyIP", 0);
- int reg_server_ip = Get_Registry_Int("ServerIP", 0);
- int reg_path_length = Get_Registry_Int("PathLength", 0);
- int reg_path_time = Get_Registry_Int("PathValid", 0);
- /*
- ** If the ip at either end of the route has changed then the path isn't valid anymore.
- */
- if (((unsigned long)reg_my_ip) == my_ip && ((unsigned long)reg_server_ip) == server_ip) {
- /*
- ** If the path is too old then we should probably not consider it valid.
- */
- unsigned long time = timeGetTime();
- unsigned long last_path_time = (unsigned long) reg_path_time;
- /*
- ** Lets only use it if it's less than 2 hours old.
- */
- if ((last_path_time < time) && (time - last_path_time < (TIMER_SECOND * 60 * 120))) {
- /*
- ** OK, the path in the registry looks good - just return that.
- */
- for (int i=0 ; i<reg_path_length ; i++) {
- sprintf(reg_name, "Path%02d", i);
- path[i] = (unsigned long) Get_Registry_Int(reg_name, 0);
- if (path[i]) {
- path_size++;
- } else {
- break;
- }
- }
- if (reg_path_length == path_size) {
- DebugString("Using path from registry\n");
- return(path_size);
- }
- }
- }
- /*
- ** The path in the registry isn't any good. Discover it for ourselves.
- */
- address.sin_addr.s_addr = htonl(server_ip);
- address.sin_port = 80; //www port number. We can use anything here.
- address.sin_family = AF_INET;
- memcpy(&host_address, &address, sizeof(host_address));
- /*
- ** 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.
- */
- int ttl = 1;
- int hops_to_server = 0;
- int packet_sequencer = 0;
- for (ttl = 1 ; 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());
- 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);
- //DebugString("Ping sent\n");
- /*
- ** 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 > 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<hops_to_server ; i++) {
- sprintf(reg_name, "Path%02d", i);
- Set_Registry_Int(reg_name, path[i]);
- }
- return(hops_to_server);
- }
- return(0);
- }
- /***********************************************************************************************
- * Ping_Host -- Send a number of pings to a host and wait for responses *
- * *
- * *
- * *
- * INPUT: Host IP address to ping *
- * My IP address *
- * Number of pings to send *
- * Payload size of ping *
- * Ptr to array to receive ping times *
- * Timeout for each ping *
- * *
- * OUTPUT: Number of pings received *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 10/8/2001 2:09PM ST : Created *
- *=============================================================================================*/
- int Ping_Host(unsigned long host_ip, unsigned long my_ip, int times, int payload_size, unsigned long *ping_times, unsigned long timeout)
- {
- static int _packet_sequencer = 0;
- int num_pings = 0;
- char temp_buffer[640];
- struct sockaddr_in host_addr;
- struct sockaddr_in address;
- unsigned long ping_dest_address = htonl(my_ip);
- /*
- ** 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());
- return(0);
- }
- host_addr.sin_addr.s_addr = htonl(host_ip);
- host_addr.sin_port = 80; //www port number. We can use anything here.
- host_addr.sin_family = AF_INET;
- /*
- ** Ping n times.
- */
- for (int i=0 ; i<times ; i++) {
- for (int b=0 ; b<sizeof(temp_buffer) ; b++) {
- temp_buffer[b] = (unsigned char) (rand() & 0xff);
- }
- /*
- ** Record the time before sending the ping.
- */
- unsigned long start_time = timeGetTime();
- /*
- ** Send the ping.
- */
- Send_Ping((char*)temp_buffer, payload_size, ICMPRawSocket, (struct sockaddr *) &host_addr, _packet_sequencer);
- PingsSent++;
- int seq_id = -1;
- /*
- ** Wait for the ping response.
- */
- while (seq_id != _packet_sequencer) {
- Get_Ping_Response(ICMPRawSocket, seq_id, (struct sockaddr *) &address, ntohl(host_addr.sin_addr.s_addr), ping_dest_address);
- if (timeGetTime() - start_time > 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<num_pings ; p++) {
- float diff = ((float)ping_times[p]) - average_ping;
- if (diff < 0) {
- diff = -diff;
- }
- if (diff < average_ping * error_permit) {
- NumConsistentPings++;
- }
- }
- }
- return(num_pings);
- }
- /***********************************************************************************************
- * Ping_Compare -- qsort compare function for unsigned longs *
- * *
- * *
- * *
- * INPUT: ping 1 *
- * ping 2 *
- * *
- * OUTPUT: result of comparison *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 10/8/2001 2:13PM ST : Created *
- *=============================================================================================*/
- int __cdecl Ping_Compare(const void *ping1, const void *ping2)
- {
- unsigned long p1 = *((unsigned long*)ping1);
- unsigned long p2 = *((unsigned long*)ping2);
- if (p1 == p2) {
- return(0);
- }
- if (p1 < p2) {
- return(-1);
- }
- return(1);
- }
- /***********************************************************************************************
- * Sort_Pings -- Sort the ping list into ascending order *
- * *
- * *
- * *
- * INPUT: Number of pings in list *
- * Ptr to ping time array *
- * *
- * OUTPUT: Nothing *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 10/8/2001 2:14PM ST : Created *
- *=============================================================================================*/
- void Sort_Pings(int num_pings, unsigned long *ping_times)
- {
- qsort(ping_times, num_pings, sizeof(unsigned long), &Ping_Compare);
- }
- /***********************************************************************************************
- * Average_Ping -- Calculate the average ping time from a list of pings. *
- * *
- * *
- * *
- * INPUT: Number of pings *
- * Ptr to ping times array *
- * Ignore low & high - filter out very low and very high values from average *
- * *
- * OUTPUT: Nothing *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 10/8/2001 2:14PM ST : Created *
- *=============================================================================================*/
- float Average_Ping(int num_pings, unsigned long *ping_times, bool ignore_low_high)
- {
- if (ignore_low_high && num_pings > 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<num_pings ; i++) {
- average_ping += (float)(ping_times[i]);
- }
- average_ping = average_ping / (float) num_pings;
- /*
- ** If we have lots of pings, see if we can improve the accurracy by filtering out very small or very big pings.
- */
- if (num_pings > 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<num_pings ; i++) {
- float diff = ((float)ping_times[i]) - average_ping;
- if (diff < 0) {
- diff = -diff;
- }
- if (diff < average_ping * 0.25f) {
- new_average += (float) ping_times[i];
- num_considered++;
- }
- }
- if (num_considered > 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<num_pings ; i++) {
- lowest_ping = min(lowest_ping, (float)(ping_times[i]));
- }
- return(lowest_ping);
- }
- /***********************************************************************************************
- * Send_Raw_UDP -- Send a raw UDP packet. *
- * *
- * *
- * *
- * INPUT: Ptr to buffer to copy packet payload from *
- * Size of packet payload *
- * Raw UDP socket to use *
- * Address to send packet to *
- * Source port to put in the UDP header *
- * Dest port to put in the UDP header *
- * *
- * OUTPUT: True if sent OK *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 10/3/2001 11:46AM ST : Created *
- *=============================================================================================*/
- bool Send_Raw_UDP(char *payload, int payload_size, SOCKET socket, struct sockaddr *address, unsigned short source_port, unsigned short dest_port)
- {
- /*
- ** Asserts.
- */
- assert(payload_size < 550);
- assert(socket != INVALID_SOCKET);
- assert(source_port >= 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<num_pings ; p++) {
- average_ping += ping_times[p];
- }
- average_ping = average_ping / num_pings;
- DebugString("Average ping time to external router is %d ms\n", average_ping);
- DebugString("Took %d ms to find average ping\n", timeGetTime() - performance_timer);
- performance_timer = timeGetTime();
- } else {
- /*
- ** If we didn't get all three pings then go round again.
- */
- router_ttl = 0;
- }
- } while (router_ttl == 0 && ttl < 8);
- #endif //(0)
|