//===========================================================================// // File: l4net.hh // // Project: MUNGA Brick: Network Manager // // Contents: Interface specification for network brick // //---------------------------------------------------------------------------// // Date Who Modification // // -------- --- ---------------------------------------------------------- // // 03/02/95 GAC Initial coding. // //---------------------------------------------------------------------------// // Copyright (C) 1994-1995, Virtual World Entertainment, Inc. // // PROPRIETARY AND CONFIDENTIAL // //===========================================================================// #pragma once #include "l4host.h" #include "..\munga\network.h" #include "..\munga\hostmgr.h" //WinSock support :ADB 01/06/07 //#include "..\munga\netnub.h" #define NETNUB_TCP_OPEN 3 // Opens a TCP stream to another computer #define NETNUB_TCP_LISTEN 4 // Queue's a TCP listen that we can accept a connection on #define MULTIPLE_SEND_PACKET_MAX 10 #define MAX_RECEIVE_DATA_SIZE 1600 #include #include class NotationFile; class L4NetworkManager__ReceiveEggFileMessage; class L4NetworkManager__AcknowledgeEggFileMessage; class L4NetworkManager__HostConnectedMessage; class L4NetworkManager__HostDisconnectedMessage; class NetNub { friend int Netnub_Open_File( const char* filename, int access, unsigned int model ); friend int Netnub_Write_File( int handle, void *buffer, size_t length ); friend int Netnub_Close_File(int handle); public: //WinSock support :ADB 01/06/07 //static void SendCommand(); }; //extern Netcom_Ptr // Net_Common_Ptr; //~~~~~~~~~~~~~~~~~~~~~ MessageQueue__SendRequest ~~~~~~~~~~~~~~~~~~~~~~~~~~ class MessageQueue__SendRequest: public Plug { friend class HostMessageBuffer__MessageQueue; friend class L4NetworkManager__MessageBuffer; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Private methods // private: MessageQueue__SendRequest( NetworkClient::ClientID client_ID, Receiver::Message *message ); ~MessageQueue__SendRequest(); Logical TestInstance() const; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Private data // private: NetworkClient::ClientID clientID; Receiver::Message *messageToSend; }; //~~~~~~~~~~~~~~~~~~~ HostMessageBuffer__MessageQueue ~~~~~~~~~~~~~~~~~~~~~~ class HostMessageBuffer__MessageQueue: public Node { friend class L4NetworkManager__MessageBuffer; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Private methods // private: HostMessageBuffer__MessageQueue(HostID host_ID); ~HostMessageBuffer__MessageQueue(); Logical TestInstance() const; void AddSendRequest( NetworkClient::ClientID client_ID, Receiver::Message *message ); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Private data // private: HostID hostID; typedef MessageQueue__SendRequest SendRequest; ChainOf sendRequestSocket; }; //~~~~~~~~~~~~~~~~~~ L4NetworkManager__MessageBuffer ~~~~~~~~~~~~~~~~~~~~~~~ class L4NetworkManager__MessageBuffer: public Node { //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Public methods // public: L4NetworkManager__MessageBuffer(L4NetworkManager *network_manager); ~L4NetworkManager__MessageBuffer(); Logical TestInstance() const; Logical IsEmpty(); void AddSendRequest( HostID host_ID, NetworkClient::ClientID client_ID, Receiver::Message *message ); void AttemptToSend(); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Private data // private: L4NetworkManager *networkManager; typedef HostMessageBuffer__MessageQueue MessageQueue; TableOf messageQueueSocket; IteratorPosition currentQueueIndex; CollectionSize bufferSize; #ifdef LAB_ONLY CollectionSize messageCount, maxBufferSize; #endif }; inline Logical L4NetworkManager__MessageBuffer::IsEmpty() { Check(this); return (bufferSize == 0); } //~~~~~~~~~~~~~~~~~~~~~~~~~~ l4Network manager~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class L4NetworkManager: public NetworkManager { friend class L4NetworkManager__MessageBuffer; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Constructor, Destructor, Testing // public: L4NetworkManager(); ~L4NetworkManager(); static Logical TestClass(); Logical TestInstance() const; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Network message methods // public: void Send( Message *what, ClientID to, HostID host_ID); void ExclusiveBroadcast( Message *what, ClientID to); void StartConnecting(Mission *mission); Logical Shutdown(); Logical CheckBuffers(NetworkPacket *packet); void RemovePacket(NetworkPacket *packet); Logical ExecuteBackground(); void Marker(char *marker_text); void Mode(NetworkMode myMode); void CreateConsoleHost(); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Network maintenance support // public: int netPlayerCount; enum NetworkState { NormalState, ConsoleOnly }; enum NetworkStartupMode { SlaveMode, MasterMode }; bool CheckSocket(SOCKET socket, SOCKADDR_IN *remoteEndpoint); bool ResolveAddress(CString host_name, SOCKADDR_IN *address); //WinSock support :ADB 01/06/07 NetworkAddress* GetMyAddress(); //WinSock support :ADB 01/06/07 SOCKET OpenConnection( int connection_type, // NETNUB_TCP_LISTEN or NETNUB_TCP_OPEN int local_port, int remote_port, int internet_address); void CloseConnection(SOCKET socket_ptr); // socket address from netnub (to close) Logical GetNextMungaPacket( NetworkPacket *network_packet, HostManager::RemoteHostIterator* all_iterator); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Shared Data support // public: static Derivation *GetClassDerivations(); static SharedData DefaultData; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Message Support // public: // // Message IDs // enum { AcknowledgeEggFileMessageID = NetworkManager::NextMessageID, HostConnectedMessageID, HostDisconnectedMessageID, NextMessageID }; // // Message types // typedef L4NetworkManager__AcknowledgeEggFileMessage AcknowledgeEggFileMessage; typedef L4NetworkManager__HostConnectedMessage HostConnectedMessage; typedef L4NetworkManager__HostDisconnectedMessage HostDisconnectedMessage; // // Message table // static const HandlerEntry MessageHandlerEntries[]; //static MessageHandlerSet MessageHandlers; static MessageHandlerSet& GetMessageHandlers(); void ReceiveEggFileMessageHandler( ReceiveEggFileMessage *EggMessage); void AcknowledgeEggFileMessageHandler( AcknowledgeEggFileMessage *AcknowledgeEgg); void HostConnectedMessageHandler( HostConnectedMessage *HostConnected); void HostDisconnectedMessageHandler( HostDisconnectedMessage *ConsoleDisconnect); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Private methods // private: typedef ChainOf DroppedMessageHostSocket; typedef ChainIteratorOf DroppedMessageHostIterator; Logical SendMessageToNetnub( Message *message, ClientID client_ID, HostID host_ID ); void SendBatchedMessageToNetnub( Message *message, ClientID client, DroppedMessageHostSocket *dropped_message_host_socket ); // // D1 RELAY MODE (BT_RELAY=host:port + BT_SELF=<[pilots] entry>): outbound- // only topology -- the pod dials the relay (extended btconsole.py) for BOTH // the console protocol (egg/launch; legacy raw frames, direction flipped) // and the game traffic (envelope-framed, one TCP connection multiplexing // every peer; UDP for the unreliable channel in a later phase). BT_RELAY // unset => relayMode False => every relay branch is dead and the classic // mesh is untouched. // Logical RelayDiscover(SOCKADDR_IN *console_endpoint); Logical RelayRequestSeat(); SOCKET RelayDialTcp(const SOCKADDR_IN &endpoint, int timeout_seconds); Logical RelaySendAll(SOCKET sock, const char *buffer, int length); NetworkPacket * BuildRelayPacket(Message *message, ClientID client, int *packet_size); Logical RelaySendFrame(int route, const NetworkPacket *packet, int packet_size); void ConnectRelayGame(HostID local_host_ID); void RelayGameDown(const char *why); Logical CheckRelay(NetworkPacket *network_packet); // // UDP unreliable channel (restores the 1995 NETNUB reliable/unreliable // split): the ~60Hz update records ride UDP so a lost/late datagram is // dropped (dead reckoning absorbs the gap) instead of head-of-line- // blocking the reliable stream. Reliable traffic + control stay on TCP. // void ConnectRelayUdp(HostID local_host_ID); Logical RelayUdpSendFrame(int route, const NetworkPacket *packet, int packet_size); void RelayUdpKeepalive(HostID local_host_ID); Logical RelayShouldUseUdp(const Message *message) const; Logical CheckRelayUdp(NetworkPacket *network_packet); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Private Data // private: int numberOfMungaHostsConnected, numberOfConsoleHostsConnected, remoteHostCount; NetworkStartupMode networkStartupMode; Logical eggAcknowledged; NetworkState currentNetworkState; L4Host *myConsoleHost; HostID nextOpenHostID; IteratorPosition lastHostIteratorPosition; typedef L4NetworkManager__MessageBuffer MessageBuffer; MessageBuffer messageBuffer; //WinSock Support WSADATA* wsaData; //hostent* thisHost; addrinfo* thisHost; SOCKET gameListenerSocket; SOCKET consoleListenerSocket; // D1 relay mode state (see the private-methods block above). All inert // unless BT_RELAY is set. Logical relayMode; char relaySelf[64]; // BT_SELF -- our [pilots] entry string SOCKADDR_IN relayConsoleAddress; // relay console endpoint (BT_RELAY port) SOCKADDR_IN relayGameAddress; // relay game endpoint (port + 1, tcp+udp) SOCKET relayGameSocket; // the ONE multiplexed game connection SOCKET relayUdpSocket; // unreliable channel (later phase) char relayPad[16384]; // relay-connection reassembly buffer int relayPadTail; Logical relayConsoleDialedOnce; // first dial gets the long timeout Logical udpUp; // UDP HELLO acked by the relay HostID relayLocalHostID; // our hostID (for UDP HELLO/keepalive/tx) unsigned long lastUdpKeepaliveTick; unsigned long lastUdpHelloTick; // HELLO retry until acked unsigned long udpTxSeq; unsigned long udpRxSeq[64]; // per-fromHost last-seen sequence NetworkMode currentNetworkMode; // Reliable/Unreliable (Mode() stores) }; //~~~~~~~~~~~~~~~~~~~~~~ L4NetworkManager inlines ~~~~~~~~~~~~~~~~~~~~~~~~~~ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // L4NetworkManager__AcknowledgeEggFileMessage // This message is sent back to the console to acknowledge receipt of the // egg, it indicates this computer has established all it's connections and // the console can procede with the next host // class L4NetworkManager__AcknowledgeEggFileMessage: public NetworkManager::Message { public: L4NetworkManager__AcknowledgeEggFileMessage(): NetworkManager::Message( L4NetworkManager::AcknowledgeEggFileMessageID, sizeof(L4NetworkManager__AcknowledgeEggFileMessage) ){} }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // L4NetworkManager__HostConnectedMessage // This message is generated internally by CheckBuffers and indicates that // a host has connected up to us. This is an INTERNAL message only and is // not ment to be sent on the network. class L4NetworkManager__HostConnectedMessage : public NetworkManager::Message { public: L4NetworkManager__HostConnectedMessage(HostID host_id, const SOCKADDR_IN &network_address, unsigned long stream_pointer) : NetworkManager::Message(L4NetworkManager::HostConnectedMessageID, sizeof(L4NetworkManager__HostConnectedMessage)), hostID(host_id), networkAddress(network_address), streamPointer(stream_pointer) { } HostID hostID; SOCKADDR_IN networkAddress; unsigned long streamPointer; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // L4NetworkManager__HostDisconnectedMessage // The console is expected to send us this message if it disconnects from us // for any reason. This allows the local host to setup the internal state // so the game will auto start even if the console can't stay connected to us // for some reason (for example, the console simulator in the game code can't // connect to more than one host at once). // !!! CheckBuffers should poll the connection state of all the streams and // generate this message automatically whenever a host drops off the net. // !!! HACK At the moment this message is always treated as if it came from // the console host, so it should only be sent down the console stream. // class L4NetworkManager__HostDisconnectedMessage : public NetworkManager::Message { public: L4NetworkManager__HostDisconnectedMessage(HostID host_id, unsigned long stream_pointer) : NetworkManager::Message(L4NetworkManager::HostDisconnectedMessageID, sizeof(L4NetworkManager__HostDisconnectedMessage)), hostID(host_id), streamPointer(stream_pointer) { } HostID hostID; unsigned long streamPointer; };