WSPROTO.CPP 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594
  1. /*
  2. ** Command & Conquer Red Alert(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:: /Sun/WSProto.cpp $*
  25. * *
  26. * $Author:: Joe_b $*
  27. * *
  28. * $Modtime:: 8/20/97 10:54a $*
  29. * *
  30. * $Revision:: 5 $*
  31. * *
  32. * *
  33. *---------------------------------------------------------------------------------------------*
  34. * *
  35. * WSProto.CPP WinsockInterfaceClass to provide an interface to Winsock protocols *
  36. * *
  37. *---------------------------------------------------------------------------------------------*
  38. * *
  39. * Functions: *
  40. * *
  41. * WIC::WinsockInterfaceClass -- constructor for the WinsockInterfaceClass *
  42. * WIC::~WinsockInterfaceClass -- destructor for the WinsockInterfaceClass *
  43. * WIC::Close -- Releases any currently in use Winsock resources. *
  44. * WIC::Close_Socket -- Close the communication socket if its open *
  45. * WIC::Start_Listening -- Enable callbacks for read/write events on our socket *
  46. * WIC::Stop_Listening -- Disable the winsock event callback *
  47. * WIC::Discard_In_Buffers -- Discard any packets in our incoming packet holding buffers *
  48. * WIC::Discard_In_Buffers -- Discard any packets in our outgoing packet holding buffers *
  49. * WIC::Init -- Initialised Winsock and this class for use. *
  50. * WIC::Read -- read any pending input from the communications socket *
  51. * WIC::WriteTo -- Send data via the Winsock socket *
  52. * WIC::Broadcast -- Send data via the Winsock socket *
  53. * WIC::Clear_Socket_Error -- Clear any outstanding erros on the socket *
  54. * WIC::Set_Socket_Options -- Sets default socket options for Winsock buffer sizes *
  55. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  56. #include "function.h"
  57. #include "WSProto.h"
  58. #include <stdio.h>
  59. /***********************************************************************************************
  60. * WIC::WinsockInterfaceClass -- constructor for the WinsockInterfaceClass *
  61. * *
  62. * *
  63. * *
  64. * INPUT: Nothing *
  65. * *
  66. * OUTPUT: Nothing *
  67. * *
  68. * WARNINGS: None *
  69. * *
  70. * HISTORY: *
  71. * 3/20/96 2:51PM ST : Created *
  72. *=============================================================================================*/
  73. WinsockInterfaceClass::WinsockInterfaceClass(void)
  74. {
  75. WinsockInitialised = false;
  76. ASync = INVALID_HANDLE_VALUE;
  77. Socket = INVALID_SOCKET;
  78. }
  79. /***********************************************************************************************
  80. * WIC::~WinsockInterfaceClass -- destructor for the WinsockInterfaceClass *
  81. * *
  82. * *
  83. * *
  84. * INPUT: Nothing *
  85. * *
  86. * OUTPUT: Nothing *
  87. * *
  88. * WARNINGS: None *
  89. * *
  90. * HISTORY: *
  91. * 3/20/96 2:52PM ST : Created *
  92. *=============================================================================================*/
  93. WinsockInterfaceClass::~WinsockInterfaceClass(void)
  94. {
  95. Close();
  96. }
  97. /***********************************************************************************************
  98. * WIC::Close -- Releases any currently in use Winsock resources. *
  99. * *
  100. * *
  101. * *
  102. * INPUT: Nothing *
  103. * *
  104. * OUTPUT: Nothing *
  105. * *
  106. * WARNINGS: None *
  107. * *
  108. * HISTORY: *
  109. * 3/20/96 2:52PM ST : Created *
  110. *=============================================================================================*/
  111. void WinsockInterfaceClass::Close(void)
  112. {
  113. /*
  114. ** If we never initialised the class in the first place then just return
  115. */
  116. if (!WinsockInitialised) return;
  117. /*
  118. ** Cancel any outstaning asyncronous events
  119. */
  120. Stop_Listening();
  121. /*
  122. ** Close any open sockets
  123. */
  124. Close_Socket();
  125. /*
  126. ** Call the Winsock cleanup function to say we are finished using Winsock
  127. */
  128. WSACleanup();
  129. WinsockInitialised = false;
  130. }
  131. /***********************************************************************************************
  132. * WIC::Close_Socket -- Close the communication socket if its open *
  133. * *
  134. * *
  135. * *
  136. * INPUT: Nothing *
  137. * *
  138. * OUTPUT: Nothing *
  139. * *
  140. * WARNINGS: None *
  141. * *
  142. * HISTORY: *
  143. * 8/5/97 11:53AM ST : Created *
  144. *=============================================================================================*/
  145. void WinsockInterfaceClass::Close_Socket (void)
  146. {
  147. if ( Socket != INVALID_SOCKET ) {
  148. closesocket (Socket);
  149. Socket = INVALID_SOCKET;
  150. }
  151. }
  152. /***********************************************************************************************
  153. * WIC::Start_Listening -- Enable callbacks for read/write events on our socket *
  154. * *
  155. * *
  156. * *
  157. * INPUT: Nothing *
  158. * *
  159. * OUTPUT: Nothing *
  160. * *
  161. * WARNINGS: None *
  162. * *
  163. * HISTORY: *
  164. * 8/5/97 11:54AM ST : Created *
  165. *=============================================================================================*/
  166. bool WinsockInterfaceClass::Start_Listening (void)
  167. {
  168. /*
  169. ** Enable asynchronous events on the socket
  170. */
  171. if ( WSAAsyncSelect ( Socket, MainWindow, Protocol_Event_Message(), FD_READ | FD_WRITE) == SOCKET_ERROR ){
  172. WWDebugString ( "TS: Async select failed.\n" );
  173. assert (false);
  174. WSACancelAsyncRequest(ASync);
  175. ASync = INVALID_HANDLE_VALUE;
  176. return (false);
  177. }
  178. return (true);
  179. }
  180. /***********************************************************************************************
  181. * WIC::Stop_Listening -- Disable the winsock event callback *
  182. * *
  183. * *
  184. * *
  185. * INPUT: Nothing *
  186. * *
  187. * OUTPUT: Nothing *
  188. * *
  189. * WARNINGS: None *
  190. * *
  191. * HISTORY: *
  192. * 8/5/97 12:06PM ST : Created *
  193. *=============================================================================================*/
  194. void WinsockInterfaceClass::Stop_Listening (void)
  195. {
  196. if ( ASync != INVALID_HANDLE_VALUE ) {
  197. WSACancelAsyncRequest ( ASync );
  198. ASync = INVALID_HANDLE_VALUE;
  199. }
  200. }
  201. /***********************************************************************************************
  202. * WIC::Discard_In_Buffers -- Discard any packets in our incoming packet holding buffers *
  203. * *
  204. * *
  205. * *
  206. * INPUT: Nothing *
  207. * *
  208. * OUTPUT: Nothing *
  209. * *
  210. * WARNINGS: None *
  211. * *
  212. * HISTORY: *
  213. * 8/5/97 11:55AM ST : Created *
  214. *=============================================================================================*/
  215. void WinsockInterfaceClass::Discard_In_Buffers (void)
  216. {
  217. WinsockBufferType *packet;
  218. while ( InBuffers.Count() ) {
  219. packet = InBuffers [ 0 ];
  220. delete packet;
  221. InBuffers.Delete (0);
  222. }
  223. }
  224. /***********************************************************************************************
  225. * WIC::Discard_In_Buffers -- Discard any packets in our outgoing packet holding buffers *
  226. * *
  227. * *
  228. * *
  229. * INPUT: Nothing *
  230. * *
  231. * OUTPUT: Nothing *
  232. * *
  233. * WARNINGS: None *
  234. * *
  235. * HISTORY: *
  236. * 8/5/97 11:55AM ST : Created *
  237. *=============================================================================================*/
  238. void WinsockInterfaceClass::Discard_Out_Buffers (void)
  239. {
  240. WinsockBufferType *packet;
  241. while ( OutBuffers.Count() ) {
  242. packet = OutBuffers [ 0 ];
  243. delete packet;
  244. OutBuffers.Delete (0);
  245. }
  246. }
  247. /***********************************************************************************************
  248. * WIC::Init -- Initialised Winsock and this class for use. *
  249. * *
  250. * *
  251. * *
  252. * INPUT: Nothing *
  253. * *
  254. * OUTPUT: true if Winsock is available and was initialised *
  255. * *
  256. * WARNINGS: None *
  257. * *
  258. * HISTORY: *
  259. * 3/20/96 2:54PM ST : Created *
  260. *=============================================================================================*/
  261. bool WinsockInterfaceClass::Init(void)
  262. {
  263. short version;
  264. int rc;
  265. /*
  266. ** Just return true if we are already set up
  267. */
  268. if (WinsockInitialised) return (true);
  269. /*
  270. ** Create a buffer much larger than the sizeof (WSADATA) would indicate since Bounds Checker
  271. ** says that a buffer of that size gets overrun.
  272. */
  273. char *buffer = new char [sizeof (WSADATA) + 1024];
  274. WSADATA *winsock_info = (WSADATA*) (&buffer[0]);
  275. /*
  276. ** Initialise socket and event handle to null
  277. */
  278. Socket =INVALID_SOCKET;
  279. ASync = INVALID_HANDLE_VALUE;
  280. Discard_In_Buffers();
  281. Discard_Out_Buffers();
  282. /*
  283. ** Start WinSock, and fill in our Winsock info structure
  284. */
  285. version = (WINSOCK_MINOR_VER << 8) | WINSOCK_MAJOR_VER;
  286. rc = WSAStartup(version, winsock_info);
  287. if (rc != 0) {
  288. char out[128];
  289. sprintf (out, "TS: Winsock failed to initialise - error code %d.\n", GetLastError() );
  290. OutputDebugString (out);
  291. delete [] buffer;
  292. return (false);
  293. }
  294. /*
  295. ** Check the Winsock version number
  296. */
  297. if ((winsock_info->wVersion & 0x00ff) != (version & 0x00ff) ||
  298. (winsock_info->wVersion >> 8) != (version >> 8)) {
  299. OutputDebugString ("TS: Winsock version is less than 1.1\n" );
  300. delete [] buffer;
  301. return (false);
  302. }
  303. /*
  304. ** Everything is OK so return success
  305. */
  306. WinsockInitialised = true;
  307. delete [] buffer;
  308. return (true);
  309. }
  310. /***********************************************************************************************
  311. * WIC::Read -- read any pending input from the communications socket *
  312. * *
  313. * *
  314. * *
  315. * INPUT: ptr to buffer to receive input *
  316. * length of buffer *
  317. * ptr to address to fill with address that packet was sent from *
  318. * length of address buffer *
  319. * *
  320. * OUTPUT: number of bytes transfered to buffer *
  321. * *
  322. * WARNINGS: The format of the address is dependent on the protocol in use. *
  323. * *
  324. * *
  325. * HISTORY: *
  326. * 3/20/96 2:58PM ST : Created *
  327. *=============================================================================================*/
  328. int WinsockInterfaceClass::Read(void *buffer, int &buffer_len, void *address, int &address_len)
  329. {
  330. address_len = address_len;
  331. /*
  332. ** Call the message loop in case there are any outstanding winsock READ messages.
  333. */
  334. Keyboard->Check();
  335. /*
  336. ** If there are no available packets then return 0
  337. */
  338. if ( InBuffers.Count() == 0 ) return (0);
  339. /*
  340. ** Get the oldest packet for reading
  341. */
  342. int packetnum = 0;
  343. WinsockBufferType *packet = InBuffers [packetnum];
  344. assert ( buffer_len >= packet->BufferLen );
  345. assert ( address_len >= sizeof (packet->Address) );
  346. /*
  347. ** Copy the data and the address it came from into the supplied buffers.
  348. */
  349. memcpy ( buffer, packet->Buffer, packet->BufferLen );
  350. memcpy ( address, packet->Address, sizeof (packet->Address) );
  351. /*
  352. ** Return the length of the packet in buffer_len.
  353. */
  354. buffer_len = packet->BufferLen;
  355. /*
  356. ** Delete the temporary storage for the packet now that it is being passed to the game.
  357. */
  358. InBuffers.Delete ( packetnum );
  359. delete packet;
  360. return ( buffer_len );
  361. }
  362. /***********************************************************************************************
  363. * WIC::WriteTo -- Send data via the Winsock socket *
  364. * *
  365. * *
  366. * *
  367. * INPUT: ptr to buffer containing data to send *
  368. * length of data to send *
  369. * address to send data to. *
  370. * *
  371. * OUTPUT: Nothing *
  372. * *
  373. * WARNINGS: The format of the address is dependent on the protocol in use. *
  374. * *
  375. * HISTORY: *
  376. * 3/20/96 3:00PM ST : Created *
  377. *=============================================================================================*/
  378. void WinsockInterfaceClass::WriteTo(void *buffer, int buffer_len, void *address)
  379. {
  380. /*
  381. ** Create a temporary holding area for the packet.
  382. */
  383. WinsockBufferType *packet = new WinsockBufferType;
  384. /*
  385. ** Copy the packet into the holding buffer.
  386. */
  387. memcpy ( packet->Buffer, buffer, buffer_len );
  388. packet->BufferLen = buffer_len;
  389. packet->IsBroadcast = false;
  390. // memcpy ( packet->Address, address, sizeof (packet->Address) );
  391. memcpy ( packet->Address, address, sizeof( IPXAddressClass ) ); // Steve Tall has revised WriteTo due to this bug.
  392. /*
  393. ** Add it to our out list.
  394. */
  395. OutBuffers.Add ( packet );
  396. /*
  397. ** Send a message to ourselves so that we can initiate a write if Winsock is idle.
  398. */
  399. SendMessage ( MainWindow, Protocol_Event_Message(), 0, (LONG)FD_WRITE );
  400. /*
  401. ** Make sure the message loop gets called.
  402. */
  403. Keyboard->Check();
  404. }
  405. /***********************************************************************************************
  406. * WIC::Broadcast -- Send data via the Winsock socket *
  407. * *
  408. * *
  409. * *
  410. * INPUT: ptr to buffer containing data to send *
  411. * length of data to send *
  412. * *
  413. * OUTPUT: Nothing *
  414. * *
  415. * WARNINGS: None *
  416. * *
  417. * HISTORY: *
  418. * 3/20/96 3:00PM ST : Created *
  419. *=============================================================================================*/
  420. void WinsockInterfaceClass::Broadcast (void *buffer, int buffer_len)
  421. {
  422. /*
  423. ** Create a temporary holding area for the packet.
  424. */
  425. WinsockBufferType *packet = new WinsockBufferType;
  426. /*
  427. ** Copy the packet into the holding buffer.
  428. */
  429. memcpy ( packet->Buffer, buffer, buffer_len );
  430. packet->BufferLen = buffer_len;
  431. /*
  432. ** Indicate that this packet should be broadcast.
  433. */
  434. packet->IsBroadcast = true;
  435. /*
  436. ** Add it to our out list.
  437. */
  438. OutBuffers.Add ( packet );
  439. /*
  440. ** Send a message to ourselves so that we can initiate a write if Winsock is idle.
  441. */
  442. SendMessage ( MainWindow, Protocol_Event_Message(), 0, (LONG)FD_WRITE );
  443. /*
  444. ** Make sure the message loop gets called.
  445. */
  446. Keyboard->Check();
  447. }
  448. /***********************************************************************************************
  449. * WIC::Clear_Socket_Error -- Clear any outstanding erros on the socket *
  450. * *
  451. * *
  452. * *
  453. * INPUT: Socket *
  454. * *
  455. * OUTPUT: Nothing *
  456. * *
  457. * WARNINGS: None *
  458. * *
  459. * HISTORY: *
  460. * 8/5/97 12:05PM ST : Created *
  461. *=============================================================================================*/
  462. void WinsockInterfaceClass::Clear_Socket_Error(SOCKET socket)
  463. {
  464. unsigned long error_code;
  465. int length = 4;
  466. getsockopt (socket, SOL_SOCKET, SO_ERROR, (char*)&error_code, &length);
  467. error_code = 0;
  468. setsockopt (socket, SOL_SOCKET, SO_ERROR, (char*)&error_code, length);
  469. }
  470. /***********************************************************************************************
  471. * WIC::Set_Socket_Options -- Sets default socket options for Winsock buffer sizes *
  472. * *
  473. * *
  474. * *
  475. * INPUT: Nothing *
  476. * *
  477. * OUTPUT: Nothing *
  478. * *
  479. * WARNINGS: None *
  480. * *
  481. * HISTORY: *
  482. * 8/5/97 12:07PM ST : Created *
  483. *=============================================================================================*/
  484. bool WinsockInterfaceClass::Set_Socket_Options ( void )
  485. {
  486. static int socket_transmit_buffer_size = SOCKET_BUFFER_SIZE;
  487. static int socket_receive_buffer_size = SOCKET_BUFFER_SIZE;
  488. /*
  489. ** Specify the size of the receive buffer.
  490. */
  491. int err = setsockopt ( Socket, SOL_SOCKET, SO_RCVBUF, (char*)&socket_receive_buffer_size, 4);
  492. if ( err == INVALID_SOCKET ) {
  493. char out[128];
  494. sprintf (out, "TS: Failed to set IPX socket option SO_RCVBUF - error code %d.\n", GetLastError() );
  495. OutputDebugString (out);
  496. assert ( err != INVALID_SOCKET );
  497. }
  498. /*
  499. ** Specify the size of the send buffer.
  500. */
  501. err = setsockopt ( Socket, SOL_SOCKET, SO_SNDBUF, (char*)&socket_transmit_buffer_size, 4);
  502. if ( err == INVALID_SOCKET ) {
  503. char out[128];
  504. sprintf (out, "TS: Failed to set IPX socket option SO_SNDBUF - error code %d.\n", GetLastError() );
  505. OutputDebugString (out);
  506. assert ( err != INVALID_SOCKET );
  507. }
  508. return ( true );
  509. }