NetworkUtil.cpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. /*
  2. ** Command & Conquer Generals(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. #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
  24. #include "GameNetwork/NetworkUtil.h"
  25. Int MAX_FRAMES_AHEAD = 128;
  26. Int MIN_RUNAHEAD = 10;
  27. Int FRAME_DATA_LENGTH = (MAX_FRAMES_AHEAD+1)*2;
  28. Int FRAMES_TO_KEEP = (MAX_FRAMES_AHEAD/2) + 1;
  29. #ifdef DEBUG_LOGGING
  30. void dumpBufferToLog(const void *vBuf, Int len, const char *fname, Int line)
  31. {
  32. DEBUG_LOG(("======= dumpBufferToLog() %d bytes =======\n", len));
  33. DEBUG_LOG(("Source: %s:%d\n", fname, line));
  34. const char *buf = (const char *)vBuf;
  35. Int numLines = len / 8;
  36. if ((len % 8) != 0)
  37. {
  38. ++numLines;
  39. }
  40. for (Int dumpindex = 0; dumpindex < numLines; ++dumpindex)
  41. {
  42. Int offset = dumpindex*8;
  43. DEBUG_LOG(("\t%5.5d\t", offset));
  44. Int dumpindex2;
  45. Int numBytesThisLine = min(8, len - offset);
  46. for (dumpindex2 = 0; dumpindex2 < numBytesThisLine; ++dumpindex2)
  47. {
  48. Int c = (buf[offset + dumpindex2] & 0xff);
  49. DEBUG_LOG(("%02X ", c));
  50. }
  51. for (; dumpindex2 < 8; ++dumpindex2)
  52. {
  53. DEBUG_LOG((" "));
  54. }
  55. DEBUG_LOG((" | "));
  56. for (dumpindex2 = 0; dumpindex2 < numBytesThisLine; ++dumpindex2)
  57. {
  58. char c = buf[offset + dumpindex2];
  59. DEBUG_LOG(("%c", (isprint(c)?c:'.')));
  60. }
  61. DEBUG_LOG(("\n"));
  62. }
  63. DEBUG_LOG(("End of packet dump\n"));
  64. }
  65. #endif // DEBUG_LOGGING
  66. /**
  67. * ResolveIP turns a string ("games2.westwood.com", or "192.168.0.1") into
  68. * a 32-bit unsigned integer.
  69. */
  70. UnsignedInt ResolveIP(AsciiString host)
  71. {
  72. struct hostent *hostStruct;
  73. struct in_addr *hostNode;
  74. if (host.getLength() == 0)
  75. {
  76. DEBUG_LOG(("ResolveIP(): Can't resolve NULL\n"));
  77. return 0;
  78. }
  79. // String such as "127.0.0.1"
  80. if (isdigit(host.getCharAt(0)))
  81. {
  82. return ( ntohl(inet_addr(host.str())) );
  83. }
  84. // String such as "localhost"
  85. hostStruct = gethostbyname(host.str());
  86. if (hostStruct == NULL)
  87. {
  88. DEBUG_LOG(("ResolveIP(): Can't resolve %s\n", host.str()));
  89. return 0;
  90. }
  91. hostNode = (struct in_addr *) hostStruct->h_addr;
  92. return ( ntohl(hostNode->s_addr) );
  93. }
  94. /**
  95. * Returns the next network command ID.
  96. */
  97. UnsignedShort GenerateNextCommandID() {
  98. static UnsignedShort commandID = 64000;
  99. ++commandID;
  100. return commandID;
  101. }
  102. /**
  103. * Returns true if this type of command requires a unique command ID.
  104. */
  105. Bool DoesCommandRequireACommandID(NetCommandType type) {
  106. if ((type == NETCOMMANDTYPE_GAMECOMMAND) ||
  107. (type == NETCOMMANDTYPE_FRAMEINFO) ||
  108. (type == NETCOMMANDTYPE_PLAYERLEAVE) ||
  109. (type == NETCOMMANDTYPE_DESTROYPLAYER) ||
  110. (type == NETCOMMANDTYPE_RUNAHEADMETRICS) ||
  111. (type == NETCOMMANDTYPE_RUNAHEAD) ||
  112. (type == NETCOMMANDTYPE_CHAT) ||
  113. (type == NETCOMMANDTYPE_DISCONNECTVOTE) ||
  114. (type == NETCOMMANDTYPE_LOADCOMPLETE) ||
  115. (type == NETCOMMANDTYPE_TIMEOUTSTART) ||
  116. (type == NETCOMMANDTYPE_WRAPPER) ||
  117. (type == NETCOMMANDTYPE_FILE) ||
  118. (type == NETCOMMANDTYPE_FILEANNOUNCE) ||
  119. (type == NETCOMMANDTYPE_FILEPROGRESS) ||
  120. (type == NETCOMMANDTYPE_DISCONNECTPLAYER) ||
  121. (type == NETCOMMANDTYPE_DISCONNECTFRAME) ||
  122. (type == NETCOMMANDTYPE_DISCONNECTSCREENOFF) ||
  123. (type == NETCOMMANDTYPE_FRAMERESENDREQUEST))
  124. {
  125. return TRUE;
  126. }
  127. return FALSE;
  128. }
  129. /**
  130. * Returns true if this type of network command requires an ack.
  131. */
  132. Bool CommandRequiresAck(NetCommandMsg *msg) {
  133. if ((msg->getNetCommandType() == NETCOMMANDTYPE_GAMECOMMAND) ||
  134. (msg->getNetCommandType() == NETCOMMANDTYPE_FRAMEINFO) ||
  135. (msg->getNetCommandType() == NETCOMMANDTYPE_PLAYERLEAVE) ||
  136. (msg->getNetCommandType() == NETCOMMANDTYPE_DESTROYPLAYER) ||
  137. (msg->getNetCommandType() == NETCOMMANDTYPE_RUNAHEADMETRICS) ||
  138. (msg->getNetCommandType() == NETCOMMANDTYPE_RUNAHEAD) ||
  139. (msg->getNetCommandType() == NETCOMMANDTYPE_CHAT) ||
  140. (msg->getNetCommandType() == NETCOMMANDTYPE_DISCONNECTVOTE) ||
  141. (msg->getNetCommandType() == NETCOMMANDTYPE_DISCONNECTPLAYER) ||
  142. (msg->getNetCommandType() == NETCOMMANDTYPE_LOADCOMPLETE) ||
  143. (msg->getNetCommandType() == NETCOMMANDTYPE_TIMEOUTSTART) ||
  144. (msg->getNetCommandType() == NETCOMMANDTYPE_WRAPPER) ||
  145. (msg->getNetCommandType() == NETCOMMANDTYPE_FILE) ||
  146. (msg->getNetCommandType() == NETCOMMANDTYPE_FILEANNOUNCE) ||
  147. (msg->getNetCommandType() == NETCOMMANDTYPE_FILEPROGRESS) ||
  148. (msg->getNetCommandType() == NETCOMMANDTYPE_DISCONNECTPLAYER) ||
  149. (msg->getNetCommandType() == NETCOMMANDTYPE_DISCONNECTFRAME) ||
  150. (msg->getNetCommandType() == NETCOMMANDTYPE_DISCONNECTSCREENOFF) ||
  151. (msg->getNetCommandType() == NETCOMMANDTYPE_FRAMERESENDREQUEST))
  152. {
  153. return TRUE;
  154. }
  155. return FALSE;
  156. }
  157. Bool IsCommandSynchronized(NetCommandType type) {
  158. if ((type == NETCOMMANDTYPE_GAMECOMMAND) ||
  159. (type == NETCOMMANDTYPE_FRAMEINFO) ||
  160. (type == NETCOMMANDTYPE_PLAYERLEAVE) ||
  161. (type == NETCOMMANDTYPE_DESTROYPLAYER) ||
  162. (type == NETCOMMANDTYPE_RUNAHEAD))
  163. {
  164. return TRUE;
  165. }
  166. return FALSE;
  167. }
  168. /**
  169. * Returns true if this type of network command requires the ack to be sent directly to the player
  170. * rather than going through the packet router. This should really only be used by commands
  171. * used on the disconnect screen.
  172. */
  173. Bool CommandRequiresDirectSend(NetCommandMsg *msg) {
  174. if ((msg->getNetCommandType() == NETCOMMANDTYPE_DISCONNECTVOTE) ||
  175. (msg->getNetCommandType() == NETCOMMANDTYPE_DISCONNECTPLAYER) ||
  176. (msg->getNetCommandType() == NETCOMMANDTYPE_LOADCOMPLETE) ||
  177. (msg->getNetCommandType() == NETCOMMANDTYPE_TIMEOUTSTART) ||
  178. (msg->getNetCommandType() == NETCOMMANDTYPE_FILE) ||
  179. (msg->getNetCommandType() == NETCOMMANDTYPE_FILEANNOUNCE) ||
  180. (msg->getNetCommandType() == NETCOMMANDTYPE_FILEPROGRESS) ||
  181. (msg->getNetCommandType() == NETCOMMANDTYPE_DISCONNECTFRAME) ||
  182. (msg->getNetCommandType() == NETCOMMANDTYPE_DISCONNECTSCREENOFF) ||
  183. (msg->getNetCommandType() == NETCOMMANDTYPE_FRAMERESENDREQUEST)) {
  184. return TRUE;
  185. }
  186. return FALSE;
  187. }
  188. AsciiString GetAsciiNetCommandType(NetCommandType type) {
  189. AsciiString s;
  190. if (type == NETCOMMANDTYPE_FRAMEINFO) {
  191. s.set("NETCOMMANDTYPE_FRAMEINFO");
  192. } else if (type == NETCOMMANDTYPE_GAMECOMMAND) {
  193. s.set("NETCOMMANDTYPE_GAMECOMMAND");
  194. } else if (type == NETCOMMANDTYPE_PLAYERLEAVE) {
  195. s.set("NETCOMMANDTYPE_PLAYERLEAVE");
  196. } else if (type == NETCOMMANDTYPE_RUNAHEADMETRICS) {
  197. s.set("NETCOMMANDTYPE_RUNAHEADMETRICS");
  198. } else if (type == NETCOMMANDTYPE_RUNAHEAD) {
  199. s.set("NETCOMMANDTYPE_RUNAHEAD");
  200. } else if (type == NETCOMMANDTYPE_DESTROYPLAYER) {
  201. s.set("NETCOMMANDTYPE_DESTROYPLAYER");
  202. } else if (type == NETCOMMANDTYPE_ACKBOTH) {
  203. s.set("NETCOMMANDTYPE_ACKBOTH");
  204. } else if (type == NETCOMMANDTYPE_ACKSTAGE1) {
  205. s.set("NETCOMMANDTYPE_ACKSTAGE1");
  206. } else if (type == NETCOMMANDTYPE_ACKSTAGE2) {
  207. s.set("NETCOMMANDTYPE_ACKSTAGE2");
  208. } else if (type == NETCOMMANDTYPE_FRAMEINFO) {
  209. s.set("NETCOMMANDTYPE_FRAMEINFO");
  210. } else if (type == NETCOMMANDTYPE_KEEPALIVE) {
  211. s.set("NETCOMMANDTYPE_KEEPALIVE");
  212. } else if (type == NETCOMMANDTYPE_DISCONNECTCHAT) {
  213. s.set("NETCOMMANDTYPE_DISCONNECTCHAT");
  214. } else if (type == NETCOMMANDTYPE_CHAT) {
  215. s.set("NETCOMMANDTYPE_CHAT");
  216. } else if (type == NETCOMMANDTYPE_MANGLERQUERY) {
  217. s.set("NETCOMMANDTYPE_MANGLERQUERY");
  218. } else if (type == NETCOMMANDTYPE_MANGLERRESPONSE) {
  219. s.set("NETCOMMANDTYPE_MANGLERRESPONSE");
  220. } else if (type == NETCOMMANDTYPE_DISCONNECTKEEPALIVE) {
  221. s.set("NETCOMMANDTYPE_DISCONNECTKEEPALIVE");
  222. } else if (type == NETCOMMANDTYPE_DISCONNECTPLAYER) {
  223. s.set("NETCOMMANDTYPE_DISCONNECTPLAYER");
  224. } else if (type == NETCOMMANDTYPE_PACKETROUTERQUERY) {
  225. s.set("NETCOMMANDTYPE_PACKETROUTERQUERY");
  226. } else if (type == NETCOMMANDTYPE_PACKETROUTERACK) {
  227. s.set("NETCOMMANDTYPE_PACKETROUTERACK");
  228. } else if (type == NETCOMMANDTYPE_DISCONNECTVOTE) {
  229. s.set("NETCOMMANDTYPE_DISCONNECTVOTE");
  230. } else if (type == NETCOMMANDTYPE_PROGRESS) {
  231. s.set("NETCOMMANDTYPE_PROGRESS");
  232. } else if (type == NETCOMMANDTYPE_LOADCOMPLETE) {
  233. s.set("NETCOMMANDTYPE_LOADCOMPLETE");
  234. } else if (type == NETCOMMANDTYPE_TIMEOUTSTART) {
  235. s.set("NETCOMMANDTYPE_TIMEOUTSTART");
  236. } else if (type == NETCOMMANDTYPE_WRAPPER) {
  237. s.set("NETCOMMANDTYPE_WRAPPER");
  238. } else if (type == NETCOMMANDTYPE_FILE) {
  239. s.set("NETCOMMANDTYPE_FILE");
  240. } else if (type == NETCOMMANDTYPE_FILEANNOUNCE) {
  241. s.set("NETCOMMANDTYPE_FILEANNOUNCE");
  242. } else if (type == NETCOMMANDTYPE_FILEPROGRESS) {
  243. s.set("NETCOMMANDTYPE_FILEPROGRESS");
  244. } else if (type == NETCOMMANDTYPE_DISCONNECTFRAME) {
  245. s.set("NETCOMMANDTYPE_DISCONNECTFRAME");
  246. } else if (type == NETCOMMANDTYPE_DISCONNECTSCREENOFF) {
  247. s.set("NETCOMMANDTYPE_DISCONNECTSCREENOFF");
  248. } else if (type == NETCOMMANDTYPE_FRAMERESENDREQUEST) {
  249. s.set("NETCOMMANDTYPE_FRAMERESENDREQUEST");
  250. } else {
  251. s.set("UNKNOWN");
  252. }
  253. return s;
  254. }