/* ************************************************************************* ArmageTron -- Just another Tron Lightcycle Game in 3D. Copyright (C) 2000 Manuel Moos (manuel@moosnet.de) ************************************************************************** This program 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 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *************************************************************************** */ #ifndef ArmageTron_NET_H #define ArmageTron_NET_H #include "tString.h" #include "tHeap.h" #include "tLinkedList.h" #include "tCallback.h" #include "nObserver.h" //#include "tCrypt.h" class nMessage; class tCrypt; class tOutput; typedef double nTimeAbsolute; // typedef for absolute time variables in network code typedef double nTimeRolling; // typedef for time variables in network code that don't have to measure large time differences extern tString sn_bigBrotherString; // the string that is sent // to the server for system information // message of day presented to clients logging in; consists of four lines extern tString sn_greeting[5]; extern tString sn_programVersion; // our version extern tString sn_serverName; // telling name of the server extern unsigned int sn_serverPort; // port we listen on when in server mode extern unsigned int sn_clientPort; // port we try to connect to in client mode extern int sn_defaultDelay; extern tString sn_DenyReason; // the reason the server gave for sending a login_deny packet // rate control extern int sn_maxRateIn,sn_maxRateOut; // exception that is thrown on any unexpected network error; // causes the owner of the current nNetObject or the sender of // the currently processed netmessage to be killed. class nKillHim{ public: nKillHim(){}; }; // call this function on any error occuring while reading a message: void nReadError(); #define MAXCLIENTS 16 // We can be single player, multiplayer server/client. typedef enum {nSTANDALONE,nSERVER,nCLIENT} nNetState; typedef enum {nOK, nTIMEOUT, nDENIED} nConnectError; // set/get the state nConnectError sn_GetLastError(); nNetState sn_GetNetState(); void sn_SetNetState(nNetState x); void sn_KillUser(int i, const tOutput& reason ); void sn_GetAdr(int user, tString& name); unsigned int sn_GetPort(int user); unsigned int sn_GetServerPort(); int sn_NumUsers(); int sn_MaxUsers(); int sn_MessagesPending(int user); // information about currently supported versions class nVersion { public: nVersion(); nVersion( int min, int max ); bool Supported( int version ) const; // check if a particular version is supported bool Merge( const nVersion& a, const nVersion& b); // merges two versions to one; the new version supports only features both versions understand. false is returned if no common denominator could be found int Min() const { return min_;} int Max() const { return max_;} bool operator != ( const nVersion& other ){ return !operator==(other); } bool operator == ( const nVersion& other ); nVersion& operator = ( const nVersion& other ); private: int min_, max_; }; nMessage& operator >> ( nMessage& m, nVersion& ver ); nMessage& operator << ( nMessage& m, const nVersion& ver ); std::istream& operator >> ( std::istream& s, nVersion& ver ); std::ostream& operator << ( std::ostream& s, const nVersion& ver ); const nVersion& sn_MyVersion(); // the version this progam maximally supports const nVersion& sn_CurrentVersion(); // the version currently supported by all connected players // features that are not available in all currently supported versions class nVersionFeature { public: nVersionFeature( int min, int max = -1 ); // creates a feature that is supported from version min to max; values of -1 indicate no border bool Supported(); private: int min_, max_; }; struct sockaddr; class nBandwidthControl; // send buffer: stores network messages temporarily before really sending them class nSendBuffer { public: int Len () const { return sendBuffer_.Len(); } // returns the length of the buffer void AddMessage ( nMessage& message , nBandwidthControl* control ); // adds a message to the buffer void Send ( int socket , const sockaddr& peer , nBandwidthControl* control ); // send the contents of the buffer to a specific socket void Broadcast ( int socket , int port , nBandwidthControl* control ); // broadcast the contents of the buffer void Clear(); // clears the buffer private: tArray sendBuffer_; }; class nBandwidthControl { public: enum Usage { Usage_Planning, Usage_Execution }; nBandwidthControl( nBandwidthControl* parent = NULL ); ~nBandwidthControl(); void Reset(); void SetRate( unsigned short rate ){ rate_ = rate; } unsigned short Rate() { return rate_; } REAL Control( Usage planned ){ return Usage_Planning == planned ? rateControlPlanned_ : rateControl_;} void Use( Usage planned, REAL bandwidth ) { ( Usage_Planning == planned ? rateControlPlanned_ : rateControl_ ) -= bandwidth; } bool CanSend(){ return rateControlPlanned_ > 0; } REAL Score(){ return rateControlPlanned_ / rate_; } void Update( REAL ts); private: REAL rateControlPlanned_; REAL rateControl_; unsigned short rate_; nBandwidthControl* parent_; #ifdef DEBUG int numChildren_; #endif }; struct nConnectionInfo // everything that is needed to manage a connection { int socket; // the network UDP socket int ackPending; REAL ping; tCrypt* crypt; // rate control nBandwidthControl bandwidthControl_; // send buffer nSendBuffer sendBuffer_; // version info nVersion version; // ack messages tJUST_CONTROLLED_PTR< nMessage > ackMess; // authentification tString userName; nConnectionInfo(); ~nConnectionInfo(); void Clear(); }; extern nConnectionInfo sn_Connections[MAXCLIENTS+2]; extern int sn_maxNoAck; //extern int sn_ackPending[MAXCLIENTS+2]; //extern int sn_sockets[MAXCLIENTS+2]; //extern REAL sn_ping[MAXCLIENTS+2]; // go to client mode and connect to server nConnectError sn_Connect(const tString &server, bool login2 ); // let the server connection socket point to a new server (EVIL!) void sn_Bend(const tString &server, unsigned int port); extern int sn_myNetID; // our network identification: 0: server // 1..MAXCLIENTS: client // Network messages and functions that know how to handle them: class nMessage; typedef void nHandler(nMessage &m); // types of network messages class nDescriptor:public tListItem{ friend class nMessage; static unsigned short s_nextID; unsigned short id; // our id nHandler *handler; // function responsible for our type of message const char *name; const bool acceptWithoutLogin; public: nDescriptor(unsigned short identification,nHandler *handle ,const char *name, bool acceptEvenIfNotLoggedIn = false); // nDescriptor(nHandler *handle, // const char *name); static void HandleMessage(nMessage &message); unsigned short ID(){return id;} }; // register the routine that gives the peer the server/client information // (game type, number of players online....) void RequestInfoHandler(nHandler *handle); // the first sn_myNetID available for external use (give some room!) #define NET_ID_FIRST 100 // Network messages. Allways to be created with new, get deleted automatically. class nMessage: public tReferencable< nMessage >{ //friend class nMessage_planned_send; friend class tControlledPTR< nMessage >; friend class tReferencable< nMessage >; friend class nDescriptor; friend class nNetObject; friend class nWaitForAck; // void AddRef(); // void Release(); protected: unsigned short descriptor; // the network message id unsigned short messageID; // number of the message for ack; zero for no ack. short senderID; // sender's identification tArray data; // assuming ints are 32 bit wide... unsigned int readOut; ~nMessage(); public: unsigned short Descriptor() const{ return descriptor; } unsigned short SenderID() const{ return senderID; } unsigned short MessageID() const{ return messageID; } unsigned short DataLen() const{ return data.Len(); } unsigned short Data(unsigned short n){ return data(n); } void ClearMessageID(){ // clear the message ID so no acks are sent for it messageID = 0; } nMessage(const nDescriptor &); // create a new message nMessage(unsigned short*& buffer, short sn_myNetID, int lenLeft ); // read a message from the network stream // immediately send the message WITHOUT the queue; dangerous! void SendImmediately(int peer,bool ack=true); // flush the buffers of that peer static void SendCollected(int peer); // broadcast the same information across the LAN static void BroadcastCollected(int peer, unsigned int port); // send it to anyone who is interested // (the server in client mode, all clients in server mode) void BroadCast(bool ack=true); // put the message into the send heap void Send(int peer,REAL priority=0,bool ack=true); void Write(const unsigned short &x){ data[data.Len()]=x; } nMessage& operator<< (const REAL &x); nMessage& operator>> (REAL &x); nMessage& operator<< (const unsigned short &x){Write(x);return *this;} nMessage& operator>> (unsigned short &x){Read(x);return *this;} nMessage& operator<< (const double &x){ return operator<<(REAL(x)); } nMessage& operator>> (double &x){ REAL y; operator>>(y); x=y; return *this; } nMessage& operator >> (tString &s); nMessage& operator << (const tString &s); template void BinWrite (const T &x){ for(unsigned int i=0;i(&x))[i]); return *this; } bool End(){return readOut>=static_cast(data.Len());} void Reset(){readOut=0;} void Read(unsigned short &x); template void BinRead (const T &x){ for(unsigned int i=0;i(&x)[i]); return *this; } nMessage& operator<< (const short &x); nMessage& operator>> (short &x); nMessage& operator<< (const int &x); nMessage& operator>> (int &x); nMessage& operator<< (const unsigned int &x){operator<<(reinterpret_cast(x));return *this;} nMessage& operator>> (unsigned int &x){operator>>(reinterpret_cast(x));return *this;} nMessage& operator<< (const bool &x); nMessage& operator>> (bool &x); template nMessage& operator<<(const tArray& a) { unsigned short len = a.Len(); Write(len); for (int i=a.Len()-1; i>=0; i--) operator<< (a(i)); return *this; } template nMessage& operator>>(tArray& a) { unsigned short len; Read(len); a.SetLen(len); for (int i=a.Len()-1; i>=0; i--) operator >> (a(i)); return *this; } template nMessage& operator << (const T* p) { if (p) Write( p->ID() ); else Write(0); return *this; } // template nMessage& operator >> ( T*& p ); template nMessage& operator << (const tControlledPTR p) { if (p) Write( p->ID() ); else Write(0); return *this; } // template nMessage& operator >> ( tControlledPTR& p ); }; // the class that is responsible for getting acknowleEdgement for // netmessages class nWaitForAck{ protected: int id; tCONTROLLED_PTR(nMessage) message; // the message int receiver; // the computer who should send the ack nTimeRolling timeSendAgain; // for timeout nTimeRolling timeFirstSent; // for ping calculation nTimeRolling timeLastSent; // for ping calculation int timeouts; public: nWaitForAck(nMessage* m,int rec); virtual ~nWaitForAck(); virtual void AckExtraAction(){}; static void Ackt(unsigned short id,unsigned short peer); static void AckAllPeer(unsigned short peer); static void Resend(); }; // process the messages from all hosts and send acks void sn_Receive(); // attempts to sync with server/all clients (<=> wait for all acks) void sn_Sync(REAL timeout,bool sync_sn_netObjects=false); // defined in nNetObject.C // causes the connected clients to print a message void sn_ConsoleOut(const tOutput &message,int client=-1); nMessage* sn_ConsoleOutMessage(const tOutput &message); // causes the connected clients to print a message in the center of the screeen void sn_CenterMessage(const tOutput &message,int client=-1); // ********************************************** class nCallbackLoginLogout: public tCallback{ static int user; static bool login; public: static int User(){return user;} static int Login(){return login;} nCallbackLoginLogout(VOIDFUNC *f); static void UserLoggedIn(int user); static void UserLoggedOut(int user); }; class nCallbackAcceptPackedWithoutConnection: public tCallbackOr{ static unsigned short descriptor; // the descriptor of the incoming packet public: static unsigned int Descriptor(){return descriptor;} nCallbackAcceptPackedWithoutConnection(BOOLRETFUNC *f); static bool Accept( const nMessage& m ); }; class nCallbackReveivedComplete: public tCallback { public: nCallbackReveivedComplete(VOIDFUNC *f); static void ReceivedComplete(); }; void sn_SendPlanned(); int sn_QueueLen(int user); void sn_Statistics(); // the SenderID of the currently handled message is stored here for reference class nCurrentSenderID { public: nCurrentSenderID():lastSenderID_( currentSenderID_ ){} nCurrentSenderID( int senderID ):lastSenderID_( currentSenderID_ ){ SetID( senderID ); } ~nCurrentSenderID(){ currentSenderID_ = lastSenderID_; } static int GetID(){ return currentSenderID_; } void SetID( int senderID ){ currentSenderID_ = senderID; } private: int lastSenderID_; static int currentSenderID_; }; #endif