TCPIP.CPP 37 KB

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