CnC_Remastered_Collection

Command and Conquer: Red Alert
Log | Files | Refs | README | LICENSE

TCPIP.CPP (35689B)


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