WSPROTO.CPP (31153B)
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/WSProto.cpp $* 23 * * 24 * $Author:: Joe_b $* 25 * * 26 * $Modtime:: 8/20/97 10:54a $* 27 * * 28 * $Revision:: 5 $* 29 * * 30 * * 31 *---------------------------------------------------------------------------------------------* 32 * * 33 * WSProto.CPP WinsockInterfaceClass to provide an interface to Winsock protocols * 34 * * 35 *---------------------------------------------------------------------------------------------* 36 * * 37 * Functions: * 38 * * 39 * WIC::WinsockInterfaceClass -- constructor for the WinsockInterfaceClass * 40 * WIC::~WinsockInterfaceClass -- destructor for the WinsockInterfaceClass * 41 * WIC::Close -- Releases any currently in use Winsock resources. * 42 * WIC::Close_Socket -- Close the communication socket if its open * 43 * WIC::Start_Listening -- Enable callbacks for read/write events on our socket * 44 * WIC::Stop_Listening -- Disable the winsock event callback * 45 * WIC::Discard_In_Buffers -- Discard any packets in our incoming packet holding buffers * 46 * WIC::Discard_In_Buffers -- Discard any packets in our outgoing packet holding buffers * 47 * WIC::Init -- Initialised Winsock and this class for use. * 48 * WIC::Read -- read any pending input from the communications socket * 49 * WIC::WriteTo -- Send data via the Winsock socket * 50 * WIC::Broadcast -- Send data via the Winsock socket * 51 * WIC::Clear_Socket_Error -- Clear any outstanding erros on the socket * 52 * WIC::Set_Socket_Options -- Sets default socket options for Winsock buffer sizes * 53 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 54 55 #include "function.h" 56 #include "WSProto.h" 57 58 #include <stdio.h> 59 60 61 /*********************************************************************************************** 62 * WIC::WinsockInterfaceClass -- constructor for the WinsockInterfaceClass * 63 * * 64 * * 65 * * 66 * INPUT: Nothing * 67 * * 68 * OUTPUT: Nothing * 69 * * 70 * WARNINGS: None * 71 * * 72 * HISTORY: * 73 * 3/20/96 2:51PM ST : Created * 74 *=============================================================================================*/ 75 WinsockInterfaceClass::WinsockInterfaceClass(void) 76 { 77 WinsockInitialised = false; 78 ASync = INVALID_HANDLE_VALUE; 79 Socket = INVALID_SOCKET; 80 } 81 82 83 /*********************************************************************************************** 84 * WIC::~WinsockInterfaceClass -- destructor for the WinsockInterfaceClass * 85 * * 86 * * 87 * * 88 * INPUT: Nothing * 89 * * 90 * OUTPUT: Nothing * 91 * * 92 * WARNINGS: None * 93 * * 94 * HISTORY: * 95 * 3/20/96 2:52PM ST : Created * 96 *=============================================================================================*/ 97 WinsockInterfaceClass::~WinsockInterfaceClass(void) 98 { 99 Close(); 100 } 101 102 103 /*********************************************************************************************** 104 * WIC::Close -- Releases any currently in use Winsock resources. * 105 * * 106 * * 107 * * 108 * INPUT: Nothing * 109 * * 110 * OUTPUT: Nothing * 111 * * 112 * WARNINGS: None * 113 * * 114 * HISTORY: * 115 * 3/20/96 2:52PM ST : Created * 116 *=============================================================================================*/ 117 void WinsockInterfaceClass::Close(void) 118 { 119 /* 120 ** If we never initialised the class in the first place then just return 121 */ 122 if (!WinsockInitialised) return; 123 124 /* 125 ** Cancel any outstaning asyncronous events 126 */ 127 Stop_Listening(); 128 129 /* 130 ** Close any open sockets 131 */ 132 Close_Socket(); 133 134 /* 135 ** Call the Winsock cleanup function to say we are finished using Winsock 136 */ 137 WSACleanup(); 138 139 WinsockInitialised = false; 140 } 141 142 143 144 /*********************************************************************************************** 145 * WIC::Close_Socket -- Close the communication socket if its open * 146 * * 147 * * 148 * * 149 * INPUT: Nothing * 150 * * 151 * OUTPUT: Nothing * 152 * * 153 * WARNINGS: None * 154 * * 155 * HISTORY: * 156 * 8/5/97 11:53AM ST : Created * 157 *=============================================================================================*/ 158 void WinsockInterfaceClass::Close_Socket (void) 159 { 160 if ( Socket != INVALID_SOCKET ) { 161 closesocket (Socket); 162 Socket = INVALID_SOCKET; 163 } 164 } 165 166 167 168 /*********************************************************************************************** 169 * WIC::Start_Listening -- Enable callbacks for read/write events on our socket * 170 * * 171 * * 172 * * 173 * INPUT: Nothing * 174 * * 175 * OUTPUT: Nothing * 176 * * 177 * WARNINGS: None * 178 * * 179 * HISTORY: * 180 * 8/5/97 11:54AM ST : Created * 181 *=============================================================================================*/ 182 bool WinsockInterfaceClass::Start_Listening (void) 183 { 184 /* 185 ** Enable asynchronous events on the socket 186 */ 187 if ( WSAAsyncSelect ( Socket, MainWindow, Protocol_Event_Message(), FD_READ | FD_WRITE) == SOCKET_ERROR ){ 188 WWDebugString ( "TS: Async select failed.\n" ); 189 assert (false); 190 WSACancelAsyncRequest(ASync); 191 ASync = INVALID_HANDLE_VALUE; 192 return (false); 193 } 194 return (true); 195 } 196 197 198 /*********************************************************************************************** 199 * WIC::Stop_Listening -- Disable the winsock event callback * 200 * * 201 * * 202 * * 203 * INPUT: Nothing * 204 * * 205 * OUTPUT: Nothing * 206 * * 207 * WARNINGS: None * 208 * * 209 * HISTORY: * 210 * 8/5/97 12:06PM ST : Created * 211 *=============================================================================================*/ 212 void WinsockInterfaceClass::Stop_Listening (void) 213 { 214 if ( ASync != INVALID_HANDLE_VALUE ) { 215 WSACancelAsyncRequest ( ASync ); 216 ASync = INVALID_HANDLE_VALUE; 217 } 218 } 219 220 221 222 223 /*********************************************************************************************** 224 * WIC::Discard_In_Buffers -- Discard any packets in our incoming packet holding buffers * 225 * * 226 * * 227 * * 228 * INPUT: Nothing * 229 * * 230 * OUTPUT: Nothing * 231 * * 232 * WARNINGS: None * 233 * * 234 * HISTORY: * 235 * 8/5/97 11:55AM ST : Created * 236 *=============================================================================================*/ 237 void WinsockInterfaceClass::Discard_In_Buffers (void) 238 { 239 WinsockBufferType *packet; 240 241 while ( InBuffers.Count() ) { 242 packet = InBuffers [ 0 ]; 243 delete packet; 244 InBuffers.Delete (0); 245 } 246 } 247 248 249 /*********************************************************************************************** 250 * WIC::Discard_In_Buffers -- Discard any packets in our outgoing packet holding buffers * 251 * * 252 * * 253 * * 254 * INPUT: Nothing * 255 * * 256 * OUTPUT: Nothing * 257 * * 258 * WARNINGS: None * 259 * * 260 * HISTORY: * 261 * 8/5/97 11:55AM ST : Created * 262 *=============================================================================================*/ 263 void WinsockInterfaceClass::Discard_Out_Buffers (void) 264 { 265 WinsockBufferType *packet; 266 267 while ( OutBuffers.Count() ) { 268 packet = OutBuffers [ 0 ]; 269 delete packet; 270 OutBuffers.Delete (0); 271 } 272 } 273 274 275 /*********************************************************************************************** 276 * WIC::Init -- Initialised Winsock and this class for use. * 277 * * 278 * * 279 * * 280 * INPUT: Nothing * 281 * * 282 * OUTPUT: true if Winsock is available and was initialised * 283 * * 284 * WARNINGS: None * 285 * * 286 * HISTORY: * 287 * 3/20/96 2:54PM ST : Created * 288 *=============================================================================================*/ 289 bool WinsockInterfaceClass::Init(void) 290 { 291 short version; 292 int rc; 293 294 /* 295 ** Just return true if we are already set up 296 */ 297 if (WinsockInitialised) return (true); 298 299 /* 300 ** Create a buffer much larger than the sizeof (WSADATA) would indicate since Bounds Checker 301 ** says that a buffer of that size gets overrun. 302 */ 303 char *buffer = new char [sizeof (WSADATA) + 1024]; 304 WSADATA *winsock_info = (WSADATA*) (&buffer[0]); 305 306 /* 307 ** Initialise socket and event handle to null 308 */ 309 Socket =INVALID_SOCKET; 310 ASync = INVALID_HANDLE_VALUE; 311 Discard_In_Buffers(); 312 Discard_Out_Buffers(); 313 314 /* 315 ** Start WinSock, and fill in our Winsock info structure 316 */ 317 version = (WINSOCK_MINOR_VER << 8) | WINSOCK_MAJOR_VER; 318 rc = WSAStartup(version, winsock_info); 319 if (rc != 0) { 320 char out[128]; 321 sprintf (out, "TS: Winsock failed to initialise - error code %d.\n", GetLastError() ); 322 OutputDebugString (out); 323 delete [] buffer; 324 return (false); 325 } 326 327 /* 328 ** Check the Winsock version number 329 */ 330 if ((winsock_info->wVersion & 0x00ff) != (version & 0x00ff) || 331 (winsock_info->wVersion >> 8) != (version >> 8)) { 332 OutputDebugString ("TS: Winsock version is less than 1.1\n" ); 333 delete [] buffer; 334 return (false); 335 } 336 337 /* 338 ** Everything is OK so return success 339 */ 340 WinsockInitialised = true; 341 342 delete [] buffer; 343 return (true); 344 345 } 346 347 348 349 350 /*********************************************************************************************** 351 * WIC::Read -- read any pending input from the communications socket * 352 * * 353 * * 354 * * 355 * INPUT: ptr to buffer to receive input * 356 * length of buffer * 357 * ptr to address to fill with address that packet was sent from * 358 * length of address buffer * 359 * * 360 * OUTPUT: number of bytes transfered to buffer * 361 * * 362 * WARNINGS: The format of the address is dependent on the protocol in use. * 363 * * 364 * * 365 * HISTORY: * 366 * 3/20/96 2:58PM ST : Created * 367 *=============================================================================================*/ 368 int WinsockInterfaceClass::Read(void *buffer, int &buffer_len, void *address, int &address_len) 369 { 370 address_len = address_len; 371 /* 372 ** Call the message loop in case there are any outstanding winsock READ messages. 373 */ 374 Keyboard->Check(); 375 376 /* 377 ** If there are no available packets then return 0 378 */ 379 if ( InBuffers.Count() == 0 ) return (0); 380 381 /* 382 ** Get the oldest packet for reading 383 */ 384 int packetnum = 0; 385 WinsockBufferType *packet = InBuffers [packetnum]; 386 387 assert ( buffer_len >= packet->BufferLen ); 388 assert ( address_len >= sizeof (packet->Address) ); 389 390 /* 391 ** Copy the data and the address it came from into the supplied buffers. 392 */ 393 memcpy ( buffer, packet->Buffer, packet->BufferLen ); 394 memcpy ( address, packet->Address, sizeof (packet->Address) ); 395 396 /* 397 ** Return the length of the packet in buffer_len. 398 */ 399 buffer_len = packet->BufferLen; 400 401 /* 402 ** Delete the temporary storage for the packet now that it is being passed to the game. 403 */ 404 InBuffers.Delete ( packetnum ); 405 delete packet; 406 407 return ( buffer_len ); 408 } 409 410 411 412 413 /*********************************************************************************************** 414 * WIC::WriteTo -- Send data via the Winsock socket * 415 * * 416 * * 417 * * 418 * INPUT: ptr to buffer containing data to send * 419 * length of data to send * 420 * address to send data to. * 421 * * 422 * OUTPUT: Nothing * 423 * * 424 * WARNINGS: The format of the address is dependent on the protocol in use. * 425 * * 426 * HISTORY: * 427 * 3/20/96 3:00PM ST : Created * 428 *=============================================================================================*/ 429 void WinsockInterfaceClass::WriteTo(void *buffer, int buffer_len, void *address) 430 { 431 /* 432 ** Create a temporary holding area for the packet. 433 */ 434 WinsockBufferType *packet = new WinsockBufferType; 435 436 /* 437 ** Copy the packet into the holding buffer. 438 */ 439 memcpy ( packet->Buffer, buffer, buffer_len ); 440 packet->BufferLen = buffer_len; 441 packet->IsBroadcast = false; 442 // memcpy ( packet->Address, address, sizeof (packet->Address) ); 443 memcpy ( packet->Address, address, sizeof( IPXAddressClass ) ); // Steve Tall has revised WriteTo due to this bug. 444 445 /* 446 ** Add it to our out list. 447 */ 448 OutBuffers.Add ( packet ); 449 450 /* 451 ** Send a message to ourselves so that we can initiate a write if Winsock is idle. 452 */ 453 SendMessage ( MainWindow, Protocol_Event_Message(), 0, (LONG)FD_WRITE ); 454 455 /* 456 ** Make sure the message loop gets called. 457 */ 458 Keyboard->Check(); 459 } 460 461 462 463 464 /*********************************************************************************************** 465 * WIC::Broadcast -- Send data via the Winsock socket * 466 * * 467 * * 468 * * 469 * INPUT: ptr to buffer containing data to send * 470 * length of data to send * 471 * * 472 * OUTPUT: Nothing * 473 * * 474 * WARNINGS: None * 475 * * 476 * HISTORY: * 477 * 3/20/96 3:00PM ST : Created * 478 *=============================================================================================*/ 479 void WinsockInterfaceClass::Broadcast (void *buffer, int buffer_len) 480 { 481 482 /* 483 ** Create a temporary holding area for the packet. 484 */ 485 WinsockBufferType *packet = new WinsockBufferType; 486 487 /* 488 ** Copy the packet into the holding buffer. 489 */ 490 memcpy ( packet->Buffer, buffer, buffer_len ); 491 packet->BufferLen = buffer_len; 492 493 /* 494 ** Indicate that this packet should be broadcast. 495 */ 496 packet->IsBroadcast = true; 497 498 /* 499 ** Add it to our out list. 500 */ 501 OutBuffers.Add ( packet ); 502 503 /* 504 ** Send a message to ourselves so that we can initiate a write if Winsock is idle. 505 */ 506 SendMessage ( MainWindow, Protocol_Event_Message(), 0, (LONG)FD_WRITE ); 507 508 /* 509 ** Make sure the message loop gets called. 510 */ 511 Keyboard->Check(); 512 } 513 514 515 516 517 /*********************************************************************************************** 518 * WIC::Clear_Socket_Error -- Clear any outstanding erros on the socket * 519 * * 520 * * 521 * * 522 * INPUT: Socket * 523 * * 524 * OUTPUT: Nothing * 525 * * 526 * WARNINGS: None * 527 * * 528 * HISTORY: * 529 * 8/5/97 12:05PM ST : Created * 530 *=============================================================================================*/ 531 void WinsockInterfaceClass::Clear_Socket_Error(SOCKET socket) 532 { 533 unsigned long error_code; 534 int length = 4; 535 536 getsockopt (socket, SOL_SOCKET, SO_ERROR, (char*)&error_code, &length); 537 error_code = 0; 538 setsockopt (socket, SOL_SOCKET, SO_ERROR, (char*)&error_code, length); 539 } 540 541 542 543 544 545 546 547 /*********************************************************************************************** 548 * WIC::Set_Socket_Options -- Sets default socket options for Winsock buffer sizes * 549 * * 550 * * 551 * * 552 * INPUT: Nothing * 553 * * 554 * OUTPUT: Nothing * 555 * * 556 * WARNINGS: None * 557 * * 558 * HISTORY: * 559 * 8/5/97 12:07PM ST : Created * 560 *=============================================================================================*/ 561 bool WinsockInterfaceClass::Set_Socket_Options ( void ) 562 { 563 static int socket_transmit_buffer_size = SOCKET_BUFFER_SIZE; 564 static int socket_receive_buffer_size = SOCKET_BUFFER_SIZE; 565 566 /* 567 ** Specify the size of the receive buffer. 568 */ 569 int err = setsockopt ( Socket, SOL_SOCKET, SO_RCVBUF, (char*)&socket_receive_buffer_size, 4); 570 if ( err == INVALID_SOCKET ) { 571 char out[128]; 572 sprintf (out, "TS: Failed to set IPX socket option SO_RCVBUF - error code %d.\n", GetLastError() ); 573 OutputDebugString (out); 574 assert ( err != INVALID_SOCKET ); 575 } 576 577 /* 578 ** Specify the size of the send buffer. 579 */ 580 err = setsockopt ( Socket, SOL_SOCKET, SO_SNDBUF, (char*)&socket_transmit_buffer_size, 4); 581 if ( err == INVALID_SOCKET ) { 582 char out[128]; 583 sprintf (out, "TS: Failed to set IPX socket option SO_SNDBUF - error code %d.\n", GetLastError() ); 584 OutputDebugString (out); 585 assert ( err != INVALID_SOCKET ); 586 } 587 588 return ( true ); 589 } 590 591