servercontrol.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563
  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 : Command & Conquer *
  23. * *
  24. * $Archive:: /Commando/Code/SControl/servercontrol.cpp $*
  25. * *
  26. * $Author:: Bhayes $*
  27. * *
  28. * $Modtime:: 3/18/02 6:04p $*
  29. * *
  30. * $Revision:: 7 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * *
  35. * *
  36. * *
  37. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  38. #include <stdlib.h>
  39. #include "servercontrol.h"
  40. #include "systimer.h"
  41. /*
  42. ** Single instance of server control.
  43. */
  44. ServerControlClass ServerControl;
  45. /***********************************************************************************************
  46. * ServerControlClass::ServerControlClass -- Class constructor *
  47. * *
  48. * *
  49. * *
  50. * INPUT: Nothing *
  51. * *
  52. * OUTPUT: Nothing *
  53. * *
  54. * WARNINGS: None *
  55. * *
  56. * HISTORY: *
  57. * 11/16/2001 4:00PM ST : Created *
  58. *=============================================================================================*/
  59. ServerControlClass::ServerControlClass(void)
  60. {
  61. AppRequestCallback = NULL;
  62. AppResponseCallback = NULL;
  63. LocalPort = 63999;
  64. strcpy(Password, "");
  65. Listening = false;
  66. WelcomeMessage[0] = 0;
  67. RemoteAdminAllowed = false;
  68. }
  69. /***********************************************************************************************
  70. * ServerControlClass::ServerControlClass -- Class destructor *
  71. * *
  72. * *
  73. * *
  74. * INPUT: Nothing *
  75. * *
  76. * OUTPUT: Nothing *
  77. * *
  78. * WARNINGS: None *
  79. * *
  80. * HISTORY: *
  81. * 11/16/2001 4:01PM ST : Created *
  82. *=============================================================================================*/
  83. ServerControlClass::~ServerControlClass(void)
  84. {
  85. Stop_Listening();
  86. }
  87. /***********************************************************************************************
  88. * ServerControlClass::Start_Listening -- Start listening for server control messages *
  89. * *
  90. * *
  91. * *
  92. * INPUT: Port to listen on *
  93. * Password to authenticate controllers *
  94. * App request callback *
  95. * App response callback *
  96. * Loopback - if set then only bind to the loopback address *
  97. * *
  98. * OUTPUT: Nothing *
  99. * *
  100. * WARNINGS: None *
  101. * *
  102. * HISTORY: *
  103. * 11/16/2001 4:01PM ST : Created *
  104. *=============================================================================================*/
  105. bool ServerControlClass::Start_Listening(unsigned short port, char *password, const char*(*app_request_callback)(char*), void(*app_response_callback)(char*), bool loopback, unsigned long ip)
  106. {
  107. LocalPort = port;
  108. if (LocalPort != 0) {
  109. strcpy(Password, password);
  110. if (Comms.Open(LocalPort, loopback, ip)) {
  111. Listening = true;
  112. AppRequestCallback = app_request_callback;
  113. AppResponseCallback = app_response_callback;
  114. Comms.Set_Encryption_Key(password);
  115. return(true);
  116. }
  117. }
  118. return(false);
  119. }
  120. /***********************************************************************************************
  121. * ServerControlClass::Stop_Listening -- Stop listening to control messages *
  122. * *
  123. * *
  124. * *
  125. * INPUT: Nothing *
  126. * *
  127. * OUTPUT: Nothing *
  128. * *
  129. * WARNINGS: None *
  130. * *
  131. * HISTORY: *
  132. * 11/16/2001 4:02PM ST : Created *
  133. *=============================================================================================*/
  134. void ServerControlClass::Stop_Listening(void)
  135. {
  136. if (Listening) {
  137. /*
  138. ** Throw off any connected controllers.
  139. */
  140. RemoteControlStruct *control;
  141. while (RemoteControllers.Count()) {
  142. control = RemoteControllers[0];
  143. if (control && control->Secure) {
  144. Respond("** Server exiting - Connection closed! **\n", control->IP, control->Port);
  145. }
  146. Remove_Remote_Control(control->IP, control->Port);
  147. }
  148. Comms.Close();
  149. Listening = false;
  150. }
  151. while (RemoteControllers.Count()) {
  152. delete RemoteControllers[0];
  153. RemoteControllers.Delete(0);
  154. }
  155. }
  156. /***********************************************************************************************
  157. * ServerControlClass::Service -- Service control messages *
  158. * *
  159. * *
  160. * *
  161. * INPUT: Nothing *
  162. * *
  163. * OUTPUT: Nothing *
  164. * *
  165. * WARNINGS: None *
  166. * *
  167. * HISTORY: *
  168. * 11/16/2001 4:03PM ST : Created *
  169. *=============================================================================================*/
  170. void ServerControlClass::Service(void)
  171. {
  172. if (Listening) {
  173. char buffer[1024];
  174. int buffer_len = sizeof(buffer);
  175. unsigned long address;
  176. unsigned short port;
  177. Comms.Service();
  178. int bytes = Comms.Read(buffer, buffer_len, &address, &port);
  179. if (bytes > 0 && bytes <= sizeof(ControlMessageStruct)) {
  180. if (Is_Authenticated(address, port)) {
  181. Reset_Timeout(address, port);
  182. }
  183. Parse_Message(buffer, bytes, address, port);
  184. }
  185. /*
  186. ** See if anyone timed out.
  187. */
  188. RemoteControlStruct *control;
  189. for (int i=0 ; i<RemoteControllers.Count() ; i++) {
  190. control = RemoteControllers[i];
  191. if (control && control->Secure) {
  192. if (TIMEGETTIME() - control->Time > CONTROL_TIMEOUT) {
  193. Respond("** Connection timed out - Bye! **\n", control->IP, control->Port);
  194. Remove_Remote_Control(control->IP, control->Port);
  195. break;
  196. }
  197. }
  198. }
  199. }
  200. }
  201. /***********************************************************************************************
  202. * ServerControlClass::Parse_Message -- Parse server control message *
  203. * *
  204. * *
  205. * *
  206. * INPUT: Buffer containing message struct *
  207. * Length of message *
  208. * Address message came from *
  209. * Port message came from *
  210. * *
  211. * OUTPUT: Nothing *
  212. * *
  213. * WARNINGS: None *
  214. * *
  215. * HISTORY: *
  216. * 11/16/2001 4:03PM ST : Created *
  217. *=============================================================================================*/
  218. void ServerControlClass::Parse_Message(void *buffer, int len, unsigned long address, unsigned short port)
  219. {
  220. ControlMessageStruct *message = (ControlMessageStruct*) buffer;
  221. assert(len <= sizeof(ControlMessageStruct));
  222. assert(message != NULL);
  223. /*
  224. ** This line prevents external control by only accepting messages from the loopback address.
  225. */
  226. if (ntohl(address) == INADDR_LOOPBACK || RemoteAdminAllowed) {
  227. /*
  228. ** Convert to upper case for parsing.
  229. */
  230. char text[MAX_SERVER_CONTROL_MESSAGE_SIZE + 1];
  231. memcpy(text, message->Message, MAX_SERVER_CONTROL_MESSAGE_SIZE);
  232. text[MAX_SERVER_CONTROL_MESSAGE_SIZE] = 0;
  233. strupr(text);
  234. switch (message->Type) {
  235. /*
  236. ** This is a request from a remote controller.
  237. */
  238. case CONTROL_REQUEST:
  239. if (strstr(text, "CONNECT")) {
  240. /*
  241. ** Someone is requesting to talk to us.
  242. */
  243. if (strlen(Password)) {
  244. Respond("Password required:", address, port);
  245. } else {
  246. Add_Remote_Control(address, port);
  247. }
  248. break;
  249. }
  250. if (strstr(text, "BYE")) {
  251. /*
  252. ** Remote controller is going away.
  253. */
  254. if (Is_Authenticated(address, port)) {
  255. Respond("Goodbye!\n", address, port);
  256. Remove_Remote_Control(address, port);
  257. }
  258. break;
  259. }
  260. /*
  261. ** Check for password authentication.
  262. */
  263. if (strlen(Password) && strstr(message->Message, Password)) {
  264. char buildbuf[256];
  265. strcpy(buildbuf, "Password accepted.\n");
  266. strcat(buildbuf, WelcomeMessage);
  267. strcat(buildbuf, "\n");
  268. Respond(buildbuf, address, port);
  269. Add_Remote_Control(address, port);
  270. break;
  271. }
  272. /*
  273. ** If we know about this controller and we have got a valid password from him then pass his message to the game.
  274. */
  275. if (AppRequestCallback && Is_Authenticated(address, port)) {
  276. const char * response = AppRequestCallback(message->Message);
  277. if (response && strlen(response)) {
  278. Respond(response, address, port);
  279. }
  280. }
  281. break;
  282. /*
  283. ** This is a response to a control message we sent out.
  284. */
  285. case CONTROL_RESPONSE:
  286. if (AppResponseCallback) {
  287. AppResponseCallback(message->Message);
  288. }
  289. break;
  290. }
  291. }
  292. }
  293. /***********************************************************************************************
  294. * ServerControlClass::Add_Remote_Control -- Add a new remote controller *
  295. * *
  296. * *
  297. * *
  298. * INPUT: IP of remote controller *
  299. * Port of remote controller *
  300. * *
  301. * OUTPUT: Nothing *
  302. * *
  303. * WARNINGS: None *
  304. * *
  305. * HISTORY: *
  306. * 11/16/2001 4:06PM ST : Created *
  307. *=============================================================================================*/
  308. void ServerControlClass::Add_Remote_Control(unsigned long ip, unsigned short port)
  309. {
  310. RemoteControlStruct *control = Get_Controller(ip, port);
  311. if (control == NULL) {
  312. control = new RemoteControlStruct;
  313. RemoteControllers.Add(control);
  314. }
  315. control->Time = TIMEGETTIME();
  316. control->Secure = true;
  317. control->IP = ip;
  318. control->Port = port;
  319. }
  320. /***********************************************************************************************
  321. * ServerControlClass::Remove_Remote_Control -- Remove a remote controller from our list *
  322. * *
  323. * *
  324. * *
  325. * INPUT: IP of remote controller *
  326. * Port of remote controller *
  327. * *
  328. * OUTPUT: Nothing *
  329. * *
  330. * WARNINGS: None *
  331. * *
  332. * HISTORY: *
  333. * 11/16/2001 4:07PM ST : Created *
  334. *=============================================================================================*/
  335. void ServerControlClass::Remove_Remote_Control(unsigned long ip, unsigned short port)
  336. {
  337. RemoteControlStruct *control;
  338. for (int i=0 ; i<RemoteControllers.Count() ; i++) {
  339. control = RemoteControllers[i];
  340. if (control->IP == ip && control->Port == port) {
  341. delete control;
  342. RemoteControllers.Delete(i);
  343. break;
  344. }
  345. }
  346. }
  347. /***********************************************************************************************
  348. * ServerControlClass::Is_Authenticated -- Has this controller presented a valid password? *
  349. * *
  350. * *
  351. * *
  352. * INPUT: IP, port *
  353. * *
  354. * OUTPUT: True if controller knows password *
  355. * *
  356. * WARNINGS: None *
  357. * *
  358. * HISTORY: *
  359. * 11/16/2001 4:07PM ST : Created *
  360. *=============================================================================================*/
  361. bool ServerControlClass::Is_Authenticated(unsigned long ip, unsigned short port)
  362. {
  363. RemoteControlStruct *control = Get_Controller(ip, port);
  364. if (control && control->Secure && TIMEGETTIME() - control->Time < CONTROL_TIMEOUT) {
  365. return(true);
  366. }
  367. return(false);
  368. }
  369. /***********************************************************************************************
  370. * ServerControlClass::Get_Controller -- Find remote controller info based on ip and port *
  371. * *
  372. * *
  373. * *
  374. * INPUT: Ip, port *
  375. * *
  376. * OUTPUT: Ptr to remote control struct. Null if not found *
  377. * *
  378. * WARNINGS: None *
  379. * *
  380. * HISTORY: *
  381. * 11/16/2001 4:08PM ST : Created *
  382. *=============================================================================================*/
  383. ServerControlClass::RemoteControlStruct *ServerControlClass::Get_Controller(unsigned long ip, unsigned short port)
  384. {
  385. RemoteControlStruct *control;
  386. for (int i=0 ; i<RemoteControllers.Count() ; i++) {
  387. control = RemoteControllers[i];
  388. if (control->IP == ip && control->Port == port) {
  389. return(control);
  390. }
  391. }
  392. return(NULL);
  393. }
  394. /***********************************************************************************************
  395. * ServerControlClass::Reset_Timeout -- Reset idle timeout for remote controller *
  396. * *
  397. * *
  398. * *
  399. * INPUT: Ip, port *
  400. * *
  401. * OUTPUT: Nothing *
  402. * *
  403. * WARNINGS: None *
  404. * *
  405. * HISTORY: *
  406. * 11/16/2001 4:09PM ST : Created *
  407. *=============================================================================================*/
  408. void ServerControlClass::Reset_Timeout(unsigned long ip, unsigned short port)
  409. {
  410. RemoteControlStruct *control = Get_Controller(ip, port);
  411. if (control && control->Secure && TIMEGETTIME() - control->Time < CONTROL_TIMEOUT) {
  412. control->Time = TIMEGETTIME();
  413. }
  414. }
  415. /***********************************************************************************************
  416. * ServerControlClass::Send_Message -- Send control message to remote server *
  417. * *
  418. * *
  419. * *
  420. * INPUT: Message text *
  421. * IP, port to send to *
  422. * *
  423. * OUTPUT: Nothing *
  424. * *
  425. * WARNINGS: None *
  426. * *
  427. * HISTORY: *
  428. * 11/16/2001 4:09PM ST : Created *
  429. *=============================================================================================*/
  430. void ServerControlClass::Send_Message(char *text, unsigned long ip, unsigned short port)
  431. {
  432. ControlMessageStruct message;
  433. message.Type = CONTROL_REQUEST;
  434. strcpy(message.Message, text);
  435. Comms.Write(&message, sizeof(message.Type) + strlen(text) + 1, &ip, port);
  436. Comms.Service();
  437. }
  438. /***********************************************************************************************
  439. * ServerControlClass::Respond -- Send a control request response to a remote controller *
  440. * *
  441. * *
  442. * *
  443. * INPUT: Text of response *
  444. * IP to send to *
  445. * port to send to *
  446. * *
  447. * OUTPUT: Nothing *
  448. * *
  449. * WARNINGS: None *
  450. * *
  451. * HISTORY: *
  452. * 11/16/2001 4:10PM ST : Created *
  453. *=============================================================================================*/
  454. void ServerControlClass::Respond(const char *text, unsigned long ip, unsigned short port)
  455. {
  456. ControlMessageStruct message;
  457. const char *outmsg = text;
  458. while (strlen(outmsg)) {
  459. message.Type = CONTROL_RESPONSE;
  460. strncpy(message.Message, outmsg, sizeof(message.Message)-1);
  461. message.Message[sizeof(message.Message)-1] = 0;
  462. int outlen = 0;
  463. if (strlen(outmsg) > sizeof(message.Message)-1) {
  464. outlen = sizeof(message.Message)-1;
  465. outmsg += (sizeof(message.Message)-1);
  466. } else {
  467. outlen = strlen(outmsg);
  468. outmsg += outlen;
  469. }
  470. Comms.Write(&message, sizeof(message.Type) + outlen + 1, &ip, port);
  471. Comms.Service();
  472. }
  473. }
  474. /***********************************************************************************************
  475. * ServerControlClass::Set_Welcome_Message -- Set the new connection welcome message *
  476. * *
  477. * *
  478. * *
  479. * INPUT: Text of message *
  480. * *
  481. * OUTPUT: Nothing *
  482. * *
  483. * WARNINGS: None *
  484. * *
  485. * HISTORY: *
  486. * 11/16/2001 4:11PM ST : Created *
  487. *=============================================================================================*/
  488. void ServerControlClass::Set_Welcome_Message(char *message)
  489. {
  490. if (message) {
  491. memset(WelcomeMessage, 0, sizeof(WelcomeMessage));
  492. strncpy(WelcomeMessage, message, sizeof(WelcomeMessage)-1);
  493. }
  494. }