CnC_Remastered_Collection

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

WSPIPX.CPP (17374B)


      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  ***              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               ***
     18  ***********************************************************************************************
     19  *                                                                                             *
     20  *                 Project Name : Command & Conquer                                            *
     21  *                                                                                             *
     22  *                     $Archive:: /Sun/WSPIPX.cpp                                             $*
     23  *                                                                                             *
     24  *                      $Author:: Joe_b                                                       $*
     25  *                                                                                             *
     26  *                     $Modtime:: 8/20/97 10:54a                                              $*
     27  *                                                                                             *
     28  *                    $Revision:: 6                                                           $*
     29  *                                                                                             *
     30  *---------------------------------------------------------------------------------------------*
     31  * Functions:                                                                                  *
     32  *                                                                                             *
     33  * IPXInterfaceClass::IPXInterfaceClass -- Class constructor                                   *
     34  * IPXInterfaceClass::Get_Network_Card_Address -- Get the ID of the installed net card         *
     35  * IPXInterfaceClass::Open_Socket -- Opens an IPX socket for reading & writing                 *
     36  * IPXInterfaceClass::Message_Handler -- Handler for windows messages relating to IPX          *
     37  * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
     38 
     39 #include	"function.h"
     40 #include	"wspipx.h"
     41 #include	"ipxaddr.h"
     42 
     43 #include	<assert.h>
     44 #include	<stdio.h>
     45 
     46 
     47 /***********************************************************************************************
     48  * IPXInterfaceClass::IPXInterfaceClass -- Class constructor                                   *
     49  *                                                                                             *
     50  *                                                                                             *
     51  *                                                                                             *
     52  * INPUT:    Nothing                                                                           *
     53  *                                                                                             *
     54  * OUTPUT:   Nothing                                                                           *
     55  *                                                                                             *
     56  * WARNINGS: None                                                                              *
     57  *                                                                                             *
     58  * HISTORY:                                                                                    *
     59  *    8/4/97 11:41AM ST : Created                                                              *
     60  *=============================================================================================*/
     61 IPXInterfaceClass::IPXInterfaceClass (void) : WinsockInterfaceClass()
     62 {
     63 	/*
     64 	** Set the net and node addressed to their default values.
     65 	*/
     66 	memset ( BroadcastNet, 0xff, sizeof (BroadcastNet) );
     67 	memset ( BroadcastNode, 0xff, sizeof (BroadcastNode) );
     68 	memset ( MyNode, 0xff, sizeof (MyNode) );
     69 }
     70 
     71 
     72 /***********************************************************************************************
     73  * IPXInterfaceClass::Get_Network_Card_Address -- Get the ID of the installed net card         *
     74  *                                                                                             *
     75  *                                                                                             *
     76  *                                                                                             *
     77  * INPUT:    card number to retrieve ID for                                                    *
     78  *           ptr to addr to return ID in                                                       *
     79  *                                                                                             *
     80  * OUTPUT:   Nothing                                                                           *
     81  *                                                                                             *
     82  * WARNINGS: None                                                                              *
     83  *                                                                                             *
     84  * HISTORY:                                                                                    *
     85  *    8/1/97 3:04PM ST : Created                                                               *
     86  *=============================================================================================*/
     87 bool IPXInterfaceClass::Get_Network_Card_Address (int card_number, SOCKADDR_IPX *addr)
     88 {
     89 	int            	cbOpt;
     90 	int					cbAddr = sizeof( SOCKADDR_IPX );
     91     SOCKET         	s;
     92     SOCKADDR_IPX   	Addr;
     93     IPX_ADDRESS_DATA  IpxData;
     94 
     95     /*
     96 	** Create a temporary IPX socket.
     97 	*/
     98     s = socket( AF_IPX, SOCK_DGRAM, NSPROTO_IPX );
     99 	if ( s == SOCKET_ERROR ) {
    100 		assert ( s != SOCKET_ERROR );
    101 		return (false);
    102 	}
    103 
    104 	/*
    105 	** Socket must be bound prior to calling IPX_MAX_ADAPTER_NUM
    106 	*/
    107     memset( &Addr, 0, sizeof( Addr ));
    108     Addr.sa_family = AF_IPX;
    109     int err = bind( s, (SOCKADDR*) &Addr, cbAddr);
    110 	if ( err == SOCKET_ERROR ) {
    111 		assert ( err != SOCKET_ERROR );
    112 		closesocket (s);
    113 		return (false);
    114 	}
    115 
    116     memset( &IpxData, 0, sizeof(IpxData));
    117 
    118 	/*
    119 	** Specify which adapter to check.
    120 	*/
    121     IpxData.adapternum = card_number;
    122     cbOpt = sizeof( IpxData );
    123 
    124 	/*
    125 	** Get information for the current adapter.
    126 	*/
    127     err = getsockopt( s, NSPROTO_IPX, IPX_ADDRESS, (char*) &IpxData, &cbOpt );
    128 	if ( err == SOCKET_ERROR ) {
    129 		assert ( err != SOCKET_ERROR );
    130 		closesocket (s);
    131 		return (false);
    132 	}
    133 
    134 	/*
    135 	** IpxData contains the address for the current adapter.
    136 	** The network number will be needed later for broadcasts as the net number ff,ff,ff,ff
    137 	** doesn't work under NT.
    138 	**
    139 	** Note: Due to a bug in Win95s implementation of Winsock, only the netnum & nodenum
    140 	** values are correctly returned. NT returns all expected values. ST - 7/31/97 0:57AM
    141 	*/
    142 	memcpy (addr->sa_netnum, IpxData.netnum, sizeof (addr->sa_netnum));
    143 	memcpy (BroadcastNet, IpxData.netnum, sizeof (addr->sa_netnum));
    144 	memcpy (addr->sa_nodenum, IpxData.nodenum, sizeof (addr->sa_nodenum));
    145 
    146 	closesocket (s);
    147 	return (true);
    148 }
    149 
    150 
    151 
    152 
    153 
    154 
    155 /***********************************************************************************************
    156  * IPXInterfaceClass::Open_Socket -- Opens an IPX socket for reading & writing                 *
    157  *                                                                                             *
    158  *                                                                                             *
    159  *                                                                                             *
    160  * INPUT:    SOCKET number to open. This is usually VIRGIN_SOCKET                              *
    161  *                                                                                             *
    162  * OUTPUT:   true if socket was opened without error                                           *
    163  *                                                                                             *
    164  * WARNINGS: None                                                                              *
    165  *                                                                                             *
    166  * HISTORY:                                                                                    *
    167  *    8/4/97 5:54PM ST : Created                                                               *
    168  *=============================================================================================*/
    169 bool IPXInterfaceClass::Open_Socket( SOCKET socketnum )
    170 {
    171 	SOCKADDR_IPX 	addr;
    172 	bool				delay = true;
    173 	int				err;
    174 
    175 	/*
    176 	** If Winsock is not initialised then do it now.
    177 	*/
    178 	if ( !WinsockInitialised ) {
    179 		if ( !Init()) return ( false );;
    180 	}
    181 
    182 	IPXSocketNumber = socketnum;
    183 
    184 	/*
    185 	** Set up the addr structure for the IPX socket
    186 	*/
    187 	addr.sa_family = AF_IPX;
    188 	memset (addr.sa_netnum, 0, sizeof (addr.sa_netnum));
    189 	memset (addr.sa_nodenum, -1, sizeof (addr.sa_nodenum));
    190 	addr.sa_socket = htons ( socketnum );
    191 
    192 	/*
    193 	** Create the socket.
    194 	*/
    195 	Socket = socket (AF_NS, SOCK_DGRAM, NSPROTO_IPX);
    196 	if (Socket == INVALID_SOCKET) {
    197 		char out[128];
    198 		sprintf (out, "TS: Failed to create IPX socket - error code %d.\n", GetLastError() );
    199 		OutputDebugString (out);
    200 		assert ( Socket != INVALID_SOCKET );
    201 		closesocket(Socket);
    202 		return ( false );
    203 	}
    204 
    205 	/*
    206 	** Get the network card address. This is needed so we can bind the socket to the net card.
    207 	*/
    208 	if ( !Get_Network_Card_Address (0, &addr)){
    209 		closesocket ( Socket );
    210 		return ( false );
    211 	}
    212 
    213 	/*
    214 	** Bind the IPX socket to the network card.
    215 	*/
    216 	if (bind ( Socket, (const struct sockaddr *) &addr, 16) == SOCKET_ERROR ){
    217 		char out[128];
    218 		sprintf (out, "TS: IPX socket bind failed with error code %d.\n", GetLastError() );
    219 		OutputDebugString (out);
    220 		assert ( false );
    221 		closesocket(Socket);
    222 		return ( false );;
    223 	}
    224 
    225 
    226 	/*
    227 	** Set the various options for this IPX socket
    228 	*/
    229 	unsigned long 	optval = true;
    230 	int 	packet_type = 4;
    231 
    232 	/*
    233 	** The SO_BROADCAST option allows broadcasting on this socket. This shouldn't be needed
    234 	** except for the bug in the Win95 implementation of Winsock which causes broadcasts to
    235 	** fail if it isn't set.
    236 	*/
    237 	if ( setsockopt ( Socket, SOL_SOCKET, SO_BROADCAST, (char*)&optval,	sizeof(optval) ) == SOCKET_ERROR ) {
    238 		char out[128];
    239 		sprintf (out, "TS: Failed to set IPX socket option SO_BROADCAST - error code %d.\n", GetLastError() );
    240 		OutputDebugString (out);
    241 		assert ( false );
    242 	}
    243 
    244 	/*
    245 	** Set the value in the packet type field for outgoing packets.
    246 	*/
    247 	err = setsockopt ( Socket, NSPROTO_IPX, IPX_PTYPE, (char*)&packet_type,	sizeof(packet_type));
    248 	if ( err == INVALID_SOCKET ) {
    249 		char out[128];
    250 		sprintf (out, "TS: Failed to set IPX protocol option IPX_PTYPE - error code %d.\n", GetLastError() );
    251 		OutputDebugString (out);
    252 		assert ( err != INVALID_SOCKET );
    253 	}
    254 
    255 	/*
    256 	** Ignore all incoming packets not of this type.
    257 	*/
    258 	err = setsockopt ( Socket, NSPROTO_IPX, IPX_FILTERPTYPE, (char*)&packet_type,	sizeof(packet_type));
    259 	if ( err == INVALID_SOCKET ) {
    260 		char out[128];
    261 		sprintf (out, "TS: Failed to set IPX protocol option IPX_FILTERTYPE - error code %d.\n", GetLastError() );
    262 		OutputDebugString (out);
    263 		assert ( err != INVALID_SOCKET );
    264 	}
    265 
    266 	/*
    267 	** Set the the base class socket options for buffer sizes.
    268 	*/
    269 	WinsockInterfaceClass::Set_Socket_Options();
    270 
    271 	/*
    272 	** Woohoo!
    273 	*/
    274 	return ( true );
    275 }
    276 
    277 
    278 
    279 
    280 
    281 
    282 
    283 
    284 
    285 /***********************************************************************************************
    286  * IPXInterfaceClass::Message_Handler -- Handler for windows messages relating to IPX          *
    287  *                                                                                             *
    288  *                                                                                             *
    289  *                                                                                             *
    290  * INPUT:    Usual windoze message handler stuff                                               *
    291  *                                                                                             *
    292  * OUTPUT:   0 if message was handled                                                          *
    293  *                                                                                             *
    294  * WARNINGS: None                                                                              *
    295  *                                                                                             *
    296  * HISTORY:                                                                                    *
    297  *    8/4/97 5:55PM ST : Created                                                               *
    298  *=============================================================================================*/
    299 long IPXInterfaceClass::Message_Handler(HWND , UINT message, UINT , LONG lParam)
    300 {
    301 
    302 	int					addr_len;		// Length of address structure
    303 	int	 				rc;				// Result code
    304 	SOCKADDR_IPX 		addr;				// Winsock IPX addressing structure
    305 	WinsockBufferType *packet;			// Ptr to packet
    306 	NetNumType			netnum;
    307 	NetNodeType			nodenum;
    308 
    309 
    310 	/*
    311 	** We only handle IPX events.
    312 	*/
    313 	if ( message != WM_IPXASYNCEVENT ) return ( 1 );
    314 
    315 
    316 	switch ( WSAGETSELECTEVENT(lParam) ) {
    317 
    318 		/*
    319 		** Read event. Winsock has data it would like to give us.
    320 		*/
    321 		case FD_READ:
    322 			/*
    323 			** Clear any outstanding errors on the socket.
    324 			*/
    325 			rc = WSAGETSELECTERROR(lParam);
    326 			if (rc != 0) {
    327 				Clear_Socket_Error (Socket);
    328 				return(0);
    329 			}
    330 
    331 			/*
    332 			** Call the Winsock recvfrom function to get the outstanding packet.
    333 			*/
    334 			addr_len = sizeof(addr);
    335 			rc = recvfrom ( Socket, (char*) ReceiveBuffer, sizeof (ReceiveBuffer), 0, (LPSOCKADDR)&addr, &addr_len );
    336 			if (rc == SOCKET_ERROR) {
    337 				if (WSAGetLastError() != WSAEWOULDBLOCK) {
    338 					Clear_Socket_Error (Socket);
    339 				}
    340 				return(0);
    341 			}
    342 
    343 			/*
    344 			** rc is the number of bytes received from Winsock
    345 			*/
    346 			if ( rc ) {
    347 
    348 				/*
    349 				** Make a copy of the address that this packet came from.
    350 				*/
    351 				memcpy ( netnum, addr.sa_netnum, sizeof (netnum) );
    352 				memcpy ( nodenum, addr.sa_nodenum, sizeof (nodenum) );
    353 
    354 				/*
    355 				** If this packet was from me then ignore it.
    356 				*/
    357 				if ( !memcmp (netnum, BroadcastNet, sizeof (BroadcastNet)) && !memcmp(nodenum, MyNode, sizeof (MyNode)) ) {
    358 					return (0);
    359 				}
    360 
    361 				/*
    362 				** Create a new buffer and store this packet in it.
    363 				*/
    364 				packet = new WinsockBufferType;
    365 				packet->BufferLen = rc;
    366 				memcpy ( packet->Buffer, ReceiveBuffer, rc );
    367 				IPXAddressClass *paddress = (IPXAddressClass*) (&packet->Address[0]);
    368 				paddress->Set_Address ( netnum, nodenum );
    369 				InBuffers.Add ( packet );
    370 			}
    371 			return(0);
    372 
    373 
    374 		/*
    375 		** Write event. We send ourselves this event when we have more data to send. This
    376 		** event will also occur automatically when a packet has finished being sent.
    377 		*/
    378 		case FD_WRITE:
    379 			/*
    380 			** Clear any outstanding erros on the socket.
    381 			*/
    382 			rc = WSAGETSELECTERROR(lParam);
    383 			if (rc != 0) {
    384 				Clear_Socket_Error ( Socket );
    385 				return(0);
    386 			}
    387 
    388 			/*
    389 			** If there are no packets waiting to be sent then bail.
    390 			*/
    391 			while ( OutBuffers.Count() != 0 ) {
    392 				int packetnum = 0;
    393 
    394 				/*
    395 				** Get a pointer to the packet.
    396 				*/
    397 				packet = OutBuffers [ packetnum ];
    398 
    399 				/*
    400 				** Set up the address structure of the outgoing packet
    401 				*/
    402 				addr.sa_family = AF_IPX;
    403 				addr.sa_socket = htons ( IPXSocketNumber );
    404 
    405 				/*
    406 				** Set up the address as either a broadcast address or the given address
    407 				*/
    408 				if ( packet->IsBroadcast ) {
    409 					memcpy ( addr.sa_netnum, BroadcastNet, sizeof (BroadcastNet) );
    410 					memcpy ( addr.sa_nodenum, BroadcastNode, sizeof (BroadcastNode) );
    411 				}else{
    412 					IPXAddressClass *paddress = (IPXAddressClass*) (&packet->Address[0]);
    413 					paddress->Get_Address ( netnum, nodenum );
    414 					memcpy ( addr.sa_netnum, netnum, sizeof (netnum) );
    415 					memcpy ( addr.sa_nodenum, nodenum, sizeof (nodenum) );
    416 				}
    417 
    418 				/*
    419 				** Send it.
    420 				** If we get a WSAWOULDBLOCK error it means that Winsock is unable to accept the packet
    421 				** at this time. In this case, we clear the socket error and just exit. Winsock will
    422 				** send us another WRITE message when it is ready to receive more data.
    423 				*/
    424 				rc = sendto ( Socket, (const char*) packet->Buffer, packet->BufferLen, 0, (LPSOCKADDR)&addr, sizeof (addr) );
    425 
    426 				if (rc == SOCKET_ERROR){
    427 					if (WSAGetLastError() != WSAEWOULDBLOCK) {
    428 						Clear_Socket_Error (Socket);
    429 						break;
    430 					}
    431 				}
    432 
    433 				/*
    434 				** Delete the sent packet.
    435 				*/
    436 				OutBuffers.Delete ( packetnum );
    437 				delete packet;
    438 			}
    439 
    440 			return(0);
    441 	}
    442 
    443 	return (0);
    444 }
    445 
    446