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