TCPIP.CPP 37 KB

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