WSPROTO.CPP 30 KB

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