BandTest.cpp 87 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487
  1. /*
  2. ** Command & Conquer Renegade(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***********************************************************************************************
  19. *** 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 ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : Bandwidth Tester *
  23. * *
  24. * $Archive:: /Commando/Code/BandTest/BandTest.cpp $*
  25. * *
  26. * $Author:: Tom_s $*
  27. * *
  28. * $Modtime:: 3/04/02 5:50p $*
  29. * *
  30. * $Revision:: 17 $*
  31. * *
  32. * *
  33. *---------------------------------------------------------------------------------------------*
  34. * *
  35. * *
  36. *---------------------------------------------------------------------------------------------*
  37. * *
  38. * Functions: *
  39. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  40. #define WIN32_LEAN_AND_MEAN
  41. #include <winsock2.h>
  42. #include <ws2tcpip.h>
  43. #pragma warning(disable:4201)
  44. #include <mmsystem.h>
  45. #pragma warning(default:4201)
  46. #include <malloc.h>
  47. #include <stdio.h>
  48. #include <conio.h>
  49. #include <stdlib.h>
  50. #include <assert.h>
  51. #include "BandTest.h"
  52. #include "..\combat\specialbuilds.h"
  53. // warning C4711: function 'xxx' selected for automatic inline expansion
  54. #pragma warning(disable:4711)
  55. /***********************************************************************************************
  56. ** Data structures
  57. */
  58. #pragma pack(4)
  59. /*
  60. ** IP header definition.
  61. */
  62. typedef struct tIPHeaderType {
  63. unsigned char Length : 4; // length of the header
  64. unsigned char Version : 4; // Version of IP (must be 4 for IP4)
  65. unsigned char TOS; // Type of service (usually 0)
  66. unsigned short PacketLen; // total length of the packet
  67. unsigned short ID; // unique identifier
  68. unsigned short Flags; // flags
  69. unsigned char TTL; // Time to live
  70. unsigned char Protocol; // protocol (TCP, UDP etc)
  71. unsigned short Checksum; // IP checksum
  72. unsigned int SourceIP; // IP this packet came from
  73. unsigned int DestIP; // IP this packet is going to
  74. } IPHeaderType;
  75. /*
  76. ** ICMP packet header. Sits after the IP header when used.
  77. */
  78. typedef struct tICMPHeaderType {
  79. char Type;
  80. char Code;
  81. unsigned short Checksum;
  82. unsigned short ID;
  83. unsigned short Sequence;
  84. } ICMPHeaderType;
  85. /*
  86. ** UDP header. Sits after the IP header when used.
  87. */
  88. typedef struct tUDPHeaderType {
  89. unsigned short SourcePort;
  90. unsigned short DestPort;
  91. unsigned short Length;
  92. unsigned short Checksum;
  93. } UDPHeaderType;
  94. /***********************************************************************************************
  95. ** Defines
  96. */
  97. /*
  98. ** Total size of ICMP echo packet. 20 + 8
  99. */
  100. #define ICMP_ECHO_SIZE 28
  101. /*
  102. ** ICMP message numbers.
  103. */
  104. #define ICMP_ECHO_REPLY 0
  105. #define ICMP_ECHO 8
  106. #define ICMP_TIME_EXCEEDED 11
  107. /*
  108. ** IP protocol numbers.
  109. */
  110. #define PROTOCOL_ICMP 1
  111. #define PROTOCOL_UDP 17
  112. /*
  113. ** Timer.
  114. */
  115. #ifndef TIMER_SECOND
  116. #define TIMER_SECOND 1000
  117. #endif //TIMER_SECOND
  118. /***********************************************************************************************
  119. ** Global data.
  120. */
  121. /*
  122. ** Sockets.
  123. */
  124. SOCKET RawSocket = INVALID_SOCKET;
  125. SOCKET ICMPRawSocket = INVALID_SOCKET;
  126. /*
  127. ** Registry.
  128. */
  129. static HKEY RegistryKey;
  130. //static char BandTestRegistryLocation[64] = {"Software\\Westwood\\Renegade\\BandTest\\"};
  131. #if defined(FREEDEDICATEDSERVER)
  132. static char BandTestRegistryLocation[64] = {"Software\\Westwood\\RenegadeFDS\\BandTest\\"};
  133. #elif defined(MULTIPLAYERDEMO)
  134. static char BandTestRegistryLocation[64] = {"Software\\Westwood\\RenegadeMPDemo\\BandTest\\"};
  135. #elif defined(BETACLIENT)
  136. static char BandTestRegistryLocation[64] = {"Software\\Westwood\\RenegadeBeta\\BandTest\\"};
  137. #else
  138. static char BandTestRegistryLocation[64] = {"Software\\Westwood\\Renegade\\BandTest\\"};
  139. #endif
  140. static char RegistryPath[1024];
  141. /*
  142. ** Packet loss.
  143. */
  144. int PingsSent = 0;
  145. int PingsLost = 0;
  146. /*
  147. ** Connection quality.
  148. */
  149. int NumConsistentPings = 0;
  150. int NumPingsCheckedForConsistency = 0;
  151. /*
  152. ** State.
  153. */
  154. bool StatsValid = false;
  155. #ifdef _DEBUG
  156. HANDLE DebugFile = INVALID_HANDLE_VALUE;
  157. char DebugFileName[256];
  158. #endif //_DEBUG
  159. /***********************************************************************************************
  160. ** Function prototypes.
  161. */
  162. static bool Open_Raw_Sockets(int &failure_code);
  163. static void Close_Raw_Sockets(void);
  164. static bool Send_Ping(char *payload, int payload_size, SOCKET socket, struct sockaddr *address, int sequence_id);
  165. static bool Get_Ping_Response(SOCKET socket, int &seq_id, struct sockaddr *address, unsigned long validate_addr, unsigned long &my_address);
  166. static unsigned short Get_IP_Checksum(unsigned short *buffer, int size);
  167. static bool Send_Raw_UDP(char *payload, int payload_size, SOCKET socket, struct sockaddr *address, unsigned short source_port, unsigned short dest_port);
  168. static unsigned long Upstream_Detect(unsigned long server_ip, unsigned long my_ip, int &failure_code, unsigned long &downstream, BandtestSettingsStruct *settings);
  169. static int Ping_Host(unsigned long host_ip, unsigned long my_ip, int times, int payload_size, unsigned long *ping_times, unsigned long timeout);
  170. static float Average_Ping(int num_pings, unsigned long *ping_times, bool ignore_low_high);
  171. static float Lowest_Ping(int num_pings, unsigned long *ping_times);
  172. static int Get_Path_To_Server(unsigned long *path, unsigned long my_ip, unsigned long server_ip);
  173. static void Ping_Profile(SOCKADDR_IN *router_addr, unsigned long my_ip);
  174. static bool Set_Registry_Int(const char *name, int value);
  175. static int Get_Registry_Int(const char *name, int def_value);
  176. static bool Open_Registry(void);
  177. static void Close_Registry(void);
  178. #ifdef _DEBUG
  179. void DebugString (char const * string, ...);
  180. char * Addr_As_String2(struct sockaddr_in *addr);
  181. char * Addr_As_String(unsigned char *addr);
  182. #else //_DEBUG
  183. #define DebugString
  184. //_forceinline void DebugString(char const *, ...) {};
  185. //inline char * Addr_As_String(sockaddr_in *) {};
  186. inline char * Addr_As_String(unsigned char *) {return NULL;};
  187. inline char * Addr_As_String2(struct sockaddr_in *){return NULL;};
  188. #endif //_DEBUG
  189. /*
  190. ** Default settings.
  191. */
  192. BandtestSettingsStruct DefaultSettings = {
  193. 0, //AlwaysICMP
  194. 0, //TTLScatter
  195. 50, //FastPingPackets
  196. 20, //SlowPingPackets
  197. 15, //FastPingThreshold
  198. 0, //PingProfile
  199. };
  200. /***********************************************************************************************
  201. ** Your actual Code. No, really.
  202. */
  203. /***********************************************************************************************
  204. * DllMain -- Dll entry point. Not used for much *
  205. * *
  206. * *
  207. * *
  208. * INPUT: Nothing *
  209. * *
  210. * OUTPUT: Nothing *
  211. * *
  212. * WARNINGS: None *
  213. * *
  214. * HISTORY: *
  215. * 10/3/2001 11:20AM ST : Created *
  216. *=============================================================================================*/
  217. bool APIENTRY DllMain(HANDLE, DWORD, void *)
  218. {
  219. return(true);
  220. }
  221. /***********************************************************************************************
  222. * Detect_Upstream_Bandwidth -- Try and figure out what our upstream bandwidth is *
  223. * *
  224. * *
  225. * *
  226. * INPUT: IP address of server to use as destination IP in tests.Server receives no packets *
  227. * My IP. *
  228. * Number of times to retry on error *
  229. * (out) Extended error code *
  230. * *
  231. * OUTPUT: Bandwidth in bits per second. 0 = couldn't detect. 0xffffffff means **BIG** *
  232. * *
  233. * WARNINGS: All IPs in host order *
  234. * *
  235. * *
  236. * HISTORY: *
  237. * 10/3/2001 11:21AM ST : Created *
  238. *=============================================================================================*/
  239. 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)
  240. {
  241. if (api_version != BANDTEST_API_VERSION) {
  242. return(BANDTEST_WRONG_API_VERSION);
  243. }
  244. if (regpath == NULL) {
  245. strcpy(RegistryPath, BandTestRegistryLocation);
  246. } else {
  247. strcpy(RegistryPath, regpath);
  248. }
  249. if (!Open_Registry()) {
  250. failure_code = BANDTEST_UNKNOWN_ERROR;
  251. return(0);
  252. }
  253. timeBeginPeriod(1);
  254. PingsSent = 0;
  255. PingsLost = 0;
  256. NumConsistentPings = 0;
  257. NumPingsCheckedForConsistency = 0;
  258. StatsValid = false;
  259. int tried = 0;
  260. int bps = 0;
  261. if (settings == NULL) {
  262. settings = &DefaultSettings;
  263. }
  264. while (tried < retries + 1) {
  265. tried++;
  266. bps = Upstream_Detect(server_ip, my_ip, failure_code, downstream, settings);
  267. if (bps != 0) {
  268. StatsValid = true;
  269. if (PingsSent) {
  270. DebugString("Packet loss: %d percent\n", (100 * PingsLost) / PingsSent);
  271. Set_Registry_Int("PingLoss", (100 * PingsLost) / PingsSent);
  272. if (NumPingsCheckedForConsistency) {
  273. DebugString("Connection quality: %d percent\n", (100 * NumConsistentPings) / NumPingsCheckedForConsistency);
  274. Set_Registry_Int("Quality", (100 * NumConsistentPings) / NumPingsCheckedForConsistency);
  275. }
  276. }
  277. break;
  278. }
  279. /*
  280. ** Error. See what the error code tells us.
  281. */
  282. switch (failure_code) {
  283. /*
  284. ** Fatal errors.
  285. */
  286. case BANDTEST_NO_WINSOCK2:
  287. case BANDTEST_NO_RAW_SOCKET_PERMISSION:
  288. case BANDTEST_NO_RAW_SOCKET_CREATE:
  289. case BANDTEST_NO_UDP_SOCKET_BIND:
  290. tried = retries + 1;
  291. break;
  292. /*
  293. ** Erros where retrying might help.
  294. */
  295. case BANDTEST_NO_TTL_SET:
  296. case BANDTEST_NO_PING_RESPONSE:
  297. case BANDTEST_NO_FINAL_PING_TIME:
  298. case BANDTEST_NO_EXTERNAL_ROUTER:
  299. case BANDTEST_NO_IP_DETECT:
  300. break;
  301. /*
  302. ** Errors we should never get.
  303. */
  304. case BANDTEST_OK:
  305. case BANDTEST_UNKNOWN_ERROR:
  306. case BANDTEST_BAD_PARAM:
  307. default:
  308. DebugString("Failed with error code %d\n", failure_code);
  309. //assert(false);
  310. break;
  311. }
  312. if (tried < retries + 1) {
  313. DebugString("Retry %d\n", tried);
  314. }
  315. }
  316. timeEndPeriod(1);
  317. Close_Registry();
  318. return(bps);
  319. }
  320. /***********************************************************************************************
  321. * Upstream_Detect-- Try and figure out what our upstream bandwidth is *
  322. * *
  323. * *
  324. * *
  325. * INPUT: IP address of server to use as destination IP in tests.Server receives no packets *
  326. * My IP. *
  327. * (out) Extended error code *
  328. * *
  329. * OUTPUT: Bandwidth in bits per second. 0 = couldn't detect. 0xffffffff means **BIG** *
  330. * *
  331. * WARNINGS: None *
  332. * *
  333. * HISTORY: *
  334. * 10/3/2001 11:21AM ST : Created *
  335. *=============================================================================================*/
  336. unsigned long Upstream_Detect(unsigned long server_ip, unsigned long my_ip, int &failure_code, unsigned long &downstream, BandtestSettingsStruct *settings)
  337. {
  338. struct sockaddr_in host_address;
  339. struct sockaddr_in address;
  340. char temp_buffer[640];
  341. int seq_id;
  342. int router_ttl = 0;
  343. struct sockaddr_in router_addr;
  344. unsigned short source_port = 1230;
  345. int ttl;
  346. unsigned short packet_sequencer = 0;
  347. float average_ping = 0.0f;
  348. //float lowest_ping = 0.0f;
  349. unsigned long ping_dest_address = 0;
  350. unsigned long path_to_server[256];
  351. int hops_to_server = 0;
  352. unsigned long upstream_bandwidth;
  353. unsigned long ping_times[100];
  354. unsigned long performance_timer = timeGetTime();
  355. unsigned long detect_start_time = performance_timer;
  356. int i;
  357. /*
  358. ** Fill the temp buffer with garbage so it doesn't compress so well on modems.
  359. */
  360. srand(timeGetTime());
  361. for (int b=0 ; b<sizeof(temp_buffer) ; b++) {
  362. temp_buffer[b] = (unsigned char) (rand() & 0xff);
  363. }
  364. /*
  365. ** Try to open the sockets we need.
  366. */
  367. if (!Open_Raw_Sockets(failure_code)) {
  368. return(0);
  369. }
  370. /*
  371. ** Bind the UDP socket to a port.
  372. */
  373. struct sockaddr_in temp_addr;
  374. temp_addr.sin_addr.s_addr = htonl(INADDR_ANY);
  375. temp_addr.sin_port = htons(source_port);
  376. temp_addr.sin_family = AF_INET;
  377. if (bind(RawSocket, (LPSOCKADDR) &temp_addr, sizeof(temp_addr)) == SOCKET_ERROR) {
  378. DebugString("bind failed with error code %d\n", WSAGetLastError());
  379. failure_code = BANDTEST_NO_UDP_SOCKET_BIND;
  380. Close_Raw_Sockets();
  381. return(0);
  382. }
  383. /*
  384. ** Bind the ICMP socket to our local address.
  385. */
  386. #if (0)
  387. temp_addr.sin_port = 0;
  388. if (bind(ICMPRawSocket, (LPSOCKADDR) &temp_addr, sizeof(temp_addr)) == SOCKET_ERROR) {
  389. DebugString("bind failed with error code %d\n", WSAGetLastError());
  390. failure_code = BANDTEST_NO_UDP_SOCKET_BIND;
  391. Close_Raw_Sockets();
  392. return(0);
  393. }
  394. #endif //(0)
  395. address.sin_addr.s_addr = htonl(server_ip);
  396. address.sin_port = 80; //www port number. We can use anything here.
  397. address.sin_family = AF_INET;
  398. memcpy(&host_address, &address, sizeof(host_address));
  399. /*
  400. ** If we don't know our own IP, ping someone we do know to find out.
  401. */
  402. if (my_ip == 0) {
  403. performance_timer = timeGetTime();
  404. DebugString("Detecting my IP\n");
  405. Send_Ping(temp_buffer, 0, ICMPRawSocket, (struct sockaddr *) &address, 50);
  406. /*
  407. ** Wait for a ping response.
  408. */
  409. unsigned long start_time = timeGetTime();
  410. seq_id = -1;
  411. while (seq_id == -1) {
  412. Get_Ping_Response(ICMPRawSocket, seq_id, (struct sockaddr *) &address, ntohl(host_address.sin_addr.s_addr), ping_dest_address);
  413. if (timeGetTime() - start_time > 2500) {
  414. DebugString("Failed to get response to IP detect ping\n");
  415. failure_code = BANDTEST_NO_IP_DETECT;
  416. Close_Raw_Sockets();
  417. return(0);
  418. }
  419. };
  420. /*
  421. ** See if the router is on the same network as me.
  422. */
  423. if (seq_id == 50) {
  424. my_ip = ping_dest_address;
  425. #ifdef _DEBUG
  426. ping_dest_address = htonl(my_ip);
  427. DebugString("Detected my IP as %s\n", Addr_As_String((unsigned char*)&ping_dest_address));
  428. #endif //_DEBUG
  429. } else {
  430. DebugString("Unexpected response to IP detect ping\n");
  431. failure_code = BANDTEST_NO_IP_DETECT;
  432. Close_Raw_Sockets();
  433. return(0);
  434. }
  435. DebugString("Took %d ms to discover my IP address\n", timeGetTime() - performance_timer);
  436. }
  437. /*
  438. ** Get the path to the server.
  439. **
  440. */
  441. performance_timer = timeGetTime();
  442. hops_to_server = Get_Path_To_Server(&path_to_server[0], my_ip, server_ip);
  443. DebugString("Took %d ms to find path to server\n", timeGetTime() - performance_timer);
  444. if (hops_to_server == 0) {
  445. DebugString("Failed to get path to server\n");
  446. failure_code = BANDTEST_NO_EXTERNAL_ROUTER;
  447. Close_Raw_Sockets();
  448. return(0);
  449. }
  450. /*
  451. ** Dump out the whole path to the server.
  452. */
  453. #ifdef _DEBUG
  454. DebugString("Found path to server...\n");
  455. for (i=0 ; i<hops_to_server ; i++) {
  456. unsigned long temp = htonl(path_to_server[i]);
  457. DebugString(" %02d : %s\n", i, Addr_As_String((unsigned char*)(&temp)));
  458. }
  459. #endif //_DEBUG
  460. int first_router = 0;
  461. if (hops_to_server > 3) {
  462. first_router = 2;
  463. }
  464. for (i=first_router ; i<hops_to_server ; i++) {
  465. if ((path_to_server[i] & 0xffff0000) != (my_ip & 0xffff0000)) {
  466. /*
  467. ** Ping the router once to see if it responds.
  468. */
  469. int pings = Ping_Host(path_to_server[i], my_ip, 1, 0, ping_times, 2*TIMER_SECOND);
  470. if (pings == 0) {
  471. pings = Ping_Host(path_to_server[i], my_ip, 1, 0, ping_times, 2*TIMER_SECOND);
  472. }
  473. /*
  474. ** If it responded, this is our man, ping it some more to establish a reference ping average.
  475. */
  476. if (pings) {
  477. performance_timer = timeGetTime();
  478. router_ttl = i + 1;
  479. router_addr.sin_addr.s_addr = htonl(path_to_server[i]);
  480. router_addr.sin_port = 80;
  481. router_addr.sin_family = AF_INET;
  482. int num_pings = 15;
  483. unsigned long timeout = ping_times[0] * 3;
  484. if (ping_times[0] < 50) {
  485. num_pings = 50;
  486. timeout = 100;
  487. } else {
  488. if (ping_times[0] > 100) {
  489. num_pings = 6;
  490. }
  491. }
  492. pings = Ping_Host(path_to_server[i], my_ip, num_pings, 0, ping_times, timeout);
  493. if (pings) {
  494. //lowest_ping = Lowest_Ping(pings, ping_times);
  495. average_ping = Average_Ping(pings, ping_times, true);
  496. //DebugString("Lowest ping time to external router is %.2f ms\n", lowest_ping);
  497. DebugString("Average ping time to external router is %.2f ms\n", average_ping);
  498. DebugString("Took %d ms to find average ping\n", timeGetTime() - performance_timer);
  499. performance_timer = timeGetTime();
  500. break;
  501. } else {
  502. DebugString("Failed to ping external router\n");
  503. failure_code = BANDTEST_NO_PING_RESPONSE;
  504. Close_Raw_Sockets();
  505. return(0);
  506. }
  507. }
  508. }
  509. }
  510. if (router_ttl == 0) {
  511. DebugString("Failed to find external router\n");
  512. failure_code = BANDTEST_NO_EXTERNAL_ROUTER;
  513. Close_Raw_Sockets();
  514. return(0);
  515. }
  516. assert(router_ttl != 0);
  517. /*
  518. ** If the ping time is low, it's *probably* a high bandwidth connection so we can get a more accurate test by sending more
  519. ** packets without taking tooooo long.
  520. */
  521. int num_udp_packets = settings->SlowPingPackets;
  522. unsigned long timeout = 8*TIMER_SECOND;
  523. if (average_ping < (float)(settings->FastPingThreshold)) {
  524. num_udp_packets = settings->FastPingPackets;
  525. timeout = 4*TIMER_SECOND;
  526. }
  527. /*
  528. ** Set the UDP TTL to the next router down the list after the one we just pinged.
  529. */
  530. SOCKET test_socket = RawSocket;
  531. if (settings->AlwaysICMP) {
  532. test_socket = ICMPRawSocket;
  533. }
  534. ttl = router_ttl + 1;
  535. int result = setsockopt(test_socket, IPPROTO_IP, IP_TTL, (char*)&ttl, sizeof(ttl));
  536. if (result == SOCKET_ERROR) {
  537. DebugString("setsockopt failed to set IP_TTL = %d on test socket - error code %d\n", ttl, WSAGetLastError());
  538. failure_code = BANDTEST_NO_TTL_SET;
  539. Close_Raw_Sockets();
  540. return(0);
  541. }
  542. /*
  543. ** Make the UDP socket buffer a bit bigger. Not really important...
  544. */
  545. int socket_transmit_buffer_size = 128000;
  546. result = setsockopt(test_socket, SOL_SOCKET, SO_RCVBUF, (char*)&socket_transmit_buffer_size, 4);
  547. if (result == SOCKET_ERROR) {
  548. DebugString("setsockopt failed to set SO_RECVBUF with error code %d\n", WSAGetLastError());
  549. }
  550. /*
  551. ** Make a note of the current time so we can see how long this whole process takes.
  552. */
  553. unsigned long start_time = timeGetTime();
  554. int base_ttl = ttl;
  555. int max_ttl = hops_to_server - 1;
  556. if (max_ttl < base_ttl) {
  557. max_ttl = base_ttl;
  558. }
  559. performance_timer = timeGetTime();
  560. /*
  561. ** Send a shitload of UDP packets to the next router down the list after the one we just pinged.
  562. */
  563. DebugString("Sending %d 500 byte UDP packets\n", num_udp_packets);
  564. for (i=0 ; i<num_udp_packets ; i++) {
  565. /*
  566. ** Use a different TTL for each packet if requested.
  567. */
  568. if (settings->TTLScatter) {
  569. ttl++;
  570. if (ttl > max_ttl) {
  571. ttl = base_ttl;
  572. }
  573. int result = setsockopt(test_socket, IPPROTO_IP, IP_TTL, (char*)&ttl, sizeof(ttl));
  574. if (result == SOCKET_ERROR) {
  575. DebugString("setsockopt failed to set IP_TTL = %d on test socket - error code %d\n", ttl, WSAGetLastError());
  576. failure_code = BANDTEST_NO_TTL_SET;
  577. }
  578. }
  579. /*
  580. ** We have to fill the packet with different garbage every time we send it otherwise a modem will be able to
  581. ** do delta compression on the packets.
  582. */
  583. for (int b=0 ; b<sizeof(temp_buffer) ; b++) {
  584. temp_buffer[b] = (unsigned char) (rand() & 0xff);
  585. }
  586. if (settings->AlwaysICMP) {
  587. Send_Ping(temp_buffer, 466, ICMPRawSocket, (struct sockaddr *) &host_address, 0);
  588. } else {
  589. Send_Raw_UDP(temp_buffer, 466, RawSocket, (struct sockaddr *) &host_address, 1234, 4321);
  590. }
  591. }
  592. DebugString("Took %d ms to send bulk packets\n", timeGetTime() - performance_timer);
  593. performance_timer = timeGetTime();
  594. /*
  595. ** 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
  596. ** windoze that might confuse TTL settings between sockets.
  597. */
  598. ttl = 255;
  599. result = setsockopt(ICMPRawSocket, IPPROTO_IP, IP_TTL, (char*)&ttl, sizeof(ttl));
  600. if (result == SOCKET_ERROR) {
  601. DebugString("setsockopt failed to set IP_TTL = %d - error code %d\n", ttl, WSAGetLastError());
  602. }
  603. /*
  604. ** 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
  605. ** ping time will include the time taken to send the UDP packets.
  606. */
  607. unsigned long new_router_ping_time = 0xffffffff;
  608. packet_sequencer = 5;
  609. unsigned long second_start_time = timeGetTime();
  610. float total_time = 0.0f;
  611. /*
  612. ** Send a couple of pings to reduce the possibility of packet loss being a factor.
  613. */
  614. Send_Ping((char*)temp_buffer, 0, ICMPRawSocket, (struct sockaddr *) &router_addr, packet_sequencer);
  615. Send_Ping((char*)temp_buffer, 0, ICMPRawSocket, (struct sockaddr *) &router_addr, packet_sequencer + 1);
  616. seq_id = -1;
  617. while (seq_id != packet_sequencer && seq_id != packet_sequencer+1) {
  618. Get_Ping_Response(ICMPRawSocket, seq_id, (struct sockaddr *) &address, 0, ping_dest_address);
  619. if (timeGetTime() - second_start_time > timeout) {
  620. break;
  621. }
  622. };
  623. if (seq_id == packet_sequencer || seq_id == packet_sequencer + 1) {
  624. unsigned long time_now = timeGetTime();
  625. new_router_ping_time = time_now - second_start_time;
  626. total_time = (float)(time_now - start_time);
  627. DebugString("Ping time to external router is now %d ms\n", new_router_ping_time);
  628. DebugString("Total time to send %d bytes plus send and receive ping is %d ms\n", num_udp_packets * 500, total_time);
  629. } else {
  630. DebugString("Failed to get final ping response in %d seconds\n", timeout / 1000);
  631. failure_code = BANDTEST_NO_FINAL_PING_TIME;
  632. Close_Raw_Sockets();
  633. return(0);
  634. }
  635. if (new_router_ping_time == 0xffffffff) {
  636. DebugString("Failed to get final ping response\n");
  637. failure_code = BANDTEST_NO_FINAL_PING_TIME;
  638. return(0);
  639. } else {
  640. total_time -= average_ping;
  641. /*
  642. ** Work out the bandwidth.
  643. ** Approx bps up = ((10000 + 28) * 8) / (time2 - time1).
  644. */
  645. if (((unsigned long) total_time) == 0 || (total_time > ((float)0x10000000))) {
  646. DebugString("Upstream bandwidth is huge :-)\n");
  647. failure_code = BANDTEST_OK;
  648. upstream_bandwidth = 0xffffffff;
  649. } else {
  650. unsigned long bw = (((num_udp_packets * 500) * 8) * 1000) / (unsigned long)total_time;
  651. if (bw > 100000) {
  652. float floater = (float)bw / 1024;
  653. DebugString("Upstream bandwidth to external router is %.1f kilobits per second\n", floater);
  654. } else {
  655. DebugString("Upstream bandwidth to external router is %d bits per second\n", bw);
  656. }
  657. failure_code = BANDTEST_OK;
  658. upstream_bandwidth = bw;
  659. //return(bw);
  660. }
  661. }
  662. DebugString("Took %d ms to get new ping time\n", timeGetTime() - performance_timer);
  663. /*
  664. ** If the bandwidth in the registry is close to what we just calculated then use the old downstream calculation from the
  665. ** registry.
  666. */
  667. unsigned long downstream_bandwidth = upstream_bandwidth;
  668. int old_band = Get_Registry_Int("Up", 0);
  669. unsigned long diff = abs(upstream_bandwidth - old_band);
  670. bool calc_down = true;
  671. if (diff < upstream_bandwidth / 10) {
  672. downstream_bandwidth = Get_Registry_Int("Down", upstream_bandwidth);
  673. if (downstream_bandwidth) {
  674. calc_down = false;
  675. }
  676. }
  677. /*
  678. ** Store the calculated bandwidth into the registry.
  679. */
  680. Set_Registry_Int("Up", upstream_bandwidth);
  681. /*
  682. **
  683. ** Well, I suppose, since we are here, we might as well have a stab at downstream bandwidth too.
  684. **
  685. **
  686. ** Try sending max size pings to our friendly router and subtracting how long we think the upstream should have taken
  687. ** from the average ping time. Assume the routers latency is 0 (which of course it isn't).
  688. */
  689. bool method_one = false;
  690. //float average_time_exceeded = 0.0f;
  691. performance_timer = timeGetTime();
  692. if (calc_down && upstream_bandwidth < 576 * 1000 && upstream_bandwidth > 8) {
  693. int new_ping_timeout = max((int)(average_ping * 5), 200);
  694. #if (0)
  695. if (upstream_bandwidth > 80000) {
  696. method_one = true;
  697. }
  698. if (method_one) {
  699. DebugString("Detecting downstream bandwidth - method 1\n");
  700. ttl = router_ttl + 1;
  701. int result = setsockopt(RawSocket, IPPROTO_IP, IP_TTL, (char*)&ttl, sizeof(ttl));
  702. if (result == SOCKET_ERROR) {
  703. DebugString("setsockopt failed to set IP_TTL = %d on test socket - error code %d\n", ttl, WSAGetLastError());
  704. failure_code = BANDTEST_NO_TTL_SET;
  705. Close_Raw_Sockets();
  706. return(0);
  707. }
  708. /*
  709. ** First we had better wait for all those time exceeded packets to come back.
  710. */
  711. seq_id = -1;
  712. start_time = timeGetTime();
  713. unsigned long last_icmp_in_time = start_time;
  714. for (;;) {
  715. Get_Ping_Response(ICMPRawSocket, seq_id, (struct sockaddr *) &address, ntohl(host_address.sin_addr.s_addr), ping_dest_address);
  716. if (seq_id != -1) {
  717. seq_id = -1;
  718. last_icmp_in_time = timeGetTime();
  719. }
  720. if (timeGetTime() - start_time > 3*TIMER_SECOND) {
  721. break;
  722. }
  723. if (timeGetTime() - last_icmp_in_time > TIMER_SECOND / 2) {
  724. break;
  725. }
  726. }
  727. /*
  728. ** Send a shitload of UDP packets to the next router down the list after the one we just pinged.
  729. ** Wait for a response for each packet before sending the next.
  730. */
  731. num_udp_packets = 50;
  732. DebugString("Sending %d 500 byte UDP packets\n", num_udp_packets);
  733. int num_pings = 0;
  734. for (i=0 ; i<num_udp_packets ; i++) {
  735. /*
  736. ** We have to fill the packet with different garbage every time we send it otherwise a modem will be able to
  737. ** do delta compression on the packets.
  738. */
  739. for (int b=0 ; b<sizeof(temp_buffer) ; b++) {
  740. temp_buffer[b] = (unsigned char) (rand() & 0xff);
  741. }
  742. start_time = timeGetTime();
  743. Send_Raw_UDP(temp_buffer, 540, RawSocket, (struct sockaddr *) &host_address, 1234, 4321);
  744. seq_id = -1;
  745. for (;;) {
  746. Get_Ping_Response(ICMPRawSocket, seq_id, (struct sockaddr *) &address, ntohl(host_address.sin_addr.s_addr), ping_dest_address);
  747. if (seq_id != -1) {
  748. seq_id = -1;
  749. unsigned long ping_time = timeGetTime() - start_time;
  750. ping_times[num_pings++] = ping_time;
  751. break;
  752. }
  753. if (timeGetTime() - start_time > (unsigned long)new_ping_timeout) {
  754. break;
  755. }
  756. }
  757. }
  758. /*
  759. ** This is the average time taken to get the TIME EXCEEDED message back.
  760. */
  761. DebugString("Quickest time exceeded came in after %.2f ms\n", Lowest_Ping(num_pings, ping_times));
  762. average_time_exceeded = Average_Ping(num_pings, ping_times, true);
  763. DebugString("Average time exceeded came in after %.2f ms\n", average_time_exceeded);
  764. }
  765. #endif //(0)
  766. DebugString("Detecting downstream bandwidth - method 2\n");
  767. /*
  768. ** First we had better wait for all those time exceeded packets to come back.
  769. */
  770. seq_id = -1;
  771. start_time = timeGetTime();
  772. unsigned long last_icmp_in_time = start_time;
  773. for (;;) {
  774. Get_Ping_Response(ICMPRawSocket, seq_id, (struct sockaddr *) &address, ntohl(host_address.sin_addr.s_addr), ping_dest_address);
  775. if (seq_id != -1) {
  776. seq_id = -1;
  777. last_icmp_in_time = timeGetTime();
  778. }
  779. if (timeGetTime() - start_time > 3*TIMER_SECOND) {
  780. break;
  781. }
  782. if (timeGetTime() - last_icmp_in_time > TIMER_SECOND / 2) {
  783. break;
  784. }
  785. }
  786. //int new_ping_timeout = max((int)(average_ping * 5), 200);
  787. float old_average_ping = average_ping;
  788. //float old_lowest_ping = lowest_ping;
  789. average_ping = 0.0f;
  790. /*
  791. ** Set the TTL back to max.
  792. */
  793. int new_ttl = 255;
  794. int result = setsockopt(ICMPRawSocket, IPPROTO_IP, IP_TTL, (char*)&new_ttl, sizeof(new_ttl));
  795. if (result == SOCKET_ERROR) {
  796. DebugString("setsockopt failed to set IP_TTL = %d - error code %d\n", new_ttl, WSAGetLastError());
  797. failure_code = BANDTEST_NO_TTL_SET;
  798. Close_Raw_Sockets();
  799. return(upstream_bandwidth);
  800. }
  801. /*
  802. ** Ping the router once to get a ballpark trip time.
  803. */
  804. int pings = Ping_Host(ntohl(router_addr.sin_addr.s_addr), my_ip, 1, 540, ping_times, new_ping_timeout);
  805. if (pings == 0) {
  806. pings = Ping_Host(ntohl(router_addr.sin_addr.s_addr), my_ip, 1, 540, ping_times, 2 * TIMER_SECOND);
  807. if (pings == 0) {
  808. pings = Ping_Host(ntohl(router_addr.sin_addr.s_addr), my_ip, 1, 540, ping_times, 2 * TIMER_SECOND);
  809. }
  810. }
  811. if (pings) {
  812. /*
  813. ** Do more pings if the ping time is low. User a smaller timeout too.
  814. */
  815. int num_pings = 15;
  816. unsigned long timeout = ping_times[0] * 3;
  817. if (ping_times[0] < 100) {
  818. num_pings = 50;
  819. timeout = 200;
  820. } else {
  821. if (ping_times[0] > 250) {
  822. num_pings = 6;
  823. }
  824. }
  825. if (method_one) {
  826. num_pings = 50;
  827. }
  828. DebugString("Sending large pings\n");
  829. pings = Ping_Host(ntohl(router_addr.sin_addr.s_addr), my_ip, num_pings, 540, ping_times, timeout);
  830. if (pings) {
  831. //lowest_ping = Lowest_Ping(pings, ping_times);
  832. DebugString("Quickest ping came in after %.2f ms\n", Lowest_Ping(num_pings, ping_times));
  833. average_ping = Average_Ping(pings, ping_times, true);
  834. //DebugString("Lowest ping time to external router is now %.2f ms\n", lowest_ping);
  835. DebugString("Average ping time to external router is now %.2f ms\n", average_ping);
  836. } else {
  837. DebugString("Failed to ping external router\n");
  838. failure_code = BANDTEST_NO_PING_RESPONSE;
  839. Close_Raw_Sockets();
  840. return(upstream_bandwidth);
  841. }
  842. /*
  843. ** Just to make sure we can never get a divide by 0.
  844. */
  845. if (upstream_bandwidth / 8 == 0) {
  846. upstream_bandwidth = 56000;
  847. }
  848. float time_upstream = (1000.0f * 540.0f) / ((float)(upstream_bandwidth / 8));
  849. DebugString("Time upstream is %.1f ms\n", time_upstream);
  850. float time_downstream = (float)((average_ping - time_upstream) - old_average_ping);
  851. /*
  852. ** 576 bytes took 'time_downstream' ms to come downstream.
  853. */
  854. if (time_downstream > 0.0) {
  855. float dbw = ((1000.0f / time_downstream) * 4320.0f); // 540*8 = 4320
  856. //downstream_bandwidth = ((1000.0f / time_downstream) * 576 * 8);
  857. downstream_bandwidth = (int)dbw;
  858. }
  859. DebugString("Took %d ms to calculate downstream bandwidth\n", timeGetTime() - performance_timer);
  860. Set_Registry_Int("Down", downstream_bandwidth);
  861. }
  862. }
  863. if (settings->PingProfile) {
  864. Ping_Profile(&router_addr, my_ip);
  865. }
  866. Close_Raw_Sockets();
  867. if (downstream_bandwidth > 100000) {
  868. float floater = (float)downstream_bandwidth / 1024;
  869. DebugString("Downstream bandwidth from external router is %.1f kilobits per second\n", floater);
  870. } else {
  871. DebugString("Downstream bandwidth from external router is %d bits per second\n", downstream_bandwidth);
  872. }
  873. /*
  874. ** Method 1 just uses the difference between then time exceeded pings and the echo pings.
  875. */
  876. #if (0)
  877. if (method_one) {
  878. float time_down = average_ping - average_time_exceeded;
  879. if (time_down > 0) {
  880. float bps_down = (1000.0f / time_down) * (float)(540);
  881. bps_down = bps_down * 8.0f;
  882. if (bps_down > 100000) {
  883. float floater = (float)bps_down / 1024;
  884. DebugString("Downstream bandwidth from external router by alt method is %.1f kilobits per second\n", floater);
  885. } else {
  886. DebugString("Downstream bandwidth from external router by alt method is %f bits per second\n", bps_down);
  887. }
  888. }
  889. }
  890. #endif //(0)
  891. /*
  892. ** Assume down is at least as much as up.
  893. */
  894. if (downstream_bandwidth < upstream_bandwidth) {
  895. downstream_bandwidth = upstream_bandwidth;
  896. }
  897. downstream = downstream_bandwidth;
  898. DebugString("Total time to detect bandwidth = %d ms\n", timeGetTime() - detect_start_time);
  899. failure_code = BANDTEST_OK;
  900. return(upstream_bandwidth);
  901. }
  902. void Ping_Profile(SOCKADDR_IN *router_addr, unsigned long my_ip)
  903. {
  904. float ping_averages[1000];
  905. unsigned long ping_times[100];
  906. char temp_buffer[128];
  907. char temp_graph[30][80];
  908. static char _ping_graph[30][80] = {
  909. " ms| \n",
  910. " | \n",
  911. " | \n",
  912. " | \n",
  913. " | \n",
  914. " | \n",
  915. " | \n",
  916. " | \n",
  917. " | \n",
  918. " | \n",
  919. " | \n",
  920. " Ping | \n",
  921. " Time | \n",
  922. " | \n",
  923. " | \n",
  924. " | \n",
  925. " | \n",
  926. " | \n",
  927. " | \n",
  928. " | \n",
  929. " | \n",
  930. " | \n",
  931. " | \n",
  932. " | \n",
  933. " | \n",
  934. " ms| \n",
  935. "________|_______________________________________________________\n",
  936. " 0 Payload Size 540\n",
  937. " \n",
  938. " \n",
  939. };
  940. DebugString("Profiling ping responses\n");
  941. memcpy(temp_graph, _ping_graph, sizeof(temp_graph));
  942. /*
  943. ** Set the TTL back to max.
  944. */
  945. int new_ttl = 255;
  946. int result = setsockopt(ICMPRawSocket, IPPROTO_IP, IP_TTL, (char*)&new_ttl, sizeof(new_ttl));
  947. if (result == SOCKET_ERROR) {
  948. DebugString("setsockopt failed to set IP_TTL = %d - error code %d\n", new_ttl, WSAGetLastError());
  949. }
  950. int ping_number = 0;
  951. for (int packet_size = 0 ; packet_size < 541 ; packet_size += 10) {
  952. /*
  953. ** Ping the router once to get a ballpark trip time.
  954. */
  955. int pings = Ping_Host(ntohl(router_addr->sin_addr.s_addr), my_ip, 1, packet_size, ping_times, 1000);
  956. if (pings == 0) {
  957. pings = Ping_Host(ntohl(router_addr->sin_addr.s_addr), my_ip, 1, packet_size, ping_times, 2 * TIMER_SECOND);
  958. if (pings == 0) {
  959. pings = Ping_Host(ntohl(router_addr->sin_addr.s_addr), my_ip, 1, packet_size, ping_times, 2 * TIMER_SECOND);
  960. }
  961. }
  962. if (pings) {
  963. /*
  964. ** Do more pings if the ping time is low. User a smaller timeout too.
  965. */
  966. int num_pings = 15;
  967. unsigned long timeout = ping_times[0] * 3;
  968. if (ping_times[0] < 100) {
  969. num_pings = 30;
  970. timeout = 200;
  971. } else {
  972. if (ping_times[0] > 250) {
  973. num_pings = 6;
  974. }
  975. }
  976. DebugString("Sending %d byte pings\n", packet_size);
  977. pings = Ping_Host(ntohl(router_addr->sin_addr.s_addr), my_ip, num_pings, packet_size, ping_times, timeout);
  978. if (pings) {
  979. float average_ping = Average_Ping(pings, ping_times, true);
  980. DebugString("Average ping time to external router is now %.2f ms\n", average_ping);
  981. ping_averages[ping_number] = average_ping;
  982. } else {
  983. DebugString("Failed to ping external router\n");
  984. ping_averages[ping_number] = 0.0;
  985. }
  986. }
  987. ping_number++;
  988. }
  989. /*
  990. ** Scale the ping graph.
  991. */
  992. float min_ping = 10000.0f;
  993. float max_ping = -1.0f;
  994. for (int i=0 ; i<ping_number ; i++) {
  995. min_ping = min(min_ping, ping_averages[i]);
  996. max_ping = max(max_ping, ping_averages[i]);
  997. }
  998. sprintf(temp_buffer, "%3.1f", max_ping);
  999. strncpy(&temp_graph[0][0], temp_buffer, strlen(temp_buffer));
  1000. sprintf(temp_buffer, "%3.1f", min_ping);
  1001. strncpy(&temp_graph[25][0], temp_buffer, strlen(temp_buffer));
  1002. float scale = 25.0f / (max_ping - min_ping);
  1003. /*
  1004. ** Draw the pings onto the graph.
  1005. */
  1006. for (i=0 ; i<ping_number ; i++) {
  1007. float ping = ping_averages[i];
  1008. int position = (int)((ping - min_ping) * scale);
  1009. position = 25 - position;
  1010. temp_graph[position][i+9] = '*';
  1011. }
  1012. /*
  1013. ** Dump it out.
  1014. */
  1015. for (i=0 ; i<30 ; i++) {
  1016. DebugString(temp_graph[i]);
  1017. cprintf(temp_graph[i]);
  1018. }
  1019. }
  1020. /***********************************************************************************************
  1021. * Get_Path_To_Server -- Trace the route to the server *
  1022. * *
  1023. * *
  1024. * *
  1025. * INPUT: Ptr to array to receive path IPs *
  1026. * My IP address *
  1027. * Servers IP address *
  1028. * *
  1029. * OUTPUT: Number of hops in path *
  1030. * *
  1031. * WARNINGS: None *
  1032. * *
  1033. * HISTORY: *
  1034. * 10/8/2001 2:07PM ST : Created *
  1035. *=============================================================================================*/
  1036. int Get_Path_To_Server(unsigned long *path, unsigned long my_ip, unsigned long server_ip)
  1037. {
  1038. char reg_name[128];
  1039. int path_size = 0;
  1040. struct sockaddr_in host_address;
  1041. struct sockaddr_in address;
  1042. char temp_buffer[640];
  1043. int seq_id;
  1044. unsigned long ping_dest_address = htonl(my_ip);
  1045. /*
  1046. ** See if the path in the registry looks valid.
  1047. */
  1048. int reg_my_ip = Get_Registry_Int("MyIP", 0);
  1049. int reg_server_ip = Get_Registry_Int("ServerIP", 0);
  1050. int reg_path_length = Get_Registry_Int("PathLength", 0);
  1051. int reg_path_time = Get_Registry_Int("PathValid", 0);
  1052. /*
  1053. ** If the ip at either end of the route has changed then the path isn't valid anymore.
  1054. */
  1055. if (((unsigned long)reg_my_ip) == my_ip && ((unsigned long)reg_server_ip) == server_ip) {
  1056. /*
  1057. ** If the path is too old then we should probably not consider it valid.
  1058. */
  1059. unsigned long time = timeGetTime();
  1060. unsigned long last_path_time = (unsigned long) reg_path_time;
  1061. /*
  1062. ** Lets only use it if it's less than 2 hours old.
  1063. */
  1064. if ((last_path_time < time) && (time - last_path_time < (TIMER_SECOND * 60 * 120))) {
  1065. /*
  1066. ** OK, the path in the registry looks good - just return that.
  1067. */
  1068. for (int i=0 ; i<reg_path_length ; i++) {
  1069. sprintf(reg_name, "Path%02d", i);
  1070. path[i] = (unsigned long) Get_Registry_Int(reg_name, 0);
  1071. if (path[i]) {
  1072. path_size++;
  1073. } else {
  1074. break;
  1075. }
  1076. }
  1077. if (reg_path_length == path_size) {
  1078. DebugString("Using path from registry\n");
  1079. return(path_size);
  1080. }
  1081. }
  1082. }
  1083. /*
  1084. ** The path in the registry isn't any good. Discover it for ourselves.
  1085. */
  1086. address.sin_addr.s_addr = htonl(server_ip);
  1087. address.sin_port = 80; //www port number. We can use anything here.
  1088. address.sin_family = AF_INET;
  1089. memcpy(&host_address, &address, sizeof(host_address));
  1090. /*
  1091. ** Try to find a router with a different address class than ours. Start at TTL = 1 and increase until we find what we
  1092. ** are looking for.
  1093. */
  1094. int ttl = 1;
  1095. int hops_to_server = 0;
  1096. int packet_sequencer = 0;
  1097. for (ttl = 1 ; ttl < 100 ; ttl++) {
  1098. memcpy(&address, &host_address, sizeof(address));
  1099. /*
  1100. ** Set the TTL.
  1101. */
  1102. int result = setsockopt(ICMPRawSocket, IPPROTO_IP, IP_TTL, (char*)&ttl, sizeof(ttl));
  1103. if (result == SOCKET_ERROR) {
  1104. DebugString("setsockopt failed to set IP_TTL = %d - error code %d\n", ttl, WSAGetLastError());
  1105. return(0);
  1106. }
  1107. unsigned long start_time = timeGetTime();
  1108. /*
  1109. ** Send a ping with the previously set TTL.
  1110. */
  1111. DebugString("Sending ping with TTL = %d\n", ttl);
  1112. Send_Ping(temp_buffer, 0, ICMPRawSocket, (struct sockaddr *) &address, packet_sequencer);
  1113. //DebugString("Ping sent\n");
  1114. /*
  1115. ** Wait for a ping response.
  1116. */
  1117. seq_id = -1;
  1118. while (seq_id == -1) {
  1119. Get_Ping_Response(ICMPRawSocket, seq_id, (struct sockaddr *) &address, ntohl(host_address.sin_addr.s_addr), ping_dest_address);
  1120. if (timeGetTime() - start_time > 1500) {
  1121. DebugString("Failed to get any response to ping with TTL = %d\n", ttl);
  1122. break;
  1123. }
  1124. };
  1125. if (seq_id != -1) {
  1126. unsigned long long_router_addr = ntohl(address.sin_addr.s_addr);
  1127. path[hops_to_server++] = long_router_addr;
  1128. /*
  1129. ** See if this router is the target. If so, we are at the end of the path.
  1130. */
  1131. if (long_router_addr == server_ip || seq_id == packet_sequencer) {
  1132. break;
  1133. }
  1134. }
  1135. packet_sequencer++;
  1136. }
  1137. /*
  1138. ** If we got a good path then store it in the registry.
  1139. */
  1140. if (hops_to_server > 0 && path[hops_to_server - 1] == server_ip) {
  1141. Set_Registry_Int("MyIP", my_ip);
  1142. Set_Registry_Int("ServerIP", server_ip);
  1143. Set_Registry_Int("PathLength", hops_to_server);
  1144. Set_Registry_Int("PathValid", (int)timeGetTime());
  1145. for (int i=0 ; i<hops_to_server ; i++) {
  1146. sprintf(reg_name, "Path%02d", i);
  1147. Set_Registry_Int(reg_name, path[i]);
  1148. }
  1149. return(hops_to_server);
  1150. }
  1151. return(0);
  1152. }
  1153. /***********************************************************************************************
  1154. * Ping_Host -- Send a number of pings to a host and wait for responses *
  1155. * *
  1156. * *
  1157. * *
  1158. * INPUT: Host IP address to ping *
  1159. * My IP address *
  1160. * Number of pings to send *
  1161. * Payload size of ping *
  1162. * Ptr to array to receive ping times *
  1163. * Timeout for each ping *
  1164. * *
  1165. * OUTPUT: Number of pings received *
  1166. * *
  1167. * WARNINGS: None *
  1168. * *
  1169. * HISTORY: *
  1170. * 10/8/2001 2:09PM ST : Created *
  1171. *=============================================================================================*/
  1172. int Ping_Host(unsigned long host_ip, unsigned long my_ip, int times, int payload_size, unsigned long *ping_times, unsigned long timeout)
  1173. {
  1174. static int _packet_sequencer = 0;
  1175. int num_pings = 0;
  1176. char temp_buffer[640];
  1177. struct sockaddr_in host_addr;
  1178. struct sockaddr_in address;
  1179. unsigned long ping_dest_address = htonl(my_ip);
  1180. /*
  1181. ** Set the TTL back to max.
  1182. */
  1183. int new_ttl = 255;
  1184. int result = setsockopt(ICMPRawSocket, IPPROTO_IP, IP_TTL, (char*)&new_ttl, sizeof(new_ttl));
  1185. if (result == SOCKET_ERROR) {
  1186. DebugString("setsockopt failed to set IP_TTL = %d - error code %d\n", new_ttl, WSAGetLastError());
  1187. return(0);
  1188. }
  1189. host_addr.sin_addr.s_addr = htonl(host_ip);
  1190. host_addr.sin_port = 80; //www port number. We can use anything here.
  1191. host_addr.sin_family = AF_INET;
  1192. /*
  1193. ** Ping n times.
  1194. */
  1195. for (int i=0 ; i<times ; i++) {
  1196. for (int b=0 ; b<sizeof(temp_buffer) ; b++) {
  1197. temp_buffer[b] = (unsigned char) (rand() & 0xff);
  1198. }
  1199. /*
  1200. ** Record the time before sending the ping.
  1201. */
  1202. unsigned long start_time = timeGetTime();
  1203. /*
  1204. ** Send the ping.
  1205. */
  1206. Send_Ping((char*)temp_buffer, payload_size, ICMPRawSocket, (struct sockaddr *) &host_addr, _packet_sequencer);
  1207. PingsSent++;
  1208. int seq_id = -1;
  1209. /*
  1210. ** Wait for the ping response.
  1211. */
  1212. while (seq_id != _packet_sequencer) {
  1213. Get_Ping_Response(ICMPRawSocket, seq_id, (struct sockaddr *) &address, ntohl(host_addr.sin_addr.s_addr), ping_dest_address);
  1214. if (timeGetTime() - start_time > timeout) {
  1215. DebugString("Failed to get response to reference ping %d\n", i);
  1216. PingsLost++;
  1217. break;
  1218. }
  1219. };
  1220. /*
  1221. ** Check the time now and record it as a ping time.
  1222. */
  1223. if (seq_id == _packet_sequencer) {
  1224. unsigned long router_ping_time = timeGetTime() - start_time;
  1225. DebugString("Ping time %d to external router %s is %d ms\n", num_pings, Addr_As_String2(&host_addr), router_ping_time);
  1226. ping_times[num_pings++] = router_ping_time;
  1227. }
  1228. _packet_sequencer++;
  1229. }
  1230. /*
  1231. ** Try and get a measure of how far off center some of the pings are.
  1232. */
  1233. if (num_pings > 5) {
  1234. NumPingsCheckedForConsistency += num_pings;
  1235. unsigned long *ping_copies = (unsigned long*) _alloca(num_pings * 4);
  1236. memcpy(ping_copies, ping_times, num_pings * 4);
  1237. float average_ping = Average_Ping(num_pings, ping_copies, true);
  1238. float error_permit = 0.25f;
  1239. if (average_ping < 100.0f) {
  1240. error_permit = 0.35f;
  1241. }
  1242. if (average_ping < 30.0f) {
  1243. error_permit = 0.5f;
  1244. }
  1245. for (int p=0 ; p<num_pings ; p++) {
  1246. float diff = ((float)ping_times[p]) - average_ping;
  1247. if (diff < 0) {
  1248. diff = -diff;
  1249. }
  1250. if (diff < average_ping * error_permit) {
  1251. NumConsistentPings++;
  1252. }
  1253. }
  1254. }
  1255. return(num_pings);
  1256. }
  1257. /***********************************************************************************************
  1258. * Ping_Compare -- qsort compare function for unsigned longs *
  1259. * *
  1260. * *
  1261. * *
  1262. * INPUT: ping 1 *
  1263. * ping 2 *
  1264. * *
  1265. * OUTPUT: result of comparison *
  1266. * *
  1267. * WARNINGS: None *
  1268. * *
  1269. * HISTORY: *
  1270. * 10/8/2001 2:13PM ST : Created *
  1271. *=============================================================================================*/
  1272. int __cdecl Ping_Compare(const void *ping1, const void *ping2)
  1273. {
  1274. unsigned long p1 = *((unsigned long*)ping1);
  1275. unsigned long p2 = *((unsigned long*)ping2);
  1276. if (p1 == p2) {
  1277. return(0);
  1278. }
  1279. if (p1 < p2) {
  1280. return(-1);
  1281. }
  1282. return(1);
  1283. }
  1284. /***********************************************************************************************
  1285. * Sort_Pings -- Sort the ping list into ascending order *
  1286. * *
  1287. * *
  1288. * *
  1289. * INPUT: Number of pings in list *
  1290. * Ptr to ping time array *
  1291. * *
  1292. * OUTPUT: Nothing *
  1293. * *
  1294. * WARNINGS: None *
  1295. * *
  1296. * HISTORY: *
  1297. * 10/8/2001 2:14PM ST : Created *
  1298. *=============================================================================================*/
  1299. void Sort_Pings(int num_pings, unsigned long *ping_times)
  1300. {
  1301. qsort(ping_times, num_pings, sizeof(unsigned long), &Ping_Compare);
  1302. }
  1303. /***********************************************************************************************
  1304. * Average_Ping -- Calculate the average ping time from a list of pings. *
  1305. * *
  1306. * *
  1307. * *
  1308. * INPUT: Number of pings *
  1309. * Ptr to ping times array *
  1310. * Ignore low & high - filter out very low and very high values from average *
  1311. * *
  1312. * OUTPUT: Nothing *
  1313. * *
  1314. * WARNINGS: None *
  1315. * *
  1316. * HISTORY: *
  1317. * 10/8/2001 2:14PM ST : Created *
  1318. *=============================================================================================*/
  1319. float Average_Ping(int num_pings, unsigned long *ping_times, bool ignore_low_high)
  1320. {
  1321. if (ignore_low_high && num_pings > 2) {
  1322. Sort_Pings(num_pings, ping_times);
  1323. memmove((char*)ping_times, ((char*)ping_times) + 4, 4 * (num_pings - 2));
  1324. num_pings -= 2;
  1325. }
  1326. float average_ping = 0.0;
  1327. for (int i=0 ; i<num_pings ; i++) {
  1328. average_ping += (float)(ping_times[i]);
  1329. }
  1330. average_ping = average_ping / (float) num_pings;
  1331. /*
  1332. ** If we have lots of pings, see if we can improve the accurracy by filtering out very small or very big pings.
  1333. */
  1334. if (num_pings > 5) {
  1335. float filter_percent = 0.25f;
  1336. if (average_ping < 10.0) {
  1337. filter_percent = 0.30f;
  1338. }
  1339. float new_average = 0;
  1340. int num_considered = 0;
  1341. for (int i=0 ; i<num_pings ; i++) {
  1342. float diff = ((float)ping_times[i]) - average_ping;
  1343. if (diff < 0) {
  1344. diff = -diff;
  1345. }
  1346. if (diff < average_ping * 0.25f) {
  1347. new_average += (float) ping_times[i];
  1348. num_considered++;
  1349. }
  1350. }
  1351. if (num_considered > 3) {
  1352. average_ping = new_average / (float) num_considered;
  1353. }
  1354. }
  1355. return(average_ping);
  1356. }
  1357. /***********************************************************************************************
  1358. * Lowest_Ping -- Get the lowest ping time from a list of pings. *
  1359. * *
  1360. * *
  1361. * *
  1362. * INPUT: Number of pings *
  1363. * Ptr to ping times array *
  1364. * *
  1365. * OUTPUT: Nothing *
  1366. * *
  1367. * WARNINGS: None *
  1368. * *
  1369. * HISTORY: *
  1370. * 10/9/2001 5:03PM ST : Created *
  1371. *=============================================================================================*/
  1372. float Lowest_Ping(int num_pings, unsigned long *ping_times)
  1373. {
  1374. float lowest_ping = 1000000.0;
  1375. for (int i=0 ; i<num_pings ; i++) {
  1376. lowest_ping = min(lowest_ping, (float)(ping_times[i]));
  1377. }
  1378. return(lowest_ping);
  1379. }
  1380. /***********************************************************************************************
  1381. * Send_Raw_UDP -- Send a raw UDP packet. *
  1382. * *
  1383. * *
  1384. * *
  1385. * INPUT: Ptr to buffer to copy packet payload from *
  1386. * Size of packet payload *
  1387. * Raw UDP socket to use *
  1388. * Address to send packet to *
  1389. * Source port to put in the UDP header *
  1390. * Dest port to put in the UDP header *
  1391. * *
  1392. * OUTPUT: True if sent OK *
  1393. * *
  1394. * WARNINGS: None *
  1395. * *
  1396. * HISTORY: *
  1397. * 10/3/2001 11:46AM ST : Created *
  1398. *=============================================================================================*/
  1399. bool Send_Raw_UDP(char *payload, int payload_size, SOCKET socket, struct sockaddr *address, unsigned short source_port, unsigned short dest_port)
  1400. {
  1401. /*
  1402. ** Asserts.
  1403. */
  1404. assert(payload_size < 550);
  1405. assert(socket != INVALID_SOCKET);
  1406. assert(source_port >= 1024);
  1407. assert(dest_port >= 1024);
  1408. assert(address != NULL);
  1409. if (address == NULL) {
  1410. return(false);
  1411. }
  1412. if (payload_size > 550) {
  1413. return(false);
  1414. }
  1415. /*
  1416. ** Build the header on the stack for convenience.
  1417. */
  1418. unsigned char packetbuf[1024];
  1419. UDPHeaderType *header = (UDPHeaderType*) packetbuf;
  1420. /*
  1421. ** Fill in the header fields.
  1422. */
  1423. header->SourcePort = source_port;
  1424. header->DestPort = htons(dest_port);
  1425. header->Length = (unsigned short) (sizeof(UDPHeaderType) + payload_size);
  1426. header->Checksum = 0;
  1427. /*
  1428. ** Copy the payload into place.
  1429. */
  1430. char *payload_ptr = ((char*)header) + sizeof(UDPHeaderType);
  1431. memcpy(payload_ptr, payload, payload_size);
  1432. /*
  1433. ** Fix up the UDP header checksum.
  1434. */
  1435. int packet_size = payload_size + sizeof(*header);
  1436. header->Checksum = Get_IP_Checksum((unsigned short *)header, packet_size);
  1437. /*
  1438. ** Send it.
  1439. */
  1440. ((struct sockaddr_in*)address)->sin_port = htons(dest_port);
  1441. int result = sendto(socket, (char*)header, packet_size, 0, address, sizeof(*address));
  1442. if (result == SOCKET_ERROR) {
  1443. DebugString("Send_Raw_UDP - sendto failed with error code %d\n", WSAGetLastError());
  1444. return(false);
  1445. }
  1446. if (result != packet_size) {
  1447. return(false);
  1448. }
  1449. return(true);
  1450. }
  1451. /***********************************************************************************************
  1452. * Send_Ping -- Use raw ICMP socket to send a ping message. *
  1453. * *
  1454. * *
  1455. * *
  1456. * INPUT: Ptr to buffer to copy packet payload from *
  1457. * Size of packet payload *
  1458. * Socket to use *
  1459. * Address to ping *
  1460. * *
  1461. * OUTPUT: True if ping sent OK *
  1462. * *
  1463. * WARNINGS: None *
  1464. * *
  1465. * HISTORY: *
  1466. * 10/3/2001 11:51AM ST : Created *
  1467. *=============================================================================================*/
  1468. bool Send_Ping(char *payload, int payload_size, SOCKET socket, struct sockaddr *address, int sequence_id)
  1469. {
  1470. //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);
  1471. /*
  1472. ** Asserts.
  1473. */
  1474. assert(payload_size < 550);
  1475. assert(socket != INVALID_SOCKET);
  1476. assert(address != NULL);
  1477. if (address == NULL) {
  1478. return(false);
  1479. }
  1480. if (payload_size > 550) {
  1481. return(false);
  1482. }
  1483. /*
  1484. ** Build the header on the stack for convenience.
  1485. */
  1486. unsigned char packetbuf[1024];
  1487. ICMPHeaderType *header = (ICMPHeaderType*) packetbuf;
  1488. /*
  1489. ** Set up the ICMP header fields.
  1490. */
  1491. header->Type = ICMP_ECHO;
  1492. header->Code = 0;
  1493. header->ID = (unsigned short) (GetCurrentProcessId() & 0xffff);
  1494. header->Checksum = 0;
  1495. header->Sequence = (unsigned short) sequence_id;
  1496. /*
  1497. ** Copy the payload into position.
  1498. */
  1499. char *payload_ptr = ((char*)header) + sizeof(ICMPHeaderType);
  1500. memcpy(payload_ptr, payload, payload_size);
  1501. /*
  1502. ** Fix up the checksum in the ICMP header.
  1503. */
  1504. int packet_size = payload_size + sizeof(*header);
  1505. header->Checksum = Get_IP_Checksum((unsigned short *)header, packet_size);
  1506. /*
  1507. ** Send it.
  1508. */
  1509. //DebugString("sendto\n");
  1510. int result = sendto(socket, (char*)header, packet_size, 0, address, sizeof(*address));
  1511. //DebugString("returned from sendto\n");
  1512. if (result == SOCKET_ERROR) {
  1513. DebugString("sendto failed with error code %d\n", WSAGetLastError());
  1514. return(false);
  1515. }
  1516. if (result != packet_size) {
  1517. return(false);
  1518. }
  1519. return(true);
  1520. }
  1521. /***********************************************************************************************
  1522. * Get_Ping_Response -- Wait for an ICMP echo reply or time exceeded message *
  1523. * *
  1524. * *
  1525. * *
  1526. * INPUT: Socket *
  1527. * Packet sequence id to look for *
  1528. * (out) Ptr to buffer to put sender address in *
  1529. * Address to use to validate pings (i.e. address ping was sent to) *
  1530. * (out) My address - filled in on ping responses *
  1531. * *
  1532. * OUTPUT: True if we got a ping response *
  1533. * *
  1534. * WARNINGS: None *
  1535. * *
  1536. * HISTORY: *
  1537. * 10/3/2001 12:57PM ST : Created *
  1538. *=============================================================================================*/
  1539. bool Get_Ping_Response(SOCKET socket, int &seq_id, struct sockaddr *address, unsigned long validate_address, unsigned long &my_address)
  1540. {
  1541. struct sockaddr_in addr;
  1542. int addr_len;
  1543. char recv_buffer[1024];
  1544. unsigned long bytes;
  1545. int result = ioctlsocket(socket, FIONREAD, &bytes);
  1546. /*
  1547. ** Result of 0 is success.
  1548. */
  1549. if (result != 0) {
  1550. Sleep(0);
  1551. return(false);
  1552. } else {
  1553. /*
  1554. ** If there is outstanding data, 'bytes' will contain the size of the next queued datagram.
  1555. */
  1556. if (bytes == 0) {
  1557. Sleep(0);
  1558. return(false);
  1559. } else {
  1560. /*
  1561. ** Call recvfrom function to get the outstanding packet.
  1562. */
  1563. addr_len = sizeof(addr);
  1564. result = recvfrom(socket, recv_buffer, sizeof(recv_buffer), 0, (LPSOCKADDR)&addr, &addr_len);
  1565. if (result == SOCKET_ERROR) {
  1566. DebugString("recvfrom failed with error code %d\n", WSAGetLastError());
  1567. return(false);
  1568. }
  1569. //DebugString("Get_Ping_Response - received packet %d bytes long\n", result);
  1570. //DebugString("Get_Ping_Response - recvfrom %s\n", Addr_As_String2(&addr));
  1571. if (result < (sizeof(IPHeaderType) + sizeof(ICMPHeaderType))) {
  1572. DebugString("Get_Ping_Response - packet header too small\n");
  1573. return(false);
  1574. }
  1575. /*
  1576. ** Decode the ping response. We get the IP header and all.
  1577. */
  1578. IPHeaderType *ip_header = (IPHeaderType*) recv_buffer;
  1579. /*
  1580. ** Get the header length. Length specified in the header is in longs so multiply it by 4 to get bytes.
  1581. */
  1582. int ip_header_size = ip_header->Length * 4;
  1583. if (result < (ip_header_size + (int)sizeof(ICMPHeaderType))) {
  1584. DebugString("Get_Ping_Response - packet header reported size too big\n");
  1585. return(false);
  1586. }
  1587. if (ip_header->Protocol == PROTOCOL_ICMP) {
  1588. //DebugString("Protocol is ICMP\n");
  1589. /*
  1590. ** Figure out where the ICMP header is.
  1591. */
  1592. //IPHeaderType *ip_header = (IPHeaderType*) recv_buffer;
  1593. ICMPHeaderType *icmp_header = (ICMPHeaderType*) (recv_buffer + ip_header_size);
  1594. my_address = ntohl(ip_header->DestIP);
  1595. switch (icmp_header->Type) {
  1596. /*
  1597. ** An echo reply is basically a ping response.
  1598. */
  1599. case ICMP_ECHO_REPLY:
  1600. //DebugString("Type is ICMP_ECHO_REPLY\n");
  1601. if (icmp_header->ID == (unsigned short)(GetCurrentProcessId() & 0xffff)) {
  1602. memcpy(address, &addr, addr_len);
  1603. seq_id = icmp_header->Sequence;
  1604. return(true);
  1605. }
  1606. break;
  1607. /*
  1608. ** A time exceeded is sent when a router discards a packet due to a TTL of 0.
  1609. */
  1610. case ICMP_TIME_EXCEEDED:
  1611. //DebugString("Type is ICMP_TIME_EXCEEDED\n");
  1612. {
  1613. /*
  1614. ** Find the packets original IP header. ICMP_TIME_EXCEEDED is 8 bytes followed by a copy of the original IP
  1615. ** header followed by the original ICMP header followed by 64 bits of the original payload. Phew. (the original
  1616. ** payload seems to be frequently lost).
  1617. */
  1618. IPHeaderType *original_ip_header = (IPHeaderType*)(((char*)icmp_header) + 8);
  1619. if (ntohl(original_ip_header->DestIP) == validate_address) {
  1620. DebugString("Received ICMP_TIME_EXCEEDED from %s\n", Addr_As_String((unsigned char*)&ip_header->SourceIP));
  1621. memcpy(address, &addr, addr_len);
  1622. seq_id = 100000;
  1623. return(true);
  1624. }
  1625. }
  1626. break;
  1627. default:
  1628. DebugString("Type is %d\n", icmp_header->Type);
  1629. break;
  1630. }
  1631. } else {
  1632. DebugString("Protocol is %d\n", ip_header->Protocol);
  1633. }
  1634. }
  1635. }
  1636. return(false);
  1637. }
  1638. /***********************************************************************************************
  1639. * Open_Raw_Sockets -- Initialize winsock and create the raw sockets we need *
  1640. * *
  1641. * *
  1642. * *
  1643. * INPUT: Nothing *
  1644. * *
  1645. * OUTPUT: Nothing *
  1646. * *
  1647. * WARNINGS: None *
  1648. * *
  1649. * HISTORY: *
  1650. * 10/3/2001 11:31AM ST : Created *
  1651. *=============================================================================================*/
  1652. bool Open_Raw_Sockets(int &failure_code)
  1653. {
  1654. WSADATA wsa_data;
  1655. bool use_group = false; //true;
  1656. /*
  1657. ** We need Winsocl 2 for raw sockets.
  1658. */
  1659. if (WSAStartup(MAKEWORD(2,1), &wsa_data) != 0) {
  1660. DebugString("WSAStartup failed: error code %d\n", GetLastError());
  1661. failure_code = BANDTEST_NO_WINSOCK2;
  1662. return(false);
  1663. }
  1664. /*
  1665. ** Create a socket for UDP packets.
  1666. */
  1667. if (use_group) {
  1668. RawSocket = WSASocket(AF_INET, SOCK_RAW, IPPROTO_UDP, NULL, SG_UNCONSTRAINED_GROUP, 0);
  1669. if (RawSocket == INVALID_SOCKET) {
  1670. DebugString("Unable to create raw UDP socket with SG_UNCONSTRAINED_GROUP - error code \n", WSAGetLastError());
  1671. use_group = false;
  1672. }
  1673. }
  1674. if (!use_group) {
  1675. RawSocket = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
  1676. }
  1677. if (RawSocket == INVALID_SOCKET) {
  1678. DebugString("Unable to create raw UDP socket - error code \n", WSAGetLastError());
  1679. WSACleanup();
  1680. if (WSAGetLastError() == WSAEACCES) {
  1681. failure_code = BANDTEST_NO_RAW_SOCKET_PERMISSION;
  1682. } else {
  1683. failure_code = BANDTEST_NO_RAW_SOCKET_CREATE;
  1684. }
  1685. return(false);
  1686. }
  1687. /*
  1688. ** Get the group number.
  1689. */
  1690. unsigned long group = 0;
  1691. int length = 4;
  1692. if (use_group) {
  1693. if (getsockopt (RawSocket, SOL_SOCKET, SO_GROUP_ID, (char*)&group, &length) == SOCKET_ERROR) {
  1694. DebugString("Unable to get group for raw socket - error code \n", WSAGetLastError());
  1695. use_group = false;
  1696. }
  1697. }
  1698. /*
  1699. ** Create a socket for ICMP packets.
  1700. */
  1701. if (use_group) {
  1702. ICMPRawSocket = WSASocket(AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, group, 0);
  1703. } else {
  1704. ICMPRawSocket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
  1705. }
  1706. if (ICMPRawSocket == INVALID_SOCKET) {
  1707. DebugString("Unable to create raw ICMP socket - error code \n", WSAGetLastError());
  1708. closesocket(RawSocket);
  1709. WSACleanup();
  1710. if (WSAGetLastError() == WSAEACCES) {
  1711. failure_code = BANDTEST_NO_RAW_SOCKET_PERMISSION;
  1712. } else {
  1713. failure_code = BANDTEST_NO_RAW_SOCKET_CREATE;
  1714. }
  1715. return(false);
  1716. }
  1717. /*
  1718. ** Set the priority for the sockets.
  1719. */
  1720. //unsigned long priority;
  1721. //getsockopt (RawSocket, SOL_SOCKET, SO_GROUP_PRIORITY, (char*)&priority, &length);
  1722. //getsockopt (ICMPRawSocket, SOL_SOCKET, SO_GROUP_PRIORITY, (char*)&priority, &length);
  1723. unsigned long new_priority = 50;
  1724. int result = setsockopt(RawSocket, SOL_SOCKET, SO_GROUP_PRIORITY, (char*)&new_priority, sizeof(new_priority));
  1725. if (result != 0) {
  1726. DebugString("Unable to set priority on UDP socket - error code %d\n", WSAGetLastError());
  1727. }
  1728. new_priority = 1;
  1729. result = setsockopt(ICMPRawSocket, SOL_SOCKET, SO_GROUP_PRIORITY, (char*)&new_priority, sizeof(new_priority));
  1730. if (result != 0) {
  1731. DebugString("Unable to set priority on ICMP socket - error code %d\n", WSAGetLastError());
  1732. }
  1733. return(true);
  1734. }
  1735. /***********************************************************************************************
  1736. * Close_Raw_Sockets -- Initialize winsock and create the raw sockets we need *
  1737. * *
  1738. * *
  1739. * *
  1740. * INPUT: Nothing *
  1741. * *
  1742. * OUTPUT: Nothing *
  1743. * *
  1744. * WARNINGS: None *
  1745. * *
  1746. * HISTORY: *
  1747. * 10/3/2001 11:31AM ST : Created *
  1748. *=============================================================================================*/
  1749. void Close_Raw_Sockets(void)
  1750. {
  1751. if (RawSocket != INVALID_SOCKET) {
  1752. closesocket(RawSocket);
  1753. }
  1754. if (RawSocket != INVALID_SOCKET) {
  1755. closesocket(ICMPRawSocket);
  1756. }
  1757. WSACleanup();
  1758. }
  1759. /***********************************************************************************************
  1760. * Get_IP_Checksum -- Create a checksum value for an IP packets *
  1761. * *
  1762. * *
  1763. * *
  1764. * INPUT: Buffer *
  1765. * Buffer size *
  1766. * *
  1767. * OUTPUT: Checksum *
  1768. * *
  1769. * WARNINGS: None *
  1770. * *
  1771. * HISTORY: *
  1772. * 10/3/2001 11:44AM ST : Created *
  1773. *=============================================================================================*/
  1774. unsigned short Get_IP_Checksum(unsigned short *buffer, int size)
  1775. {
  1776. unsigned long checksum = 0;
  1777. int new_size = size;
  1778. unsigned short *bufptr = buffer;
  1779. while(new_size >1) {
  1780. checksum += *bufptr++;
  1781. new_size -= sizeof(unsigned short);
  1782. }
  1783. if (new_size) {
  1784. checksum += *(unsigned char*) bufptr;
  1785. }
  1786. checksum = (checksum >> 16) + (checksum & 0xffff);
  1787. checksum += (checksum >> 16);
  1788. checksum = ~checksum;
  1789. return ((unsigned short) checksum);
  1790. }
  1791. bool Set_Registry_Int(const char *name, int value)
  1792. {
  1793. int result = RegSetValueEx(RegistryKey, name, 0, REG_DWORD, (unsigned char*)&value, sizeof(value));
  1794. return((result == ERROR_SUCCESS) ? true : false);
  1795. }
  1796. int Get_Registry_Int(const char *name, int def_value)
  1797. {
  1798. unsigned long type;
  1799. unsigned long data;
  1800. unsigned long data_size = sizeof(data);
  1801. if (RegQueryValueEx(RegistryKey, name, NULL, &type, (unsigned char*)&data, &data_size) == ERROR_SUCCESS) {
  1802. return(data);
  1803. }
  1804. return(def_value);
  1805. }
  1806. bool Open_Registry(void)
  1807. {
  1808. HKEY key;
  1809. unsigned long disposition;
  1810. long result = RegCreateKeyEx(HKEY_LOCAL_MACHINE, RegistryPath, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &key, &disposition);
  1811. if (result == ERROR_SUCCESS) {
  1812. RegistryKey = key;
  1813. return(true);
  1814. }
  1815. return(false);
  1816. }
  1817. void Close_Registry(void)
  1818. {
  1819. RegCloseKey(RegistryKey);
  1820. }
  1821. #ifdef _DEBUG
  1822. /***********************************************************************************************
  1823. * DebugString -- Debug output *
  1824. * *
  1825. * *
  1826. * *
  1827. * INPUT: Printf format *
  1828. * *
  1829. * OUTPUT: Nothing *
  1830. * *
  1831. * WARNINGS: None *
  1832. * *
  1833. * HISTORY: *
  1834. * 10/3/2001 11:36AM ST : Created *
  1835. *=============================================================================================*/
  1836. void DebugString (char const * string, ...)
  1837. {
  1838. static char buffer[1024];
  1839. static char filebuf[1024];
  1840. static char path_to_exe[512];
  1841. static char drive[_MAX_DRIVE];
  1842. static char dir[_MAX_DIR];
  1843. va_list va;
  1844. strcpy(buffer, "BandTest: ");
  1845. va_start(va, string);
  1846. vsprintf(&buffer[10], string, va);
  1847. va_end(va);
  1848. DWORD actual;
  1849. if (DebugFile == INVALID_HANDLE_VALUE) {
  1850. GetModuleFileName (GetModuleHandle(NULL), &path_to_exe[0], 512);
  1851. _splitpath(path_to_exe, drive, dir, NULL, NULL);
  1852. _makepath(DebugFileName, drive, dir, "bandtest", "txt");
  1853. DebugFile = CreateFile(DebugFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  1854. } else {
  1855. DebugFile = CreateFile(DebugFileName, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  1856. }
  1857. OutputDebugString (buffer);
  1858. if (DebugFile != INVALID_HANDLE_VALUE) {
  1859. SetFilePointer (DebugFile, 0, NULL, FILE_END);
  1860. char *srcbuf = buffer;
  1861. char *destbuf = filebuf;
  1862. char c;
  1863. while (*srcbuf != 0) {
  1864. c = *srcbuf++;
  1865. if (c == '\n') {
  1866. *destbuf++ = '\r';
  1867. }
  1868. *destbuf++ = c;
  1869. }
  1870. *destbuf = 0;
  1871. WriteFile(DebugFile, filebuf, strlen(filebuf), &actual, NULL);
  1872. CloseHandle (DebugFile);
  1873. }
  1874. }
  1875. /***********************************************************************************************
  1876. * Addr_As_String -- Get a human readable internet address *
  1877. * *
  1878. * *
  1879. * *
  1880. * INPUT: Address ptr *
  1881. * *
  1882. * OUTPUT: String representation *
  1883. * *
  1884. * WARNINGS: None *
  1885. * *
  1886. * HISTORY: *
  1887. * 8/31/2001 3:48PM ST : Created *
  1888. *=============================================================================================*/
  1889. char * Addr_As_String2(struct sockaddr_in *addr)
  1890. {
  1891. static char _string[128];
  1892. sprintf(_string, "%d.%d.%d.%d ; %d", (int)(addr->sin_addr.S_un.S_un_b.s_b1),
  1893. (int)(addr->sin_addr.S_un.S_un_b.s_b2),
  1894. (int)(addr->sin_addr.S_un.S_un_b.s_b3),
  1895. (int)(addr->sin_addr.S_un.S_un_b.s_b4),
  1896. (int)(addr->sin_port));
  1897. return(_string);
  1898. }
  1899. /***********************************************************************************************
  1900. * Addr_As_String -- Get a human readable internet address *
  1901. * *
  1902. * *
  1903. * *
  1904. * INPUT: Address ptr *
  1905. * *
  1906. * OUTPUT: String representation *
  1907. * *
  1908. * WARNINGS: None *
  1909. * *
  1910. * HISTORY: *
  1911. * 8/31/2001 3:48PM ST : Created *
  1912. *=============================================================================================*/
  1913. char * Addr_As_String(unsigned char *addr)
  1914. {
  1915. static char _string[128];
  1916. sprintf(_string, "%d.%d.%d.%d", (int)(addr[0]), (int)(addr[1]), (int)(addr[2]), (int)(addr[3]));
  1917. return(_string);
  1918. }
  1919. #endif //_DEBUG
  1920. #if (0)
  1921. /*
  1922. ** Try to find a router with a different address class than ours. Start at TTL = 1 and increase until we find what we
  1923. ** are looking for.
  1924. */
  1925. ttl = 1;
  1926. hops_to_server = 0;
  1927. found_whole_path = false;
  1928. do {
  1929. performance_timer = timeGetTime();
  1930. router_ttl = 0;
  1931. for (ttl ; ttl < 100 ; ttl++) {
  1932. memcpy(&address, &host_address, sizeof(address));
  1933. /*
  1934. ** Set the TTL.
  1935. */
  1936. int result = setsockopt(ICMPRawSocket, IPPROTO_IP, IP_TTL, (char*)&ttl, sizeof(ttl));
  1937. if (result == SOCKET_ERROR) {
  1938. DebugString("setsockopt failed to set IP_TTL = %d - error code %d\n", ttl, WSAGetLastError());
  1939. failure_code = BANDTEST_NO_TTL_SET;
  1940. Close_Raw_Sockets();
  1941. return(0);
  1942. }
  1943. unsigned long start_time = timeGetTime();
  1944. /*
  1945. ** Send a ping with the previously set TTL.
  1946. */
  1947. DebugString("Sending ping with TTL = %d\n", ttl);
  1948. Send_Ping(temp_buffer, 0, ICMPRawSocket, (struct sockaddr *) &address, packet_sequencer);
  1949. /*
  1950. ** Wait for a ping response.
  1951. */
  1952. seq_id = -1;
  1953. while (seq_id == -1) {
  1954. Get_Ping_Response(ICMPRawSocket, seq_id, (struct sockaddr *) &address, ntohl(host_address.sin_addr.s_addr), ping_dest_address);
  1955. if (timeGetTime() - start_time > 5000) {
  1956. DebugString("Failed to get response to ping with TTL = %d\n", ttl);
  1957. break;
  1958. //failure_code = BANDTEST_NO_PING_RESPONSE;
  1959. //Close_Raw_Sockets();
  1960. //return(0);
  1961. }
  1962. };
  1963. if (seq_id != -1) {
  1964. unsigned long long_router_addr = ntohl(address.sin_addr.s_addr);
  1965. if (!found_whole_path) {
  1966. path_to_server[hops_to_server++] = long_router_addr;
  1967. }
  1968. /*
  1969. ** See if this router is the target. If so, we are at the end of the path.
  1970. */
  1971. if (long_router_addr == server_ip || seq_id == packet_sequencer) {
  1972. /*
  1973. ** We better have found an external router by now...
  1974. */
  1975. assert(router_ttl != 0);
  1976. found_whole_path = true;
  1977. break;
  1978. }
  1979. /*
  1980. ** See if the router is on the same network as me.
  1981. */
  1982. if (router_ttl == 0 && (long_router_addr & 0xffff0000) != (my_ip & 0xffff0000)) {
  1983. memcpy(&router_addr, &address, sizeof(router_addr));
  1984. router_ttl = ttl;
  1985. DebugString("Found external router at %s - ttl = %d\n", Addr_As_String((unsigned char*)&address.sin_addr.s_addr), router_ttl);
  1986. if (found_whole_path || settings->TTLScatter == 0) {
  1987. break;
  1988. }
  1989. }
  1990. }
  1991. packet_sequencer++;
  1992. }
  1993. //if (router_ttl == 0) {
  1994. // DebugString("Failed to find external router\n");
  1995. // failure_code = BANDTEST_NO_EXTERNAL_ROUTER;
  1996. // Close_Raw_Sockets();
  1997. // return(0);
  1998. //}
  1999. //assert(router_ttl != 0);
  2000. if (router_ttl == 0) {
  2001. continue;
  2002. }
  2003. DebugString("Took %d ms to find external router\n", timeGetTime() - performance_timer);
  2004. performance_timer = timeGetTime();
  2005. average_ping = 0;
  2006. /*
  2007. ** Set the TTL back to max.
  2008. */
  2009. int new_ttl = 255;
  2010. int result = setsockopt(ICMPRawSocket, IPPROTO_IP, IP_TTL, (char*)&new_ttl, sizeof(new_ttl));
  2011. if (result == SOCKET_ERROR) {
  2012. DebugString("setsockopt failed to set IP_TTL = %d - error code %d\n", new_ttl, WSAGetLastError());
  2013. failure_code = BANDTEST_NO_TTL_SET;
  2014. Close_Raw_Sockets();
  2015. return(0);
  2016. }
  2017. /*
  2018. ** Ping the router directly to get a reference round trip time.
  2019. ** Try 3 pings and take an average.
  2020. */
  2021. packet_sequencer = 0;
  2022. memset(ping_times, 0xff, sizeof(ping_times));
  2023. num_pings = 0;
  2024. for (i=0 ; i<3 ; i++) {
  2025. unsigned long start_time = timeGetTime();
  2026. Send_Ping((char*)temp_buffer, 0, ICMPRawSocket, (struct sockaddr *) &router_addr, packet_sequencer);
  2027. seq_id = -1;
  2028. while (seq_id != packet_sequencer) {
  2029. Get_Ping_Response(ICMPRawSocket, seq_id, (struct sockaddr *) &address, ntohl(host_address.sin_addr.s_addr), ping_dest_address);
  2030. if (timeGetTime() - start_time > 2000) {
  2031. DebugString("Failed to get response to reference ping %d\n", i);
  2032. failure_code = BANDTEST_NO_PING_RESPONSE;
  2033. break;
  2034. //Close_Raw_Sockets();
  2035. //return(0);
  2036. }
  2037. };
  2038. //assert(seq_id == packet_sequencer);
  2039. //assert(seq_id < 3);
  2040. if (seq_id == packet_sequencer) {
  2041. unsigned long router_ping_time = timeGetTime() - start_time;
  2042. DebugString("Ping time %d to external router %s is %d ms\n", num_pings, Addr_As_String2(&router_addr), router_ping_time);
  2043. ping_times[num_pings++] = router_ping_time;
  2044. }
  2045. packet_sequencer++;
  2046. }
  2047. //assert(num_pings == 3);
  2048. average_ping = 0;
  2049. if (num_pings > 0) {
  2050. for (int p=0 ; p<num_pings ; p++) {
  2051. average_ping += ping_times[p];
  2052. }
  2053. average_ping = average_ping / num_pings;
  2054. DebugString("Average ping time to external router is %d ms\n", average_ping);
  2055. DebugString("Took %d ms to find average ping\n", timeGetTime() - performance_timer);
  2056. performance_timer = timeGetTime();
  2057. } else {
  2058. /*
  2059. ** If we didn't get all three pings then go round again.
  2060. */
  2061. router_ttl = 0;
  2062. }
  2063. } while (router_ttl == 0 && ttl < 8);
  2064. #endif //(0)