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