IPXCONN.CPP (29007B)
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: F:\projects\c&c\vcs\code\ipxconn.cpv 1.9 16 Oct 1995 16:50:52 JOE_BOSTIC $ */ 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 : IPXCONN.CPP * 24 * * 25 * Programmer : Bill Randolph * 26 * * 27 * Start Date : December 20, 1994 * 28 * * 29 * Last Update : April 9, 1995 [BRR] * 30 * * 31 *-------------------------------------------------------------------------* 32 * Functions: * 33 * IPXConnClass::IPXConnClass -- class constructor * 34 * IPXConnClass::~IPXConnClass -- class destructor * 35 * IPXConnClass::Init -- hardware-specific initialization routine * 36 * IPXConnClass::Configure -- One-time initialization routine * 37 * IPXConnClass::Start_Listening -- commands IPX to listen * 38 * IPXConnClass::Stop_Listening -- commands IPX to stop listen * 39 * IPXConnClass::Send -- sends a packet; invoked by SequencedConnection * 40 * IPXConnClass::Open_Socket -- opens communications socket * 41 * IPXConnClass::Close_Socket -- closes the socket * 42 * IPXConnClass::Send_To -- sends the packet to the given address * 43 * IPXConnClass::Broadcast -- broadcasts the given packet * 44 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 45 46 #include "function.h" 47 #include "ipx95.h" 48 #include "tcpip.h" 49 50 /* 51 ********************************* Globals *********************************** 52 */ 53 unsigned short IPXConnClass::Socket; 54 int IPXConnClass::ConnectionNum; 55 ECBType * IPXConnClass::ListenECB; 56 IPXHeaderType * IPXConnClass::ListenHeader; 57 char * IPXConnClass::ListenBuf; 58 ECBType * IPXConnClass::SendECB; 59 IPXHeaderType * IPXConnClass::SendHeader; 60 char * IPXConnClass::SendBuf; 61 long IPXConnClass::Handler; 62 int IPXConnClass::Configured = 0; 63 int IPXConnClass::SocketOpen = 0; 64 int IPXConnClass::Listening = 0; 65 int IPXConnClass::PacketLen; 66 67 68 /*************************************************************************** 69 * IPXConnClass::IPXConnClass -- class constructor * 70 * * 71 * INPUT: * 72 * numsend desired # of entries for the send queue * 73 * numreceive desired # of entries for the recieve queue * 74 * maxlen max length of an application packet * 75 * magicnum the packet "magic number" for this connection * 76 * address address of destination (NULL = no address) * 77 * id connection's unique numerical ID * 78 * name connection's name * 79 * * 80 * OUTPUT: * 81 * none. * 82 * * 83 * WARNINGS: * 84 * none. * 85 * * 86 * HISTORY: * 87 * 12/20/1994 BR : Created. * 88 *=========================================================================*/ 89 IPXConnClass::IPXConnClass (int numsend, int numreceive, int maxlen, 90 unsigned short magicnum, IPXAddressClass *address, int id, char *name) : 91 #ifdef SEQ_NET 92 SequencedConnClass (numsend, numreceive, maxlen, magicnum, 93 #else 94 NonSequencedConnClass (numsend, numreceive, maxlen, magicnum, 95 #endif 96 2, // retry delta 97 -1, // max retries 98 60) // timeout 99 { 100 NetNumType net; 101 NetNodeType node; 102 103 /*------------------------------------------------------------------------ 104 Save the values passed in 105 ------------------------------------------------------------------------*/ 106 if (address) 107 Address = (*address); 108 ID = id; 109 strcpy (Name, name); 110 111 if (!Winsock.Get_Connected()){ 112 /*------------------------------------------------------------------------ 113 If our Address field is an actual address (ie NULL wasn't passed to the 114 constructor), pre-compute the ImmediateAddress value for the SendECB. 115 This allows pre-computing of the ImmediateAddress for all connections 116 created after Configure() is called. 117 ------------------------------------------------------------------------*/ 118 if (!Address.Is_Broadcast() && Configured==1) { 119 Address.Get_Address(net,node); 120 /*..................................................................... 121 If the user is logged in & has a valid Novell Connection Number, get the 122 bridge address the "official" way 123 .....................................................................*/ 124 if (ConnectionNum != 0) { 125 if (IPX_Get_Local_Target (net, node, Socket, ImmediateAddress)!=0) 126 memcpy(ImmediateAddress,node,6); 127 } else { 128 129 /*..................................................................... 130 Otherwise, use the destination node address as the ImmediateAddress, and 131 just hope there's no network bridge in the path. 132 .....................................................................*/ 133 memcpy(ImmediateAddress,node,6); 134 } 135 136 Immed_Set = 1; 137 } else { 138 memset (ImmediateAddress, 0, 6); 139 Immed_Set = 0; 140 } 141 } 142 143 } /* end of IPXConnClass */ 144 145 146 /*************************************************************************** 147 * IPXConnClass::Init -- hardware-specific initialization routine * 148 * * 149 * INPUT: * 150 * none. * 151 * * 152 * OUTPUT: * 153 * none. * 154 * * 155 * WARNINGS: * 156 * none. * 157 * * 158 * HISTORY: * 159 * 12/20/1994 BR : Created. * 160 *=========================================================================*/ 161 void IPXConnClass::Init (void) 162 { 163 /*------------------------------------------------------------------------ 164 Invoke the parent's Init routine 165 ------------------------------------------------------------------------*/ 166 #ifdef SEQ_NET 167 SequencedConnClass::Init(); 168 #else 169 NonSequencedConnClass::Init(); 170 #endif 171 } 172 173 174 /*************************************************************************** 175 * IPXConnClass::Configure -- One-time initialization routine * 176 * * 177 * This routine sets up static members that are shared by all IPX * 178 * connections (ie those variables used by the Send/Listen/Broadcast * 179 * routines). * 180 * * 181 * INPUT: * 182 * socket socket ID for sending & receiving * 183 * conn_num local IPX Connection Number (0 = not logged in) * 184 * listen_ecb ptr to ECBType for listening * 185 * send_ecb ptr to ECBType for sending * 186 * listen_header ptr to IPXHeaderType for listening * 187 * send_header ptr to IPXHeaderType for sending * 188 * listen_buf ptr to buffer for listening * 189 * send_buf ptr to buffer for sending * 190 * handler_rm_ptr REAL-MODE pointer to event service routine * 191 * (high word = segment, low word = offset) * 192 * maxpacketlen max packet size to listen for * 193 * * 194 * OUTPUT: * 195 * none. * 196 * * 197 * WARNINGS: * 198 * - All pointers must be protected-mode pointers, but must point to * 199 * DOS real-mode memory (except the Handler segment/offset) * 200 * * 201 * HISTORY: * 202 * 12/20/1994 BR : Created. * 203 *=========================================================================*/ 204 void IPXConnClass::Configure (unsigned short socket, int conn_num, 205 ECBType *listen_ecb, ECBType *send_ecb, IPXHeaderType *listen_header, 206 IPXHeaderType *send_header, char *listen_buf, char *send_buf, 207 long handler_rm_ptr, int maxpacketlen) 208 { 209 /*------------------------------------------------------------------------ 210 Save the values passed in 211 ------------------------------------------------------------------------*/ 212 Socket = socket; 213 ConnectionNum = conn_num; 214 ListenECB = listen_ecb; 215 SendECB = send_ecb; 216 ListenHeader = listen_header; 217 SendHeader = send_header; 218 ListenBuf = listen_buf; 219 SendBuf = send_buf; 220 Handler = handler_rm_ptr; 221 PacketLen = maxpacketlen; 222 223 Configured = 1; 224 225 } /* end of Configure */ 226 227 228 /*************************************************************************** 229 * IPXConnClass::Start_Listening -- commands IPX to listen * 230 * * 231 * This routine may be used to start listening in polled mode (if the * 232 * ECB's Event_Service_Routine is NULL), or in interrupt mode; it's * 233 * up to the caller to fill the ECB in. If in polled mode, Listening * 234 * must be restarted every time a packet comes in. * 235 * * 236 * INPUT: * 237 * none. * 238 * * 239 * OUTPUT: * 240 * none. * 241 * * 242 * WARNINGS: * 243 * - The ListenECB must have been properly filled in by the IPX Manager.* 244 * - Configure must be called before calling this routine. * 245 * * 246 * HISTORY: * 247 * 12/16/1994 BR : Created. * 248 *=========================================================================*/ 249 bool IPXConnClass::Start_Listening(void) 250 { 251 252 #ifndef NOT_FOR_WIN95 253 254 if (Winsock.Get_Connected()) return (true); 255 256 /*------------------------------------------------------------------------ 257 Open the Socket 258 ------------------------------------------------------------------------*/ 259 if (!Open_Socket(Socket)) 260 return(false); 261 262 if (IPX_Start_Listening95()){ 263 Listening =1; 264 return (TRUE); 265 }else{ 266 return (FALSE); 267 } 268 269 #else 270 271 void *hdr_ptr; 272 unsigned long hdr_val; 273 void *buf_ptr; 274 unsigned long buf_val; 275 int rc; 276 277 /*------------------------------------------------------------------------ 278 Don't do a thing unless we've been configured, and we're not listening. 279 ------------------------------------------------------------------------*/ 280 if (Configured==0 || Listening==1) 281 return(false); 282 283 /*------------------------------------------------------------------------ 284 Open the Socket 285 ------------------------------------------------------------------------*/ 286 if (!Open_Socket(Socket)) 287 return(false); 288 289 /*------------------------------------------------------------------------ 290 Clear the ECB & header 291 ------------------------------------------------------------------------*/ 292 memset(ListenECB, 0, sizeof(ECBType)); 293 memset(ListenHeader, 0, sizeof(IPXHeaderType)); 294 295 /*------------------------------------------------------------------------ 296 Convert protected-mode ptrs to real-mode ptrs 297 ------------------------------------------------------------------------*/ 298 hdr_val = (unsigned long)ListenHeader; 299 hdr_ptr = (void *)(((hdr_val & 0xffff0) << 12) | (hdr_val & 0x000f)); 300 301 buf_val = (unsigned long)ListenBuf; 302 buf_ptr = (void *)(((buf_val & 0xffff0) << 12) | (buf_val & 0x000f)); 303 304 /*------------------------------------------------------------------------ 305 Fill in the ECB 306 ------------------------------------------------------------------------*/ 307 ListenECB->SocketNumber = Socket; 308 ListenECB->PacketCount = 2; 309 ListenECB->Packet[0].Address = hdr_ptr; 310 ListenECB->Packet[0].Length = sizeof(IPXHeaderType); 311 ListenECB->Packet[1].Address = buf_ptr; 312 ListenECB->Packet[1].Length = (unsigned short)PacketLen; 313 314 ((long &)ListenECB->Event_Service_Routine) = Handler; 315 316 /*------------------------------------------------------------------------ 317 Command IPX to listen 318 ------------------------------------------------------------------------*/ 319 rc = IPX_Listen_For_Packet(ListenECB); 320 if (rc!=0) { 321 Close_Socket(Socket); 322 return(false); 323 } else { 324 Listening = 1; 325 return(true); 326 } 327 328 #endif //NOT_FOR_WIN95 329 } /* end of Start_Listening */ 330 331 332 /*************************************************************************** 333 * IPXConnClass::Stop_Listening -- commands IPX to stop listen * 334 * * 335 * INPUT: * 336 * none. * 337 * * 338 * OUTPUT: * 339 * none. * 340 * * 341 * WARNINGS: * 342 * - This routine MUST NOT be called if IPX is not listening already! * 343 * * 344 * HISTORY: * 345 * 12/16/1994 BR : Created. * 346 *=========================================================================*/ 347 bool IPXConnClass::Stop_Listening(void) 348 { 349 /*------------------------------------------------------------------------ 350 Don't do anything unless we're already Listening. 351 ------------------------------------------------------------------------*/ 352 if (Listening==0) 353 return(false); 354 355 #ifndef NOT_FOR_WIN95 356 357 if (Winsock.Get_Connected()){ 358 Listening = 0; 359 return (true); 360 }else{ 361 IPX_Shut_Down95(); 362 Close_Socket(Socket); 363 } 364 365 #else //NOT_FOR_WIN95 366 367 /*------------------------------------------------------------------------ 368 Shut IPX down. 369 ------------------------------------------------------------------------*/ 370 IPX_Cancel_Event(ListenECB); 371 Close_Socket(Socket); 372 373 #endif //NOT_FOR_WIN95 374 375 Listening = 0; 376 377 /*------------------------------------------------------------------------ 378 All done. 379 ------------------------------------------------------------------------*/ 380 return(true); 381 382 } /* end of Stop_Listening */ 383 384 385 /*************************************************************************** 386 * IPXConnClass::Send -- sends a packet; invoked by SequencedConnection * 387 * * 388 * INPUT: * 389 * socket desired socket ID number * 390 * * 391 * OUTPUT: * 392 * 1 = OK, 0 = error * 393 * * 394 * WARNINGS: * 395 * none. * 396 * * 397 * HISTORY: * 398 * 12/16/1994 BR : Created. * 399 *=========================================================================*/ 400 int IPXConnClass::Send(char *buf, int buflen) 401 { 402 /*------------------------------------------------------------------------ 403 Invoke our own Send_To routine, filling in our Address as the destination. 404 ------------------------------------------------------------------------*/ 405 if (Immed_Set) { 406 return(Send_To (buf, buflen, &Address, ImmediateAddress)); 407 } else { 408 return(Send_To (buf, buflen, &Address, NULL)); 409 } 410 411 } /* end of Send */ 412 413 414 /*************************************************************************** 415 * IPXConnClass::Open_Socket -- opens communications socket * 416 * * 417 * INPUT: * 418 * socket desired socket ID number * 419 * * 420 * OUTPUT: * 421 * 1 = OK, 0 = error * 422 * * 423 * WARNINGS: * 424 * none. * 425 * * 426 * HISTORY: * 427 * 12/16/1994 BR : Created. * 428 *=========================================================================*/ 429 int IPXConnClass::Open_Socket(unsigned short socket) 430 { 431 int rc; 432 433 if (Winsock.Get_Connected()){ 434 SocketOpen = 1; 435 return (true); 436 } 437 438 SocketOpen = 0; 439 440 /*------------------------------------------------------------------------ 441 Try to open a listen socket. The socket may have been left open by 442 a previously-crashed program, so ignore the state of the SocketOpen 443 flag for this call; use IPX to determine if the socket was already open. 444 ------------------------------------------------------------------------*/ 445 rc = IPX_Open_Socket(socket); 446 if (rc) { 447 /* 448 ................. If already open, close & reopen it .................. 449 */ 450 if (rc==IPXERR_SOCKET_ERROR) { 451 IPX_Close_Socket(socket); 452 rc = IPX_Open_Socket(socket); 453 /* 454 .................. Still can't open: return error .................. 455 */ 456 if (rc) { 457 return(false); 458 } 459 } 460 } 461 462 SocketOpen = 1; 463 464 return(true); 465 } 466 467 468 /*************************************************************************** 469 * IPXConnClass::Close_Socket -- closes the socket * 470 * * 471 * INPUT: * 472 * socket desired socket ID number * 473 * * 474 * OUTPUT: * 475 * none. * 476 * * 477 * WARNINGS: * 478 * Calling this routine when the sockets aren't open may crash! * 479 * * 480 * HISTORY: * 481 * 12/16/1994 BR : Created. * 482 *=========================================================================*/ 483 void IPXConnClass::Close_Socket(unsigned short socket) 484 { 485 if (Winsock.Get_Connected()){ 486 SocketOpen = 0; 487 return; 488 } 489 /*------------------------------------------------------------------------ 490 Never, ever, ever, under any circumstances whatsoever, close a socket 491 that isn't open. You'll regret it forever (or until at least until you're 492 through rebooting, which, if you're on a Pentium is the same thing). 493 ------------------------------------------------------------------------*/ 494 if (SocketOpen==1) 495 IPX_Close_Socket(socket); 496 497 SocketOpen = 0; 498 499 } /* end of Close_Socket */ 500 501 502 /*************************************************************************** 503 * IPXConnClass::Send_To -- sends the packet to the given address * 504 * * 505 * The "ImmediateAddress" field of the SendECB must be filled in with the * 506 * address of a bridge, or the node address of the destination if there * 507 * is no bridge. The NETX call to find this address will always crash * 508 * if NETX isn't loaded (ConnectionNum is 0), so this case is trapped & * 509 * prevented. * 510 * Also, if the address of this IPX connection is known when the * 511 * constructor is called, and Configure has been called, Get_Local_Target * 512 * is called to precompute the ImmediateAddress; this case is detected & * 513 * if the value is already computed, it's just memcpy'd over. * 514 * * 515 * INPUT: * 516 * buf buffer to send * 517 * buflen length of buffer * 518 * address Address to send to * 519 * immed ImmediateAddress value, NULL if none * 520 * * 521 * OUTPUT: * 522 * 1 = OK, 0 = error * 523 * * 524 * WARNINGS: * 525 * none. * 526 * * 527 * HISTORY: * 528 * 12/16/1994 BR : Created. * 529 *=========================================================================*/ 530 //#pragma off (unreferenced) 531 int IPXConnClass::Send_To(char *buf, int buflen, IPXAddressClass *address, 532 NetNodeType immed) 533 { 534 535 //void *hdr_ptr; 536 //void *buf_ptr; 537 //unsigned long hdr_val; 538 //unsigned long buf_val; 539 NetNumType net; 540 NetNodeType node; 541 int rc; 542 543 //unsigned short target_mask; 544 545 unsigned char send_address[6]; 546 547 if (Winsock.Get_Connected()){ 548 549 #ifdef VIRTUAL_SUBNET_SERVER 550 if (immed){ 551 memcpy(send_address, immed, 6); 552 }else{ 553 address->Get_Address(net,node); 554 memcpy (send_address, node, 6); 555 } 556 /* 557 ** Use first two bytes of ipx address as target mask 558 */ 559 unsigned short *maskptr = (unsigned short*)&send_address[0]; 560 target_mask = *maskptr; 561 562 char *tempsend = new char [buflen + sizeof (target_mask)]; 563 564 *(unsigned short*)tempsend = htons(target_mask); 565 memcpy (tempsend+2, buf, buflen); 566 #if (0) 567 char tempbuf[256]; 568 CommHeaderType *packet = (CommHeaderType *)(&tempsend[2]); 569 static char pcode [4][18]={ 570 "PACKET_DATA_ACK", // this is a data packet requiring an ACK 571 "PACKET_DATA_NOACK", // this is a data packet not requiring an ACK 572 "PACKET_ACK", // this is an ACK for a packet 573 "PACKET_COUNT" // for computational purposes 574 }; 575 576 sprintf (tempbuf, "Sending unicast packet type %d, ID=%d, code=%s, length=%d\n", tempsend[sizeof(CommHeaderType)+2], 577 packet->PacketID, 578 pcode[packet->Code], 579 buflen + sizeof (target_mask)); 580 CCDebugString (tempbuf); 581 #endif //(0) 582 583 Winsock.Write((void*)tempsend, buflen + sizeof (target_mask)); 584 delete [] tempsend; 585 #else // VIRTUAL_SUBNET_SERVER 586 Winsock.Write((void*)buf, buflen); 587 #endif // VIRTUAL_SUBNET_SERVER 588 589 return (true); 590 } 591 592 593 594 if (immed) { 595 memcpy(send_address, immed, 6); 596 //memcpy(node, immed, 6); 597 //memset (net, 0, sizeof(net) ); 598 address->Get_Address(net,node); 599 } else { 600 address->Get_Address(net,node); 601 /*..................................................................... 602 If the user is logged in & has a valid Novell Connection Number, get the 603 bridge address the "official" way 604 .....................................................................*/ 605 if (ConnectionNum != 0) { 606 rc = IPX_Get_Local_Target (net, node, Socket, &send_address[0]); 607 if (rc!=0) { 608 return(false); 609 } 610 } else { 611 /*..................................................................... 612 Otherwise, use the destination node address as the ImmediateAddress, and 613 just hope there's no network bridge in the path. 614 .....................................................................*/ 615 memcpy(send_address,node,6); 616 } 617 } 618 619 return (IPX_Send_Packet95(&send_address[0], (unsigned char*)buf, buflen, (unsigned char*)net, (unsigned char*)node)); 620 621 622 } 623 //#pragma on (unreferenced) 624 625 /*************************************************************************** 626 * IPXConnClass::Broadcast -- broadcasts the given packet * 627 * * 628 * INPUT: * 629 * socket desired socket ID number * 630 * * 631 * OUTPUT: * 632 * 1 = OK, 0 = error * 633 * * 634 * WARNINGS: * 635 * none. * 636 * * 637 * HISTORY: * 638 * 12/16/1994 BR : Created. * 639 *=========================================================================*/ 640 int IPXConnClass::Broadcast(char *buf, int buflen) 641 { 642 643 if (Winsock.Get_Connected()){ 644 #ifdef VIRTUAL_SUBNET_SERVER 645 char *tempsend = new char [buflen + sizeof (unsigned short)]; 646 memcpy (tempsend+2, buf, buflen); 647 *tempsend = 0; 648 *(tempsend+1) = 0; 649 #if (0) 650 char tempbuf[256]; 651 CommHeaderType *packet = (CommHeaderType *)(&tempsend[2]); 652 static char pcode [4][18]={ 653 "PACKET_DATA_ACK", // this is a data packet requiring an ACK 654 "PACKET_DATA_NOACK", // this is a data packet not requiring an ACK 655 "PACKET_ACK", // this is an ACK for a packet 656 "PACKET_COUNT" // for computational purposes 657 }; 658 659 sprintf (tempbuf, "Sending multicast packet type %d, ID=%d, code=%s, length=%d\n", tempsend[sizeof(CommHeaderType)+2], 660 packet->PacketID, 661 pcode[packet->Code], 662 buflen + sizeof (unsigned short)); 663 CCDebugString (tempbuf); 664 #endif //(0) 665 666 Winsock.Write((void*)tempsend, buflen + sizeof (unsigned short)); 667 delete [] tempsend; 668 #else // VIRTUAL_SUBNET_SERVER 669 Winsock.Write((void*)buf, buflen); 670 #endif // VIRTUAL_SUBNET_SERVER 671 return(true); 672 }else{ 673 return (IPX_Broadcast_Packet95((unsigned char*)buf, buflen)); 674 } 675 676 } 677