IPXGCONN.CPP (24226B)
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 /* $Header: /CounterStrike/IPXGCONN.CPP 3 10/13/97 2:20p Steve_t $ */ 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 : IPXGCONN.CPP * 24 * * 25 * Programmer : Bill Randolph * 26 * * 27 * Start Date : December 20, 1994 * 28 * * 29 * Last Update : July 6, 1995 [BRR] * 30 *-------------------------------------------------------------------------* 31 * Functions: * 32 * IPXGlobalConnClass::IPXGlobalConnClass -- class constructor * 33 * IPXGlobalConnClass::~IPXGlobalConnClass -- class destructor * 34 * IPXGlobalConnClass::Send_Packet -- adds a packet to the send queue * 35 * IPXGlobalConnClass::Receive_Packet -- adds packet to the receive queue* 36 * IPXGlobalConnClass::Get_Packet -- gets a packet from the receive queue* 37 * IPXGlobalConnClass::Send -- sends a packet * 38 * IPXGlobalConnClass::Service_Receive_Queue -- services receive queue * 39 * IPXGlobalConnClass::Set_Bridge -- Sets up connection to cross a bridge* 40 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 41 42 #include "function.h" 43 #include <stdio.h> 44 //#include <mem.h> 45 #include "ipxgconn.h" 46 47 48 /*************************************************************************** 49 * IPXGlobalConnClass::IPXGlobalConnClass -- class constructor * 50 * * 51 * This routine chains to the parent constructor, but it adjusts the size * 52 * of the packet by the added bytes in the GlobalHeaderType structure. * 53 * This forces the parent classes to allocate the proper sized PacketBuf * 54 * for outgoing packets, and to set MaxPacketLen to the proper value. * 55 * * 56 * INPUT: * 57 * numsend desired # of entries for the send queue * 58 * numreceive desired # of entries for the receive queue * 59 * maxlen max length of an application packet * 60 * product_id unique ID for this product * 61 * * 62 * OUTPUT: * 63 * none. * 64 * * 65 * WARNINGS: * 66 * none. * 67 * * 68 * HISTORY: * 69 * 12/20/1994 BR : Created. * 70 *=========================================================================*/ 71 IPXGlobalConnClass::IPXGlobalConnClass (int numsend, int numreceive, 72 int maxlen, unsigned short product_id) : 73 IPXConnClass (numsend, numreceive, 74 maxlen + sizeof(GlobalHeaderType) - sizeof(CommHeaderType), 75 GLOBAL_MAGICNUM, // magic number for this connection 76 NULL, // IPX Address (none) 77 0, // Connection ID 78 "", // Connection Name 79 sizeof (IPXAddressClass)) // extra storage for the sender's address 80 { 81 int i; 82 83 ProductID = product_id; 84 IsBridge = 0; 85 86 for (i = 0; i < 4; i++) { 87 LastPacketID[i] = 0xffffffff; 88 } 89 LastRXIndex = 0; 90 91 } /* end of IPXGlobalConnClass */ 92 93 94 /*************************************************************************** 95 * IPXGlobalConnClass::Send_Packet -- adds a packet to the send queue * 96 * * 97 * This routine prefixes the given buffer with a GlobalHeaderType and * 98 * queues the resulting packet into the Send Queue. The packet's * 99 * MagicNumber, Code, PacketID, destination Address and ProductID are set * 100 * here. * 101 * * 102 * INPUT: * 103 * buf buffer to send * 104 * buflen length of buffer * 105 * address address to send the packet to (NULL = Broadcast) * 106 * ack_req 1 = ACK is required for this packet; 0 = isn't * 107 * * 108 * OUTPUT: * 109 * 1 = OK, 0 = error * 110 * * 111 * WARNINGS: * 112 * none. * 113 * * 114 * HISTORY: * 115 * 12/20/1994 BR : Created. * 116 *=========================================================================*/ 117 int IPXGlobalConnClass::Send_Packet (void * buf, int buflen, 118 IPXAddressClass *address, int ack_req) 119 { 120 IPXAddressClass dest_addr; 121 122 /*------------------------------------------------------------------------ 123 Store the packet's Magic Number 124 ------------------------------------------------------------------------*/ 125 ((GlobalHeaderType *)PacketBuf)->Header.MagicNumber = MagicNum; 126 127 /*------------------------------------------------------------------------ 128 If this is a ACK-required packet, sent to a specific system, mark it as 129 ACK-required; otherwise, mark as no-ACK-required. 130 ------------------------------------------------------------------------*/ 131 if (ack_req && address != NULL) { 132 ((GlobalHeaderType *)PacketBuf)->Header.Code = PACKET_DATA_ACK; 133 } 134 else { 135 ((GlobalHeaderType *)PacketBuf)->Header.Code = PACKET_DATA_NOACK; 136 } 137 138 /*------------------------------------------------------------------------ 139 Fill in the packet ID. This will have very limited meaning; it only 140 allows us to determine if an ACK packet we receive later goes with this 141 packet; it doesn't let us detect re-sends of other systems' packets. 142 ------------------------------------------------------------------------*/ 143 ((GlobalHeaderType *)PacketBuf)->Header.PacketID = Queue->Send_Total(); 144 145 /*------------------------------------------------------------------------ 146 Set the product ID for this packet. 147 ------------------------------------------------------------------------*/ 148 ((GlobalHeaderType *)PacketBuf)->ProductID = ProductID; 149 150 /*------------------------------------------------------------------------ 151 Set this packet's destination address. If no address is specified, use 152 a Broadcast address (which IPXAddressClass's default constructor creates). 153 ------------------------------------------------------------------------*/ 154 if (address != NULL) { 155 dest_addr = (*address); 156 } 157 158 /*------------------------------------------------------------------------ 159 Copy the application's data 160 ------------------------------------------------------------------------*/ 161 memcpy(PacketBuf + sizeof(GlobalHeaderType), buf, buflen); 162 163 /*------------------------------------------------------------------------ 164 Queue it, along with the destination address 165 ------------------------------------------------------------------------*/ 166 return(Queue->Queue_Send(PacketBuf,buflen + sizeof(GlobalHeaderType), 167 &dest_addr, sizeof (IPXAddressClass))); 168 169 } /* end of Send_Packet */ 170 171 172 /*************************************************************************** 173 * IPXGlobalConnClass::Receive_Packet -- adds packet to the receive queue * 174 * * 175 * INPUT: * 176 * buf buffer to process (already includes GlobalHeaderType) * 177 * buflen length of buffer to process * 178 * address the address of the sender (the IPX Manager class must * 179 * extract this from the IPX Header of the received packet.) * 180 * * 181 * OUTPUT: * 182 * 1 = OK, 0 = error * 183 * * 184 * WARNINGS: * 185 * none. * 186 * * 187 * HISTORY: * 188 * 12/20/1994 BR : Created. * 189 *=========================================================================*/ 190 int IPXGlobalConnClass::Receive_Packet (void * buf, int buflen, 191 IPXAddressClass *address) 192 { 193 GlobalHeaderType *packet; // ptr to this packet 194 SendQueueType *send_entry; // ptr to send entry header 195 GlobalHeaderType *entry_data; // ptr to queue entry data 196 GlobalHeaderType ackpacket; // ACK packet to send 197 int i; 198 int resend; 199 200 /*------------------------------------------------------------------------ 201 Check the magic # 202 ------------------------------------------------------------------------*/ 203 packet = (GlobalHeaderType *)buf; 204 if (packet->Header.MagicNumber!=MagicNum) { 205 return(0); 206 } 207 208 /*------------------------------------------------------------------------ 209 Process the packet based on its Code 210 ------------------------------------------------------------------------*/ 211 switch (packet->Header.Code) { 212 //..................................................................... 213 // DATA_ACK: Check for a resend by comparing the source address & 214 // ID of this packet with our last 4 received packets. 215 // Send an ACK for the packet, regardless of whether it's a resend 216 // or not. 217 //..................................................................... 218 case PACKET_DATA_ACK: 219 { 220 //.................................................................. 221 // Check for a resend 222 //.................................................................. 223 resend = 0; 224 for (i = 0; i < 4; i++) { 225 if ((unsigned int)i >= Queue->Receive_Total()) { 226 break; 227 } 228 if ((*address)==LastAddress[i] && 229 packet->Header.PacketID==LastPacketID[i]) { 230 resend = 1; 231 break; 232 } 233 } 234 235 bool send_ack = true; 236 237 //.................................................................. 238 // If it's not a resend, queue it; then, record the sender's address 239 // & the packet ID for future resend detection. 240 //.................................................................. 241 if (!resend) { 242 if (Queue->Queue_Receive (buf, buflen, address, sizeof(IPXAddressClass))) { 243 LastAddress[LastRXIndex] = (*address); 244 LastPacketID[LastRXIndex] = packet->Header.PacketID; 245 LastRXIndex++; 246 if (LastRXIndex >= 4) { 247 LastRXIndex = 0; 248 } 249 }else{ 250 //.................................................................. 251 // Don't send an ack if we didn't have room to store the packet. 252 //.................................................................. 253 send_ack = false; 254 } 255 } 256 257 258 //.................................................................. 259 // Send an ACK for this packet 260 //.................................................................. 261 if (send_ack) { 262 ackpacket.Header.MagicNumber = MagicNum; 263 ackpacket.Header.Code = PACKET_ACK; 264 ackpacket.Header.PacketID = packet->Header.PacketID; 265 ackpacket.ProductID = ProductID; 266 Send ((char *)&ackpacket, sizeof(GlobalHeaderType), 267 address, sizeof(IPXAddressClass)); 268 } 269 270 271 break; 272 } 273 /*..................................................................... 274 DATA_NOACK: Queue this message, along with the sender's address. 275 Don't bother checking for a Re-Send, since the other system will only 276 send this packet once. 277 .....................................................................*/ 278 case PACKET_DATA_NOACK: 279 Queue->Queue_Receive (buf, buflen, address, sizeof(IPXAddressClass)); 280 break; 281 282 /*..................................................................... 283 ACK: If this ACK is for any of my packets, mark that packet as 284 acknowledged, then throw this packet away. Otherwise, ignore the ACK 285 (if we re-sent before we received the other system's first ACK, this 286 ACK will be a leftover) 287 .....................................................................*/ 288 case PACKET_ACK: 289 for (i = 0; i < Queue->Num_Send(); i++) { 290 /*............................................................... 291 Get queue entry ptr 292 ...............................................................*/ 293 send_entry = Queue->Get_Send(i); 294 295 /*............................................................... 296 If ptr is valid, get ptr to its data 297 ...............................................................*/ 298 entry_data = (GlobalHeaderType *)(send_entry->Buffer); 299 300 /*............................................................... 301 If ACK is for this entry, mark it 302 ...............................................................*/ 303 if (packet->Header.PacketID==entry_data->Header.PacketID && 304 entry_data->Header.Code == PACKET_DATA_ACK) { 305 send_entry->IsACK = 1; 306 break; 307 } 308 } 309 break; 310 311 /*..................................................................... 312 Default: ignore the packet 313 .....................................................................*/ 314 default: 315 break; 316 } 317 318 return(1); 319 320 } /* end of Receive_Packet */ 321 322 323 /*************************************************************************** 324 * IPXGlobalConnClass::Get_Packet -- gets a packet from the receive queue * 325 * * 326 * INPUT: * 327 * buf location to store buffer * 328 * buflen filled in with length of 'buf' * 329 * address filled in with sender's address * 330 * product_id filled in with sender's ProductID * 331 * * 332 * OUTPUT: * 333 * 1 = OK, 0 = error * 334 * * 335 * WARNINGS: * 336 * none. * 337 * * 338 * HISTORY: * 339 * 12/20/1994 BR : Created. * 340 *=========================================================================*/ 341 int IPXGlobalConnClass::Get_Packet (void * buf, int *buflen, 342 IPXAddressClass *address, unsigned short *product_id) 343 { 344 ReceiveQueueType *rec_entry; // ptr to receive entry header 345 GlobalHeaderType *packet; 346 int packetlen; // size of received packet 347 348 /*------------------------------------------------------------------------ 349 Return if nothing to do 350 ------------------------------------------------------------------------*/ 351 if (Queue->Num_Receive() == 0) { 352 return(0); 353 } 354 355 /*------------------------------------------------------------------------ 356 Get ptr to the next available entry 357 ------------------------------------------------------------------------*/ 358 rec_entry = Queue->Get_Receive(0); 359 360 /*------------------------------------------------------------------------ 361 Read it if it's un-read 362 ------------------------------------------------------------------------*/ 363 if (rec_entry!=NULL && rec_entry->IsRead==0) { 364 365 /*..................................................................... 366 Mark as read 367 .....................................................................*/ 368 rec_entry->IsRead = 1; 369 370 /*..................................................................... 371 Copy data packet 372 .....................................................................*/ 373 packet = (GlobalHeaderType *)(rec_entry->Buffer); 374 packetlen = rec_entry->BufLen - sizeof(GlobalHeaderType); 375 if (packetlen > 0) { 376 memcpy(buf, rec_entry->Buffer + sizeof(GlobalHeaderType), packetlen); 377 } 378 (*buflen) = packetlen; 379 (*product_id) = packet->ProductID; 380 (*address) = (*((IPXAddressClass *)(rec_entry->ExtraBuffer))); 381 382 return(1); 383 } 384 385 return(0); 386 387 } /* end of Get_Packet */ 388 389 390 /*************************************************************************** 391 * IPXGlobalConnClass::Send -- sends a packet * 392 * * 393 * This routine gets invoked by NonSequencedConn, when it's processing * 394 * the Send & Receive Queues. The buffer provided will already have the * 395 * GlobalHeaderType header embedded in it. * 396 * * 397 * INPUT: * 398 * buf buffer to send * 399 * buflen length of buffer * 400 * extrabuf extra buffer to send * 401 * extralen length of extra buffer * 402 * * 403 * OUTPUT: * 404 * 1 = OK, 0 = error * 405 * * 406 * WARNINGS: * 407 * none. * 408 * * 409 * HISTORY: * 410 * 12/20/1994 BR : Created. * 411 *=========================================================================*/ 412 int IPXGlobalConnClass::Send(char *buf, int buflen, void *extrabuf, int ) 413 { 414 IPXAddressClass *addr; 415 int rc; 416 417 /*------------------------------------------------------------------------ 418 Extract the packet's embedded IPX address 419 ------------------------------------------------------------------------*/ 420 addr = (IPXAddressClass *)extrabuf; 421 422 /*------------------------------------------------------------------------ 423 If it's a broadcast address, broadcast it 424 ------------------------------------------------------------------------*/ 425 if (addr->Is_Broadcast()) { 426 return(Broadcast (buf, buflen)); 427 } 428 429 /*------------------------------------------------------------------------ 430 Otherwise, send it 431 ------------------------------------------------------------------------*/ 432 else { 433 if (IsBridge && !memcmp (addr, BridgeNet, 4)) { 434 rc = Send_To (buf, buflen, addr, BridgeNode); 435 } 436 else { 437 rc = Send_To (buf, buflen, addr, NULL); 438 } 439 return (rc); 440 } 441 442 } /* end of Send */ 443 444 445 /*************************************************************************** 446 * IPXGlobalConnClass::Service_Receive_Queue -- services the receive queue * 447 * * 448 * This routine is necessary because the regular ConnectionClass checks * 449 * for sequential packet ID's before removing them from the receive queue; * 450 * this class cannot do that. * 451 * * 452 * INPUT: * 453 * none. * 454 * * 455 * OUTPUT: * 456 * 1 = OK, 0 = error * 457 * * 458 * WARNINGS: * 459 * none. * 460 * * 461 * HISTORY: * 462 * 12/20/1994 BR : Created. * 463 *=========================================================================*/ 464 int IPXGlobalConnClass::Service_Receive_Queue (void) 465 { 466 int i; 467 ReceiveQueueType *rec_entry; // ptr to receive entry header 468 469 //------------------------------------------------------------------------ 470 // Remove all dead packets: If a packet's been read, throw it away. 471 //------------------------------------------------------------------------ 472 for (i = 0; i < Queue->Num_Receive(); i++) { 473 rec_entry = Queue->Get_Receive(i); 474 475 if (rec_entry->IsRead) { 476 Queue->UnQueue_Receive(NULL,NULL,i,NULL,NULL); 477 i--; 478 } 479 } 480 481 return (1); 482 483 } /* end of Service_Receive_Queue */ 484 485 486 /*************************************************************************** 487 * Set_Bridge -- Sets up connection to cross a bridge * 488 * * 489 * This routine is designed to prevent the connection from having to * 490 * call Get_Local_Target, except the minimum number of times, since that * 491 * routine is buggy & goes away for long periods sometimes. * 492 * * 493 * INPUT: * 494 * bridge network number of the destination bridge * 495 * * 496 * OUTPUT: * 497 * none * 498 * * 499 * WARNINGS: * 500 * none * 501 * * 502 * HISTORY: * 503 * 07/06/1995 BRR : Created. * 504 *=========================================================================*/ 505 void IPXGlobalConnClass::Set_Bridge(NetNumType bridge) 506 { 507 #ifdef WINSOCK_IPX 508 509 if (Configured) { 510 bridge = bridge; 511 IsBridge = 0; 512 } 513 514 #else //WINSOCK_IPX 515 if (Configured) { 516 memcpy (BridgeNet, bridge, 4); 517 memset (BridgeNode, 0xff, 6); 518 519 if (IPX_Get_Local_Target (BridgeNet, BridgeNode, Socket, BridgeNode)==0) { 520 IsBridge = 1; 521 } 522 else { 523 IsBridge = 0; 524 } 525 } 526 #endif //WINSOCK_IPX 527 528 } /* end of Set_Bridge */ 529 530 531 /************************** end of ipxgconn.cpp ****************************/