CnC_Remastered_Collection

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

TCPIP.CPP (38057B)


      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                        *
     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 
     57 #include "function.h"
     58 #include "tcpip.h"
     59 
     60 #ifdef FORCE_WINSOCK
     61 
     62 
     63 /*
     64 ** Nasty globals
     65 */
     66 bool					Server;			//Is this player acting as client or server
     67 TcpipManagerClass	Winsock;			//The object for interfacing with Winsock
     68 
     69 
     70 
     71 /***********************************************************************************************
     72  * TMC::TcpipManagerClass -- constructor for the TcpipManagerClass                             *
     73  *                                                                                             *
     74  *                                                                                             *
     75  *                                                                                             *
     76  * INPUT:    Nothing                                                                           *
     77  *                                                                                             *
     78  * OUTPUT:   Nothing                                                                           *
     79  *                                                                                             *
     80  * WARNINGS: None                                                                              *
     81  *                                                                                             *
     82  * HISTORY:                                                                                    *
     83  *    3/20/96 2:51PM ST : Created                                                              *
     84  *=============================================================================================*/
     85 TcpipManagerClass::TcpipManagerClass(void)
     86 {
     87 	WinsockInitialised = FALSE;
     88 	Connected = FALSE;
     89 	UseUDP = TRUE;
     90 	SocketReceiveBuffer = 4096;
     91 	SocketSendBuffer = 4096;
     92 
     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 	//InBufferHead = 0;
    261 	//InBufferTail = 0;
    262 	//OutBufferHead= 0;
    263 	//OutBufferTail= 0;
    264 
    265 	TXBufferHead = 0;
    266 	TXBufferTail = 0;
    267 	RXBufferHead = 0;
    268 	RXBufferTail = 0;
    269 
    270 	for (i=0 ; i<WS_NUM_TX_BUFFERS ; i++){
    271 		TransmitBuffers[i].InUse = false;
    272 	}
    273 
    274 	for (i=0 ; i<WS_NUM_RX_BUFFERS ; i++){
    275 		ReceiveBuffers[i].InUse = false;
    276 	}
    277 
    278 	/*
    279 	** Flag that we are the server side not the client
    280 	*/
    281 	IsServer = TRUE;
    282 	UseUDP = TRUE;
    283 #if (0)
    284 	/*
    285 	** Create our socket and bind it to our port number
    286 	*/
    287 	ListenSocket = socket(AF_INET, SOCK_STREAM, 0);
    288 	if (ListenSocket == INVALID_SOCKET) {
    289 		ConnectStatus = NOT_CONNECTING;
    290 		return ;
    291 	}
    292 
    293 	addr.sin_family = AF_INET;
    294 	addr.sin_port = htons(PORTNUM);
    295 	addr.sin_addr.s_addr = htonl(INADDR_ANY);
    296 
    297 	if (bind(ListenSocket, (LPSOCKADDR)&addr, sizeof(addr)) ==
    298 		SOCKET_ERROR) {
    299 		Close_Socket(ListenSocket);
    300 		ConnectStatus = NOT_CONNECTING;
    301 		return;
    302 	}
    303 
    304 	/*
    305 	** Start listening for connections on this socket
    306 	*/
    307 	if (listen(ListenSocket, 1) == SOCKET_ERROR) {
    308 		Close_Socket(ListenSocket);
    309 		ConnectStatus = NOT_CONNECTING;
    310 		return;
    311 	}
    312 
    313 	/*
    314 	** Select the asynchronous events we want to process
    315 	*/
    316 	if (WSAAsyncSelect (ListenSocket, MainWindow, WM_ACCEPT, FD_ACCEPT) == SOCKET_ERROR) {
    317 		Close_Socket(ListenSocket);
    318 		ConnectStatus = NOT_CONNECTING;
    319 		return;
    320 	}
    321 #endif
    322 	ConnectStatus = CONNECTING;
    323 
    324 }
    325 
    326 
    327 
    328 
    329 /***********************************************************************************************
    330  * TMC::Read -- read any pending input from the stream socket                                  *
    331  *                                                                                             *
    332  *                                                                                             *
    333  *                                                                                             *
    334  * INPUT:    ptr to buffer to receive input                                                    *
    335  *           length of buffer                                                                  *
    336  *                                                                                             *
    337  * OUTPUT:   number of bytes transfered to buffer                                              *
    338  *                                                                                             *
    339  * WARNINGS: None                                                                              *
    340  *                                                                                             *
    341  * HISTORY:                                                                                    *
    342  *    3/20/96 2:58PM ST : Created                                                              *
    343  *=============================================================================================*/
    344 
    345 int TcpipManagerClass::Read(void *buffer, int buffer_len)
    346 {
    347 	int 	bytes_copied = 0;
    348 	char 	*dest_buf = (char*) buffer;
    349 
    350 	/*
    351 	** Make sure the message loop gets called because all the Winsock notifications
    352 	** are done via messages.
    353 	*/
    354 	Keyboard::Check();
    355 
    356 	/*
    357 	** Copy any outstanding incoming data to the buffer provided
    358 	*/
    359 	if (ReceiveBuffers[RXBufferTail].InUse){
    360 		memcpy (buffer, ReceiveBuffers[RXBufferTail].Buffer,
    361 					MIN(ReceiveBuffers[RXBufferTail].DataLength, buffer_len));
    362 		ReceiveBuffers[RXBufferTail].InUse = false;
    363 
    364 		bytes_copied = MIN(ReceiveBuffers[RXBufferTail++].DataLength, buffer_len);
    365 
    366 		RXBufferTail &= WS_NUM_RX_BUFFERS-1;
    367 	}
    368 
    369 	return (bytes_copied);
    370 }
    371 
    372 
    373 
    374 /***********************************************************************************************
    375  * TMC::Write -- Send data via the Winsock UDP socket                                          *
    376  *                                                                                             *
    377  *                                                                                             *
    378  *                                                                                             *
    379  * INPUT:    ptr to buffer containing data to send                                             *
    380  *           length of data to send                                                            *
    381  *                                                                                             *
    382  * OUTPUT:   Nothing                                                                           *
    383  *                                                                                             *
    384  * WARNINGS: None                                                                              *
    385  *                                                                                             *
    386  * HISTORY:                                                                                    *
    387  *    3/20/96 3:00PM ST : Created                                                              *
    388  *=============================================================================================*/
    389 
    390 void TcpipManagerClass::Write(void *buffer, int buffer_len)
    391 {
    392 	char 	*source_buf = (char*) buffer;
    393 
    394 	/*
    395 	** Copy the data to one of the classes internal buffers
    396 	*/
    397 	if (!TransmitBuffers[TXBufferHead].InUse){
    398 		memcpy (TransmitBuffers[TXBufferHead].Buffer,
    399 					buffer,
    400 					MIN (buffer_len, WS_INTERNET_BUFFER_LEN));
    401 		TransmitBuffers[TXBufferHead].InUse = true;
    402 		TransmitBuffers[TXBufferHead++].DataLength = MIN(buffer_len, WS_INTERNET_BUFFER_LEN);
    403 		TXBufferHead &= WS_NUM_TX_BUFFERS-1;
    404 	}
    405 
    406 	/*
    407 	** Send a message to ourselves to start off the event
    408 	*/
    409 	if (UseUDP){
    410 		SendMessage(MainWindow, WM_UDPASYNCEVENT, 0, (LONG)FD_WRITE);
    411 	}else{
    412 		SendMessage(MainWindow, WM_ASYNCEVENT, 0, (LONG)FD_WRITE);
    413 	}
    414 	Keyboard::Check();
    415 }
    416 
    417 
    418 
    419 
    420 
    421 
    422 /***********************************************************************************************
    423  * TMC::Add_Client -- a client has requested to connect. Make the connection                   *
    424  *                                                                                             *
    425  *                                                                                             *
    426  *                                                                                             *
    427  * INPUT:    Nothing                                                                           *
    428  *                                                                                             *
    429  * OUTPUT:   TRUE if client was successfully connected                                         *
    430  *                                                                                             *
    431  * WARNINGS: None                                                                              *
    432  *                                                                                             *
    433  * HISTORY:                                                                                    *
    434  *    3/20/96 3:02PM ST : Created                                                              *
    435  *=============================================================================================*/
    436 
    437 BOOL TcpipManagerClass::Add_Client(void)
    438 {
    439 	struct 	sockaddr_in addr;
    440 	int 		addrsize;
    441 	bool 		delay = TRUE;
    442 
    443 	/*
    444 	** Accept the connection. If there is an error then dont do anything else
    445 	*/
    446 	addrsize = sizeof(addr);
    447 	ConnectSocket = accept (ListenSocket, (LPSOCKADDR)&addr, &addrsize);
    448 	if (ConnectSocket == INVALID_SOCKET) {
    449 		//Show_Error("accept", WSAGetLastError());
    450 		return(FALSE);
    451 	}
    452 
    453 	/*
    454 	** Set options for this socket
    455 	*/
    456 	setsockopt (ConnectSocket, IPPROTO_TCP, TCP_NODELAY, (char*)&delay, 4);
    457 	setsockopt (ConnectSocket, SOL_SOCKET, SO_RCVBUF, (char*)&SocketReceiveBuffer, 4);
    458 	setsockopt (ConnectSocket, SOL_SOCKET, SO_SNDBUF, (char*)&SocketSendBuffer, 4);
    459 
    460 	/*
    461 	** Save the clients address
    462 	*/
    463 	memcpy(&ClientIPAddress, &addr.sin_addr.s_addr,4);
    464 	memcpy(&UDPIPAddress, &addr.sin_addr.s_addr,4);
    465 
    466 	/*
    467 	** Initiate an asynchronous host lookup by address. Our window will receive notification
    468 	** when this is complete or when it times out.
    469 	*/
    470 	Async = WSAAsyncGetHostByAddr (MainWindow, WM_HOSTBYADDRESS,
    471 		(char const *)&addr.sin_addr, 4, PF_INET, &HostBuff[0],
    472 		MAXGETHOSTSTRUCT);
    473 
    474 	/*
    475 	** Enable asynchronous events on this socket
    476 	*/
    477 	if (WSAAsyncSelect (ConnectSocket, MainWindow, WM_ASYNCEVENT,
    478 		FD_READ | FD_WRITE | FD_CLOSE) == SOCKET_ERROR){
    479 		WSACancelAsyncRequest(Async);
    480 		Close_Socket (ConnectSocket);
    481 		return(FALSE);
    482 	}
    483 
    484 	/*
    485 	** Create our UDP socket
    486 	*/
    487 	UDPSocket = socket(AF_INET, SOCK_DGRAM, 0);
    488 	if (UDPSocket == INVALID_SOCKET) {
    489 		return (FALSE);
    490 	}
    491 
    492 	/*
    493 	** Bind our UDP socket to our UDP port number
    494 	*/
    495 	addr.sin_family = AF_INET;
    496 	addr.sin_port = htons(PlanetWestwoodPortNumber);
    497 	addr.sin_addr.s_addr = htonl(INADDR_ANY);
    498 
    499 	if (bind(UDPSocket, (LPSOCKADDR)&addr, sizeof(addr)) ==
    500 		SOCKET_ERROR) {
    501 		Close_Socket(UDPSocket);
    502 		ConnectStatus = NOT_CONNECTING;
    503 		return(FALSE);
    504 	}
    505 
    506 	/*
    507 	** Set options for the UDP socket
    508 	*/
    509 	setsockopt (UDPSocket, SOL_SOCKET, SO_RCVBUF, (char*)&SocketReceiveBuffer, 4);
    510 	setsockopt (UDPSocket, SOL_SOCKET, SO_SNDBUF, (char*)&SocketSendBuffer, 4);
    511 
    512 	/*
    513 	** Enable asynchronous events on this socket
    514 	*/
    515 	if (WSAAsyncSelect (UDPSocket, MainWindow, WM_UDPASYNCEVENT,
    516 		FD_READ | FD_WRITE) == SOCKET_ERROR){
    517 		WSACancelAsyncRequest(Async);
    518 		Close_Socket (UDPSocket);
    519 		Close_Socket (ConnectSocket);
    520 		return(FALSE);
    521 	}
    522 
    523 	return (TRUE);
    524 
    525 }
    526 
    527 
    528 
    529 
    530 /***********************************************************************************************
    531  * TMC::Message_Handler -- Message handler function for Winsock related messages               *
    532  *                                                                                             *
    533  *                                                                                             *
    534  *                                                                                             *
    535  * INPUT:    Windows message handler stuff                                                     *
    536  *                                                                                             *
    537  * OUTPUT:   Nothing                                                                           *
    538  *                                                                                             *
    539  * WARNINGS: None                                                                              *
    540  *                                                                                             *
    541  * HISTORY:                                                                                    *
    542  *    3/20/96 3:05PM ST : Created                                                              *
    543  *=============================================================================================*/
    544 
    545 void TcpipManagerClass::Message_Handler(HWND, UINT message, UINT , LONG lParam)
    546 {
    547 	struct 	hostent *hentry;
    548 	struct 	sockaddr_in addr;
    549 	int	 	event;
    550 	int	 	rc;
    551 	int		addr_len;
    552 
    553 	switch (message){
    554 
    555 		/*
    556 		** Handle the GetHostByAddress result
    557 		*/
    558 		case WM_HOSTBYADDRESS:
    559 
    560 			if (IsServer){
    561 				/*
    562 				** We are the server
    563 				*/
    564 				ConnectStatus = CONNECTING;
    565 				if (WSAGETASYNCERROR(lParam)==0) {
    566 					hentry = (struct hostent *)&HostBuff[0];
    567 					strcpy (&ClientName[0], hentry->h_name);
    568 				}
    569 				Async = 0;
    570 				return;
    571 
    572 			}else{
    573 				/*
    574 				** We are the client
    575 				*/
    576 				ConnectStatus = CONTACTING_SERVER;
    577 				if (WSAGETASYNCERROR(lParam)==0) {
    578 					hentry = (struct hostent *)&HostBuff[0];
    579 					strcpy (Server.Name, hentry->h_name);
    580 				}
    581 				else {
    582 					Server.Name[0] = 0;
    583 				}
    584 				Async = 0;
    585 				return;
    586 			}
    587 
    588 
    589 		/*
    590 		** Retrieve host by name: Start connecting now that we have the
    591 		** address.
    592 		*/
    593 		case WM_HOSTBYNAME:
    594 			if (WSAGETASYNCERROR(lParam)==0) {
    595 				hentry = (struct hostent *)&HostBuff[0];
    596 				memcpy (&(Server.Addr.s_addr), hentry->h_addr, 4);
    597 				memcpy(&UDPIPAddress, hentry->h_addr, 4);
    598 				strcpy (Server.DotAddr, inet_ntoa(Server.Addr));
    599 				ConnectStatus = CONNECTED_OK;
    600 				Connected = TRUE;
    601 			}
    602 			else {
    603 				Server.Name[0] = 0;
    604 				strcpy (Server.DotAddr, "????");
    605 				ConnectStatus = SERVER_ADDRESS_LOOKUP_FAILED;
    606 			}
    607 			Async = 0;
    608 			return;
    609 
    610 
    611 		/*
    612 		** Connection is ready - accept the client
    613 		*/
    614 		case WM_ACCEPT:
    615 			rc = WSAGETSELECTERROR(lParam);
    616 			if (rc != 0) {
    617 				ConnectStatus = UNABLE_TO_ACCEPT_CLIENT;
    618 				return;
    619 			}
    620 			if (Add_Client()) {
    621 				ConnectStatus = CONNECTED_OK;
    622 				Connected = TRUE;
    623 			}
    624 			else {
    625 				ConnectStatus = UNABLE_TO_ACCEPT_CLIENT;
    626 			}
    627 			return;
    628 
    629 
    630 
    631 		/*
    632 		** Handle UDP packet events
    633 		*/
    634 		case WM_UDPASYNCEVENT:
    635 			event = WSAGETSELECTEVENT(lParam);
    636 			switch (event) {
    637 
    638 				case FD_READ:
    639 					rc = WSAGETSELECTERROR(lParam);
    640 					if (rc != 0) {
    641 						Clear_Socket_Error(UDPSocket);
    642 						return;
    643 					}
    644 					addr_len = sizeof(addr);
    645 					rc = recvfrom(UDPSocket, ReceiveBuffer, WS_RECEIVE_BUFFER_LEN, 0,
    646 					(LPSOCKADDR)&addr, &addr_len);
    647 					if (rc == SOCKET_ERROR) {
    648 						Clear_Socket_Error(UDPSocket);
    649 						return;
    650 					}
    651 					memcpy(&UDPIPAddress, &addr.sin_addr.s_addr, 4);
    652 					Copy_To_In_Buffer(rc);
    653 					return;
    654 
    655 
    656 				case FD_WRITE:
    657 					if (UseUDP){
    658 						rc = WSAGETSELECTERROR(lParam);
    659 						if (rc != 0) {
    660 							Clear_Socket_Error(UDPSocket);
    661 							return;
    662 						}
    663 
    664 						addr.sin_family = AF_INET;
    665 						addr.sin_port = htons(PlanetWestwoodPortNumber);
    666 						memcpy (&addr.sin_addr.s_addr, &UDPIPAddress, 4);
    667 
    668 						/*
    669 						**  Send as many bytes as there are in the buffer; if there's
    670 						**  an error, just bail out.  If we get a WOULDBLOCK error,
    671 						**  WinSock will send us another message when the socket is
    672 						**  available for another write.
    673 						*/
    674 						while (TransmitBuffers[TXBufferTail].InUse){
    675 							rc = sendto(UDPSocket,
    676 											TransmitBuffers[TXBufferTail].Buffer,
    677 											TransmitBuffers[TXBufferTail].DataLength,
    678 											0,
    679 											(LPSOCKADDR)&addr,
    680 											sizeof (addr));
    681 
    682 							if (rc == SOCKET_ERROR){
    683 								if (WSAGetLastError() != WSAEWOULDBLOCK) {
    684 									Clear_Socket_Error(UDPSocket);
    685 								}
    686 								break;
    687 							}
    688 							TransmitBuffers[TXBufferTail++].InUse = false;
    689 							TXBufferTail &= WS_NUM_TX_BUFFERS-1;
    690 						}
    691 						return;
    692 					}
    693 			}
    694 
    695 
    696 
    697 		/*
    698 		** Handle the asynchronous event callbacks
    699 		*/
    700 		case WM_ASYNCEVENT:
    701 			event = WSAGETSELECTEVENT(lParam);
    702 			switch (event) {
    703 				/*
    704 				** FD_CLOSE: the client has gone away. Remove the client from our system.
    705 				*/
    706 				case FD_CLOSE:
    707 					rc = WSAGETSELECTERROR(lParam);
    708 					if (rc != 0 && rc != WSAECONNRESET) {
    709 						ConnectStatus = CONNECTION_LOST;
    710 						return;
    711 					}
    712 					if (Async != 0) {
    713 						WSACancelAsyncRequest(Async);
    714 					}
    715 					WSAAsyncSelect (ConnectSocket, MainWindow, WM_ASYNCEVENT, 0);
    716 					Close_Socket (ConnectSocket);
    717 					ConnectSocket = INVALID_SOCKET;
    718 					//Connected = FALSE;
    719 					ConnectStatus = CONNECTION_LOST;
    720 					break;
    721 #if (0)
    722 				/*
    723 				** FD_READ: Data is available on our socket. This message is sent every time
    724 				**  data becomes available so we only have to do one read
    725 				*/
    726 				case FD_READ:
    727 					if (!UseUDP){
    728 						rc = WSAGETSELECTERROR(lParam);
    729 						if (rc != 0) {
    730 							return;
    731 						}
    732 						rc = recv(ConnectSocket, ReceiveBuffer, WS_RECEIVE_BUFFER_LEN, 0);
    733 						if (rc == SOCKET_ERROR) {
    734 							Clear_Socket_Error(ConnectSocket);
    735 							return;
    736 						}
    737 						Copy_To_In_Buffer(rc);
    738 						return;
    739 					}
    740 
    741 				/*
    742 				** FD_WRITE: The socket is available for writing. We may actually have sent this
    743 				** message from elewhere in the class.
    744 				*/
    745 				case FD_WRITE:
    746 					rc = WSAGETSELECTERROR(lParam);
    747 					if (rc != 0) {
    748 						return;
    749 					}
    750 					/*
    751 					**  Send as many bytes as there are in the buffer; if there's
    752 					**  an error, just bail out.  If we get a WOULDBLOCK error,
    753 					**  WinSock will send us another message when the socket is
    754 					**  available for another write.
    755 					*/
    756 					while (OutBufferHead > OutBufferTail){
    757 						rc = send(ConnectSocket, OutBuffer + OutBufferTail,
    758 									OutBufferHead - OutBufferTail, 0);
    759 						if (rc == SOCKET_ERROR){
    760 							if (WSAGetLastError() != WSAEWOULDBLOCK) {
    761 								Clear_Socket_Error(ConnectSocket);
    762 							}
    763 							break;
    764 						}
    765 						OutBufferTail+=rc;
    766 					}
    767 					if (OutBufferHead == OutBufferTail){
    768 						OutBufferHead = OutBufferTail = 0;
    769 					}
    770 					return;
    771 #endif	//(0)
    772 				/*
    773 				** FD_CONNECT: A connection was made, or an error occurred.
    774 				*/
    775 				case FD_CONNECT:
    776 					rc = WSAGETSELECTERROR(lParam);
    777 					if (rc != 0) {
    778 						ConnectStatus = UNABLE_TO_CONNECT;
    779 						return;
    780 					}
    781 
    782 					ConnectStatus = CONNECTED_OK;
    783 					Connected = TRUE;
    784 					return;
    785 
    786 			}
    787 	}
    788 }
    789 
    790 
    791 
    792 /***********************************************************************************************
    793  * TMC::Copy_To_In_Buffer -- copy data from our winsock buffer to our internal buffer          *
    794  *                                                                                             *
    795  *                                                                                             *
    796  *                                                                                             *
    797  * INPUT:    bytes to copy                                                                     *
    798  *                                                                                             *
    799  * OUTPUT:   Nothing                                                                           *
    800  *                                                                                             *
    801  * WARNINGS: None                                                                              *
    802  *                                                                                             *
    803  * HISTORY:                                                                                    *
    804  *    3/20/96 3:17PM ST : Created                                                              *
    805  *=============================================================================================*/
    806 void TcpipManagerClass::Copy_To_In_Buffer(int bytes)
    807 {
    808 	if (!ReceiveBuffers[RXBufferHead].InUse){
    809 		memcpy (ReceiveBuffers[RXBufferHead].Buffer, ReceiveBuffer, MIN(bytes, WS_INTERNET_BUFFER_LEN));
    810 		ReceiveBuffers[RXBufferHead].InUse = true;
    811 		ReceiveBuffers[RXBufferHead++].DataLength = MIN(bytes, WS_INTERNET_BUFFER_LEN);
    812 		RXBufferHead &= WS_NUM_RX_BUFFERS-1;
    813 	}
    814 }
    815 
    816 
    817 
    818 /***********************************************************************************************
    819  * TMC::Set_Host_Address -- Set the address of the host game we want to connect to             *
    820  *                                                                                             *
    821  *                                                                                             *
    822  *                                                                                             *
    823  * INPUT:    ptr to address string                                                             *
    824  *                                                                                             *
    825  * OUTPUT:   Nothing                                                                           *
    826  *                                                                                             *
    827  * WARNINGS: None                                                                              *
    828  *                                                                                             *
    829  * HISTORY:                                                                                    *
    830  *    3/20/96 3:19PM ST : Created                                                              *
    831  *=============================================================================================*/
    832 void TcpipManagerClass::Set_Host_Address(char *address)
    833 {
    834 	strcpy(HostAddress, address);
    835 }
    836 
    837 
    838 
    839 /***********************************************************************************************
    840  * TMC::Start_Client -- Start trying to connect to a game host                                 *
    841  *                                                                                             *
    842  *                                                                                             *
    843  *                                                                                             *
    844  * INPUT:    Nothing                                                                           *
    845  *                                                                                             *
    846  * OUTPUT:   Nothing                                                                           *
    847  *                                                                                             *
    848  * WARNINGS: None                                                                              *
    849  *                                                                                             *
    850  * HISTORY:                                                                                    *
    851  *    3/20/96 3:19PM ST : Created                                                              *
    852  *=============================================================================================*/
    853 
    854 void TcpipManagerClass::Start_Client(void)
    855 {
    856 	struct 	sockaddr_in addr;
    857 	bool		delay = true;
    858 	int 		i;
    859 
    860 	addr.sin_family = AF_INET;
    861 	addr.sin_port = 0;
    862 	addr.sin_addr.s_addr = htonl(INADDR_ANY);
    863 
    864 	/*
    865 	** Set up the incoming and outgoing data buffers head and tail pointers
    866 	*/
    867 //	InBufferHead = 0;
    868 //	InBufferTail = 0;
    869 //	OutBufferHead= 0;
    870 //	OutBufferTail= 0;
    871 
    872 	TXBufferHead = 0;
    873 	TXBufferTail = 0;
    874 	RXBufferHead = 0;
    875 	RXBufferTail = 0;
    876 
    877 	for (i=0 ; i<WS_NUM_TX_BUFFERS ; i++){
    878 		TransmitBuffers[i].InUse = false;
    879 	}
    880 
    881 	for (i=0 ; i<WS_NUM_RX_BUFFERS ; i++){
    882 		ReceiveBuffers[i].InUse = false;
    883 	}
    884 
    885 	Connected = FALSE;
    886 	/*
    887 	** Flag that we are the client side not the server
    888 	*/
    889 	IsServer = FALSE;
    890 	UseUDP = TRUE;
    891 
    892 	/*
    893 	** Create our UDP socket
    894 	*/
    895 	UDPSocket = socket(AF_INET, SOCK_DGRAM, 0);
    896 	if (UDPSocket == INVALID_SOCKET) {
    897 		Close_Socket(ConnectSocket);
    898 		ConnectStatus = NOT_CONNECTING;
    899 		return;
    900 	}
    901 	/*
    902 	** Bind our UDP socket to our UDP port number
    903 	*/
    904 	addr.sin_family = AF_INET;
    905 	addr.sin_port = htons(PlanetWestwoodPortNumber);
    906 	addr.sin_addr.s_addr = htonl(INADDR_ANY);
    907 
    908 	if (bind(UDPSocket, (LPSOCKADDR)&addr, sizeof(addr)) ==
    909 		SOCKET_ERROR) {
    910 		Close_Socket(UDPSocket);
    911 		Close_Socket(ConnectSocket);
    912 		ConnectStatus = NOT_CONNECTING;
    913 		return;
    914 	}
    915 
    916 	/*
    917 	** Set options for the UDP socket
    918 	*/
    919 	setsockopt (UDPSocket, SOL_SOCKET, SO_RCVBUF, (char*)&SocketReceiveBuffer, 4);
    920 	setsockopt (UDPSocket, SOL_SOCKET, SO_SNDBUF, (char*)&SocketSendBuffer, 4);
    921 
    922 	/*
    923 	** Enable asynchronous events on the UDP socket
    924 	*/
    925 	if (WSAAsyncSelect (UDPSocket, MainWindow, WM_UDPASYNCEVENT,
    926 		FD_READ | FD_WRITE) == SOCKET_ERROR){
    927 		WSACancelAsyncRequest(Async);
    928 		Close_Socket (UDPSocket);
    929 		Close_Socket (ConnectSocket);
    930 		ConnectStatus = NOT_CONNECTING;
    931 		return;
    932 	}
    933 
    934 	/*
    935 	** If the name is not a dot-decimal ip address then do a nameserver lookup
    936 	*/
    937 
    938 
    939 	Server.Addr.s_addr = inet_addr(PlanetWestwoodIPAddress);
    940 	memcpy(&UDPIPAddress, &Server.Addr.s_addr, 4);
    941 	if (Server.Addr.s_addr == INADDR_NONE){
    942 		strcpy (Server.Name, PlanetWestwoodIPAddress);
    943 		Async = WSAAsyncGetHostByName(MainWindow, WM_HOSTBYNAME,
    944 			Server.Name, HostBuff, MAXGETHOSTSTRUCT);
    945 		ConnectStatus = RESOLVING_HOST_ADDRESS;
    946 	}else{
    947 		ConnectStatus = CONNECTED_OK;
    948 		Connected = TRUE;
    949 	}
    950 
    951 }
    952 
    953 
    954 
    955 /***********************************************************************************************
    956  * TMC::Close_Socket -- Close an opened Winsock socket.                                        *
    957  *                                                                                             *
    958  *                                                                                             *
    959  *                                                                                             *
    960  * INPUT:    Socket to close                                                                   *
    961  *                                                                                             *
    962  * OUTPUT:   Nothing                                                                           *
    963  *                                                                                             *
    964  * WARNINGS: None                                                                              *
    965  *                                                                                             *
    966  * HISTORY:                                                                                    *
    967  *    3/20/96 3:24PM ST : Created                                                              *
    968  *=============================================================================================*/
    969 
    970 void TcpipManagerClass::Close_Socket(SOCKET s)
    971 {
    972 	LINGER ling;
    973 
    974 	ling.l_onoff = 0;		// linger off
    975 	ling.l_linger = 0;	// timeout in seconds (ie close now)
    976 	setsockopt(s, SOL_SOCKET, SO_LINGER, (LPSTR)&ling, sizeof(ling));
    977 	closesocket (s);
    978 }
    979 
    980 
    981 void TcpipManagerClass::Set_Protocol_UDP(BOOL state)
    982 {
    983 	UseUDP = state;
    984 }
    985 
    986 
    987 
    988 void TcpipManagerClass::Clear_Socket_Error(SOCKET socket)
    989 {
    990 	unsigned long error_code;
    991 	int length = 4;
    992 
    993 	getsockopt (socket, SOL_SOCKET, SO_ERROR, (char*)&error_code, &length);
    994 	error_code = 0;
    995 	setsockopt (socket, SOL_SOCKET, SO_ERROR, (char*)&error_code, length);
    996 }
    997 
    998 
    999 
   1000 #endif	//FORCE_WINSOCK
   1001 
   1002