MainMenuUtils.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827
  1. /*
  2. ** Command & Conquer Generals Zero Hour(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. // //
  20. // (c) 2001-2003 Electronic Arts Inc. //
  21. // //
  22. ////////////////////////////////////////////////////////////////////////////////
  23. ///////////////////////////////////////////////////////////////////////////////////////
  24. // FILE: MainMenuUtils.cpp
  25. // Author: Matthew D. Campbell, Sept 2002
  26. // Description: GameSpy version check, patch download, etc utils
  27. ///////////////////////////////////////////////////////////////////////////////////////
  28. // INCLUDES ///////////////////////////////////////////////////////////////////////////
  29. #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
  30. #include <fcntl.h>
  31. //#include "Common/Registry.h"
  32. #include "Common/UserPreferences.h"
  33. #include "Common/Version.h"
  34. #include "GameClient/GameText.h"
  35. #include "GameClient/MessageBox.h"
  36. #include "GameClient/Shell.h"
  37. #include "GameLogic/ScriptEngine.h"
  38. #include "GameClient/ShellHooks.h"
  39. #include "GameSpy/ghttp/ghttp.h"
  40. #include "GameNetwork/DownloadManager.h"
  41. #include "GameNetwork/GameSpy/BuddyThread.h"
  42. #include "GameNetwork/GameSpy/MainMenuUtils.h"
  43. #include "GameNetwork/GameSpy/PeerDefs.h"
  44. #include "GameNetwork/GameSpy/PeerThread.h"
  45. #include "WWDownload/Registry.h"
  46. #include "WWDownload/URLBuilder.h"
  47. #ifdef _INTERNAL
  48. // for occasional debugging...
  49. //#pragma optimize("", off)
  50. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  51. #endif
  52. ///////////////////////////////////////////////////////////////////////////////////////
  53. static Bool checkingForPatchBeforeGameSpy = FALSE;
  54. static Int checksLeftBeforeOnline = 0;
  55. static Int timeThroughOnline = 0; // used to avoid having old callbacks cause problems
  56. static Bool mustDownloadPatch = FALSE;
  57. static Bool cantConnectBeforeOnline = FALSE;
  58. static std::list<QueuedDownload> queuedDownloads;
  59. static char *MOTDBuffer = NULL;
  60. static char *configBuffer = NULL;
  61. GameWindow *onlineCancelWindow = NULL;
  62. static Bool s_asyncDNSThreadDone = TRUE;
  63. static Bool s_asyncDNSThreadSucceeded = FALSE;
  64. static Bool s_asyncDNSLookupInProgress = FALSE;
  65. static HANDLE s_asyncDNSThreadHandle = NULL;
  66. enum {
  67. LOOKUP_INPROGRESS,
  68. LOOKUP_FAILED,
  69. LOOKUP_SUCCEEDED,
  70. };
  71. ///////////////////////////////////////////////////////////////////////////////////////
  72. static void startOnline( void );
  73. static void reallyStartPatchCheck( void );
  74. ///////////////////////////////////////////////////////////////////////////////////////
  75. // someone has hit a button allowing downloads to start
  76. void StartDownloadingPatches( void )
  77. {
  78. if (queuedDownloads.empty())
  79. {
  80. HandleCanceledDownload();
  81. return;
  82. }
  83. WindowLayout *layout;
  84. layout = TheWindowManager->winCreateLayout( AsciiString( "Menus/DownloadMenu.wnd" ) );
  85. layout->runInit();
  86. layout->hide( FALSE );
  87. layout->bringForward();
  88. HandleCanceledDownload(FALSE);
  89. DEBUG_ASSERTCRASH(TheDownloadManager, ("No download manager!"));
  90. if (TheDownloadManager)
  91. {
  92. std::list<QueuedDownload>::iterator it = queuedDownloads.begin();
  93. while (it != queuedDownloads.end())
  94. {
  95. QueuedDownload q = *it;
  96. TheDownloadManager->queueFileForDownload(q.server, q.userName, q.password,
  97. q.file, q.localFile, q.regKey, q.tryResume);
  98. queuedDownloads.pop_front();
  99. it = queuedDownloads.begin();
  100. }
  101. TheDownloadManager->downloadNextQueuedFile();
  102. }
  103. }
  104. ///////////////////////////////////////////////////////////////////////////////////////
  105. // user agrees to patch before going online
  106. static void patchBeforeOnlineCallback( void )
  107. {
  108. StartDownloadingPatches();
  109. }
  110. // user doesn't want to patch before going online
  111. static void noPatchBeforeOnlineCallback( void )
  112. {
  113. queuedDownloads.clear();
  114. if (mustDownloadPatch || cantConnectBeforeOnline)
  115. {
  116. // go back to normal
  117. HandleCanceledDownload();
  118. }
  119. else
  120. {
  121. // clear out unneeded downloads and go on
  122. startOnline();
  123. }
  124. }
  125. ///////////////////////////////////////////////////////////////////////////////////////
  126. static Bool hasWriteAccess()
  127. {
  128. const char* filename = "PatchAccessTest.txt";
  129. remove(filename);
  130. int handle = _open( filename, _O_CREAT | _O_RDWR, _S_IREAD | _S_IWRITE);
  131. if (handle == -1)
  132. {
  133. return false;
  134. }
  135. _close(handle);
  136. remove(filename);
  137. unsigned int val;
  138. if (!GetUnsignedIntFromRegistry("", "Version", val))
  139. {
  140. return false;
  141. }
  142. if (!SetUnsignedIntInRegistry("", "Version", val))
  143. {
  144. return false;
  145. }
  146. return true;
  147. }
  148. ///////////////////////////////////////////////////////////////////////////////////////
  149. static void startOnline( void )
  150. {
  151. checkingForPatchBeforeGameSpy = FALSE;
  152. DEBUG_ASSERTCRASH(checksLeftBeforeOnline==0, ("starting online with pending callbacks"));
  153. if (onlineCancelWindow)
  154. {
  155. TheWindowManager->winDestroy(onlineCancelWindow);
  156. onlineCancelWindow = NULL;
  157. }
  158. if (cantConnectBeforeOnline)
  159. {
  160. MessageBoxOk(TheGameText->fetch("GUI:CannotConnectToServservTitle"),
  161. TheGameText->fetch("GUI:CannotConnectToServserv"),
  162. noPatchBeforeOnlineCallback);
  163. return;
  164. }
  165. if (queuedDownloads.size())
  166. {
  167. if (!hasWriteAccess())
  168. {
  169. MessageBoxOk(TheGameText->fetch("GUI:Error"),
  170. TheGameText->fetch("GUI:MustHaveAdminRights"),
  171. noPatchBeforeOnlineCallback);
  172. }
  173. else if (mustDownloadPatch)
  174. {
  175. MessageBoxOkCancel(TheGameText->fetch("GUI:PatchAvailable"),
  176. TheGameText->fetch("GUI:MustPatchForOnline"),
  177. patchBeforeOnlineCallback, noPatchBeforeOnlineCallback);
  178. }
  179. else
  180. {
  181. MessageBoxYesNo(TheGameText->fetch("GUI:PatchAvailable"),
  182. TheGameText->fetch("GUI:CanPatchForOnline"),
  183. patchBeforeOnlineCallback, noPatchBeforeOnlineCallback);
  184. }
  185. return;
  186. }
  187. TheScriptEngine->signalUIInteract(TheShellHookNames[SHELL_SCRIPT_HOOK_MAIN_MENU_ONLINE_SELECTED]);
  188. DEBUG_ASSERTCRASH( !TheGameSpyBuddyMessageQueue, ("TheGameSpyBuddyMessageQueue exists!") );
  189. DEBUG_ASSERTCRASH( !TheGameSpyPeerMessageQueue, ("TheGameSpyPeerMessageQueue exists!") );
  190. DEBUG_ASSERTCRASH( !TheGameSpyInfo, ("TheGameSpyInfo exists!") );
  191. SetUpGameSpy(MOTDBuffer, configBuffer);
  192. if (MOTDBuffer)
  193. {
  194. delete[] MOTDBuffer;
  195. MOTDBuffer = NULL;
  196. }
  197. if (configBuffer)
  198. {
  199. delete[] configBuffer;
  200. configBuffer = NULL;
  201. }
  202. #ifdef ALLOW_NON_PROFILED_LOGIN
  203. UserPreferences pref;
  204. pref.load("GameSpyLogin.ini");
  205. UserPreferences::const_iterator it = pref.find("useProfiles");
  206. if (it != pref.end() && it->second.compareNoCase("yes") == 0)
  207. #endif ALLOW_NON_PROFILED_LOGIN
  208. TheShell->push( AsciiString("Menus/GameSpyLoginProfile.wnd") );
  209. #ifdef ALLOW_NON_PROFILED_LOGIN
  210. else
  211. TheShell->push( AsciiString("Menus/GameSpyLoginQuick.wnd") );
  212. #endif ALLOW_NON_PROFILED_LOGIN
  213. }
  214. ///////////////////////////////////////////////////////////////////////////////////////
  215. static void queuePatch(Bool mandatory, AsciiString downloadURL)
  216. {
  217. QueuedDownload q;
  218. Bool success = TRUE;
  219. AsciiString connectionType;
  220. success &= downloadURL.nextToken(&connectionType, ":");
  221. AsciiString server;
  222. success &= downloadURL.nextToken(&server, ":/");
  223. AsciiString user;
  224. success &= downloadURL.nextToken(&user, ":@");
  225. AsciiString pass;
  226. success &= downloadURL.nextToken(&pass, "@/");
  227. AsciiString filePath;
  228. success &= downloadURL.nextToken(&filePath, "");
  229. if (!success && user.isNotEmpty())
  230. {
  231. // no user/pass combo - move the file into it's proper place
  232. filePath = user;
  233. user = ""; // LFeenanEA - Credentials removed as per Security requirements
  234. pass = "";
  235. success = TRUE;
  236. }
  237. AsciiString fileStr = filePath;
  238. const char *s = filePath.reverseFind('/');
  239. if (s)
  240. fileStr = s+1;
  241. AsciiString fileName = "patches\\";
  242. fileName.concat(fileStr);
  243. DEBUG_LOG(("download URL split: %d [%s] [%s] [%s] [%s] [%s] [%s]\n",
  244. success, connectionType.str(), server.str(), user.str(), pass.str(),
  245. filePath.str(), fileName.str()));
  246. if (!success)
  247. return;
  248. q.file = filePath;
  249. q.localFile = fileName;
  250. q.password = pass;
  251. q.regKey = "";
  252. q.server = server;
  253. q.tryResume = TRUE;
  254. q.userName = user;
  255. std::list<QueuedDownload>::iterator it = queuedDownloads.begin();
  256. while (it != queuedDownloads.end())
  257. {
  258. if (it->localFile == q.localFile)
  259. return; // don't add it if it exists already (because we can check multiple times)
  260. ++it;
  261. }
  262. queuedDownloads.push_back(q);
  263. }
  264. ///////////////////////////////////////////////////////////////////////////////////////
  265. static GHTTPBool motdCallback( GHTTPRequest request, GHTTPResult result,
  266. char * buffer, int bufferLen, void * param )
  267. {
  268. Int run = (Int)param;
  269. if (run != timeThroughOnline)
  270. {
  271. DEBUG_CRASH(("Old callback being called!"));
  272. return GHTTPTrue;
  273. }
  274. if (MOTDBuffer)
  275. {
  276. delete[] MOTDBuffer;
  277. MOTDBuffer = NULL;
  278. }
  279. MOTDBuffer = NEW char[bufferLen];
  280. memcpy(MOTDBuffer, buffer, bufferLen);
  281. MOTDBuffer[bufferLen-1] = 0;
  282. --checksLeftBeforeOnline;
  283. DEBUG_ASSERTCRASH(checksLeftBeforeOnline>=0, ("Too many callbacks"));
  284. if (onlineCancelWindow && !checksLeftBeforeOnline)
  285. {
  286. TheWindowManager->winDestroy(onlineCancelWindow);
  287. onlineCancelWindow = NULL;
  288. }
  289. DEBUG_LOG(("------- Got MOTD before going online -------\n"));
  290. DEBUG_LOG(("%s\n", (MOTDBuffer)?MOTDBuffer:""));
  291. DEBUG_LOG(("--------------------------------------------\n"));
  292. if (!checksLeftBeforeOnline)
  293. startOnline();
  294. return GHTTPTrue;
  295. }
  296. ///////////////////////////////////////////////////////////////////////////////////////
  297. static GHTTPBool configCallback( GHTTPRequest request, GHTTPResult result,
  298. char * buffer, int bufferLen, void * param )
  299. {
  300. Int run = (Int)param;
  301. if (run != timeThroughOnline)
  302. {
  303. DEBUG_CRASH(("Old callback being called!"));
  304. return GHTTPTrue;
  305. }
  306. if (configBuffer)
  307. {
  308. delete[] configBuffer;
  309. configBuffer = NULL;
  310. }
  311. if (result != GHTTPSuccess || bufferLen < 100)
  312. {
  313. if (!checkingForPatchBeforeGameSpy)
  314. return GHTTPTrue;
  315. --checksLeftBeforeOnline;
  316. if (onlineCancelWindow && !checksLeftBeforeOnline)
  317. {
  318. TheWindowManager->winDestroy(onlineCancelWindow);
  319. onlineCancelWindow = NULL;
  320. }
  321. cantConnectBeforeOnline = TRUE;
  322. if (!checksLeftBeforeOnline)
  323. {
  324. startOnline();
  325. }
  326. return GHTTPTrue;
  327. }
  328. configBuffer = NEW char[bufferLen];
  329. memcpy(configBuffer, buffer, bufferLen);
  330. configBuffer[bufferLen-1] = 0;
  331. AsciiString fname;
  332. fname.format("%sGeneralsOnline\\Config.txt", TheGlobalData->getPath_UserData().str());
  333. FILE *fp = fopen(fname.str(), "wb");
  334. if (fp)
  335. {
  336. fwrite(configBuffer, bufferLen, 1, fp);
  337. fclose(fp);
  338. }
  339. --checksLeftBeforeOnline;
  340. DEBUG_ASSERTCRASH(checksLeftBeforeOnline>=0, ("Too many callbacks"));
  341. if (onlineCancelWindow && !checksLeftBeforeOnline)
  342. {
  343. TheWindowManager->winDestroy(onlineCancelWindow);
  344. onlineCancelWindow = NULL;
  345. }
  346. DEBUG_LOG(("Got Config before going online\n"));
  347. if (!checksLeftBeforeOnline)
  348. startOnline();
  349. return GHTTPTrue;
  350. }
  351. ///////////////////////////////////////////////////////////////////////////////////////
  352. static GHTTPBool configHeadCallback( GHTTPRequest request, GHTTPResult result,
  353. char * buffer, int bufferLen, void * param )
  354. {
  355. Int run = (Int)param;
  356. if (run != timeThroughOnline)
  357. {
  358. DEBUG_CRASH(("Old callback being called!"));
  359. return GHTTPTrue;
  360. }
  361. DEBUG_LOG(("HTTP head resp: res=%d, len=%d, buf=[%s]\n", result, bufferLen, buffer));
  362. if (result == GHTTPSuccess)
  363. {
  364. DEBUG_LOG(("Headers are [%s]\n", ghttpGetHeaders( request )));
  365. AsciiString headers(ghttpGetHeaders( request ));
  366. AsciiString line;
  367. while (headers.nextToken(&line, "\n\r"))
  368. {
  369. AsciiString key, val;
  370. line.nextToken(&key, ": ");
  371. line.nextToken(&val, ": \r\n");
  372. if (key.compare("Content-Length") == 0 && val.isNotEmpty())
  373. {
  374. Int serverLen = atoi(val.str());
  375. Int fileLen = 0;
  376. AsciiString fname;
  377. fname.format("%sGeneralsOnline\\Config.txt", TheGlobalData->getPath_UserData().str());
  378. FILE *fp = fopen(fname.str(), "rb");
  379. if (fp)
  380. {
  381. fseek(fp, 0, SEEK_END);
  382. fileLen = ftell(fp);
  383. fclose(fp);
  384. }
  385. if (serverLen == fileLen)
  386. {
  387. // we don't need to download the MOTD again
  388. --checksLeftBeforeOnline;
  389. DEBUG_ASSERTCRASH(checksLeftBeforeOnline>=0, ("Too many callbacks"));
  390. if (onlineCancelWindow && !checksLeftBeforeOnline)
  391. {
  392. TheWindowManager->winDestroy(onlineCancelWindow);
  393. onlineCancelWindow = NULL;
  394. }
  395. if (configBuffer)
  396. {
  397. delete[] configBuffer;
  398. configBuffer = NULL;
  399. }
  400. AsciiString fname;
  401. fname.format("%sGeneralsOnline\\Config.txt", TheGlobalData->getPath_UserData().str());
  402. FILE *fp = fopen(fname.str(), "rb");
  403. if (fp)
  404. {
  405. configBuffer = NEW char[fileLen];
  406. fread(configBuffer, fileLen, 1, fp);
  407. configBuffer[fileLen-1] = 0;
  408. fclose(fp);
  409. DEBUG_LOG(("Got Config before going online\n"));
  410. if (!checksLeftBeforeOnline)
  411. startOnline();
  412. return GHTTPTrue;
  413. }
  414. }
  415. }
  416. }
  417. }
  418. // we need to download the MOTD again
  419. std::string gameURL, mapURL;
  420. std::string configURL, motdURL;
  421. FormatURLFromRegistry(gameURL, mapURL, configURL, motdURL);
  422. ghttpGet( configURL.c_str(), GHTTPFalse, configCallback, param );
  423. return GHTTPTrue;
  424. }
  425. ///////////////////////////////////////////////////////////////////////////////////////
  426. static GHTTPBool gamePatchCheckCallback( GHTTPRequest request, GHTTPResult result, char * buffer, int bufferLen, void * param )
  427. {
  428. Int run = (Int)param;
  429. if (run != timeThroughOnline)
  430. {
  431. DEBUG_CRASH(("Old callback being called!"));
  432. return GHTTPTrue;
  433. }
  434. --checksLeftBeforeOnline;
  435. DEBUG_ASSERTCRASH(checksLeftBeforeOnline>=0, ("Too many callbacks"));
  436. DEBUG_LOG(("Result=%d, buffer=[%s], len=%d\n", result, buffer, bufferLen));
  437. if (result != GHTTPSuccess)
  438. {
  439. if (!checkingForPatchBeforeGameSpy)
  440. return GHTTPTrue;
  441. cantConnectBeforeOnline = TRUE;
  442. if (!checksLeftBeforeOnline)
  443. {
  444. startOnline();
  445. }
  446. return GHTTPTrue;
  447. }
  448. AsciiString message = buffer;
  449. AsciiString line;
  450. while (message.nextToken(&line, "\r\n"))
  451. {
  452. AsciiString type, req, url;
  453. Bool ok = TRUE;
  454. ok &= line.nextToken(&type, " ");
  455. ok &= line.nextToken(&req, " ");
  456. ok &= line.nextToken(&url, " ");
  457. if (ok && type == "patch")
  458. {
  459. DEBUG_LOG(("Saw a patch: %d/[%s]\n", atoi(req.str()), url.str()));
  460. queuePatch( atoi(req.str()), url );
  461. if (atoi(req.str()))
  462. {
  463. mustDownloadPatch = TRUE;
  464. }
  465. }
  466. else if (ok && type == "server")
  467. {
  468. }
  469. }
  470. if (!checksLeftBeforeOnline)
  471. {
  472. startOnline();
  473. }
  474. return GHTTPTrue;
  475. }
  476. ///////////////////////////////////////////////////////////////////////////////////////
  477. void CancelPatchCheckCallbackAndReopenDropdown( void )
  478. {
  479. HandleCanceledDownload();
  480. CancelPatchCheckCallback();
  481. }
  482. void CancelPatchCheckCallback( void )
  483. {
  484. s_asyncDNSLookupInProgress = FALSE;
  485. HandleCanceledDownload(FALSE); // don't dropdown
  486. checkingForPatchBeforeGameSpy = FALSE;
  487. checksLeftBeforeOnline = 0;
  488. if (onlineCancelWindow)
  489. {
  490. TheWindowManager->winDestroy(onlineCancelWindow);
  491. onlineCancelWindow = NULL;
  492. }
  493. queuedDownloads.clear();
  494. if (MOTDBuffer)
  495. {
  496. delete[] MOTDBuffer;
  497. MOTDBuffer = NULL;
  498. }
  499. if (configBuffer)
  500. {
  501. delete[] configBuffer;
  502. configBuffer = NULL;
  503. }
  504. }
  505. ///////////////////////////////////////////////////////////////////////////////////////
  506. static GHTTPBool overallStatsCallback( GHTTPRequest request, GHTTPResult result, char * buffer, int bufferLen, void * param )
  507. {
  508. DEBUG_LOG(("overallStatsCallback() - Result=%d, len=%d\n", result, bufferLen));
  509. if (result != GHTTPSuccess)
  510. {
  511. return GHTTPTrue;
  512. }
  513. HandleOverallStats( buffer, bufferLen );
  514. return GHTTPTrue;
  515. }
  516. ///////////////////////////////////////////////////////////////////////////////////////
  517. static GHTTPBool numPlayersOnlineCallback( GHTTPRequest request, GHTTPResult result, char * buffer, int bufferLen, void * param )
  518. {
  519. DEBUG_LOG(("numPlayersOnlineCallback() - Result=%d, buffer=[%s], len=%d\n", result, buffer, bufferLen));
  520. if (result != GHTTPSuccess)
  521. {
  522. return GHTTPTrue;
  523. }
  524. AsciiString message = buffer;
  525. message.trim();
  526. const char *s = message.reverseFind('\\');
  527. if (!s)
  528. {
  529. return GHTTPTrue;
  530. }
  531. if (*s == '\\')
  532. ++s;
  533. DEBUG_LOG(("Message was '%s', trimmed to '%s'=%d\n", buffer, s, atoi(s)));
  534. HandleNumPlayersOnline(atoi(s));
  535. return GHTTPTrue;
  536. }
  537. ///////////////////////////////////////////////////////////////////////////////////////
  538. void CheckOverallStats( void )
  539. {
  540. ghttpGet("http://gamestats.gamespy.com/ccgenzh/display.html",
  541. GHTTPFalse, overallStatsCallback, NULL);
  542. }
  543. ///////////////////////////////////////////////////////////////////////////////////////
  544. void CheckNumPlayersOnline( void )
  545. {
  546. ghttpGet("http://launch.gamespyarcade.com/software/launch/arcadecount2.dll?svcname=ccgenzh",
  547. GHTTPFalse, numPlayersOnlineCallback, NULL);
  548. }
  549. ///////////////////////////////////////////////////////////////////////////////////////
  550. DWORD WINAPI asyncGethostbynameThreadFunc( void * szName )
  551. {
  552. HOSTENT *he = gethostbyname( (const char *)szName );
  553. if (he)
  554. {
  555. s_asyncDNSThreadSucceeded = TRUE;
  556. }
  557. else
  558. {
  559. s_asyncDNSThreadSucceeded = FALSE;
  560. }
  561. s_asyncDNSThreadDone = TRUE;
  562. return 0;
  563. }
  564. ///////////////////////////////////////////////////////////////////////////////////////
  565. int asyncGethostbyname(char * szName)
  566. {
  567. static int stat = 0;
  568. static unsigned long threadid;
  569. if( stat == 0 )
  570. {
  571. /* Kick off gethostname thread */
  572. s_asyncDNSThreadDone = FALSE;
  573. s_asyncDNSThreadHandle = CreateThread( NULL, 0, asyncGethostbynameThreadFunc, szName, 0, &threadid );
  574. if( s_asyncDNSThreadHandle == NULL )
  575. {
  576. return( LOOKUP_FAILED );
  577. }
  578. stat = 1;
  579. }
  580. if( stat == 1 )
  581. {
  582. if( s_asyncDNSThreadDone )
  583. {
  584. /* Thread finished */
  585. stat = 0;
  586. s_asyncDNSLookupInProgress = FALSE;
  587. s_asyncDNSThreadHandle = NULL;
  588. return( (s_asyncDNSThreadSucceeded)?LOOKUP_SUCCEEDED:LOOKUP_FAILED );
  589. }
  590. }
  591. return( LOOKUP_INPROGRESS );
  592. }
  593. ///////////////////////////////////////////////////////////////////////////////////////
  594. // GameSpy's HTTP SDK has had at least 1 crash bug, so we're going to just bail and
  595. // never try again if they crash us. We won't be able to get back online again (we'll
  596. // time out) but at least we'll live.
  597. static Bool isHttpOk = TRUE;
  598. void HTTPThinkWrapper( void )
  599. {
  600. if (s_asyncDNSLookupInProgress)
  601. {
  602. Int ret = asyncGethostbyname("servserv.generals.ea.com");
  603. switch(ret)
  604. {
  605. case LOOKUP_FAILED:
  606. cantConnectBeforeOnline = TRUE;
  607. startOnline();
  608. break;
  609. case LOOKUP_SUCCEEDED:
  610. reallyStartPatchCheck();
  611. break;
  612. }
  613. }
  614. if (isHttpOk)
  615. {
  616. try
  617. {
  618. ghttpThink();
  619. }
  620. catch (...)
  621. {
  622. isHttpOk = FALSE; // we can't abort the login, since we might be done with the
  623. // required checks and are fetching extras. If it is a required
  624. // check, we'll time out normally.
  625. }
  626. }
  627. }
  628. ///////////////////////////////////////////////////////////////////////////////////////
  629. void StopAsyncDNSCheck( void )
  630. {
  631. if (s_asyncDNSThreadHandle)
  632. {
  633. #ifdef DEBUG_CRASHING
  634. Int res =
  635. #endif
  636. TerminateThread(s_asyncDNSThreadHandle,0);
  637. DEBUG_ASSERTCRASH(res, ("Could not terminate the Async DNS Lookup thread!")); // Thread still not killed!
  638. }
  639. s_asyncDNSThreadHandle = NULL;
  640. s_asyncDNSLookupInProgress = FALSE;
  641. }
  642. ///////////////////////////////////////////////////////////////////////////////////////
  643. void StartPatchCheck( void )
  644. {
  645. checkingForPatchBeforeGameSpy = TRUE;
  646. cantConnectBeforeOnline = FALSE;
  647. timeThroughOnline++;
  648. checksLeftBeforeOnline = 0;
  649. onlineCancelWindow = MessageBoxCancel(TheGameText->fetch("GUI:CheckingForPatches"),
  650. TheGameText->fetch("GUI:CheckingForPatches"), CancelPatchCheckCallbackAndReopenDropdown);
  651. s_asyncDNSLookupInProgress = TRUE;
  652. Int ret = asyncGethostbyname("servserv.generals.ea.com");
  653. switch(ret)
  654. {
  655. case LOOKUP_FAILED:
  656. cantConnectBeforeOnline = TRUE;
  657. startOnline();
  658. break;
  659. case LOOKUP_SUCCEEDED:
  660. reallyStartPatchCheck();
  661. break;
  662. }
  663. }
  664. ///////////////////////////////////////////////////////////////////////////////////////
  665. static void reallyStartPatchCheck( void )
  666. {
  667. checksLeftBeforeOnline = 4;
  668. std::string gameURL, mapURL;
  669. std::string configURL, motdURL;
  670. FormatURLFromRegistry(gameURL, mapURL, configURL, motdURL);
  671. std::string proxy;
  672. if (GetStringFromRegistry("", "Proxy", proxy))
  673. {
  674. if (!proxy.empty())
  675. {
  676. ghttpSetProxy(proxy.c_str());
  677. }
  678. }
  679. // check for a patch first
  680. DEBUG_LOG(("Game patch check: [%s]\n", gameURL.c_str()));
  681. DEBUG_LOG(("Map patch check: [%s]\n", mapURL.c_str()));
  682. DEBUG_LOG(("Config: [%s]\n", configURL.c_str()));
  683. DEBUG_LOG(("MOTD: [%s]\n", motdURL.c_str()));
  684. ghttpGet(gameURL.c_str(), GHTTPFalse, gamePatchCheckCallback, (void *)timeThroughOnline);
  685. ghttpGet(mapURL.c_str(), GHTTPFalse, gamePatchCheckCallback, (void *)timeThroughOnline);
  686. ghttpHead(configURL.c_str(), GHTTPFalse, configHeadCallback, (void *)timeThroughOnline);
  687. ghttpGet(motdURL.c_str(), GHTTPFalse, motdCallback, (void *)timeThroughOnline);
  688. // check total game stats
  689. CheckOverallStats();
  690. // check the users online
  691. CheckNumPlayersOnline();
  692. }
  693. ///////////////////////////////////////////////////////////////////////////////////////