| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446 |
- //
- // Copyright 2020 Electronic Arts Inc.
- //
- // TiberianDawn.DLL and RedAlert.dll and corresponding source code is free
- // software: you can redistribute it and/or modify it under the terms of
- // the GNU General Public License as published by the Free Software Foundation,
- // either version 3 of the License, or (at your option) any later version.
- // TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed
- // in the hope that it will be useful, but with permitted additional restrictions
- // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT
- // distributed with this program. You should have received a copy of the
- // GNU General Public License along with permitted additional restrictions
- // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
- /***********************************************************************************************
- *** 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 ***
- ***********************************************************************************************
- * *
- * Project Name : Command & Conquer *
- * *
- * $Archive:: /Sun/WSPIPX.cpp $*
- * *
- * $Author:: Joe_b $*
- * *
- * $Modtime:: 8/20/97 10:54a $*
- * *
- * $Revision:: 6 $*
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * *
- * IPXInterfaceClass::IPXInterfaceClass -- Class constructor *
- * IPXInterfaceClass::Get_Network_Card_Address -- Get the ID of the installed net card *
- * IPXInterfaceClass::Open_Socket -- Opens an IPX socket for reading & writing *
- * IPXInterfaceClass::Message_Handler -- Handler for windows messages relating to IPX *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- #include "function.h"
- #include "wspipx.h"
- #include "ipxaddr.h"
- #include <assert.h>
- #include <stdio.h>
- /***********************************************************************************************
- * IPXInterfaceClass::IPXInterfaceClass -- Class constructor *
- * *
- * *
- * *
- * INPUT: Nothing *
- * *
- * OUTPUT: Nothing *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 8/4/97 11:41AM ST : Created *
- *=============================================================================================*/
- IPXInterfaceClass::IPXInterfaceClass (void) : WinsockInterfaceClass()
- {
- /*
- ** Set the net and node addressed to their default values.
- */
- memset ( BroadcastNet, 0xff, sizeof (BroadcastNet) );
- memset ( BroadcastNode, 0xff, sizeof (BroadcastNode) );
- memset ( MyNode, 0xff, sizeof (MyNode) );
- }
- /***********************************************************************************************
- * IPXInterfaceClass::Get_Network_Card_Address -- Get the ID of the installed net card *
- * *
- * *
- * *
- * INPUT: card number to retrieve ID for *
- * ptr to addr to return ID in *
- * *
- * OUTPUT: Nothing *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 8/1/97 3:04PM ST : Created *
- *=============================================================================================*/
- bool IPXInterfaceClass::Get_Network_Card_Address (int card_number, SOCKADDR_IPX *addr)
- {
- int cbOpt;
- int cbAddr = sizeof( SOCKADDR_IPX );
- SOCKET s;
- SOCKADDR_IPX Addr;
- IPX_ADDRESS_DATA IpxData;
- /*
- ** Create a temporary IPX socket.
- */
- s = socket( AF_IPX, SOCK_DGRAM, NSPROTO_IPX );
- if ( s == SOCKET_ERROR ) {
- assert ( s != SOCKET_ERROR );
- return (false);
- }
- /*
- ** Socket must be bound prior to calling IPX_MAX_ADAPTER_NUM
- */
- memset( &Addr, 0, sizeof( Addr ));
- Addr.sa_family = AF_IPX;
- int err = bind( s, (SOCKADDR*) &Addr, cbAddr);
- if ( err == SOCKET_ERROR ) {
- assert ( err != SOCKET_ERROR );
- closesocket (s);
- return (false);
- }
- memset( &IpxData, 0, sizeof(IpxData));
- /*
- ** Specify which adapter to check.
- */
- IpxData.adapternum = card_number;
- cbOpt = sizeof( IpxData );
- /*
- ** Get information for the current adapter.
- */
- err = getsockopt( s, NSPROTO_IPX, IPX_ADDRESS, (char*) &IpxData, &cbOpt );
- if ( err == SOCKET_ERROR ) {
- assert ( err != SOCKET_ERROR );
- closesocket (s);
- return (false);
- }
- /*
- ** IpxData contains the address for the current adapter.
- ** The network number will be needed later for broadcasts as the net number ff,ff,ff,ff
- ** doesn't work under NT.
- **
- ** Note: Due to a bug in Win95s implementation of Winsock, only the netnum & nodenum
- ** values are correctly returned. NT returns all expected values. ST - 7/31/97 0:57AM
- */
- memcpy (addr->sa_netnum, IpxData.netnum, sizeof (addr->sa_netnum));
- memcpy (BroadcastNet, IpxData.netnum, sizeof (addr->sa_netnum));
- memcpy (addr->sa_nodenum, IpxData.nodenum, sizeof (addr->sa_nodenum));
- closesocket (s);
- return (true);
- }
- /***********************************************************************************************
- * IPXInterfaceClass::Open_Socket -- Opens an IPX socket for reading & writing *
- * *
- * *
- * *
- * INPUT: SOCKET number to open. This is usually VIRGIN_SOCKET *
- * *
- * OUTPUT: true if socket was opened without error *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 8/4/97 5:54PM ST : Created *
- *=============================================================================================*/
- bool IPXInterfaceClass::Open_Socket( SOCKET socketnum )
- {
- SOCKADDR_IPX addr;
- bool delay = true;
- int err;
- /*
- ** If Winsock is not initialised then do it now.
- */
- if ( !WinsockInitialised ) {
- if ( !Init()) return ( false );;
- }
- IPXSocketNumber = socketnum;
- /*
- ** Set up the addr structure for the IPX socket
- */
- addr.sa_family = AF_IPX;
- memset (addr.sa_netnum, 0, sizeof (addr.sa_netnum));
- memset (addr.sa_nodenum, -1, sizeof (addr.sa_nodenum));
- addr.sa_socket = htons ( socketnum );
- /*
- ** Create the socket.
- */
- Socket = socket (AF_NS, SOCK_DGRAM, NSPROTO_IPX);
- if (Socket == INVALID_SOCKET) {
- char out[128];
- sprintf (out, "TS: Failed to create IPX socket - error code %d.\n", GetLastError() );
- OutputDebugString (out);
- assert ( Socket != INVALID_SOCKET );
- closesocket(Socket);
- return ( false );
- }
- /*
- ** Get the network card address. This is needed so we can bind the socket to the net card.
- */
- if ( !Get_Network_Card_Address (0, &addr)){
- closesocket ( Socket );
- return ( false );
- }
- /*
- ** Bind the IPX socket to the network card.
- */
- if (bind ( Socket, (const struct sockaddr *) &addr, 16) == SOCKET_ERROR ){
- char out[128];
- sprintf (out, "TS: IPX socket bind failed with error code %d.\n", GetLastError() );
- OutputDebugString (out);
- assert ( false );
- closesocket(Socket);
- return ( false );;
- }
- /*
- ** Set the various options for this IPX socket
- */
- unsigned long optval = true;
- int packet_type = 4;
- /*
- ** The SO_BROADCAST option allows broadcasting on this socket. This shouldn't be needed
- ** except for the bug in the Win95 implementation of Winsock which causes broadcasts to
- ** fail if it isn't set.
- */
- if ( setsockopt ( Socket, SOL_SOCKET, SO_BROADCAST, (char*)&optval, sizeof(optval) ) == SOCKET_ERROR ) {
- char out[128];
- sprintf (out, "TS: Failed to set IPX socket option SO_BROADCAST - error code %d.\n", GetLastError() );
- OutputDebugString (out);
- assert ( false );
- }
- /*
- ** Set the value in the packet type field for outgoing packets.
- */
- err = setsockopt ( Socket, NSPROTO_IPX, IPX_PTYPE, (char*)&packet_type, sizeof(packet_type));
- if ( err == INVALID_SOCKET ) {
- char out[128];
- sprintf (out, "TS: Failed to set IPX protocol option IPX_PTYPE - error code %d.\n", GetLastError() );
- OutputDebugString (out);
- assert ( err != INVALID_SOCKET );
- }
- /*
- ** Ignore all incoming packets not of this type.
- */
- err = setsockopt ( Socket, NSPROTO_IPX, IPX_FILTERPTYPE, (char*)&packet_type, sizeof(packet_type));
- if ( err == INVALID_SOCKET ) {
- char out[128];
- sprintf (out, "TS: Failed to set IPX protocol option IPX_FILTERTYPE - error code %d.\n", GetLastError() );
- OutputDebugString (out);
- assert ( err != INVALID_SOCKET );
- }
- /*
- ** Set the the base class socket options for buffer sizes.
- */
- WinsockInterfaceClass::Set_Socket_Options();
- /*
- ** Woohoo!
- */
- return ( true );
- }
- /***********************************************************************************************
- * IPXInterfaceClass::Message_Handler -- Handler for windows messages relating to IPX *
- * *
- * *
- * *
- * INPUT: Usual windoze message handler stuff *
- * *
- * OUTPUT: 0 if message was handled *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 8/4/97 5:55PM ST : Created *
- *=============================================================================================*/
- long IPXInterfaceClass::Message_Handler(HWND , UINT message, UINT , LONG lParam)
- {
- int addr_len; // Length of address structure
- int rc; // Result code
- SOCKADDR_IPX addr; // Winsock IPX addressing structure
- WinsockBufferType *packet; // Ptr to packet
- NetNumType netnum;
- NetNodeType nodenum;
- /*
- ** We only handle IPX events.
- */
- if ( message != WM_IPXASYNCEVENT ) return ( 1 );
- switch ( WSAGETSELECTEVENT(lParam) ) {
- /*
- ** Read event. Winsock has data it would like to give us.
- */
- case FD_READ:
- /*
- ** Clear any outstanding errors on the socket.
- */
- rc = WSAGETSELECTERROR(lParam);
- if (rc != 0) {
- Clear_Socket_Error (Socket);
- return(0);
- }
- /*
- ** Call the Winsock recvfrom function to get the outstanding packet.
- */
- addr_len = sizeof(addr);
- rc = recvfrom ( Socket, (char*) ReceiveBuffer, sizeof (ReceiveBuffer), 0, (LPSOCKADDR)&addr, &addr_len );
- if (rc == SOCKET_ERROR) {
- if (WSAGetLastError() != WSAEWOULDBLOCK) {
- Clear_Socket_Error (Socket);
- }
- return(0);
- }
- /*
- ** rc is the number of bytes received from Winsock
- */
- if ( rc ) {
- /*
- ** Make a copy of the address that this packet came from.
- */
- memcpy ( netnum, addr.sa_netnum, sizeof (netnum) );
- memcpy ( nodenum, addr.sa_nodenum, sizeof (nodenum) );
- /*
- ** If this packet was from me then ignore it.
- */
- if ( !memcmp (netnum, BroadcastNet, sizeof (BroadcastNet)) && !memcmp(nodenum, MyNode, sizeof (MyNode)) ) {
- return (0);
- }
- /*
- ** Create a new buffer and store this packet in it.
- */
- packet = new WinsockBufferType;
- packet->BufferLen = rc;
- memcpy ( packet->Buffer, ReceiveBuffer, rc );
- IPXAddressClass *paddress = (IPXAddressClass*) (&packet->Address[0]);
- paddress->Set_Address ( netnum, nodenum );
- InBuffers.Add ( packet );
- }
- return(0);
- /*
- ** Write event. We send ourselves this event when we have more data to send. This
- ** event will also occur automatically when a packet has finished being sent.
- */
- case FD_WRITE:
- /*
- ** Clear any outstanding erros on the socket.
- */
- rc = WSAGETSELECTERROR(lParam);
- if (rc != 0) {
- Clear_Socket_Error ( Socket );
- return(0);
- }
- /*
- ** If there are no packets waiting to be sent then bail.
- */
- while ( OutBuffers.Count() != 0 ) {
- int packetnum = 0;
- /*
- ** Get a pointer to the packet.
- */
- packet = OutBuffers [ packetnum ];
- /*
- ** Set up the address structure of the outgoing packet
- */
- addr.sa_family = AF_IPX;
- addr.sa_socket = htons ( IPXSocketNumber );
- /*
- ** Set up the address as either a broadcast address or the given address
- */
- if ( packet->IsBroadcast ) {
- memcpy ( addr.sa_netnum, BroadcastNet, sizeof (BroadcastNet) );
- memcpy ( addr.sa_nodenum, BroadcastNode, sizeof (BroadcastNode) );
- }else{
- IPXAddressClass *paddress = (IPXAddressClass*) (&packet->Address[0]);
- paddress->Get_Address ( netnum, nodenum );
- memcpy ( addr.sa_netnum, netnum, sizeof (netnum) );
- memcpy ( addr.sa_nodenum, nodenum, sizeof (nodenum) );
- }
- /*
- ** Send it.
- ** If we get a WSAWOULDBLOCK error it means that Winsock is unable to accept the packet
- ** at this time. In this case, we clear the socket error and just exit. Winsock will
- ** send us another WRITE message when it is ready to receive more data.
- */
- rc = sendto ( Socket, (const char*) packet->Buffer, packet->BufferLen, 0, (LPSOCKADDR)&addr, sizeof (addr) );
- if (rc == SOCKET_ERROR){
- if (WSAGetLastError() != WSAEWOULDBLOCK) {
- Clear_Socket_Error (Socket);
- break;
- }
- }
- /*
- ** Delete the sent packet.
- */
- OutBuffers.Delete ( packetnum );
- delete packet;
- }
- return(0);
- }
- return (0);
- }
|