TCPIP.CPP 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906
  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 - Red Alert *
  19. * *
  20. * File Name : TCPIP.CPP *
  21. * *
  22. * Programmer : Steve Tall *
  23. * *
  24. * Start Date : March 11th, 1996 *
  25. * *
  26. * Last Update : March 20th, 1996 [ST] *
  27. * *
  28. *-------------------------------------------------------------------------*
  29. * Overview: *
  30. * *
  31. * Member functions of the TcpipManagerClass which provides the Winsock *
  32. * interface for C&C *
  33. * *
  34. * *
  35. *-------------------------------------------------------------------------*
  36. * Functions: *
  37. * *
  38. * TMC::TcpipManagerClass -- constructor for the TcpipManagerClass *
  39. * TMC::~TcpipManagerClass -- destructor for the TcpipManagerClass *
  40. * TMC::Close -- restores any currently in use Winsock resources *
  41. * TMC::Init -- Initialised Winsock for use. *
  42. * TMC::Start_Server -- Initialise connection and start listening. *
  43. * TMC::Read -- read any pending input from the stream socket *
  44. * TMC::Write -- Send data via the Winsock streaming socket *
  45. * TMC::Add_Client -- A client has requested to connect. *
  46. * TMC::Message_Handler -- Message handler for Winsock. *
  47. * TMC::Set_Host_Address -- Set the address of the host *
  48. * TMC::Start_Client -- Start trying to connect to a game host *
  49. * TMC::Close_Socket -- Close an opened Winsock socket. *
  50. * TMC::Copy_To_In_Buffer -- copy data from our winsock buffer *
  51. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  52. #ifdef WIN32
  53. #include "function.h"
  54. #include "tcpip.h"
  55. /*
  56. ** Nasty globals
  57. */
  58. #ifndef WOLAPI_INTEGRATION
  59. bool Server; //Is this player acting as client or server
  60. #endif
  61. TcpipManagerClass Winsock; //The object for interfacing with Winsock
  62. /***********************************************************************************************
  63. * TMC::TcpipManagerClass -- constructor for the TcpipManagerClass *
  64. * *
  65. * *
  66. * *
  67. * INPUT: Nothing *
  68. * *
  69. * OUTPUT: Nothing *
  70. * *
  71. * WARNINGS: None *
  72. * *
  73. * HISTORY: *
  74. * 3/20/96 2:51PM ST : Created *
  75. *=============================================================================================*/
  76. TcpipManagerClass::TcpipManagerClass(void)
  77. {
  78. WinsockInitialised = FALSE;
  79. Connected = FALSE;
  80. UseUDP = TRUE;
  81. SocketReceiveBuffer = 4096;
  82. SocketSendBuffer = 4096;
  83. }
  84. /***********************************************************************************************
  85. * TMC::~TcpipManagerClass -- destructor for the TcpipManagerClass *
  86. * *
  87. * *
  88. * *
  89. * INPUT: Nothing *
  90. * *
  91. * OUTPUT: Nothing *
  92. * *
  93. * WARNINGS: None *
  94. * *
  95. * HISTORY: *
  96. * 3/20/96 2:52PM ST : Created *
  97. *=============================================================================================*/
  98. TcpipManagerClass::~TcpipManagerClass(void)
  99. {
  100. Close();
  101. }
  102. /***********************************************************************************************
  103. * TMC::Close -- restores any currently in use Winsock resources *
  104. * *
  105. * *
  106. * *
  107. * INPUT: Nothing *
  108. * *
  109. * OUTPUT: Nothing *
  110. * *
  111. * WARNINGS: None *
  112. * *
  113. * HISTORY: *
  114. * 3/20/96 2:52PM ST : Created *
  115. *=============================================================================================*/
  116. void TcpipManagerClass::Close(void)
  117. {
  118. /*
  119. ** If we never initialised the class in the first place then just return
  120. */
  121. if (!WinsockInitialised) return;
  122. /*
  123. ** Cancel any outstaning asyncronous events
  124. */
  125. if (Async){
  126. WSACancelAsyncRequest(Async);
  127. }
  128. /*
  129. ** Close any open sockets
  130. */
  131. if (ConnectSocket != INVALID_SOCKET){
  132. Close_Socket(ConnectSocket);
  133. ConnectSocket = INVALID_SOCKET;
  134. }
  135. if (ListenSocket != INVALID_SOCKET){
  136. Close_Socket(ListenSocket);
  137. ListenSocket = INVALID_SOCKET;
  138. }
  139. if (UDPSocket != INVALID_SOCKET){
  140. Close_Socket(ListenSocket);
  141. UDPSocket = INVALID_SOCKET;
  142. }
  143. /*
  144. ** Call the Winsock cleanup function to say we are finished using Winsock
  145. */
  146. WSACleanup();
  147. WinsockInitialised = FALSE;
  148. Connected = FALSE;
  149. }
  150. /***********************************************************************************************
  151. * TMC::Init -- Initialised Winsock for use. *
  152. * *
  153. * *
  154. * *
  155. * INPUT: Nothing *
  156. * *
  157. * OUTPUT: TRUE if Winsock is available and was initialised *
  158. * *
  159. * WARNINGS: None *
  160. * *
  161. * HISTORY: *
  162. * 3/20/96 2:54PM ST : Created *
  163. *=============================================================================================*/
  164. BOOL TcpipManagerClass::Init(void)
  165. {
  166. short version;
  167. int rc;
  168. /*
  169. ** Just return true if we are already set up
  170. */
  171. if (WinsockInitialised) return (TRUE);
  172. /*
  173. ** Initialise sockets to null
  174. */
  175. ListenSocket = INVALID_SOCKET;
  176. ConnectSocket =INVALID_SOCKET;
  177. UDPSocket = INVALID_SOCKET;
  178. /*
  179. ** Start WinSock, and fill in our WinSockData
  180. */
  181. version = (WINSOCK_MINOR_VER << 8) | WINSOCK_MAJOR_VER;
  182. rc = WSAStartup(version, &WinsockInfo);
  183. if (rc != 0) {
  184. return (FALSE);
  185. }
  186. /*
  187. ** Check the Winsock version number
  188. */
  189. if ((WinsockInfo.wVersion & 0x00ff) != (version & 0x00ff) ||
  190. (WinsockInfo.wVersion >> 8) != (version >> 8)) {
  191. return (FALSE);
  192. }
  193. /*
  194. ** Everything is OK so return success
  195. */
  196. WinsockInitialised = TRUE;
  197. return (TRUE);
  198. }
  199. /***********************************************************************************************
  200. * TMC::Start_Server -- initialise out connection as the server. Start listening for clients. *
  201. * *
  202. * *
  203. * *
  204. * INPUT: Nothing *
  205. * *
  206. * OUTPUT: Nothing *
  207. * *
  208. * WARNINGS: None *
  209. * *
  210. * HISTORY: *
  211. * 3/20/96 2:56PM ST : Created *
  212. *=============================================================================================*/
  213. void TcpipManagerClass::Start_Server(void)
  214. {
  215. int i;
  216. //struct sockaddr_in addr;
  217. Start_Client();
  218. /*
  219. ** Set up the incoming and outgoing data buffers head and tail pointers
  220. */
  221. TXBufferHead = 0;
  222. TXBufferTail = 0;
  223. RXBufferHead = 0;
  224. RXBufferTail = 0;
  225. for (i=0 ; i<WS_NUM_TX_BUFFERS ; i++){
  226. TransmitBuffers[i].InUse = false;
  227. }
  228. for (i=0 ; i<WS_NUM_RX_BUFFERS ; i++){
  229. ReceiveBuffers[i].InUse = false;
  230. }
  231. /*
  232. ** Flag that we are the server side not the client
  233. */
  234. IsServer = TRUE;
  235. UseUDP = TRUE;
  236. ConnectStatus = CONNECTING;
  237. }
  238. /***********************************************************************************************
  239. * TMC::Read -- read any pending input from the stream socket *
  240. * *
  241. * *
  242. * *
  243. * INPUT: ptr to buffer to receive input *
  244. * length of buffer *
  245. * *
  246. * OUTPUT: number of bytes transfered to buffer *
  247. * *
  248. * WARNINGS: None *
  249. * *
  250. * HISTORY: *
  251. * 3/20/96 2:58PM ST : Created *
  252. *=============================================================================================*/
  253. int TcpipManagerClass::Read(void *buffer, int buffer_len)
  254. {
  255. int bytes_copied = 0;
  256. char *dest_buf = (char*) buffer;
  257. /*
  258. ** Make sure the message loop gets called because all the Winsock notifications
  259. ** are done via messages.
  260. */
  261. Keyboard->Check();
  262. /*
  263. ** Copy any outstanding incoming data to the buffer provided
  264. */
  265. if (ReceiveBuffers[RXBufferTail].InUse){
  266. memcpy (buffer, ReceiveBuffers[RXBufferTail].Buffer,
  267. MIN(ReceiveBuffers[RXBufferTail].DataLength, buffer_len));
  268. ReceiveBuffers[RXBufferTail].InUse = false;
  269. bytes_copied = MIN(ReceiveBuffers[RXBufferTail++].DataLength, buffer_len);
  270. RXBufferTail &= WS_NUM_RX_BUFFERS-1;
  271. }
  272. return (bytes_copied);
  273. }
  274. /***********************************************************************************************
  275. * TMC::Write -- Send data via the Winsock UDP socket *
  276. * *
  277. * *
  278. * *
  279. * INPUT: ptr to buffer containing data to send *
  280. * length of data to send *
  281. * *
  282. * OUTPUT: Nothing *
  283. * *
  284. * WARNINGS: None *
  285. * *
  286. * HISTORY: *
  287. * 3/20/96 3:00PM ST : Created *
  288. *=============================================================================================*/
  289. void TcpipManagerClass::Write(void *buffer, int buffer_len)
  290. {
  291. char *source_buf = (char*) buffer;
  292. /*
  293. ** Copy the data to one of the classes internal buffers
  294. */
  295. if (!TransmitBuffers[TXBufferHead].InUse){
  296. memcpy (TransmitBuffers[TXBufferHead].Buffer,
  297. buffer,
  298. MIN (buffer_len, WS_INTERNET_BUFFER_LEN));
  299. TransmitBuffers[TXBufferHead].InUse = true;
  300. TransmitBuffers[TXBufferHead++].DataLength = MIN(buffer_len, WS_INTERNET_BUFFER_LEN);
  301. TXBufferHead &= WS_NUM_TX_BUFFERS-1;
  302. }
  303. /*
  304. ** Send a message to ourselves to start off the event
  305. */
  306. if (UseUDP){
  307. SendMessage(MainWindow, WM_UDPASYNCEVENT, 0, (LONG)FD_WRITE);
  308. }else{
  309. SendMessage(MainWindow, WM_ASYNCEVENT, 0, (LONG)FD_WRITE);
  310. }
  311. /*
  312. ** Make sure the message loop gets called because all the Winsock notifications
  313. ** are done via messages.
  314. */
  315. Keyboard->Check();
  316. }
  317. /***********************************************************************************************
  318. * TMC::Add_Client -- a client has requested to connect. Make the connection *
  319. * *
  320. * *
  321. * *
  322. * INPUT: Nothing *
  323. * *
  324. * OUTPUT: TRUE if client was successfully connected *
  325. * *
  326. * WARNINGS: None *
  327. * *
  328. * HISTORY: *
  329. * 3/20/96 3:02PM ST : Created *
  330. *=============================================================================================*/
  331. BOOL TcpipManagerClass::Add_Client(void)
  332. {
  333. struct sockaddr_in addr;
  334. int addrsize;
  335. bool delay = TRUE;
  336. /*
  337. ** Accept the connection. If there is an error then dont do anything else
  338. */
  339. addrsize = sizeof(addr);
  340. ConnectSocket = accept (ListenSocket, (LPSOCKADDR)&addr, &addrsize);
  341. if (ConnectSocket == INVALID_SOCKET) {
  342. //Show_Error("accept", WSAGetLastError());
  343. return(FALSE);
  344. }
  345. /*
  346. ** Set options for this socket
  347. */
  348. setsockopt (ConnectSocket, IPPROTO_TCP, TCP_NODELAY, (char*)&delay, 4);
  349. setsockopt (ConnectSocket, SOL_SOCKET, SO_RCVBUF, (char*)&SocketReceiveBuffer, 4);
  350. setsockopt (ConnectSocket, SOL_SOCKET, SO_SNDBUF, (char*)&SocketSendBuffer, 4);
  351. /*
  352. ** Save the clients address
  353. */
  354. memcpy(&ClientIPAddress, &addr.sin_addr.s_addr,4);
  355. memcpy(&UDPIPAddress, &addr.sin_addr.s_addr,4);
  356. /*
  357. ** Initiate an asynchronous host lookup by address. Our window will receive notification
  358. ** when this is complete or when it times out.
  359. */
  360. Async = WSAAsyncGetHostByAddr (MainWindow, WM_HOSTBYADDRESS,
  361. (char const *)&addr.sin_addr, 4, PF_INET, &HostBuff[0],
  362. MAXGETHOSTSTRUCT);
  363. /*
  364. ** Enable asynchronous events on this socket
  365. */
  366. if (WSAAsyncSelect (ConnectSocket, MainWindow, WM_ASYNCEVENT,
  367. FD_READ | FD_WRITE | FD_CLOSE) == SOCKET_ERROR){
  368. WSACancelAsyncRequest(Async);
  369. Close_Socket (ConnectSocket);
  370. return(FALSE);
  371. }
  372. /*
  373. ** Create our UDP socket
  374. */
  375. UDPSocket = socket(AF_INET, SOCK_DGRAM, 0);
  376. if (UDPSocket == INVALID_SOCKET) {
  377. return (FALSE);
  378. }
  379. /*
  380. ** Bind our UDP socket to our UDP port number
  381. */
  382. addr.sin_family = AF_INET;
  383. addr.sin_port = htons(PlanetWestwoodPortNumber);
  384. addr.sin_addr.s_addr = htonl(INADDR_ANY);
  385. if (bind(UDPSocket, (LPSOCKADDR)&addr, sizeof(addr)) ==
  386. SOCKET_ERROR) {
  387. Close_Socket(UDPSocket);
  388. ConnectStatus = NOT_CONNECTING;
  389. return(FALSE);
  390. }
  391. /*
  392. ** Set options for the UDP socket
  393. */
  394. setsockopt (UDPSocket, SOL_SOCKET, SO_RCVBUF, (char*)&SocketReceiveBuffer, 4);
  395. setsockopt (UDPSocket, SOL_SOCKET, SO_SNDBUF, (char*)&SocketSendBuffer, 4);
  396. /*
  397. ** Enable asynchronous events on this socket
  398. */
  399. if (WSAAsyncSelect (UDPSocket, MainWindow, WM_UDPASYNCEVENT,
  400. FD_READ | FD_WRITE) == SOCKET_ERROR){
  401. WSACancelAsyncRequest(Async);
  402. Close_Socket (UDPSocket);
  403. Close_Socket (ConnectSocket);
  404. return(FALSE);
  405. }
  406. return (TRUE);
  407. }
  408. /***********************************************************************************************
  409. * TMC::Message_Handler -- Message handler function for Winsock related messages *
  410. * *
  411. * *
  412. * *
  413. * INPUT: Windows message handler stuff *
  414. * *
  415. * OUTPUT: Nothing *
  416. * *
  417. * WARNINGS: None *
  418. * *
  419. * HISTORY: *
  420. * 3/20/96 3:05PM ST : Created *
  421. *=============================================================================================*/
  422. void TcpipManagerClass::Message_Handler(HWND, UINT message, UINT , LONG lParam)
  423. {
  424. struct hostent *hentry;
  425. struct sockaddr_in addr;
  426. int event;
  427. int rc;
  428. int addr_len;
  429. switch (message){
  430. /*
  431. ** Handle the GetHostByAddress result
  432. */
  433. case WM_HOSTBYADDRESS:
  434. if (IsServer){
  435. /*
  436. ** We are the server
  437. */
  438. ConnectStatus = CONNECTING;
  439. if (WSAGETASYNCERROR(lParam)==0) {
  440. hentry = (struct hostent *)&HostBuff[0];
  441. strcpy (&ClientName[0], hentry->h_name);
  442. }
  443. Async = 0;
  444. return;
  445. }else{
  446. /*
  447. ** We are the client
  448. */
  449. ConnectStatus = CONTACTING_SERVER;
  450. if (WSAGETASYNCERROR(lParam)==0) {
  451. hentry = (struct hostent *)&HostBuff[0];
  452. strcpy (Server.Name, hentry->h_name);
  453. }
  454. else {
  455. Server.Name[0] = 0;
  456. }
  457. Async = 0;
  458. return;
  459. }
  460. /*
  461. ** Retrieve host by name: Start connecting now that we have the
  462. ** address.
  463. */
  464. case WM_HOSTBYNAME:
  465. if (WSAGETASYNCERROR(lParam)==0) {
  466. hentry = (struct hostent *)&HostBuff[0];
  467. memcpy (&(Server.Addr.s_addr), hentry->h_addr, 4);
  468. memcpy(&UDPIPAddress, hentry->h_addr, 4);
  469. strcpy (Server.DotAddr, inet_ntoa(Server.Addr));
  470. ConnectStatus = CONNECTED_OK;
  471. Connected = TRUE;
  472. }
  473. else {
  474. Server.Name[0] = 0;
  475. strcpy (Server.DotAddr, "????");
  476. ConnectStatus = SERVER_ADDRESS_LOOKUP_FAILED;
  477. }
  478. Async = 0;
  479. return;
  480. /*
  481. ** Connection is ready - accept the client
  482. */
  483. case WM_ACCEPT:
  484. rc = WSAGETSELECTERROR(lParam);
  485. if (rc != 0) {
  486. ConnectStatus = UNABLE_TO_ACCEPT_CLIENT;
  487. return;
  488. }
  489. if (Add_Client()) {
  490. ConnectStatus = CONNECTED_OK;
  491. Connected = TRUE;
  492. }
  493. else {
  494. ConnectStatus = UNABLE_TO_ACCEPT_CLIENT;
  495. }
  496. return;
  497. /*
  498. ** Handle UDP packet events
  499. */
  500. case WM_UDPASYNCEVENT:
  501. event = WSAGETSELECTEVENT(lParam);
  502. switch (event) {
  503. case FD_READ:
  504. rc = WSAGETSELECTERROR(lParam);
  505. if (rc != 0) {
  506. Clear_Socket_Error(UDPSocket);
  507. return;
  508. }
  509. addr_len = sizeof(addr);
  510. rc = recvfrom(UDPSocket, ReceiveBuffer, WS_RECEIVE_BUFFER_LEN, 0,
  511. (LPSOCKADDR)&addr, &addr_len);
  512. if (rc == SOCKET_ERROR) {
  513. Clear_Socket_Error(UDPSocket);
  514. return;
  515. }
  516. memcpy(&UDPIPAddress, &addr.sin_addr.s_addr, 4);
  517. Copy_To_In_Buffer(rc);
  518. return;
  519. case FD_WRITE:
  520. if (UseUDP){
  521. rc = WSAGETSELECTERROR(lParam);
  522. if (rc != 0) {
  523. Clear_Socket_Error(UDPSocket);
  524. return;
  525. }
  526. addr.sin_family = AF_INET;
  527. addr.sin_port = htons(PlanetWestwoodPortNumber);
  528. memcpy (&addr.sin_addr.s_addr, &UDPIPAddress, 4);
  529. /*
  530. ** Send as many bytes as there are in the buffer; if there's
  531. ** an error, just bail out. If we get a WOULDBLOCK error,
  532. ** WinSock will send us another message when the socket is
  533. ** available for another write.
  534. */
  535. while (TransmitBuffers[TXBufferTail].InUse){
  536. rc = sendto(UDPSocket,
  537. TransmitBuffers[TXBufferTail].Buffer,
  538. TransmitBuffers[TXBufferTail].DataLength,
  539. 0,
  540. (LPSOCKADDR)&addr,
  541. sizeof (addr));
  542. if (rc == SOCKET_ERROR){
  543. if (WSAGetLastError() != WSAEWOULDBLOCK) {
  544. Clear_Socket_Error(UDPSocket);
  545. }
  546. break;
  547. }
  548. TransmitBuffers[TXBufferTail++].InUse = false;
  549. TXBufferTail &= WS_NUM_TX_BUFFERS-1;
  550. }
  551. return;
  552. }
  553. }
  554. /*
  555. ** Handle the asynchronous event callbacks
  556. */
  557. case WM_ASYNCEVENT:
  558. event = WSAGETSELECTEVENT(lParam);
  559. switch (event) {
  560. /*
  561. ** FD_CLOSE: the client has gone away. Remove the client from our system.
  562. */
  563. case FD_CLOSE:
  564. rc = WSAGETSELECTERROR(lParam);
  565. if (rc != 0 && rc != WSAECONNRESET) {
  566. ConnectStatus = CONNECTION_LOST;
  567. return;
  568. }
  569. if (Async != 0) {
  570. WSACancelAsyncRequest(Async);
  571. }
  572. WSAAsyncSelect (ConnectSocket, MainWindow, WM_ASYNCEVENT, 0);
  573. Close_Socket (ConnectSocket);
  574. ConnectSocket = INVALID_SOCKET;
  575. //Connected = FALSE;
  576. ConnectStatus = CONNECTION_LOST;
  577. break;
  578. /*
  579. ** FD_CONNECT: A connection was made, or an error occurred.
  580. */
  581. case FD_CONNECT:
  582. rc = WSAGETSELECTERROR(lParam);
  583. if (rc != 0) {
  584. ConnectStatus = UNABLE_TO_CONNECT;
  585. return;
  586. }
  587. ConnectStatus = CONNECTED_OK;
  588. Connected = TRUE;
  589. return;
  590. }
  591. }
  592. }
  593. /***********************************************************************************************
  594. * TMC::Copy_To_In_Buffer -- copy data from our winsock buffer to our internal buffer *
  595. * *
  596. * *
  597. * *
  598. * INPUT: bytes to copy *
  599. * *
  600. * OUTPUT: Nothing *
  601. * *
  602. * WARNINGS: None *
  603. * *
  604. * HISTORY: *
  605. * 3/20/96 3:17PM ST : Created *
  606. *=============================================================================================*/
  607. void TcpipManagerClass::Copy_To_In_Buffer(int bytes)
  608. {
  609. if (!ReceiveBuffers[RXBufferHead].InUse){
  610. memcpy (ReceiveBuffers[RXBufferHead].Buffer, ReceiveBuffer, MIN(bytes, WS_INTERNET_BUFFER_LEN));
  611. ReceiveBuffers[RXBufferHead].InUse = true;
  612. ReceiveBuffers[RXBufferHead++].DataLength = MIN(bytes, WS_INTERNET_BUFFER_LEN);
  613. RXBufferHead &= WS_NUM_RX_BUFFERS-1;
  614. }
  615. }
  616. /***********************************************************************************************
  617. * TMC::Set_Host_Address -- Set the address of the host game we want to connect to *
  618. * *
  619. * *
  620. * *
  621. * INPUT: ptr to address string *
  622. * *
  623. * OUTPUT: Nothing *
  624. * *
  625. * WARNINGS: None *
  626. * *
  627. * HISTORY: *
  628. * 3/20/96 3:19PM ST : Created *
  629. *=============================================================================================*/
  630. void TcpipManagerClass::Set_Host_Address(char *address)
  631. {
  632. strcpy(HostAddress, address);
  633. }
  634. /***********************************************************************************************
  635. * TMC::Start_Client -- Start trying to connect to a game host *
  636. * *
  637. * *
  638. * *
  639. * INPUT: Nothing *
  640. * *
  641. * OUTPUT: Nothing *
  642. * *
  643. * WARNINGS: None *
  644. * *
  645. * HISTORY: *
  646. * 3/20/96 3:19PM ST : Created *
  647. *=============================================================================================*/
  648. void TcpipManagerClass::Start_Client(void)
  649. {
  650. struct sockaddr_in addr;
  651. bool delay = true;
  652. int i;
  653. addr.sin_family = AF_INET;
  654. addr.sin_port = 0;
  655. addr.sin_addr.s_addr = htonl(INADDR_ANY);
  656. /*
  657. ** Set up the incoming and outgoing data buffers head and tail pointers
  658. */
  659. TXBufferHead = 0;
  660. TXBufferTail = 0;
  661. RXBufferHead = 0;
  662. RXBufferTail = 0;
  663. for (i=0 ; i<WS_NUM_TX_BUFFERS ; i++){
  664. TransmitBuffers[i].InUse = false;
  665. }
  666. for (i=0 ; i<WS_NUM_RX_BUFFERS ; i++){
  667. ReceiveBuffers[i].InUse = false;
  668. }
  669. Connected = FALSE;
  670. /*
  671. ** Flag that we are the client side not the server
  672. */
  673. IsServer = FALSE;
  674. UseUDP = TRUE;
  675. /*
  676. ** Create our UDP socket
  677. */
  678. UDPSocket = socket(AF_INET, SOCK_DGRAM, 0);
  679. if (UDPSocket == INVALID_SOCKET) {
  680. Close_Socket(ConnectSocket);
  681. ConnectStatus = NOT_CONNECTING;
  682. return;
  683. }
  684. /*
  685. ** Bind our UDP socket to our UDP port number
  686. */
  687. addr.sin_family = AF_INET;
  688. addr.sin_port = htons(PlanetWestwoodPortNumber);
  689. addr.sin_addr.s_addr = htonl(INADDR_ANY);
  690. if (bind(UDPSocket, (LPSOCKADDR)&addr, sizeof(addr)) ==
  691. SOCKET_ERROR) {
  692. Close_Socket(UDPSocket);
  693. Close_Socket(ConnectSocket);
  694. ConnectStatus = NOT_CONNECTING;
  695. return;
  696. }
  697. /*
  698. ** Set options for the UDP socket
  699. */
  700. setsockopt (UDPSocket, SOL_SOCKET, SO_RCVBUF, (char*)&SocketReceiveBuffer, 4);
  701. setsockopt (UDPSocket, SOL_SOCKET, SO_SNDBUF, (char*)&SocketSendBuffer, 4);
  702. /*
  703. ** Enable asynchronous events on the UDP socket
  704. */
  705. if (WSAAsyncSelect (UDPSocket, MainWindow, WM_UDPASYNCEVENT,
  706. FD_READ | FD_WRITE) == SOCKET_ERROR){
  707. WSACancelAsyncRequest(Async);
  708. Close_Socket (UDPSocket);
  709. Close_Socket (ConnectSocket);
  710. ConnectStatus = NOT_CONNECTING;
  711. return;
  712. }
  713. /*
  714. ** If the name is not a dot-decimal ip address then do a nameserver lookup
  715. */
  716. Server.Addr.s_addr = inet_addr(PlanetWestwoodIPAddress);
  717. memcpy(&UDPIPAddress, &Server.Addr.s_addr, 4);
  718. if (Server.Addr.s_addr == INADDR_NONE){
  719. strcpy (Server.Name, PlanetWestwoodIPAddress);
  720. Async = WSAAsyncGetHostByName(MainWindow, WM_HOSTBYNAME,
  721. Server.Name, HostBuff, MAXGETHOSTSTRUCT);
  722. ConnectStatus = RESOLVING_HOST_ADDRESS;
  723. }else{
  724. ConnectStatus = CONNECTED_OK;
  725. Connected = TRUE;
  726. }
  727. }
  728. /***********************************************************************************************
  729. * TMC::Close_Socket -- Close an opened Winsock socket. *
  730. * *
  731. * *
  732. * *
  733. * INPUT: Socket to close *
  734. * *
  735. * OUTPUT: Nothing *
  736. * *
  737. * WARNINGS: None *
  738. * *
  739. * HISTORY: *
  740. * 3/20/96 3:24PM ST : Created *
  741. *=============================================================================================*/
  742. void TcpipManagerClass::Close_Socket(SOCKET s)
  743. {
  744. LINGER ling;
  745. ling.l_onoff = 0; // linger off
  746. ling.l_linger = 0; // timeout in seconds (ie close now)
  747. setsockopt(s, SOL_SOCKET, SO_LINGER, (LPSTR)&ling, sizeof(ling));
  748. closesocket (s);
  749. }
  750. void TcpipManagerClass::Set_Protocol_UDP(BOOL state)
  751. {
  752. UseUDP = state;
  753. }
  754. void TcpipManagerClass::Clear_Socket_Error(SOCKET socket)
  755. {
  756. unsigned long error_code;
  757. int length = 4;
  758. getsockopt (socket, SOL_SOCKET, SO_ERROR, (char*)&error_code, &length);
  759. error_code = 0;
  760. setsockopt (socket, SOL_SOCKET, SO_ERROR, (char*)&error_code, length);
  761. }
  762. #endif //WIN32