slavemaster.cpp 54 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266
  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 : Combat *
  23. * *
  24. * $Archive:: /Commando/Code/Commando/slavemaster.cpp $*
  25. * *
  26. * Author:: Steve Tall *
  27. * *
  28. * $Modtime:: 2/15/02 12:44p $*
  29. * *
  30. * $Revision:: 18 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. #include "always.h"
  36. #include <windows.h>
  37. #include "slavemaster.h"
  38. #include "wwdebug.h"
  39. #include "registry.h"
  40. #include "_globals.h"
  41. #include "autostart.h"
  42. #include "ini.h"
  43. #include "rawfile.h"
  44. #include "inisup.h"
  45. #include "natter.h"
  46. #include "gamesideservercontrol.h"
  47. #include "win.h"
  48. #include "gamedata.h"
  49. #include "serversettings.h"
  50. #include "bandwidth.h"
  51. #include "consolemode.h"
  52. #include "specialbuilds.h"
  53. #include "useroptions.h"
  54. #include <string.h>
  55. #include <stdio.h>
  56. #define KEY_NUM_SLAVES "Count"
  57. #define KEY_SLAVE_NAME "Name"
  58. #define KEY_SLAVE_SERIAL "Serial"
  59. #define KEY_SLAVE_ENABLE "Enable"
  60. #define KEY_SLAVE_PORT "Port"
  61. #define KEY_SLAVE_RUNNING_ID "RunningID"
  62. #define KEY_SLAVE_SETTINGS "Settings"
  63. #define KEY_SLAVE_BANDWIDTH "Bandwidth"
  64. #define KEY_SLAVE_PASSWORD "Password"
  65. const char *RegistryFileName = "slave.ini";
  66. SlaveMasterClass SlaveMaster;
  67. extern char DefaultRegistryModifier[1024];
  68. /***********************************************************************************************
  69. * SlaveServerClass::SlaveServerClass -- SlaveServerClass constuctor *
  70. * *
  71. * *
  72. * *
  73. * INPUT: Nothing *
  74. * *
  75. * OUTPUT: Nothing *
  76. * *
  77. * WARNINGS: None *
  78. * *
  79. * HISTORY: *
  80. * 11/21/2001 3:51PM ST : Created *
  81. *=============================================================================================*/
  82. SlaveServerClass::SlaveServerClass(void)
  83. {
  84. Enable = false;
  85. NickName[0] = 0;
  86. Serial[0] = 0;
  87. Port = 0;
  88. Bandwidth = 0;
  89. Password[0] = 0;
  90. }
  91. /***********************************************************************************************
  92. * SlaveServerClass::~SlaveServerClass -- SlaveServerClass desturctor *
  93. * *
  94. * *
  95. * *
  96. * INPUT: Nothing *
  97. * *
  98. * OUTPUT: Nothing *
  99. * *
  100. * WARNINGS: None *
  101. * *
  102. * HISTORY: *
  103. * 11/21/2001 3:51PM ST : Created *
  104. *=============================================================================================*/
  105. SlaveServerClass::~SlaveServerClass(void)
  106. {
  107. }
  108. /***********************************************************************************************
  109. * SlaveServerClass::Set -- Set info about this slave *
  110. * *
  111. * *
  112. * *
  113. * INPUT: Is slave enabled? *
  114. * Nickname to use with this slave *
  115. * Serial number to use with this slave *
  116. * Port to use with this slave *
  117. * *
  118. * OUTPUT: Nothing *
  119. * *
  120. * WARNINGS: None *
  121. * *
  122. * HISTORY: *
  123. * 11/21/2001 3:50PM ST : Created *
  124. *=============================================================================================*/
  125. void SlaveServerClass::Set(bool enable, char *nick, char *serial, unsigned short port, char *settings_file, int bandwidth, char *password)
  126. {
  127. Enable = enable;
  128. Port = port;
  129. Bandwidth = bandwidth;
  130. if (nick) {
  131. strncpy(NickName, nick, sizeof(NickName));
  132. }
  133. if (serial) {
  134. strncpy(Serial, serial, sizeof(Serial));
  135. }
  136. if (password) {
  137. strncpy(Password, password, sizeof(Password));
  138. }
  139. if (settings_file) {
  140. strncpy(SettingsFileName, settings_file, sizeof(SettingsFileName));
  141. }
  142. }
  143. /***********************************************************************************************
  144. * SlaveServerClass::Get -- Get info about this slave *
  145. * *
  146. * *
  147. * *
  148. * INPUT: Is slave enabled? *
  149. * Nickname to use with this slave *
  150. * Serial number to use with this slave *
  151. * Port to use with this slave *
  152. * *
  153. * OUTPUT: Nothing *
  154. * *
  155. * WARNINGS: None *
  156. * *
  157. * HISTORY: *
  158. * 11/21/2001 3:49PM ST : Created *
  159. *=============================================================================================*/
  160. void SlaveServerClass::Get(bool &enable, char *nick, char *serial, unsigned short &port, char *settings_file, int &bandwidth, char *password)
  161. {
  162. enable = Enable;
  163. port = Port;
  164. bandwidth = Bandwidth;
  165. if (nick) {
  166. strcpy(nick, NickName);
  167. }
  168. if (serial) {
  169. strcpy(serial, Serial);
  170. }
  171. if (password) {
  172. strcpy(password, Password);
  173. }
  174. if (settings_file) {
  175. strcpy(settings_file, SettingsFileName);
  176. }
  177. }
  178. /***********************************************************************************************
  179. * SlaveMasterClass::SlaveMasterClass -- SlaveMasterClass constructor *
  180. * *
  181. * *
  182. * *
  183. * INPUT: Nothing *
  184. * *
  185. * OUTPUT: Nothing *
  186. * *
  187. * WARNINGS: None *
  188. * *
  189. * HISTORY: *
  190. * 11/21/2001 3:49PM ST : Created *
  191. *=============================================================================================*/
  192. SlaveMasterClass::SlaveMasterClass(void)
  193. {
  194. NumSlaveServers = 0;
  195. SlaveMode = false;
  196. }
  197. /***********************************************************************************************
  198. * SlaveMasterClass::~SlaveMasterClass -- SlaveMasterClass destructor *
  199. * *
  200. * *
  201. * *
  202. * INPUT: Nothing *
  203. * *
  204. * OUTPUT: Nothing *
  205. * *
  206. * WARNINGS: None *
  207. * *
  208. * HISTORY: *
  209. * 11/21/2001 3:49PM ST : Created *
  210. *=============================================================================================*/
  211. SlaveMasterClass::~SlaveMasterClass(void)
  212. {
  213. /*
  214. ** Make sure all slaves are gone before we quit.
  215. */
  216. Wait_For_Slave_Shutdown();
  217. }
  218. /***********************************************************************************************
  219. * SlaveMasterClass::Wait_For_Slave_Shutdown -- Wait for slaves to exit *
  220. * *
  221. * *
  222. * *
  223. * INPUT: Nothing *
  224. * *
  225. * OUTPUT: Nothing *
  226. * *
  227. * WARNINGS: None *
  228. * *
  229. * HISTORY: *
  230. * 1/7/2002 2:58PM ST : Created *
  231. *=============================================================================================*/
  232. void SlaveMasterClass::Wait_For_Slave_Shutdown(void)
  233. {
  234. if (!SlaveMode) {
  235. unsigned long time = TIMEGETTIME();
  236. int num_running = 0;
  237. int last_num_running = 0;
  238. bool forced = false;
  239. /*
  240. ** Don't wait longer than 35 secs. It takes 15 secs for the slave to do it's intermission.
  241. */
  242. while (TIMEGETTIME() - time < 40000) {
  243. num_running = 0;
  244. for (int i=0 ; i<NumSlaveServers ; i++) {
  245. if (SlaveServers[i].IsRunning) {
  246. if (SlaveServers[i].ProcessInfo.hProcess) {
  247. unsigned long code;
  248. int res = GetExitCodeProcess(SlaveServers[i].ProcessInfo.hProcess, &code);
  249. if (res && code == STILL_ACTIVE) {
  250. num_running++;
  251. }
  252. } else {
  253. if (SlaveServers[i].ProcessInfo.dwProcessId) {
  254. unsigned long ver = GetProcessVersion(SlaveServers[i].ProcessInfo.dwProcessId);
  255. if (ver && ver == GetProcessVersion(GetCurrentProcessId())) {
  256. num_running++;
  257. }
  258. }
  259. }
  260. }
  261. }
  262. if (num_running && num_running != last_num_running) {
  263. ConsoleBox.Print("Waiting for %d slave(s) to shut down\n", num_running);
  264. WWDEBUG_SAY(("Waiting for %d slave(s) to shut down\n", num_running));
  265. last_num_running = num_running;
  266. }
  267. if (num_running == 0) {
  268. break;
  269. }
  270. /*
  271. ** Force a shutdown if they are not cooperating.
  272. */
  273. if (!forced && TIMEGETTIME() - time > 27000) {
  274. forced = true;
  275. for (int i=0 ; i<NumSlaveServers ; i++) {
  276. if (SlaveServers[i].ProcessInfo.dwProcessId) {
  277. unsigned long ver = GetProcessVersion(SlaveServers[i].ProcessInfo.dwProcessId);
  278. if (ver && ver == GetProcessVersion(GetCurrentProcessId())) {
  279. WWDEBUG_SAY(("Terminating process %d due to timeout\n", SlaveServers[i].ProcessInfo.dwProcessId));
  280. /*
  281. ** Get a handle to the process.
  282. */
  283. HANDLE proc_handle = OpenProcess(PROCESS_TERMINATE, false, SlaveServers[i].ProcessInfo.dwProcessId);
  284. if (proc_handle != INVALID_HANDLE_VALUE) {
  285. TerminateProcess(proc_handle, 0);
  286. CloseHandle(proc_handle);
  287. } else {
  288. WWDEBUG_SAY(("Failed to get process handle for termination - error code %d\n", GetLastError()));
  289. }
  290. num_running++;
  291. }
  292. }
  293. }
  294. }
  295. }
  296. }
  297. }
  298. /***********************************************************************************************
  299. * SlaveMasterClass::Get_Slave -- Get slave server entry by index *
  300. * *
  301. * *
  302. * *
  303. * INPUT: Index *
  304. * *
  305. * OUTPUT: Ptr to slave server *
  306. * *
  307. * WARNINGS: None *
  308. * *
  309. * HISTORY: *
  310. * 11/21/2001 3:48PM ST : Created *
  311. *=============================================================================================*/
  312. SlaveServerClass *SlaveMasterClass::Get_Slave(int index)
  313. {
  314. WWASSERT(index < NumSlaveServers);
  315. WWASSERT(index >= 0);
  316. if (index >= 0 && index <NumSlaveServers) {
  317. return(&SlaveServers[index]);
  318. }
  319. return(NULL);
  320. }
  321. /***********************************************************************************************
  322. * SlaveMasterClass::Save -- Save slave server info to registry *
  323. * *
  324. * *
  325. * *
  326. * INPUT: Nothing *
  327. * *
  328. * OUTPUT: Nothing *
  329. * *
  330. * WARNINGS: None *
  331. * *
  332. * HISTORY: *
  333. * 11/21/2001 3:48PM ST : Created *
  334. *=============================================================================================*/
  335. void SlaveMasterClass::Save(void)
  336. {
  337. RegistryClass reg(APPLICATION_SUB_KEY_NAME_NET_SLAVE);
  338. if (reg.Is_Valid()) {
  339. reg.Set_Int(KEY_NUM_SLAVES, NumSlaveServers);
  340. }
  341. for (int i=0 ; i<NumSlaveServers ; i++) {
  342. char entry[256];
  343. sprintf(entry, "%s%d", KEY_SLAVE_NAME, i);
  344. reg.Set_String(entry, SlaveServers[i].NickName);
  345. sprintf(entry, "%s%d", KEY_SLAVE_PASSWORD, i);
  346. reg.Set_String(entry, SlaveServers[i].Password);
  347. sprintf(entry, "%s%d", KEY_SLAVE_SETTINGS, i);
  348. reg.Set_String(entry, SlaveServers[i].SettingsFileName);
  349. sprintf(entry, "%s%d", KEY_SLAVE_ENABLE, i);
  350. reg.Set_Bool(entry, SlaveServers[i].Enable);
  351. sprintf(entry, "%s%d", KEY_SLAVE_PORT, i);
  352. reg.Set_Int(entry, SlaveServers[i].Port);
  353. sprintf(entry, "%s%d", KEY_SLAVE_BANDWIDTH, i);
  354. reg.Set_Int(entry, SlaveServers[i].Bandwidth);
  355. sprintf(entry, "%s%d", KEY_SLAVE_SERIAL, i);
  356. StringClass serial(SlaveServers[i].Serial, true);
  357. StringClass encrypted_serial = serial;
  358. if (serial.Get_Length()) {
  359. ServerSettingsClass::Encrypt_Serial(serial, encrypted_serial);
  360. }
  361. reg.Set_String(entry, encrypted_serial.Peek_Buffer());
  362. }
  363. }
  364. /***********************************************************************************************
  365. * SlaveMasterClass::Load -- Fetch slave server info from registry *
  366. * *
  367. * *
  368. * *
  369. * INPUT: Nothing *
  370. * *
  371. * OUTPUT: Nothing *
  372. * *
  373. * WARNINGS: None *
  374. * *
  375. * HISTORY: *
  376. * 11/21/2001 3:47PM ST : Created *
  377. *=============================================================================================*/
  378. void SlaveMasterClass::Load(void)
  379. {
  380. RegistryClass reg(APPLICATION_SUB_KEY_NAME_NET_SLAVE);
  381. if (reg.Is_Valid()) {
  382. NumSlaveServers = reg.Get_Int(KEY_NUM_SLAVES, 0);
  383. }
  384. char entry[256];
  385. for (int i=0 ; i<NumSlaveServers ; i++) {
  386. sprintf(entry, "%s%d", KEY_SLAVE_NAME, i);
  387. reg.Get_String(entry, SlaveServers[i].NickName, sizeof(SlaveServers[i].NickName), "");
  388. sprintf(entry, "%s%d", KEY_SLAVE_PASSWORD, i);
  389. reg.Get_String(entry, SlaveServers[i].Password, sizeof(SlaveServers[i].Password), "");
  390. sprintf(entry, "%s%d", KEY_SLAVE_ENABLE, i);
  391. SlaveServers[i].Enable = reg.Get_Bool(entry, false);
  392. sprintf(entry, "%s%d", KEY_SLAVE_PORT, i);
  393. SlaveServers[i].Port = reg.Get_Int(entry, false);
  394. sprintf(entry, "%s%d", KEY_SLAVE_BANDWIDTH, i);
  395. SlaveServers[i].Bandwidth = reg.Get_Int(entry, false);
  396. sprintf(entry, "%s%d", KEY_SLAVE_SETTINGS, i);
  397. reg.Get_String(entry, SlaveServers[i].SettingsFileName, sizeof(SlaveServers[i].SettingsFileName), "");
  398. sprintf(entry, "%s%d", KEY_SLAVE_SERIAL, i);
  399. reg.Get_String(entry, SlaveServers[i].Serial, sizeof(SlaveServers[i].Serial), "");
  400. if (strlen(SlaveServers[i].Serial)) {
  401. StringClass serial(SlaveServers[i].Serial, true);
  402. StringClass decrypted_serial = serial;
  403. if (serial.Get_Length()) {
  404. ServerSettingsClass::Decrypt_Serial(serial, decrypted_serial);
  405. }
  406. strcpy(SlaveServers[i].Serial, decrypted_serial.Peek_Buffer());
  407. }
  408. char filename[MAX_PATH];
  409. sprintf(filename, "data\\%s", SlaveServers[i].SettingsFileName);
  410. RawFileClass file(filename);
  411. if (!file.Is_Available()) {
  412. strcpy(SlaveServers[i].SettingsFileName, "svrcfg_cnc.ini");
  413. }
  414. }
  415. }
  416. /***********************************************************************************************
  417. * SlaveMasterClass::Reset -- Clear out slave server list *
  418. * *
  419. * *
  420. * *
  421. * INPUT: Nothing *
  422. * *
  423. * OUTPUT: Nothing *
  424. * *
  425. * WARNINGS: None *
  426. * *
  427. * HISTORY: *
  428. * 11/21/2001 3:47PM ST : Created *
  429. *=============================================================================================*/
  430. void SlaveMasterClass::Reset(void)
  431. {
  432. for (int i=0 ; i<NumSlaveServers ; i++) {
  433. SlaveServers[i].Set(false, "", "", 0, "", 0, "");
  434. }
  435. NumSlaveServers = 0;
  436. }
  437. /***********************************************************************************************
  438. * SlaveMasterClass::Add_Slave -- Add slave to list *
  439. * *
  440. * *
  441. * *
  442. * INPUT: Is slave enabled? *
  443. * Nickname for this slave to use *
  444. * Serial number for this slave to use *
  445. * Port number for this slave to use *
  446. * *
  447. * OUTPUT: Nothing *
  448. * *
  449. * WARNINGS: None *
  450. * *
  451. * HISTORY: *
  452. * 11/21/2001 3:46PM ST : Created *
  453. *=============================================================================================*/
  454. void SlaveMasterClass::Add_Slave(bool enable, char *nick, char *serial, unsigned short port, char *settings_file, int bandwidth, char *password)
  455. {
  456. WWASSERT(NumSlaveServers < MAX_SLAVES);
  457. SlaveServers[NumSlaveServers++].Set(enable, nick, serial, port, settings_file, bandwidth, password);
  458. }
  459. /***********************************************************************************************
  460. * SlaveMasterClass::Aquire_Slave -- Find a running slave by it's process ID *
  461. * *
  462. * *
  463. * *
  464. * INPUT: Nothing *
  465. * *
  466. * OUTPUT: Nothing *
  467. * *
  468. * WARNINGS: None *
  469. * *
  470. * HISTORY: *
  471. * 12/16/2001 11:34PM ST : Created *
  472. *=============================================================================================*/
  473. bool SlaveMasterClass::Aquire_Slave(int index)
  474. {
  475. int proc_id = 0;
  476. /*
  477. ** Try the slaves record of his process ID. If it's not there, it can't have run yet.
  478. */
  479. char slave_name[64];
  480. sprintf(slave_name, "\\slave_%d", index);
  481. strcpy(DefaultRegistryModifier, slave_name+1);
  482. RegistryClass slave_reg(APPLICATION_SUB_KEY_NAME);
  483. DefaultRegistryModifier[0] = 0;
  484. if (slave_reg.Is_Valid()) {
  485. proc_id = slave_reg.Get_Int("ProcessId", proc_id);
  486. }
  487. /*
  488. ** Try our record of the slaves process ID.
  489. */
  490. if (proc_id == 0) {
  491. RegistryClass reg(APPLICATION_SUB_KEY_NAME_NET_SLAVE);
  492. if (reg.Is_Valid()) {
  493. char entry[128];
  494. sprintf(entry, "%s%d", KEY_SLAVE_RUNNING_ID, index);
  495. proc_id = reg.Get_Int(entry, 0);
  496. }
  497. }
  498. /*
  499. ** Search for the slave's console window if we are in console mode. This is a better test than just hoping the Process ID is
  500. ** correct.
  501. */
  502. if (ConsoleBox.Is_Exclusive()) {
  503. HWND slave_window = ConsoleBox.Get_Slave_Window_By_Title(SlaveServers[index].NickName, SlaveServers[index].SettingsFileName);
  504. if (slave_window != NULL) {
  505. /*
  506. ** Note the process ID for later.
  507. */
  508. SlaveServers[index].ProcessInfo.hProcess = NULL; // Don't know handle.
  509. GetWindowThreadProcessId(slave_window, &SlaveServers[index].ProcessInfo.dwProcessId);
  510. WWDEBUG_SAY(("Slave found by HWND with process ID %d\n", SlaveServers[index].ProcessInfo.dwProcessId));
  511. RegistryClass reg(APPLICATION_SUB_KEY_NAME_NET_SLAVE);
  512. if (reg.Is_Valid()) {
  513. char entry[128];
  514. sprintf(entry, "%s%d", KEY_SLAVE_RUNNING_ID, index);
  515. reg.Set_Int(entry, SlaveServers[index].ProcessInfo.dwProcessId);
  516. }
  517. return(true);
  518. }
  519. }
  520. /*
  521. ** See if the process is already running.
  522. */
  523. if (proc_id) {
  524. unsigned long ver = GetProcessVersion(proc_id);
  525. if (ver && ver == GetProcessVersion(GetCurrentProcessId())) {
  526. /*
  527. ** It looks like one of our slaves. See if we already know about it.
  528. */
  529. if (SlaveServers[index].IsRunning && SlaveServers[index].ProcessInfo.dwProcessId == (unsigned) proc_id) {
  530. return(true);
  531. }
  532. /*
  533. ** Note the process ID for later.
  534. */
  535. SlaveServers[index].ProcessInfo.hProcess = NULL; // Don't know handle.
  536. SlaveServers[index].ProcessInfo.dwProcessId = proc_id;
  537. WWDEBUG_SAY(("Slave found with process ID %d\n", SlaveServers[index].ProcessInfo.dwProcessId));
  538. return(true);
  539. }
  540. }
  541. return(false);
  542. }
  543. /***********************************************************************************************
  544. * SlaveMasterClass::Startup_Slaves -- Create extra slave server processes *
  545. * *
  546. * *
  547. * *
  548. * INPUT: Nothing *
  549. * *
  550. * OUTPUT: Nothing *
  551. * *
  552. * WARNINGS: None *
  553. * *
  554. * HISTORY: *
  555. * 11/21/2001 3:46PM ST : Created *
  556. *=============================================================================================*/
  557. void SlaveMasterClass::Startup_Slaves(void)
  558. {
  559. if (!SlaveMode) {
  560. /*
  561. ** Make sure we are a dedicated server.
  562. */
  563. if (!The_Game() || The_Game()->IsDedicated.Is_True()) {
  564. /*
  565. ** Slaves only available in windowed or console mode.
  566. */
  567. if (WW3D::Is_Windowed() || ConsoleBox.Is_Exclusive()) {
  568. /*
  569. ** Slaves only available in internet mode.
  570. */
  571. GameModeClass *game_mode = GameModeManager::Find("WOL");
  572. if (game_mode && game_mode->Is_Active()) {
  573. Wait_For_Slave_Shutdown();
  574. Load();
  575. Delete_Registry_Copies();
  576. Create_Registry_Copies();
  577. /*
  578. ** Spawn the servers.
  579. */
  580. char command_line[300];
  581. for (int i=0 ; i<NumSlaveServers ; i++) {
  582. if (SlaveServers[i].Enable) {
  583. bool slave_running = false;
  584. /*
  585. ** Get an access point into the slaves registry base.
  586. */
  587. char slave_name[64];
  588. sprintf(slave_name, "\\slave_%d", i);
  589. strcpy(DefaultRegistryModifier, slave_name+1);
  590. RegistryClass slave_reg(APPLICATION_SUB_KEY_NAME);
  591. DefaultRegistryModifier[0] = 0;
  592. /*
  593. ** If we are autostarting then take inventory of which slaves are running already.
  594. ** An autostart after a crash should still see the slaves running. An autostart after a reboot will see no slaves.
  595. */
  596. if (AutoRestart.Is_Active()) {
  597. slave_running = Aquire_Slave(i);
  598. }
  599. /*
  600. ** Figure out the name of the .exe to run.
  601. */
  602. char path_to_exe[256];
  603. char drive[_MAX_DRIVE];
  604. char dir[_MAX_DIR];
  605. char path[_MAX_PATH];
  606. GetModuleFileName(ProgramInstance, path_to_exe, sizeof(path_to_exe));
  607. _splitpath(path_to_exe, drive, dir, NULL, NULL);
  608. #ifdef FREEDEDICATEDSERVER
  609. _makepath(path, drive, dir, "renegadeserver", "exe");
  610. #else //FREEDEDICATEDSERVER
  611. _makepath(path, drive, dir, "renegade", "exe");
  612. #endif //FREEDEDICATEDSERVER
  613. sprintf(command_line, "%s /MULTI /SLAVE /REGMOD=slave_%d", path, i);
  614. if (ConsoleBox.Is_Exclusive()) {
  615. strcat(command_line, " /NODX");
  616. }
  617. STARTUPINFO startup_info;
  618. memset(&startup_info, 0, sizeof(startup_info));
  619. startup_info.cb = sizeof(startup_info);
  620. int result = 1;
  621. if (!slave_running) {
  622. if (slave_reg.Is_Valid()) {
  623. slave_reg.Set_Int("ProcessId", 0);
  624. }
  625. result = CreateProcess(path, command_line, NULL, NULL, false, 0, NULL, NULL, &startup_info, &SlaveServers[i].ProcessInfo);
  626. }
  627. if (result) {
  628. SlaveServers[i].IsRunning = true;
  629. /*
  630. ** The process ID we have here is actually the ID of the slaves launcher. We need the ID of the actual
  631. ** game process. Wait a few seconds until the slave sets his ID into his registry location.
  632. */
  633. if (!slave_running) {
  634. unsigned long time = TIMEGETTIME();
  635. while (TIMEGETTIME() - time < 10000) {
  636. if (!slave_reg.Is_Valid()) {
  637. break;
  638. }
  639. /*
  640. ** Break out once we read the slaves process ID from the registry indicating that the slave
  641. ** has already parsed its command line.
  642. */
  643. int process_id = slave_reg.Get_Int("ProcessId", 0);
  644. if (process_id != 0) {
  645. SlaveServers[i].ProcessInfo.dwProcessId = process_id;
  646. break;
  647. }
  648. Sleep(250);
  649. }
  650. }
  651. /*
  652. ** Set a registry flag to say this server is active. We need to know this if the master server (us)
  653. ** crashes and restarts.
  654. */
  655. RegistryClass reg(APPLICATION_SUB_KEY_NAME_NET_SLAVE);
  656. if (reg.Is_Valid()) {
  657. char entry[128];
  658. sprintf(entry, "%s%d", KEY_SLAVE_RUNNING_ID, i);
  659. reg.Set_Int(entry, SlaveServers[i].ProcessInfo.dwProcessId);
  660. }
  661. } else {
  662. WWDEBUG_SAY(("Failed to start slave process - error code %d\n", GetLastError()));
  663. SlaveServers[i].IsRunning = false;
  664. }
  665. }
  666. }
  667. }
  668. }
  669. }
  670. }
  671. GameSideServerControlClass::Set_Welcome_Message();
  672. }
  673. /***********************************************************************************************
  674. * SlaveMasterClass::Shutdown_Slaves -- Send quit message to all slaves *
  675. * *
  676. * *
  677. * *
  678. * INPUT: Nothing *
  679. * *
  680. * OUTPUT: Nothing *
  681. * *
  682. * WARNINGS: None *
  683. * *
  684. * HISTORY: *
  685. * 11/21/2001 3:45PM ST : Created *
  686. *=============================================================================================*/
  687. void SlaveMasterClass::Shutdown_Slaves(void)
  688. {
  689. if (!SlaveMode) {
  690. char password[64] = DEFAULT_SERVER_CONTROL_PASSWORD;
  691. RegistryClass reg(APPLICATION_SUB_KEY_NAME_NET_SERVER_CONTROL);
  692. reg.Get_String(SERVER_CONTROL_PASSWORD_KEY, password, sizeof(password), password);
  693. for (int i=0 ; i<NumSlaveServers ; i++) {
  694. if (SlaveServers[i].IsRunning) {
  695. /*
  696. ** In case the slave was restarted - we won't know it's new process ID.
  697. */
  698. Aquire_Slave(i);
  699. /*
  700. ** Set the slaves auto-restart flag to false or it will just start right up again.
  701. */
  702. char slave_name[64];
  703. sprintf(slave_name, "\\slave_%d", i);
  704. strcpy(DefaultRegistryModifier, slave_name+1);
  705. RegistryClass slave_reg(APPLICATION_SUB_KEY_NAME_WOLSETTINGS);
  706. DefaultRegistryModifier[0] = 0;
  707. slave_reg.Set_Int(AutoRestartClass::REG_VALUE_AUTO_RESTART_FLAG, 0);
  708. /*
  709. ** Send the password to the slave to authenticate the connection.
  710. */
  711. GameSideServerControlClass::Send_Message(password, ntohl(INADDR_LOOPBACK), SlaveServers[i].ControlPort);
  712. Sleep(10);
  713. GameSideServerControlClass::Send_Message("quit", ntohl(INADDR_LOOPBACK), SlaveServers[i].ControlPort);
  714. /*
  715. ** Remember that we shut this guy down.
  716. */
  717. RegistryClass reg(APPLICATION_SUB_KEY_NAME_NET_SLAVE);
  718. if (reg.Is_Valid()) {
  719. char entry[128];
  720. sprintf(entry, "%s%d", KEY_SLAVE_RUNNING_ID, i);
  721. reg.Set_Int(entry, 0);
  722. }
  723. }
  724. }
  725. }
  726. }
  727. /***********************************************************************************************
  728. * SlaveMasterClass::Shutdown_Slaves -- Send quit message to all slaves *
  729. * *
  730. * *
  731. * *
  732. * INPUT: Slave login name *
  733. * *
  734. * OUTPUT: Nothing *
  735. * *
  736. * WARNINGS: None *
  737. * *
  738. * HISTORY: *
  739. * 11/21/2001 3:45PM ST : Created *
  740. *=============================================================================================*/
  741. bool SlaveMasterClass::Shutdown_Slave(char *slave_login)
  742. {
  743. if (!SlaveMode && slave_login) {
  744. char password[64] = DEFAULT_SERVER_CONTROL_PASSWORD;
  745. RegistryClass reg(APPLICATION_SUB_KEY_NAME_NET_SERVER_CONTROL);
  746. reg.Get_String(SERVER_CONTROL_PASSWORD_KEY, password, sizeof(password), password);
  747. for (int i=0 ; i<NumSlaveServers ; i++) {
  748. if (SlaveServers[i].IsRunning && stricmp(slave_login, SlaveServers[i].NickName) == 0) {
  749. /*
  750. ** In case the slave was restarted - we won't know it's new process ID.
  751. */
  752. Aquire_Slave(i);
  753. /*
  754. ** Set the slaves auto-restart flag to false or it will just start right up again.
  755. */
  756. char slave_name[64];
  757. sprintf(slave_name, "\\slave_%d", i);
  758. strcpy(DefaultRegistryModifier, slave_name+1);
  759. RegistryClass slave_reg(APPLICATION_SUB_KEY_NAME_WOLSETTINGS);
  760. DefaultRegistryModifier[0] = 0;
  761. slave_reg.Set_Int(AutoRestartClass::REG_VALUE_AUTO_RESTART_FLAG, 0);
  762. /*
  763. ** Send the password to the slave to authenticate the connection.
  764. */
  765. GameSideServerControlClass::Send_Message(password, ntohl(INADDR_LOOPBACK), SlaveServers[i].ControlPort);
  766. Sleep(10);
  767. GameSideServerControlClass::Send_Message("quit", ntohl(INADDR_LOOPBACK), SlaveServers[i].ControlPort);
  768. /*
  769. ** Remember that we shut this guy down.
  770. */
  771. RegistryClass reg(APPLICATION_SUB_KEY_NAME_NET_SLAVE);
  772. if (reg.Is_Valid()) {
  773. char entry[128];
  774. sprintf(entry, "%s%d", KEY_SLAVE_RUNNING_ID, i);
  775. reg.Set_Int(entry, 0);
  776. }
  777. SlaveServers[i].IsRunning = false;
  778. return(true);
  779. }
  780. }
  781. }
  782. return(false);
  783. }
  784. /***********************************************************************************************
  785. * SlaveMasterClass::Get_Slave_Info -- Get text slave info *
  786. * *
  787. * *
  788. * *
  789. * INPUT: Ptr to text buffer *
  790. * buffer size *
  791. * *
  792. * OUTPUT: Nothing *
  793. * *
  794. * WARNINGS: None *
  795. * *
  796. * HISTORY: *
  797. * 11/21/2001 3:45PM ST : Created *
  798. *=============================================================================================*/
  799. char *SlaveMasterClass::Get_Slave_Info(char *buffer, int buflen)
  800. {
  801. bool any = false;
  802. if (buffer) {
  803. assert(buflen >= 500);
  804. *buffer = 0;
  805. for (int i=0 ; i<NumSlaveServers ; i++) {
  806. if (SlaveServers[i].IsRunning) {
  807. any = true;
  808. char temp[64];
  809. sprintf(temp, " Slave %d on port %d\n", i+1, SlaveServers[i].ControlPort);
  810. if (strlen(temp) + strlen(buffer) < (unsigned)buflen) {
  811. strcat(buffer, temp);
  812. }
  813. }
  814. }
  815. if (!any) {
  816. strcpy(buffer, "No slave servers active\n");
  817. }
  818. }
  819. return(buffer);
  820. }
  821. /***********************************************************************************************
  822. * SlaveMasterClass::Create_Registry_Copies -- Create 'shadow' registry copies for slaves *
  823. * *
  824. * *
  825. * *
  826. * INPUT: Nothing *
  827. * *
  828. * OUTPUT: Nothing *
  829. * *
  830. * WARNINGS: None *
  831. * *
  832. * HISTORY: *
  833. * 11/21/2001 3:44PM ST : Created *
  834. *=============================================================================================*/
  835. void SlaveMasterClass::Create_Registry_Copies(void)
  836. {
  837. WWASSERT(!SlaveMode);
  838. /*
  839. ** Make sure the Process ID isn't set in our base registry. It's shouldn't be unless I ran with the /slave command during dev.
  840. */
  841. RegistryClass reg(APPLICATION_SUB_KEY_NAME);
  842. if (reg.Is_Valid()) {
  843. reg.Delete_Value("ProcessId");
  844. }
  845. RegistryClass::Save_Registry(RegistryFileName, APPLICATION_SUB_KEY_NAME);
  846. char new_path[1024];
  847. char slave_name[64];
  848. for (int i=0 ; i<NumSlaveServers ; i++) {
  849. if (SlaveServers[i].Enable) {
  850. strcpy(new_path, APPLICATION_SUB_KEY_NAME);
  851. sprintf(slave_name, "\\slave_%d", i);
  852. strcat(new_path, slave_name);
  853. RegistryClass::Load_Registry(RegistryFileName, APPLICATION_SUB_KEY_NAME, new_path);
  854. /*
  855. ** Store the slave settings into the registry.
  856. */
  857. /*
  858. ** Port numbers.
  859. */
  860. {
  861. strcpy(DefaultRegistryModifier, slave_name+1);
  862. RegistryClass reg(APPLICATION_SUB_KEY_NAME_NET_FIREWALL);
  863. DefaultRegistryModifier[0] = 0;
  864. RegistryClass my_reg(APPLICATION_SUB_KEY_NAME_NET_FIREWALL);
  865. if (SlaveServers[i].Port != 0) {
  866. reg.Set_Int("ForcePort", SlaveServers[i].Port);
  867. } else {
  868. reg.Set_Int("ForcePort", 0);
  869. int port = my_reg.Get_Int("PortBase", PORT_BASE_MIN);
  870. port = port + ((i+1) * 256);
  871. if (port >= PORT_BASE_MAX-1) {
  872. port -= (PORT_BASE_MAX - PORT_BASE_MIN);
  873. }
  874. reg.Set_Int("PortBase", port);
  875. port = my_reg.Get_Int("PortPool", PORT_BASE_MIN);
  876. port = port + ((i+1) * 1024);
  877. if (port >= PORT_POOL_MAX-1) {
  878. port -= (PORT_POOL_MAX - PORT_POOL_MIN);
  879. }
  880. reg.Set_Int("PortPool", port);
  881. }
  882. }
  883. /*
  884. ** Server control info.
  885. */
  886. {
  887. strcpy(DefaultRegistryModifier, slave_name+1);
  888. RegistryClass reg(APPLICATION_SUB_KEY_NAME_NET_SERVER_CONTROL);
  889. DefaultRegistryModifier[0] = 0;
  890. RegistryClass my_reg(APPLICATION_SUB_KEY_NAME_NET_SERVER_CONTROL);
  891. /*
  892. ** The password will be the same for all slaves but they each need a port to listen on.
  893. */
  894. int my_sc_port = my_reg.Get_Int(SERVER_CONTROL_PORT_KEY, DEFAULT_SERVER_CONTROL_PORT);
  895. int slave_port = my_sc_port;
  896. if (my_sc_port == 0) {
  897. /*
  898. ** If server control isn't enabled for me then we need to make up some port.
  899. */
  900. slave_port = DEFAULT_SERVER_CONTROL_PORT;
  901. }
  902. slave_port += i;
  903. slave_port++;
  904. SlaveServers[i].ControlPort = slave_port;
  905. reg.Set_Int(SERVER_CONTROL_PORT_KEY, slave_port);
  906. /*
  907. ** Inherit this from the master now.
  908. */
  909. //if (my_sc_port == 0) {
  910. // reg.Set_Int(SERVER_CONTROL_LOOPBACK_KEY, 1);
  911. //} else {
  912. // reg.Set_Int(SERVER_CONTROL_LOOPBACK_KEY, 0);
  913. //}
  914. }
  915. /*
  916. ** Login name.
  917. */
  918. {
  919. strcpy(DefaultRegistryModifier, slave_name+1);
  920. RegistryClass reg(APPLICATION_SUB_KEY_NAME_WOLSETTINGS);
  921. DefaultRegistryModifier[0] = 0;
  922. reg.Set_String("AutoLogin", SlaveServers[i].NickName);
  923. reg.Set_String("LastLogin", SlaveServers[i].NickName);
  924. }
  925. /*
  926. ** Password name.
  927. */
  928. {
  929. strcpy(DefaultRegistryModifier, slave_name+1);
  930. RegistryClass reg(APPLICATION_SUB_KEY_NAME_WOLSETTINGS);
  931. DefaultRegistryModifier[0] = 0;
  932. reg.Set_String("AutoPassword", SlaveServers[i].Password);
  933. }
  934. /*
  935. ** Serial number.
  936. */
  937. {
  938. strcpy(DefaultRegistryModifier, slave_name+1);
  939. RegistryClass reg(APPLICATION_SUB_KEY_NAME);
  940. DefaultRegistryModifier[0] = 0;
  941. StringClass serial(SlaveServers[i].Serial, true);
  942. StringClass encrypted_serial = serial;
  943. if (serial.Get_Length()) {
  944. ServerSettingsClass::Encrypt_Serial(serial, encrypted_serial);
  945. }
  946. reg.Set_String(KEY_SLAVE_SERIAL, encrypted_serial.Peek_Buffer());
  947. }
  948. /*
  949. ** Make it autostart.
  950. */
  951. {
  952. strcpy(DefaultRegistryModifier, slave_name+1);
  953. RegistryClass reg(APPLICATION_SUB_KEY_NAME_WOLSETTINGS);
  954. DefaultRegistryModifier[0] = 0;
  955. if (reg.Is_Valid()) {
  956. reg.Set_Int(AutoRestartClass::REG_VALUE_AUTO_RESTART_FLAG, 1);
  957. int game_type = 0;
  958. GameModeClass *game_mode = GameModeManager::Find("WOL");
  959. if (game_mode && game_mode->Is_Active()) {
  960. game_type = 1;
  961. }
  962. reg.Set_Int(AutoRestartClass::REG_VALUE_AUTO_RESTART_TYPE, game_type);
  963. }
  964. }
  965. /*
  966. ** Tell it which multiplayer settings to use.
  967. */
  968. {
  969. strcpy(DefaultRegistryModifier, slave_name+1);
  970. RegistryClass reg(APPLICATION_SUB_KEY_NAME_OPTIONS);
  971. DefaultRegistryModifier[0] = 0;
  972. reg.Set_String("MultiplayerSettings", SlaveServers[i].SettingsFileName);
  973. }
  974. /*
  975. ** Set the SKU number to be the FDS SKU. Do this whether the Master is a FDS or not.
  976. */
  977. {
  978. strcpy(DefaultRegistryModifier, slave_name+1);
  979. RegistryClass reg(APPLICATION_SUB_KEY_NAME);
  980. DefaultRegistryModifier[0] = 0;
  981. reg.Set_Int("SKU", RENEGADE_FDS_SKU);
  982. }
  983. /*
  984. ** Set the bandwidth information.
  985. ** A value of 0 means auto. A value of 0xffffffff means not specified (i.e. use master settings).
  986. */
  987. {
  988. int bw = SlaveServers[i].Bandwidth;
  989. if (bw != -1) {
  990. strcpy(DefaultRegistryModifier, slave_name+1);
  991. RegistryClass reg_netopt(APPLICATION_SUB_KEY_NAME_NETOPTIONS);
  992. RegistryClass reg_bw(APPLICATION_SUB_KEY_NAME_BANDTEST);
  993. DefaultRegistryModifier[0] = 0;
  994. RegistryClass my_reg_netopt(APPLICATION_SUB_KEY_NAME_NETOPTIONS);
  995. RegistryClass my_reg_bw(APPLICATION_SUB_KEY_NAME_BANDTEST);
  996. //reg_netopt.Set_Int("BandwidthType", BANDWIDTH_AUTO);
  997. cUserOptions::Set_Bandwidth_Type(BANDWIDTH_AUTO);
  998. int slave_bw = bw;
  999. /*
  1000. ** If bandwidth is set to auto then divide it by the number of servers on this box.
  1001. */
  1002. if (slave_bw == 0) {
  1003. slave_bw = my_reg_bw.Get_Int("Up", 0);
  1004. int num = Get_Num_Enabled_Slaves();
  1005. if (num) {
  1006. slave_bw = slave_bw / (num+1);
  1007. }
  1008. }
  1009. reg_bw.Set_Int("Up", slave_bw);
  1010. reg_bw.Set_Int("Down", slave_bw);
  1011. }
  1012. }
  1013. #if (0)
  1014. /*
  1015. ** Give the window a different position so we are not completely overlapping.
  1016. */
  1017. {
  1018. strcpy(DefaultRegistryModifier, slave_name+1);
  1019. RegistryClass reg(APPLICATION_SUB_KEY_NAME_OPTIONS);
  1020. DefaultRegistryModifier[0] = 0;
  1021. reg.Set_Int("WindowX", (i * 32) + 32);
  1022. reg.Set_Int("WindowY", (i * 32) + 32);
  1023. }
  1024. #endif //(0)
  1025. }
  1026. }
  1027. }
  1028. /***********************************************************************************************
  1029. * SlaveMasterClass::Delete_Registry_Copies -- Delete old slave registry copies *
  1030. * *
  1031. * *
  1032. * *
  1033. * INPUT: Nothing *
  1034. * *
  1035. * OUTPUT: Nothing *
  1036. * *
  1037. * WARNINGS: None *
  1038. * *
  1039. * HISTORY: *
  1040. * 11/21/2001 3:44PM ST : Created *
  1041. *=============================================================================================*/
  1042. void SlaveMasterClass::Delete_Registry_Copies(void)
  1043. {
  1044. HKEY base_key;
  1045. long result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, APPLICATION_SUB_KEY_NAME, 0, KEY_ALL_ACCESS, &base_key);
  1046. WWASSERT(result == ERROR_SUCCESS);
  1047. if (result == ERROR_SUCCESS) {
  1048. int index = 0;
  1049. char new_path[1024];
  1050. char slave_name[64];
  1051. while (index < MAX_SLAVES) {
  1052. strcpy(new_path, APPLICATION_SUB_KEY_NAME);
  1053. sprintf(slave_name, "\\slave_%d", index);
  1054. strcat(new_path, slave_name);
  1055. RegistryClass::Delete_Registry_Tree(new_path);
  1056. index++;
  1057. }
  1058. }
  1059. }
  1060. /***********************************************************************************************
  1061. * SlaveMasterClass::Get_Num_Enabled_Slaves -- How many slaves are enabled? *
  1062. * *
  1063. * *
  1064. * *
  1065. * INPUT: Nothing *
  1066. * *
  1067. * OUTPUT: Number of enabled slaves *
  1068. * *
  1069. * WARNINGS: None *
  1070. * *
  1071. * HISTORY: *
  1072. * 1/5/2002 11:47PM ST : Created *
  1073. *=============================================================================================*/
  1074. int SlaveMasterClass::Get_Num_Enabled_Slaves(void)
  1075. {
  1076. int enabled = 0;
  1077. for (int i=0 ; i<NumSlaveServers ; i++) {
  1078. if (SlaveServers[i].Enable) {
  1079. enabled++;
  1080. }
  1081. }
  1082. return(enabled);
  1083. }