3
*************************************************************************
5
ArmageTron -- Just another Tron Lightcycle Game in 3D.
6
Copyright (C) 2000 Manuel Moos (manuel@moosnet.de)
8
**************************************************************************
10
This program is free software; you can redistribute it and/or
11
modify it under the terms of the GNU General Public License
12
as published by the Free Software Foundation; either version 2
13
of the License, or (at your option) any later version.
15
This program is distributed in the hope that it will be useful,
16
but WITHOUT ANY WARRANTY; without even the implied warranty of
17
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
GNU General Public License for more details.
20
You should have received a copy of the GNU General Public License
21
along with this program; if not, write to the Free Software
22
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24
***************************************************************************
28
#include "tMemManager.h"
29
#include "tInitExit.h"
30
#include "nSimulatePing.h"
33
#include "nServerInfo.h"
35
#include "tDirectories.h"
40
#include "tRecorder.h"
48
#include <netinet/in.h>
55
// my IP address. Master server/game server hopefully tell me a correct one.
56
static tString sn_myAddress ("*.*.*.*:*");
57
tString const & sn_GetMyAddress()
62
//! checks wheter a given address is on the user's LAN (or on loopback).
63
bool sn_IsLANAddress( tString const & address )
65
if ( address.StartsWith("127.") || address.StartsWith("10.") || address.StartsWith("192.168.") )
67
// easy LANs. Accept the client sent IP, we don't know our own LAN address.
71
if( address.StartsWith( "172." ) && address[6] == '.' )
73
// more complicated LAN :)
74
int second = address.SubStr(4,2).toInt();
75
if ( 16 <= second && second < 32 )
86
nMessage* sn_WatchMessage = NULL;
87
unsigned int sn_WatchMessageID = 76;
92
tString sn_bigBrotherString;
93
// tString sn_greeting[5]; //made 4 = 5 (lol i broke the laws of maths. subby), k's bug fix
97
#include "nTrueVersion.h"
100
#ifndef TRUE_ARMAGETRONAD_VERSION
101
#define TRUE_ARMAGETRONAD_VERSION VERSION
104
tString sn_programVersion (TRUE_ARMAGETRONAD_VERSION) ;
106
tString sn_serverName("Unnamed Server");
108
const unsigned int sn_defaultPort = 4534;
109
unsigned int sn_serverPort = 4534;
110
bool sn_decorateTS = false;
112
tString net_hostip("ANY");
114
bool big_brother=true;
115
static tConfItem<bool> sn_bb("BIG_BROTHER",big_brother);
117
static tConfItemLine sn_sn("SERVER_NAME", sn_serverName);
119
static tConfItem<int> sn_sport("SERVER_PORT",reinterpret_cast<int&>(sn_serverPort));
121
static tConfItemLine sn_sbtip("SERVER_IP", net_hostip);
123
void sn_DisconnectUserNoWarn(int i, const tOutput& reason, nServerInfoBase * redirectTo = 0 );
125
int sn_defaultDelay=10000;
127
//! pause a bit, abort pause on network activity
130
sn_BasicNetworkSystem.Select( sn_defaultDelay / 1000000.0 );
134
int sn_maxRateIn=8; // maximum data rate in kb/s
135
int sn_maxRateOut=8; // maximum output data rate in kb/s
137
static nConnectError sn_Error = nOK;
139
//tArray<unsigned short> send_buffer[MAXCLIENTS+2];
140
//REAL planned_rate_control[MAXCLIENTS+2];
141
//REAL rate_control[MAXCLIENTS+2];
142
//unsigned short rate[MAXCLIENTS+2];
145
//extern unsigned short client_gamestate[MAXCLIENTS+2];
149
static REAL maxTimeout=1; // the maximal timeout in seconds
150
static REAL minTimeout=.01; // the minimal timeout in seconds
151
static REAL pingTimeout=1; // the normal timeout in multiples of the ping
152
static REAL pingVarianceTimeout=1; // the normal timeout in multiples of the ping variance
153
static REAL zeroTimeout=.01; // additional timeout of first packet
155
static REAL sn_GetTimeout( int user )
157
tASSERT( user >= 0 && user <= MAXCLIENTS+1 );
159
nPingAverager & averager = sn_Connections[ user ].ping;
161
REAL timeout = pingTimeout * averager.GetPing() + pingVarianceTimeout * sqrtf( averager.GetSnailAverager().GetAverageVariance() );
163
if ( timeout < minTimeout )
164
timeout = minTimeout;
165
if ( timeout > maxTimeout )
166
timeout = maxTimeout;
172
static REAL killTimeout=30;
174
static REAL killTimeout=30;
177
static const int kickOnDemandTimeout = 10;
179
static bool send_again_warn=false;
182
static int simulate_loss=0;
184
//static int simulate_loss=0;
187
int sn_maxNoAck=100; // the maximum number of not ack messages
188
// before more are send
190
//int sn_ackPending[MAXCLIENTS+2];
191
// int sn_ackAckPending[MAXCLIENTS+2];
193
//static nMessage * ack_mess[MAXCLIENTS+2];
195
static nNetState current_state;
196
//int sn_sockets[MAXCLIENTS+2]; // server mode:
197
// elements 1...MAXCLIENTS are the incoming connections,
198
// client mode: element 0 connects to the server.
199
// element MAXCLIENTS+1: currently logging in
201
nConnectionInfo sn_Connections[MAXCLIENTS+2];
203
static nAddress peers[MAXCLIENTS+2]; // the same logic for the peer adresses.
204
static int timeouts[MAXCLIENTS+2];
207
static unsigned short lastacks[MAXCLIENTS+2][ACKBACK];
208
static unsigned short lastackPos[MAXCLIENTS+2];
209
static unsigned short highest_ack[MAXCLIENTS+2];
212
//********************************************************
214
//********************************************************
216
static int sn_MaxBackwardsCompatibility = 1000;
217
static tSettingItem<int> sn_mxc("BACKWARD_COMPATIBILITY",sn_MaxBackwardsCompatibility);
219
static int sn_newFeatureDelay = 0;
220
static tSettingItem<int> sn_nfd("NEW_FEATURE_DELAY",sn_newFeatureDelay);
222
// from nConfig.cpp. Adapt version string array there to bump protocol version.
223
int sn_GetCurrentProtocolVersion();
225
static const int sn_currentProtocolVersion = sn_GetCurrentProtocolVersion(); // the current version number of the network protocol
226
static const int sn_backwardCompatibleProtocolVersion = 0; // the smallest version of the network protocol this program is compatible with
227
static const nVersion sn_myVersion( sn_backwardCompatibleProtocolVersion, sn_currentProtocolVersion);
228
static nVersion sn_currentVersion( sn_myVersion );
230
const nVersion& sn_MyVersion() // the version this progam maximally supports
235
const nVersion& sn_CurrentVersion() // the version currently supported
237
return sn_currentVersion;
246
nVersion::nVersion( int min, int max )
248
tASSERT( min <= max );
253
bool nVersion::Supported( int version ) const // check if a particular version is supported
255
tASSERT( min_ <= max_ );
256
return version >= min_ && version <= max_;
259
bool nVersion::Merge( const nVersion& a,
260
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
286
bool nVersion::operator == ( const nVersion& other )
288
return this->max_ == other.max_ && this->min_ == other.min_;
291
nVersion& nVersion::operator = ( const nVersion& other )
293
this->min_ = other.min_;
294
this->max_ = other.max_;
299
nMessage& operator >> ( nMessage& m, nVersion& ver )
305
ver = nVersion( min, max );
310
nMessage& operator << ( nMessage& m, const nVersion& ver )
318
std::istream& operator >> ( std::istream& s, nVersion& ver )
324
ver = nVersion( min, max );
329
std::ostream& operator << ( std::ostream& s, const nVersion& ver )
331
s << ver.Min() << " ";
337
nVersionFeature::nVersionFeature( int min, int max ) // creates a feature that is supported from version min to max; values of -1 indicate no border
339
tASSERT( min_ >= sn_MyVersion().Min() );
340
tASSERT( max < 0 || max <= sn_MyVersion().Max() );
346
bool nVersionFeature::Supported() const
348
return ( min_ < 0 || sn_CurrentVersion().Max() >= min_ ) && ( max_ < 0 || sn_CurrentVersion().Min() <= max_ );
351
bool nVersionFeature::Supported( int client ) const
353
if ( client < 0 || client > MAXCLIENTS )
356
// the version to check the feature for
357
const nVersion * version = &sn_CurrentVersion();
359
if ( sn_GetNetState() == nCLIENT )
361
// clientside code: override the currently active version with the server version ( if that has been sent )
362
if ( sn_Connections[0].version.Max() > 0 )
363
version = &sn_Connections[0].version;
367
// serverside code: override version to use with the client's version
368
version = &sn_Connections[ client ].version;
371
// see if the feature is supported
372
return ( min_ < 0 || version->Max() >= min_ ) && ( max_ < 0 || version->Min() <= max_ );
375
void handle_version_control( nMessage& m )
377
if ( sn_GetNetState() == nCLIENT )
379
m >> sn_currentVersion;
381
// inform configuration of changes
382
nConfItemVersionWatcher::OnVersionChange( sn_currentVersion );
386
nDescriptor versionControl(10, handle_version_control,"version" );
388
void sn_UpdateCurrentVersion()
390
// update the current version from the native version and the versions of all attached clients
392
// allow maximally sn_MaxBackwardsCompatibility old versions to connect
393
int min = sn_myVersion.Max() - sn_MaxBackwardsCompatibility;
394
if ( min < sn_myVersion.Min() )
395
min = sn_myVersion.Min();
397
// disable features that are too new
398
int max = sn_myVersion.Max() - sn_newFeatureDelay;
402
nVersion version( min, max );
404
// ask configuration if version is OK
405
nConfItemVersionWatcher::AdaptVersion( version );
407
nVersion maxVersion = version;
409
if ( sn_GetNetState() == nCLIENT )
411
sn_currentVersion = version;
415
for ( int i = MAXCLIENTS; i>0; --i )
417
const nConnectionInfo& info = sn_Connections[i];
420
if ( ! version.Merge( version, info.version ) )
422
// kick user; it has gotten incompatible.
423
static bool recurse = true;
427
sn_DisconnectUser( i, "$network_kill_incompatible" );
431
version = maxVersion;
436
// inform configuration of changes
437
nConfItemVersionWatcher::OnVersionChange( version );
439
if ( version != sn_currentVersion )
441
sn_currentVersion = version;
443
nMessage* m = tNEW( nMessage )( versionControl );
450
//********************************************************
452
nConnectError sn_GetLastError()
454
nConnectError ret = sn_Error;
461
// REAL sn_ping[MAXCLIENTS+2];
463
static void reset_last_acks(int i){
464
for(int j=ACKBACK-1;j>=0;j--)
472
int sn_maxClients=MAXCLIENTS;
474
bool restrictMaxClients( int const &newValue )
476
if (newValue > MAXCLIENTS)
479
o.SetTemplateParameter(1, MAXCLIENTS);
480
o << "$max_clients_limit";
487
static tSettingItem< int > sn_maxClientsConf( "MAX_CLIENTS", sn_maxClients, &restrictMaxClients );
489
int sn_allowSameIPCountSoft=4;
490
static tSettingItem< int > sn_allowSameIPCountSoftConf( "MAX_CLIENTS_SAME_IP_SOFT", sn_allowSameIPCountSoft );
492
int sn_allowSameIPCountHard=8;
493
static tSettingItem< int > sn_allowSameIPCountHardConf( "MAX_CLIENTS_SAME_IP_HARD", sn_allowSameIPCountHard );
499
int sn_myNetID=0; // our network identification: 0: server
500
// 1..MAXCLIENTS: client
502
#define IDS_RESERVED 16 // number of message IDs reserved for special purposes: id 0 is reserved for no-ack messages.
503
unsigned short current_id=1; // current running network number
506
// the classes that are responsible for the queuing of network send tEvents:
507
class planned_send:public tHeapElement{
511
planned_send(REAL priority,int peer);
514
virtual tHeapBase *Heap() const; // in wich heap are we?
516
// change our priority:
517
void add_to_priority(REAL diff);
519
// what is to be done if the sceduled tEvent is executed?
520
virtual void execute()=0;
523
class nMessage_planned_send:public planned_send{
524
tCONTROLLED_PTR(nMessage) m;
528
nMessage_planned_send(nMessage *m,REAL priority,bool ack,int peer);
529
~nMessage_planned_send();
531
virtual void execute();
534
// *************************************************************
536
unsigned short nDescriptor::s_nextID(1);
538
#define MAXDESCRIPTORS 400
539
static nDescriptor* descriptors[MAXDESCRIPTORS];
541
static nDescriptor* nDescriptor_anchor;
543
nDescriptor::nDescriptor(unsigned short identification,
544
nHandler *handle,const char *Name, bool awl)
545
:tListItem<nDescriptor>(nDescriptor_anchor),
546
id(identification),handler(handle),name(Name), acceptWithoutLogin(awl)
550
// con << "Descriptor " << id << ": " << name << '\n';
553
if (MAXDESCRIPTORS<=id || descriptors[id]!=NULL){
554
con << "Descriptor " << id << " already used!\n";
558
descriptors[id]=this;
562
nDescriptor::nDescriptor(nHandler *handle,const char *Name)
563
:id(s_nextID++),handler(handle),name(Name)
566
con << "Descriptor " << id << ": " << name << '\n';
569
if (descriptors.Len()>id && descriptors[id]!=NULL){
570
con << "Descriptor " << id << " already used!\n";
573
descriptors[id]=this;
577
int nCurrentSenderID::currentSenderID_ = 0;
579
void nDescriptor::HandleMessage(nMessage &message){
580
static tArray<bool> warned;
582
// store sender ID for console
583
nCurrentSenderID currentSender( message.SenderID() );
586
if (message.descriptor>1)
587
con << "RMT " << message.descriptor << "\n";
595
// z-man: security check ( thanks, Luigi Auriemma! )
596
if ( message.descriptor < MAXDESCRIPTORS )
597
nd=descriptors[message.descriptor];
600
if ((message.SenderID() <= MAXCLIENTS) || nd->acceptWithoutLogin)
601
nd->handler(message);
604
if (!warned[message.Descriptor()]){
606
warn.SetTemplateParameter(1, message.Descriptor());
607
warn << "$network_warn_unknowndescriptor";
609
warned[message.Descriptor()]=true;
613
catch(nIgnore const &){
616
catch(nKillHim const &){
618
con << tOutput("$network_error");
619
sn_DisconnectUser(message.SenderID(), "$network_kill_error" );
625
// *************************************************************
628
void ack_handler(nMessage &m){
630
sn_Connections[m.SenderID()].AckReceived();
634
//con << "Got ack:" << ack << ":" << m.SenderID() << '\n';
635
nWaitForAck::Ackt(ack,m.SenderID());
639
static nDescriptor s_Acknowledge(1,ack_handler,"ack");
643
static tList<nWaitForAck> sn_pendingAcks;
645
//static eTimer netTimer;
646
static nTimeRolling netTime;
650
static int max_acks=0;
653
nWaitForAck::nWaitForAck(nMessage* m,int rec)
654
:id(-1),message(m),receiver(rec)
657
// don't message yourself
658
if ( rec == 0 && sn_GetNetState() == nSERVER )
663
tERR_ERROR("Null ack!");
665
if (message->Descriptor()!=s_Acknowledge.ID())
666
sn_Connections[receiver].ackPending++;
668
tERR_ERROR("Should not wait for ack of an ack message itself.");
670
// sn_ackAckPending[receiver]++;
675
timeFirstSent=::netTime;
676
timeLastSent=::netTime;
680
timeout=sn_GetTimeout( rec );
682
#ifdef nSIMULATE_PING
683
timeSendAgain=::netTime + nSIMULATE_PING;
685
tRandomizer & randomizer = tReproducibleRandomizer::GetInstance();
686
timeSendAgain+= randomizer.Get() * nSIMULATE_PING_VARIANT;
687
// timeSendAgain+=(nSIMULATE_PING_VARIANT*random())/RAND_MAX;
690
const REAL packetLossScale = .003; // packet loss rate that is considered big
691
const REAL maxTimeoutFactor = 1.2; // maximal stretching of initial timeout value for flawless connections
692
// factor mutliplied to timeout; 1 if the connection loses a lot of packets, 1.2 for a
693
// flawless connection
694
REAL timeoutFactor = 1 + (maxTimeoutFactor-1)*packetLossScale/(sn_Connections[receiver].PacketLoss() + packetLossScale);
695
timeSendAgain=::netTime + timeout*timeoutFactor + zeroTimeout;
697
sn_pendingAcks.Add(this,id);
700
nWaitForAck::~nWaitForAck(){
705
// con << "MA=" << max_acks << '\n';
709
if (bool(message) && message->Descriptor()!=s_Acknowledge.ID())
711
sn_Connections[receiver].ackPending--;
712
sn_Connections[receiver].ReliableMessageSent();
716
tERR_ERROR( "No message." );
718
// sn_ackAckPending[receiver]--;
720
sn_pendingAcks.Remove(this,id);
724
void nWaitForAck::Ackt(unsigned short id,unsigned short peer){
726
for(int i=sn_pendingAcks.Len()-1;i>=0;i--){
727
nWaitForAck * ack = sn_pendingAcks(i);
728
if (ack->message->MessageID()==id &&
729
ack->receiver==peer){
733
// if (sn_pendingAcks(i)->message == sn_WatchMessage)
738
if (ack->message->descriptor>1)
739
con << "AT " << ack->message->descriptor << '\n';
742
// calculate and average ping
743
REAL thisping=netTime - ack->timeFirstSent;
744
sn_Connections[peer].ping.Add( thisping, 1/(1 + 10 * REAL(ack->timeouts * ack->timeouts * ack->timeouts ) ) );
746
ack->AckExtraAction();
749
if (i<sn_pendingAcks.Len()-1) i++;
754
if (!success && peer!=MAXCLIENTS+1)
756
con << "Ack " << id << ':' << peer << " was not asked for.\n";
757
if (sn_pendingAcks.Len()) con << "Expected:\n";
758
for(int i=sn_pendingAcks.Len()-1;i>=0;i--){
760
<< sn_pendingAcks[i]->message->messageIDBig_ << ":"
761
<< sn_pendingAcks[i]->receiver << '\n';
767
void nWaitForAck::AckAllPeer(unsigned short peer){
768
for(int i=sn_pendingAcks.Len()-1;i>=0;i--){
769
if (sn_pendingAcks(i)->receiver==peer){
770
delete sn_pendingAcks(i);
771
if (i<sn_pendingAcks.Len()-1) i++;
776
void nWaitForAck::Resend(){
777
static tReproducibleRandomizer randomizer;
779
for(int i=sn_pendingAcks.Len()-1;i>=0;i--){
780
nWaitForAck* pendingAck = sn_pendingAcks(i);
782
nConnectionInfo & connection = sn_Connections[pendingAck->receiver];
784
// don't resend if you can't.
785
if ( !connection.bandwidthControl_.CanSend() )
788
REAL packetLoss = connection.PacketLoss();
789
REAL timeout = pendingAck->timeout;
791
// should we resend the packet? Certainly it if it is overdue
792
bool resend = (pendingAck->timeSendAgain + timeout * .1 <=netTime);
794
// or if there is already a message waiting...
795
if ( !resend && connection.sendBuffer_.Len() > 0 )
797
// and we are on time
798
if ( pendingAck->timeSendAgain <= netTime )
800
// or the packet loss is so high that it is advisable to resend every message
801
// multiple times if bandwidth is available ( we aim for 99% reliability )
802
else if ( pendingAck->timeouts < 3 && pow( packetLoss, pendingAck->timeouts + 1 ) > .01 &&
803
connection.bandwidthControl_.Control( nBandwidthControl::Usage_Planning ) >100 )
806
/* + sn_GetTimeout( pendingAck->receiver ) *
807
( 3.0 / ( pendingAck->timeouts + 1 ) )
808
( packetLoss * ( randomizer.Get() + .5 ) ) )
813
//con << net_ticks-sn_pendingAcks[i]->ticks_first_sent << '\n';
815
// update timeout counters
816
::timeouts[pendingAck->receiver]++;
817
pendingAck->timeouts++;
819
if(netTime - pendingAck->timeFirstSent > killTimeout &&
820
::timeouts[pendingAck->receiver] > 20){
821
// total timeout. Kill connection.
822
if (pendingAck->receiver<=MAXCLIENTS){
824
o.SetTemplateParameter(1, pendingAck->receiver);
825
o << "$network_error_timeout";
827
sn_DisconnectUser(pendingAck->receiver, "$network_kill_timeout" );
831
if (i>=sn_pendingAcks.Len())
832
i=sn_pendingAcks.Len()-1;
834
else // it is just in the login slot. Ignore it.
839
//if (pendingAck->message == sn_WatchMessage)
843
if (connection.socket){
844
// if(sn_Connections[].rateControlPlanned[pendingAck->receiver]>-1000)
846
REAL timeoutFactor = .9 + .1 * pendingAck->timeouts + randomizer.Get() * .1;
847
pendingAck->timeSendAgain=netTime+timeout * timeoutFactor;
848
pendingAck->timeLastSent=netTime;
850
if (send_again_warn){
851
con << "sending packet again: " ;
854
connection.ReliableMessageSent();
855
pendingAck->message->SendImmediately
856
(pendingAck->receiver,false);
868
// defined in netobjec.C
869
// void ClearKnows(int user);
873
static int nMessages=0;
874
static int max_nMessages=0;
878
void BreakOnMessageID( unsigned int messageID )
880
if (messageID == sn_WatchMessageID && messageID != 0 )
888
class nMessageIDExpander
890
unsigned long quarters[4];
894
for (int i=3; i>=0; --i)
898
unsigned long ExpandMessageID( unsigned short id )
900
// the current ID is in this quarter
901
int thisQuarter = ( id >> 14 ) & 3;
903
// the following quarter will be this
904
int nextQuarter = ( thisQuarter + 1 ) & 3;
906
// make sure the following quarter has a higher upper ID completion than this
907
quarters[nextQuarter] = quarters[thisQuarter] + ( 1 << 14 );
909
// replace high two bits of incoming ID with the counted up ID
910
return quarters[thisQuarter] | id;
914
//! expands a short message ID to a full int message ID, assuming it is from a message that was
916
static unsigned long int sn_ExpandMessageID( unsigned short id, unsigned short sender )
919
BreakOnMessageID( id );
922
static nMessageIDExpander expanders[MAXCLIENTS+2];
924
tASSERT( sender <= MAXCLIENTS+2 )
925
return expanders[sender].ExpandMessageID(id);
928
nMessage::nMessage(unsigned short*& buffer,short sender, int lenLeft )
929
:descriptor(ntohs(*(buffer++))),messageIDBig_(sn_ExpandMessageID(ntohs(*(buffer++)),sender)),
930
senderID(sender),readOut(0){
935
tRecorderSync< unsigned long >::Archive( "_MESSAGE_ID_IN", 3, messageIDBig_ );
936
tRecorderSync< unsigned short >::Archive( "_MESSAGE_DECL_IN", 3, descriptor );
938
unsigned short len=ntohs(*(buffer++));
947
for(int i=0;i<len;i++)
948
data[i]=ntohs(*(buffer++));
951
BreakOnMessageID( messageIDBig_ );
955
nMessage::nMessage(const nDescriptor &d)
957
senderID(::sn_myNetID), readOut(0){
963
if (current_id <= IDS_RESERVED)
964
current_id = IDS_RESERVED + 1;
966
messageIDBig_ = current_id;
969
con << "Message " << d.id << " " << current_id << "\n";
973
BreakOnMessageID( messageIDBig_ );
976
tRecorderSync< unsigned long >::Archive( "_MESSAGE_ID_OUT", 3, messageIDBig_ );
977
tRecorderSync< unsigned short >::Archive( "_MESSAGE_DECL_OUT", 3, descriptor );
981
nMessage::~nMessage(){
984
if (nMessages>max_nMessages){
985
max_nMessages=nMessages;
986
con << "MN=" << max_nMessages <<'\n';
992
con << "DMT " << descriptor << "\n";
1001
void nMessage::BroadCast(bool ack){
1002
tControlledPTR< nMessage > keep( this );
1003
if (sn_GetNetState()==nCLIENT)
1006
if (sn_GetNetState()==nSERVER){
1007
for(int i=MAXCLIENTS;i>0;i--){
1008
if (sn_Connections[i].socket)
1015
static nVersionFeature sn_ZeroMessageCrashfix( 1 );
1017
nMessage& nMessage::operator << (const tString &s){
1018
unsigned short len=s.Len();
1020
// clamp away excess zeroes
1021
while(len > 1 && s(len-2)==0)
1026
// check whether all clients support zero length strings
1027
if ( !sn_ZeroMessageCrashfix.Supported() )
1031
static tString replacement("");
1032
return this->operator<<( replacement );
1035
else if ( len == 1 && s(0) == 0 )
1037
// do away with the the trailing zero in zero length strings.
1044
// write first pairs of bytes
1045
for(i=0;i+1<len;i+=2)
1047
// yep. Signed arithmetic. That gives
1048
// nice overflows. By the time we noticed,
1049
// it was too late to change :)
1050
signed char lo = s[i];
1051
signed char hi = s[i+1];
1053
// combine the two into a single short
1054
Write( short(lo) + (short(hi) << 8) );
1059
Write( static_cast< signed char >( s[i] ) );
1064
nMessage& nMessage::operator << (const tColoredString &s){
1065
return *this << static_cast< const tString & >( s );
1068
nMessage& nMessage::operator << ( const tOutput &o ){
1069
return *this << tString( static_cast< const char * >( o ) );
1072
nMessage& nMessage::ReadRaw(tString &s )
1075
unsigned short w,len;
1080
for(int i=0;i<len;i+=2){
1083
// carefully reverse the signed
1085
signed char lo = w & 0xff;
1086
signed short hi = ((short)w) - lo;
1098
bool sn_filterColorStrings = false;
1099
static tConfItem<bool> sn_filterColorStringsConf("FILTER_COLOR_STRINGS",sn_filterColorStrings);
1100
bool sn_filterDarkColorStrings = false;
1101
static tConfItem<bool> sn_filterDarkColorStringsConf("FILTER_DARK_COLOR_STRINGS",sn_filterDarkColorStrings);
1103
nMessage& nMessage::operator >> (tColoredString &s )
1105
// read the raw data
1108
// filter client string messages
1109
if ( sn_GetNetState() == nSERVER )
1112
s.RemoveTrailingColor();
1115
// filter color codes away
1116
if ( sn_filterColorStrings )
1117
s = tColoredString::RemoveColors( s, false );
1118
else if ( sn_filterDarkColorStrings )
1119
s = tColoredString::RemoveColors( s, true );
1124
nMessage& nMessage::operator >> (tString &s )
1126
tColoredString safe;
1135
#define EXP (32-MANT)
1141
unsigned int exp:EXP;
1145
nMessage& nMessage::operator<<(const REAL &x){
1149
// con << "write x= " << x;
1152
if(sizeof(myfloat)!=sizeof(int))
1153
tERR_ERROR_INT("floating ePoint format does not work!");
1156
REAL nachkomma=x-floor(x);
1157
Write(short(x-nachkomma));
1158
Write(60000*nachkomma);
1160
// no fuss. Read and write floats in binary format.
1161
// will likely cause problems for systems other than i386.
1163
//Write(((short *)&x)[0]);
1164
//Write(((short *)&x)[1]);
1166
// right. Caused severe problems with the AIX port.
1168
// new way: own floating ePoint format that is not good with small numbers
1169
// (we do not need them anyway)
1172
unsigned int negative=0;
1179
while ( fabs(y)>=64 && exp < (1<<EXP)-6 )
1184
while ( fabs(y)>=1 && exp < (1<<EXP)-1 )
1190
unsigned int mant=int(y*(1<<MS));
1191
// now x=mant*2^exp * (1/ (1<<MANT))
1194
if (mant>((1<<MS))-1)
1197
if (exp>(1<<EXP)-1){
1203
// put them together:
1205
unsigned int trans=(mant & ((1<<MS)-1)) | (negative << MS) | (exp << MANT);
1212
operator<<(reinterpret_cast<int &>(trans));
1216
con << "mant: " << mant
1218
<< ", negative: " << negative;
1221
unsigned int mant2=trans & ((1 << MS)-1);
1222
unsigned int negative2=(trans >> MS) & 1;
1223
unsigned int nt=trans-mant-(negative << MS);
1224
unsigned int exp2=nt >> MANT;
1226
if (mant2!=mant || negative2!=negative || exp2!=exp)
1227
tERR_ERROR_INT("Floating ePoint tranfer failure!");
1230
con << ", x: " << x;
1232
con << ", mant: " << mant
1234
<< ", negative: " << negative;
1239
REAL z=REAL(mant)/(1<<MS);
1252
if (fabs(z-x)>(fabs(x)+1)*.001)
1253
tERR_ERROR_INT("Floating ePoint tranfer failure!");
1255
//con << ", z: " << z << '\n';
1261
nMessage& nMessage::operator>>(REAL &x){
1264
unsigned short nachkomma;
1265
Read((unsigned short &)vorkomma);
1267
x=vorkomma+nachkomma/60000.0;
1269
Read(((unsigned short *)&x)[0]);
1270
Read(((unsigned short *)&x)[1]);
1274
operator>>(reinterpret_cast<int &>(trans));
1276
int mant=trans & ((1 << MS)-1);
1277
unsigned int negative=(trans >> MS) & 1;
1278
unsigned int exp=(trans-mant-(negative << MS)) >> MANT;
1280
x=REAL(mant)/(1<<MS);
1285
// con << "read mant: " <<mant << ", exp: " << exp;
1301
// con << " , x= " << x << '\n';
1307
nMessage& nMessage::operator<< (const short &x){
1308
Write((reinterpret_cast<const short *>(&x))[0]);
1313
nMessage& nMessage::operator>> (short &x){
1314
Read(reinterpret_cast<unsigned short *>(&x)[0]);
1319
nMessage& nMessage::operator<< (const int &x){
1320
unsigned short a=x & (0xFFFF);
1321
short b=(x-a) >> 16;
1329
nMessage& nMessage::operator>> (int &x){
1341
nMessage& nMessage::operator<< (const bool &x){
1350
nMessage& nMessage::operator>> (bool &x){
1359
void nMessage::Read(unsigned short &x){
1363
o.SetTemplateParameter(1, senderID);
1364
o << "$network_error_shortmessage";
1366
// sn_DisconnectUser(senderID, "$network_kill_error");
1367
nReadError( false );
1374
// **********************************************
1375
// Basic communication classes: login
1376
// **********************************************
1378
static bool login_failed=false;
1379
static bool login_succeeded=false;
1381
// salt value sent as past login tokens. They are returned by
1382
// the server as you sent them, and make sure you only accept
1383
// the right answer.
1384
static nKrawall::nSalt loginSalt;
1386
static nHandler *real_req_info_handler=NULL;
1388
void req_info_handler(nMessage &m){
1389
if (real_req_info_handler)
1390
(*real_req_info_handler)(m);
1391
if (m.SenderID()==MAXCLIENTS+1)
1392
sn_DisconnectUser(MAXCLIENTS+1, "$network_kill_logout");
1395
static nDescriptor req_info(2,req_info_handler,"req_info");
1397
void RequestInfoHandler(nHandler *handle){
1398
real_req_info_handler=handle;
1401
// the server we are redirected to
1402
static std::auto_ptr< nServerInfoBase > sn_redirectTo;
1403
std::auto_ptr< nServerInfoBase > sn_GetRedirectTo()
1405
return sn_redirectTo;
1408
nServerInfoBase * sn_PeekRedirectTo()
1410
return sn_redirectTo.get();
1413
void login_deny_handler(nMessage &m){
1418
// sn_DenyReason = output;
1423
sn_DenyReason = tOutput( "$network_kill_unknown" );
1428
// read redirection data from message
1429
tString connectionName;
1430
m >> connectionName;
1434
if ( connectionName.Len() > 1 )
1436
// create server info and fill it with data
1437
sn_redirectTo = std::auto_ptr< nServerInfoBase>( new nServerInfoRedirect( connectionName, port ) );
1442
con << tOutput("$network_login_denial");
1443
if (sn_GetNetState()!=nSERVER){
1445
login_succeeded=false;
1446
sn_SetNetState(nSTANDALONE);
1450
static nDescriptor login_deny(3,login_deny_handler,"login_deny");
1452
void login_handler_1( nMessage&m );
1453
void login_handler_2( nMessage&m );
1454
void logout_handler( nMessage&m );
1456
nDescriptor login(6,login_handler_1,"login1", true);
1457
nDescriptor login_2(11,login_handler_2,"login2", true);
1458
nDescriptor logout(7,logout_handler,"logout");
1460
tString sn_DenyReason;
1462
void login_ignore_handler(nMessage &m){
1463
if (sn_GetNetState()!=nSERVER && !login_succeeded){
1466
login_succeeded=false;
1468
// kicking the one who uses our place
1469
// (he is probably timing out anyway..)
1470
nMessage *lo=new nMessage(logout);
1471
lo->Write((unsigned short)sn_myNetID);
1476
(new nMessage(login))->Send(0);
1483
static nDescriptor login_ignore(4,login_ignore_handler,"login_ignore");
1486
void first_fill_ids();
1488
// from nServerInfo.cpp
1489
extern bool sn_AcceptingFromMaster;
1491
void login_accept_handler(nMessage &m){
1492
if (sn_GetNetState()!=nSERVER && m.SenderID() == 0){
1493
unsigned short id=0;
1496
// read or reset server version info
1499
m >> sn_Connections[0].version;
1507
// last checked to be compatible with 0.3.1_pb from trunk.
1508
// It's ulikely this branch will introduce more bugs/network code revisions, so we're fine accepting all
1509
int lastCheckedTrunkVersion = 21;
1511
// start of trunk as seen from this branch
1512
int trunkBegin = 20;
1514
// maximal allowed version from this branch
1515
int maxVersionThisBranch = sn_currentProtocolVersion + 1;
1517
// expiration for public beta versions
1518
if ( !sn_AcceptingFromMaster &&
1519
( strstr( VERSION, "rc" ) || strstr( VERSION, "alpha" ) || strstr( VERSION, "beta" ) ) &&
1520
( sn_Connections[0].version.Max() > lastCheckedTrunkVersion ||
1521
( sn_Connections[0].version.Max() > maxVersionThisBranch && sn_Connections[0].version.Max() < trunkBegin )
1525
throw tGenericException( tOutput("$testing_version_expired"), tOutput("$testing_version_expired_title" ) );
1531
sn_Connections[0].version = nVersion( 0, 0);
1533
// read my public IP
1536
// only accept it if it is not a LAN address
1539
if ( !sn_IsLANAddress( address ) )
1541
if ( sn_myAddress != address )
1543
con << "Got address " << address << ".\n";
1545
sn_myAddress = address;
1548
// read salt reply and compare it to what we sent
1549
nKrawall::nSalt replySalt;
1550
nKrawall::ReadScrambledPassword( m, replySalt );
1552
int compare = memcmp( &loginSalt,&replySalt, sizeof(replySalt) );
1554
// since we generate a different random salt on playback, record the comparison result
1555
static const char * section = "LOGIN_SALT";
1556
tRecorder::Playback( section, compare );
1557
tRecorder::Record( section, compare );
1561
nReadError( false );
1565
// only now, login can be considered a success
1566
login_succeeded=true;
1573
static nDescriptor login_accept(5,login_accept_handler,"login_accept", true);
1577
//static short new_id=0;
1579
// counts the number of logins with the same IP
1580
int CountSameIP( int user, bool reset=false )
1582
static int sameIP[ MAXCLIENTS+2 ];
1583
tASSERT( user >= 0 && user <= MAXCLIENTS+1 );
1588
for(int user2=1;user2<=MAXCLIENTS;++user2)
1590
if(!sn_Connections[user2].socket)
1593
if ( user2 != user && nAddress::Compare( peers[user], peers[user2] ) >=0 )
1599
sameIP[user] = count;
1602
return sameIP[user];
1605
// counts the number of logins with the same Connection
1606
int CountSameConnection( int user )
1609
for(int user2=1;user2<=MAXCLIENTS;++user2)
1611
if( NULL == sn_Connections[user2].socket )
1614
if ( user2 != user && nAddress::Compare( peers[user], peers[user2] ) == 0 )
1623
// determine a free connection slot or at least one where the user won't be missed
1628
// level 1: look for free slot
1629
if ( sn_NumUsers() < sn_maxClients )
1631
for(user=1;user<=sn_maxClients;++user)
1633
// look for empty slot
1634
if(!sn_Connections[user].socket)
1643
// level 2 kicked out users who were timing out and was not a good idea.
1645
int bestCount = sn_allowSameIPCountSoft-1;
1647
// level 3: look for dublicate IPs
1648
for(user=1;user<=MAXCLIENTS;++user)
1650
int count = CountSameIP( user );
1651
if ( count > bestCount )
1663
static REAL sn_minBan = 120; // minimal ban time in seconds for trying to connect while you're banned
1664
static tSettingItem< REAL > sn_minBanSetting( "NETWORK_MIN_BAN", sn_minBan );
1666
// defined in nServerInfo.cpp
1667
extern bool FloodProtection( nMessage const & m );
1669
// flag to disable 0.2.8 test version lockout
1670
static bool sn_lockOut028tTest = true;
1671
static tSettingItem< bool > sn_lockOut028TestConf( "NETWORK_LOCK_OUT_028_TEST", sn_lockOut028tTest );
1673
int login_handler( nMessage &m, unsigned short rate ){
1674
nCurrentSenderID senderID;
1676
// read version and suppored authentication methods
1678
tString supportedAuthenticationMethods("");
1679
nKrawall::nSalt salt; // it's OK that this may stay uninitialized
1685
// ok, clients that send a version do have at lesat basic authentication.
1686
supportedAuthenticationMethods = "bmd5";
1690
// read authentication methods
1691
m >> supportedAuthenticationMethods;
1695
// also read a login salt, the client expects to get it returned verbatim
1696
nKrawall::ReadScrambledPassword( m, salt );
1699
// don't accept logins in client mode
1700
if (sn_GetNetState() != nSERVER)
1704
nMachine & machine = nMachine::GetMachine( m.SenderID() );
1705
REAL banned = machine.IsBanned();
1708
// the reason for the ban
1709
tString const & reason = machine.GetBanReason();
1711
// ban user some more so he learns
1712
if ( banned < sn_minBan )
1714
machine.Ban( sn_minBan );
1718
con << tOutput( "$network_ban", machine.GetIP() , int(banned/60), reason.Len() > 1 ? reason : tOutput( "$network_ban_noreason" ) );
1720
sn_DisconnectUser(m.SenderID(), tOutput( "$network_kill_banned", int(banned/60), reason ) );
1723
// ignore multiple logins
1724
if( CountSameConnection( m.SenderID() ) > 0 )
1727
// ignore login floods
1728
if ( FloodProtection( m ) )
1736
// sn_DisconnectUser(m.SenderID(), "$network_kill_incompatible");
1739
nVersion mergedVersion;
1740
if ( !mergedVersion.Merge( version, sn_CurrentVersion() ) )
1742
sn_DisconnectUser(m.SenderID(), "$network_kill_incompatible");
1745
// expire 0.2.8 test versions, they have a security flaw
1746
if ( sn_lockOut028tTest && version.Max() >= 5 && version.Max() <= 10 )
1748
sn_DisconnectUser(m.SenderID(), "0.2.8_beta and 0.2.8.0_rc versions have a dangerous security flaw and are obsoleted, please upgrade to 0.2.8.2.1.");
1751
if (m.SenderID()!=MAXCLIENTS+1)
1753
//con << "Ignoring second login from " << m.SenderID() << ".\n";
1754
(new nMessage(login_ignore))->Send(m.SenderID());
1756
else if (sn_Connections[m.SenderID()].socket)
1758
if ( sn_maxClients > MAXCLIENTS )
1759
sn_maxClients = MAXCLIENTS;
1761
// count doublicate IPs
1762
if ( CountSameIP( m.SenderID(), true ) < sn_allowSameIPCountHard )
1764
// find new free ( or freeable ) ID
1765
new_id = GetFreeSlot();
1768
if(sn_Connections[new_id].socket)
1769
sn_DisconnectUser( new_id, "$network_kill_full" );
1773
senderID.SetID( new_id );
1775
sn_Connections [ new_id ].socket = sn_Connections[MAXCLIENTS+1].socket; // the new connection has number MC+1
1776
peers [ new_id ] = peers[MAXCLIENTS+1];
1777
timeouts [ new_id ] = kickOnDemandTimeout/2;
1779
// sn_Connections [ MAXCLIENTS+1 ].socket = NULL;
1780
// peers [ MAXCLIENTS+1 ].sa_family = 0;
1781
// nCallbackLoginLogout::UserLoggedIn(i);
1783
sn_Connections [ new_id ].supportedAuthenticationMethods_ = supportedAuthenticationMethods;
1785
// recount doublicate IPs
1786
CountSameIP( new_id, true );
1790
// log login to console
1792
o.SetTemplateParameter(1, peers[m.SenderID()].ToString() );
1793
o.SetTemplateParameter(2, sn_Connections[m.SenderID()].socket->GetAddress().ToString() );
1794
o.SetTemplateParameter(3, sn_GetClientVersionString(version.Max()) );
1795
o.SetTemplateParameter(4, version.Max() );
1796
o << "$network_server_login";
1802
o.SetTemplateParameter(1, new_id);
1803
o << "$network_server_login_success";
1806
// s << "User " << new_id << " logged in.\n";
1808
sn_Connections[new_id].ping.Reset();
1809
sn_Connections[new_id].bandwidthControl_.Reset();
1810
reset_last_acks(new_id);
1812
if (rate>sn_maxRateOut)
1815
sn_Connections[new_id].bandwidthControl_.SetRate( rate );
1816
sn_Connections[new_id].version = version;
1818
nWaitForAck::AckAllPeer(MAXCLIENTS+1);
1819
reset_last_acks(MAXCLIENTS+1);
1820
if (sn_Connections[MAXCLIENTS+1].ackMess)
1822
sn_Connections[MAXCLIENTS+1].ackMess=NULL;
1825
// send login accept message with high priority
1826
nMessage *rep=new nMessage(login_accept);
1828
(*rep) << sn_myVersion;
1829
(*rep) << peers[m.SenderID()].ToString();
1830
nKrawall::WriteScrambledPassword( salt, *rep );
1832
rep->Send(new_id, -killTimeout);
1834
nMessage::SendCollected( new_id );
1836
nConfItemBase::s_SendConfig(true, new_id);
1839
nMachine & machine = nMachine::GetMachine( new_id );
1840
machine.AddPlayer();
1841
machine.RemovePlayer();
1843
nCallbackLoginLogout::UserLoggedIn(new_id);
1845
// ANET_Listen(false);
1846
// ANET_Listen(true);
1848
else if (m.SenderID()==MAXCLIENTS+1)
1850
sn_DisconnectUser(MAXCLIENTS+1, "$network_kill_full");
1853
sn_UpdateCurrentVersion();
1858
void login_handler_1(nMessage& m)
1860
unsigned short rate;
1864
if ( !m.End() ){ // we get a big brother message (ignore it)
1869
login_handler( m, rate );
1872
void login_handler_2(nMessage& m)
1874
unsigned short rate;
1882
{ // we get a big brother message
1886
int new_ID = login_handler( m, rate );
1890
nMessage* m = tNEW( nMessage )( versionControl );
1891
(*m) << sn_currentVersion;
1898
if ( tDirectories::Var().Open(s, "big_brother",std::ios::app) )
1899
s << rem_bb << '\n';
1905
void logout_handler(nMessage &m){
1906
unsigned short id = m.SenderID();
1909
if (sn_Connections[id].socket)
1912
o.SetTemplateParameter(1, id);
1913
o << "$network_logout_server";
1916
nWaitForAck::AckAllPeer(id);
1918
if (0<id && id<=MAXCLIENTS)
1920
sn_DisconnectUser(id, "$network_kill_logout");
1925
#define MAX_MESS_LEN 300
1928
static REAL sn_OrderPriority = 0;
1931
int sn_SentBytes = 0;
1932
int sn_SentPackets = 0;
1933
int sn_ReceivedBytes = 0;
1934
int sn_ReceivedPackets = 0;
1935
nTimeRolling sn_StatsTime = 0;
1938
// adds a message to the buffer
1939
void nSendBuffer::AddMessage ( nMessage& message, nBandwidthControl* control )
1941
unsigned long id = message.MessageID();
1942
unsigned short len = message.DataLen();
1943
tRecorderSync< unsigned long >::Archive( "_MESSAGE_ID_SEND", 5, id );
1945
sendBuffer_[sendBuffer_.Len()]=htons(message.Descriptor());
1947
sendBuffer_[sendBuffer_.Len()]=htons(message.MessageID());
1949
sendBuffer_[sendBuffer_.Len()]=htons(message.DataLen());
1950
for(int i=0;i<len;i++)
1951
sendBuffer_[sendBuffer_.Len()]=htons(message.Data(i));
1953
tRecorderSync< unsigned short >::Archive( "_MESSAGE_SEND_LEN", 5, len );
1957
control->Use( nBandwidthControl::Usage_Planning, len * 2 );
1961
// send the contents of the buffer to a specific socket
1962
void nSendBuffer::Send ( nSocket const & socket
1963
, const nAddress & peer
1964
,nBandwidthControl* control )
1966
if (sendBuffer_.Len()){
1968
sn_SentBytes += sendBuffer_.Len() * 2 + OVERHEAD;
1971
sendBuffer_[sendBuffer_.Len()]=htons(::sn_myNetID);
1973
socket.Write( reinterpret_cast<int8 *>(&(sendBuffer_[0])),
1974
2*sendBuffer_.Len(), peer);
1978
control->Use( nBandwidthControl::Usage_Execution, 2*sendBuffer_.Len() + OVERHEAD );
1985
// broadcast the contents of the buffer
1986
void nSendBuffer::Broadcast ( nSocket const & socket
1988
, nBandwidthControl* control )
1990
if (sendBuffer_.Len()){
1992
sn_SentBytes += sendBuffer_.Len() * 2 + OVERHEAD;
1995
sendBuffer_[sendBuffer_.Len()]=htons(::sn_myNetID);
1997
socket.Broadcast( reinterpret_cast<int8 *>(&(sendBuffer_[0])),
1998
2*sendBuffer_.Len(), port);
2004
control->Use( nBandwidthControl::Usage_Execution, 2*sendBuffer_.Len() + OVERHEAD );
2009
// clears the buffer
2010
void nSendBuffer::Clear()
2012
for(int i=sendBuffer_.Len()-1;i>=0;i--)
2015
sendBuffer_.SetLen( 0 );
2019
nBandwidthControl::nBandwidthControl( nBandwidthControl* parent )
2023
parent->numChildren_ ++;
2032
nBandwidthControl::~nBandwidthControl()
2036
parent_->numChildren_ --;
2038
tASSERT( numChildren_ == 0 );
2042
void nBandwidthControl::Reset()
2044
rateControlPlanned_ = rateControl_ = 1000.0f;
2048
void nBandwidthControl::Use( Usage planned, REAL bandwidth )
2050
tRecorderSync< REAL >::Archive( "_RATE_CONTROL_USAGE", 4, bandwidth );
2051
( Usage_Planning == planned ? rateControlPlanned_ : rateControl_ ) -= bandwidth;
2054
void nBandwidthControl::Update( REAL ts)
2056
tRecorderSync< REAL >::Archive( "_RATE_CONTROL", 12, rateControl_ );
2057
tRecorderSync< REAL >::Archive( "_RATE_CONTROL_PLANNED", 12, rateControlPlanned_ );
2059
rateControl_ += ( rate_ * 1000 ) * ts;
2061
if ( rateControl_ > 1000.0f )
2063
rateControl_ = 1000.0f;
2066
rateControlPlanned_ = rateControl_;
2069
void nMessage::SendCollected(int peer)
2071
//if ( peer == 7 && sn_Connections[peer].sendBuffer_.Len() > 0 )
2072
// con << tSysTimeFloat() << "\n";
2074
sn_OrderPriority = 0;
2076
if (peer<0 || peer > MAXCLIENTS+1 || !sn_Connections[peer].socket)
2077
tERR_ERROR("Invalid peer!");
2079
sn_Connections[peer].sendBuffer_.Send( *sn_Connections[peer].socket, peers[peer], &sn_Connections[peer].bandwidthControl_ );
2083
void nMessage::BroadcastCollected(int peer, unsigned int port){
2084
if (peer<0 || peer > MAXCLIENTS+1 || !sn_Connections[peer].socket)
2085
tERR_ERROR("Invalid peer!");
2087
sn_Connections[peer].sendBuffer_.Broadcast( *sn_Connections[peer].socket, port, &sn_Connections[peer].bandwidthControl_ );
2092
void nMessage::SendImmediately(int peer,bool ack){
2096
tASSERT(messageIDBig_);
2098
new nWaitForAck(this,peer);
2100
#ifdef nSIMULATE_PING
2105
// server: messages to yourself are a bit strange...
2106
if ( sn_GetNetState() == nSERVER && peer == 0 && ack )
2109
tJUST_CONTROLLED_PTR< nMessage > bounce(this);
2116
con << "SMT " << descriptor << "\n";
2121
if (sn_Connections[].rate_control[peer]<-2000)
2122
tERR_ERROR("Heavy network overflow.");
2126
// if (peer==0 && sn_GetNetState()==nSERVER)
2127
// tERR_ERROR("talking to yourself, eh?");
2129
if (peer==MAXCLIENTS+1){
2131
if(descriptor==s_Acknowledge.id)
2132
con << "Sending ack to login slot.\n";
2134
// else if (descriptor
2135
// tERR_ERROR("the last user only should receive denials or acks.");
2139
if (sn_Connections[peer].sendBuffer_.Len()+data.Len()+3 > MAX_MESS_LEN/2){
2140
SendCollected(peer);
2141
//con << "Overflow packets sent to " << peer << '\n';
2145
if (sn_Connections[peer].socket)
2147
sn_Connections[peer].sendBuffer_.AddMessage( *this, &sn_Connections[peer].bandwidthControl_ );
2150
if (sn_Connections[].rate_control[peer]>0)
2151
send_collected(peer);
2153
unsigned short *b=new (unsigned short)[data.Len()+3];
2155
b[0]=htons(descriptor);
2156
b[1]=htons(messageID);
2157
b[2]=htons(data.Len());
2159
for(int i=0;i<len;i++)
2160
b[3+i]=htons(data(i));
2163
ANET_Write(sn_Connections[].socket[peer],(int8 *)b,
2164
2*(data.Len()+3),&peers[peer]);
2166
//std::cerr << "Sent " << 2*len+6 << " bytes.\n";
2167
sn_Connections[].rate_control[peer]-=2*(len+3)+OVERHEAD;
2173
con << "Sent " <<descriptor << ':' << messageIDBig_ << ":"
2177
tControlledPTR< nMessage > bounce( this ); // delete this message if nobody is interested in it any more
2180
REAL sent_per_messid[MAXDESCRIPTORS+100];
2182
void nMessage::Send(int peer,REAL priority,bool ack){
2188
// don't send messages to unsupported peers
2189
if( peer > MAXCLIENTS+1 )
2191
tJUST_CONTROLLED_PTR< nMessage > bounce(this);
2196
// messages to yourself are a bit strange...
2197
if ( sn_GetNetState() == nSERVER && peer == 0 && ack )
2200
tJUST_CONTROLLED_PTR< nMessage > bounce(this);
2206
if (peer==MAXCLIENTS+1){
2207
if(descriptor==s_Acknowledge.id)
2208
con << "Sending ack to login slot.\n";
2209
// else if (descriptor
2210
// tERR_ERROR("the last user only should receive denials or acks.");
2216
con << "PMT " << descriptor << "\n";
2219
// the next line was redundant; the send buffer handles that part of accounting.
2220
//sn_Connections[peer].bandwidthControl_.Use( nBandwidthControl::Usage_Planning, 2*(data.Len()+3) );
2222
sent_per_messid[descriptor]+=2*(data.Len()+3);
2224
tASSERT(Descriptor()!=s_Acknowledge.ID() || !ack);
2226
new nMessage_planned_send(this,priority+sn_OrderPriority,ack,peer);
2227
sn_OrderPriority += .01; // to roughly keep the relative order of netmessages
2230
// ack messages: don't get an ID
2231
class nAckMessage: public nMessage
2234
nAckMessage(): nMessage( s_Acknowledge ){ messageIDBig_ = 0; }
2237
// receive and s_Acknowledge the recently reveived network messages
2239
typedef std::deque< tJUST_CONTROLLED_PTR< nMessage > > nMessageFifo;
2241
static void rec_peer(unsigned int peer){
2242
tASSERT( sn_Connections[peer].socket );
2246
// temporary fifo for received messages
2247
//static tArray< tJUST_CONTROLLED_PTR< nMessage > > receivedMessages;
2248
static nMessageFifo receivedMessages;
2250
// the growing buffer we read messages into
2251
const int serverMaxAcceptedSize=2000;
2252
static tArray< unsigned short > storage(2000);
2253
int maxrec = 0; maxrec = storage.Len();
2254
unsigned short * buff = 0; buff = &storage[0];
2256
// short buff[maxrec];
2257
if (sn_Connections[peer].socket){
2260
while (len>=0 && sn_Connections[peer].socket)
2262
nAddress addrFrom; // the sender of the current packet
2263
len = sn_Connections[peer].socket->Read( reinterpret_cast<int8 *>(buff),maxrec*2, addrFrom);
2266
if ( len >= maxrec*2 )
2268
// the message was too long to receive. What to do?
2269
if ( sn_GetNetState() != nSERVER || len < serverMaxAcceptedSize )
2271
// expand the buffer. The message is lost now, but the
2272
// peer will certainly resend it. Hopefully, the buffer will be large enough to hold it then.
2273
storage[maxrec*2-1]=0;
2274
maxrec = storage.Len();
2277
tERR_WARN( "Oversized network packet received. Read buffer has been enlargened to catch it the next time.");
2279
// no use in processing the truncated packet. Some messages may get lost,
2280
// but that's better than the inevitable network error and connection
2281
// termination that expects us if we go on.
2286
// terminate the connection
2287
sn_DisconnectUser( peer, "$network_kill_error" );
2291
unsigned short *b=buff;
2292
unsigned short *bend=buff+(len/2-1);
2294
sn_ReceivedPackets++;
2295
sn_ReceivedBytes += len + OVERHEAD;
2297
unsigned short claim_id=ntohs(*bend);
2299
// z-man: security check ( thanks, Luigi Auriemma! )
2300
if ( claim_id > MAXCLIENTS+1 )
2301
continue; // drop packet, maybe it was just truncated.
2304
std::cerr << "Received " << len << " bytes";
2305
con << " from user " << claim_id << '\n';
2309
unsigned int id=peer;
2310
// for(unsigned int i=1;i<=(unsigned int)maxclients;i++)
2311
int comp=nAddress::Compare( addrFrom, peers[claim_id] );
2312
if ( comp == 0 ) // || claim_id == MAXCLIENTS+1 )
2314
// everything seems allright. accept the id.
2319
// assume it's a new connection
2321
peers[ MAXCLIENTS+1 ] = addrFrom;
2322
sn_Connections[ MAXCLIENTS+1 ].socket = sn_Connections[peer].socket;
2326
// con << "Changed incoming address.\n";
2327
int lenleft = bend - b;
2333
while( lenleft > 0 ){
2334
tJUST_CONTROLLED_PTR< nMessage > pmess;
2335
pmess = tNEW( nMessage )(b,id,lenleft);
2336
nMessage& mess = *pmess;
2340
bool mess_is_new=true;
2341
// see if we have got this packet before
2342
unsigned short mess_id=mess.MessageID();
2345
if ( (simulate_loss && rand()%simulate_loss==0)){
2346
// simulate packet loss
2347
con << "Losing packet " << mess_id << ":" << id << ".\n";
2350
if(// (id==MAXCLIENTS+1 && !nCallbackAcceptPackedWithoutConnection::Accept( mess ) ) ||
2351
// do not accept normal packages from the login
2352
// slot; just login and information packets are allowed.
2353
( sn_GetNetState() != nSERVER && !login_succeeded && !nCallbackAcceptPackedWithoutConnection::Accept( mess ) )
2354
// if we are not yet logged in, accept only login and login_deny.
2357
// con << "Ignoring packet " << mess_id << ":" << id << ".\n";
2361
if (id <= MAXCLIENTS && mess_id != 0) // messages with ID 0 are non-ack messages and come really often. they are always new.
2363
unsigned short diff=mess_id-highest_ack[id];
2364
if ( ( diff>0 && diff<10000 ) ||
2366
mess.Descriptor() == login_accept.ID() ||
2367
mess.Descriptor() == login_deny.ID() ||
2368
mess.Descriptor() == login.ID()
2369
) && highest_ack[id] == 0)
2371
// the message has a more recent id than anything before.
2372
// it is surely new.
2373
highest_ack[id]=mess_id;
2376
// do a better check
2377
for(int i=ACKBACK-1;i>=0;i--)
2378
if (mess_id==lastacks[id][i])
2384
// acknowledge the message, even if it was old (the sender
2385
// then thinks it got lost the first time)
2387
// special situation: logout. Do not sent ack any more.
2388
if ((!sn_Connections[id].socket))
2390
sn_Connections[id].ackMess=NULL;
2394
(mess.MessageID()) &&
2396
(mess.Descriptor()!=login_ignore.ID() ||
2398
// do not ack the login_ignore packet that did not let you in.
2401
if ( id > MAXCLIENTS )
2403
con << "Sending ack to login slot.\n";
2407
if(sn_Connections[id].ackMess==NULL)
2409
sn_Connections[id].ackMess=new nAckMessage();
2412
sn_Connections[id].ackMess->Write(mess.MessageID());
2413
if (sn_Connections[id].ackMess->DataLen()>100){
2414
sn_Connections[id].ackMess->Send(id, 0, false);
2415
sn_Connections[id].ackMess=NULL;
2420
// mark the message as old
2423
lastacks[id][lastackPos[id]]=mess_id;
2424
if(++lastackPos[id]>=ACKBACK) lastackPos[id]=0;
2428
// special situation: login. Change peer number permanently
2429
if (peer==MAXCLIENTS+1 && new_id>0){
2434
if (sn_GetNetState() != nSTANDALONE)
2436
// store the message for later processing
2437
receivedMessages.push_back( pmess );
2441
//con << "Message " << mess_id << ":" << id << " was not new.\n";
2449
con << "nKillHim signal caught.\n";
2450
sn_DisconnectUser(peer, "$network_kill_error");
2458
static int recursionCount = 0;
2462
while ( receivedMessages.begin() != receivedMessages.end() )
2464
tJUST_CONTROLLED_PTR< nMessage > mess = receivedMessages.front();
2465
receivedMessages.pop_front();
2467
// perhaps the connection died?
2468
if ( sn_Connections[ mess->SenderID() ].socket )
2469
nDescriptor::HandleMessage( *mess );
2472
if ( --recursionCount <= 0 )
2474
nCallbackReceivedComplete::ReceivedComplete();
2480
catch(nKillHim const &)
2482
con << "nKillHim signal caught.\n";
2483
sn_DisconnectUser(peer, "$network_kill_error");
2491
// receives and processes data from control socket
2492
void sn_ReceiveFromControlSocket()
2497
// discards data from control socket
2498
void sn_DiscardFromControlSocket()
2500
// new facts: pending incoming data on the control socket causes the idle loops
2501
// to use 100% CPU time, we need to fetch and discard the data instead of ignoring it.
2502
if ( sn_Connections[0].socket )
2506
sn_Connections[0].socket->Read( reinterpret_cast<int8 *>(buff),0, addrFrom);
2511
nNetState sn_GetNetState(){
2512
return current_state;
2515
void clear_owners();
2517
// tries to open listening sockets according to specification, but falls back to increasing ports
2518
static bool sn_Listen( unsigned int & net_hostport, const tString& net_hostip )
2520
unsigned int net_hostport_before = net_hostport;
2524
nSocketListener & listener = sn_BasicNetworkSystem.AccessListener();
2526
listener.SetIpList( net_hostip );
2528
bool reported = false;
2530
// try ports in a range
2531
while ( net_hostport < sn_serverPort + 100 )
2533
if ( listener.SetPort( net_hostport ).Listen( true ) )
2538
con << "sn_SetNetState: Unable to open accept socket on desired port " << net_hostport << ", Trying next ports...\n";
2545
con << "sn_SetNetState: Giving up setting up listening sockets for IP list " << net_hostip << ".\n";
2547
catch( const tException & e )
2549
con << "sn_SetNetState: can't setup listening sockets. Reason given:\n"
2550
<< e.GetName() << ": " << e.GetDescription() << "\n";
2554
net_hostport = net_hostport_before;
2559
// save and load machine info
2560
static void sn_SaveMachines();
2561
static void sn_LoadMachines();
2563
static void sn_DisconnectAll()
2565
for(int i=MAXCLIENTS+1;i>=0;i--)
2567
if( sn_Connections[i].socket )
2569
sn_DisconnectUser(i, "$network_kill_shutdown");
2570
tVERIFY( !sn_Connections[i].socket );
2573
nCallbackLoginLogout::UserLoggedOut(0);
2576
// flag set as long as the network sockets should not be closed and reopened
2577
static bool sn_noReset = false;
2578
nSocketResetInhibitor::nSocketResetInhibitor()
2582
nSocketResetInhibitor::~nSocketResetInhibitor()
2587
void sn_SetNetState(nNetState x){
2588
static bool reentry=false;
2589
if(!reentry && x!=current_state){
2590
sn_UpdateCurrentVersion();
2593
unsigned int net_hostport = sn_serverPort;
2595
// save/load machines on entering/leaving server mode
2598
else if ( current_state == nSERVER )
2599
if ( !tRecorder::IsPlayingBack() )
2614
if (!sn_Connections[0].socket)
2615
sn_Connections[0].socket=sn_BasicNetworkSystem.Init();
2616
// bool success = true;
2620
sn_Listen( net_hostport, net_hostip ) || // first try: do it according to user specs
2621
sn_Listen( net_hostport, tString( "ANY" ) ) || // second try: bind to generic IP
2622
sn_Listen( net_hostport, tString( "ALL" ) ); // last try: bind to all available IPs
2625
// save host port that worked, otherwise it may change from the port sent to the master server
2626
sn_serverPort = net_hostport;
2633
for(int i=MAXCLIENTS+1;i>=0;i--){
2634
if(sn_Connections[i].socket){
2635
if (i==0 && current_state!=nSERVER)
2636
{ // logout: fire and forget
2637
con << tOutput("$network_logout_process");
2638
for(int j=3;j>=0;j--){ // just to make sure
2639
nMessage *lo=new nMessage(logout);
2640
lo->Write(static_cast<unsigned short>(sn_myNetID));
2641
lo->ClearMessageID();
2642
lo->SendImmediately(0, false);
2643
nMessage::SendCollected(0);
2646
con << tOutput("$network_logout_done");
2648
sn_myNetID=0; // MAXCLIENTS+1; // reset network id
2651
sn_DisconnectUserNoWarn(i, "$network_kill_shutdown");
2654
// repeat to clear out pending stuff created during
2655
// the last run (destruction messages, for example)
2656
for(int i=MAXCLIENTS+1;i>=0;i--)
2658
sn_DisconnectUserNoWarn(i, "$network_kill_shutdown");
2661
sn_Connections[0].socket = 0;
2663
// shutdown network system to get new socket
2665
sn_BasicNetworkSystem.Shutdown();
2672
sn_UpdateCurrentVersion();
2677
// go to client mode and connect to server
2680
void sn_Bend( nAddress const & address )
2682
if ((sn_GetNetState() == nSTANDALONE))
2683
sn_SetNetState(nCLIENT);
2688
void sn_Bend( tString const & server, unsigned int port)
2690
// fill address info
2692
address.SetHostname( server );
2693
address.SetPort( port );
2699
nConnectError sn_Connect( nAddress const & server, nLoginType loginType, nSocket const * socket ){
2702
// reset redirection
2703
sn_redirectTo.release();
2705
// pings in the beginning of the login are not really representative
2706
nPingAverager::SetWeight(.0001);
2708
// net_hostport = sn_clientPort;
2710
sn_SetNetState(nSTANDALONE);
2711
sn_SetNetState(nCLIENT);
2713
// set user requested socket
2715
sn_Connections[0].socket = socket;
2717
sn_Connections[0].ping.Reset();
2722
nCallbackLoginLogout::UserLoggedOut(0);
2723
sn_Connections[0].sendBuffer_.Clear();
2725
tASSERT( sn_Connections[0].socket );
2727
// sn_Connections[0].socket->Connect( peers[0] ); // useless
2728
sn_Connections[0].bandwidthControl_.SetRate( sn_maxRateOut );
2730
sn_myNetID=0; // MAXCLIENTS+1; // reset network id
2732
// first, get all pending messages
2737
// reset version control until the true value is given by the server.
2738
sn_currentVersion = nVersion(0,0);
2741
tJUST_CONTROLLED_PTR< nMessage > mess;
2742
if ( loginType != Login_Pre0252 )
2744
mess=new nMessage(login_2);
2745
mess->Write(sn_maxRateIn);
2747
unsigned short bb = big_brother;
2750
(*mess) << sn_bigBrotherString;
2756
mess=new nMessage(login);
2757
mess->Write(sn_maxRateIn);
2759
// send (worthless) big brother string
2762
(*mess) << sn_bigBrotherString;
2766
(*mess) << tString("");
2772
// write our version
2773
(*mess) << sn_MyVersion();
2775
// write our supported authentication methods
2776
(*mess) << nKrawall::nMethod::SupportedMethods();
2778
// write a random salt
2779
nKrawall::RandomSalt( loginSalt );
2780
nKrawall::WriteScrambledPassword( loginSalt, *mess );
2782
mess->ClearMessageID();
2783
mess->SendImmediately(0,false);
2784
nMessage::SendCollected(0);
2786
con << tOutput("$network_login_process");
2789
login_succeeded=false;
2791
nTimeRolling timeout=tSysTimeFloat()+5;
2793
static REAL resend = .25;
2794
nTimeAbsolute nextSend = tSysTimeFloat() + resend/5;
2795
while(sn_GetNetState()==nCLIENT && tSysTimeFloat()<timeout &&
2796
!login_failed && !login_succeeded){
2797
if ( tSysTimeFloat() > nextSend )
2799
// con << "retrying...\n";
2800
nextSend = tSysTimeFloat() + resend;
2801
mess->SendImmediately(0,false);
2802
nMessage::SendCollected(0);
2805
tAdvanceFrame(10000);
2809
// check for user abort
2810
if ( tConsole::Idle() )
2812
con << tOutput("$network_login_failed_abort");
2813
sn_SetNetState(nSTANDALONE);
2819
con << tOutput("$network_login_failed");
2820
sn_SetNetState(nSTANDALONE);
2823
else if (tSysTimeFloat()>=timeout || sn_GetNetState()!=nCLIENT){
2824
if ( loginType == Login_All )
2826
return sn_Connect( server, Login_Pre0252, socket );
2830
con << tOutput("$network_login_failed_timeout");
2831
sn_SetNetState(nSTANDALONE);
2836
nCallbackLoginLogout::UserLoggedIn(0);
2839
mess.SetTemplateParameter(1, sn_myNetID);
2840
mess << "$network_login_success";
2842
con << tOutput("$network_login_sync");
2844
con << tOutput("$network_login_relabeling");
2845
con << tOutput("$network_login_sync2");
2847
con << tOutput("$network_login_done");
2849
// marginalize past ping values
2850
nPingAverager::SetWeight(1);
2857
void nReadError( bool critical )
2866
con << "\nI told you not to use PGCC! Now we need to leave the\n"
2867
<< "system in an undefined state. The progam will crash now.\n"
2873
static short sn_decorateID = true;
2874
static tConfItem< short > sn_decorateIDConf( "CONSOLE_DECORATE_ID", sn_decorateID );
2876
static short sn_decorateIP = false;
2877
static tConfItem< short > sn_decorateIPConf( "CONSOLE_DECORATE_IP", sn_decorateIP );
2879
static tConfItem< bool > sn_decorateTSConf( "CONSOLE_DECORATE_TIMESTAMP", sn_decorateTS );
2881
// console with filter for better machine readable log format
2882
class nConsoleFilter:public tConsoleFilter{
2884
virtual void DoFilterLine( tString &line )
2886
if ( sn_decorateID )
2888
tString orig = line;
2890
int id = nCurrentSenderID::GetID();
2891
bool printIP = ( id > 0 && sn_decorateIP );
2895
if ( sn_decorateID )
2897
if ( sn_decorateID && sn_decorateTS )
2899
if ( sn_decorateTS )
2900
line << st_GetCurrentTime("TS=%Y/%m/%d-%H:%M:%S");
2901
if ( (sn_decorateID || sn_decorateTS) && printIP )
2907
sn_GetAdr( id, IP );
2908
line << "IP=" << IP;
2911
line << "] " << orig;
2916
static nConsoleFilter sn_consoleFilter;
2919
static void sn_ConsoleOut_handler(nMessage &m){
2920
if (sn_GetNetState()!=nSERVER){
2928
static nDescriptor sn_ConsoleOut_nd(8,sn_ConsoleOut_handler,"sn_ConsoleOut");
2930
// rough maximal packet size, better send nothig bigger, or it will
2934
// causes the connected clients to print a message
2935
nMessage* sn_ConsoleOutMessage( tString const & message )
2937
// truncate message to about 1.5K, a safe size for all UDP packets
2938
static const int maxLen = MTU+100;
2939
static bool recurse = true;
2940
if ( message.Len() > maxLen && recurse )
2943
tERR_WARN( "Long console message truncated.");
2944
nMessage * m = sn_ConsoleOutMessage( message.SubStr( 0, MTU ) );
2949
nMessage* m=new nMessage(sn_ConsoleOut_nd);
2955
void sn_ConsoleOutRaw( tString & message,int client){
2956
tJUST_CONTROLLED_PTR< nMessage > m = sn_ConsoleOutMessage( message );
2962
else if (client==sn_myNetID)
2972
void sn_ConsoleOutString( tString & message,int client){
2973
// check if string is too long
2974
if ( message.Len() <= MTU )
2976
// no? Fine, just send it in one go.
2977
message << "0xffffff";
2978
sn_ConsoleOutRaw( message, client );
2983
// darn, it is too long. Try to find a good spot to cut it
2985
while ( cut > 0 && message(cut) != '\n' )
2991
// no suitable spot found, just cut anywhere.
2996
tString beginning = message.SubStr( 0, cut ) + "0xffffff";
2997
tString rest = message.SubStr( cut );
2999
// and send the bits
3000
sn_ConsoleOutRaw( beginning, client );
3001
sn_ConsoleOutString( rest, client );
3004
void sn_ConsoleOut(const tOutput& o,int client){
3005
// transform message to string
3006
tString message( o );
3007
sn_ConsoleOutString( message, client );
3010
static void client_cen_handler(nMessage &m){
3011
if (sn_GetNetState()!=nSERVER){
3014
con.CenterDisplay(s);
3018
static nDescriptor client_cen_nd(9,client_cen_handler,"client_cen");
3020
// causes the connected clients to print a message in the center of the screeen
3021
void sn_CenterMessage(const tOutput &o,int client){
3024
tJUST_CONTROLLED_PTR< nMessage > m=new nMessage(client_cen_nd);
3028
con.CenterDisplay(message);
3030
else if (client==sn_myNetID)
3031
con.CenterDisplay(message);
3036
static void ConsoleOut_conf(std::istream &s)
3040
message.ReadLine( s, true );
3045
sn_ConsoleOut( message );
3048
static tConfItemFunc ConsoleOut_c("CONSOLE_MESSAGE",&ConsoleOut_conf);
3049
static tAccessLevelSetter sn_ConsoleConfLevel( ConsoleOut_c, tAccessLevel_Moderator );
3051
static void CeterMessage_conf(std::istream &s)
3055
message.ReadLine( s, true );
3058
sn_CenterMessage( message );
3061
static tConfItemFunc CenterMessage_c("CENTER_MESSAGE",&CeterMessage_conf);
3062
static tAccessLevelSetter sn_CenterConfLevel( CenterMessage_c, tAccessLevel_Moderator );
3064
// ****************************************************************
3066
// ****************************************************************
3068
// the network stuff planned to send:
3069
tHeap<planned_send> send_queue[MAXCLIENTS+2];
3071
planned_send::planned_send(REAL priority,int Peer){
3074
SetVal( priority, send_queue[peer] );
3077
planned_send::~planned_send(){
3081
tHeapBase *planned_send::Heap() const
3083
return &send_queue[peer];
3086
// change our priority:
3087
void planned_send::add_to_priority(REAL diff)
3089
SetVal( Val() + diff, send_queue[peer] );
3092
// **********************************************
3094
nMessage_planned_send::nMessage_planned_send
3095
(nMessage *M,REAL priority,bool Ack,int Peer)
3096
:planned_send(priority,Peer),m(M),ack(Ack){
3100
nMessage_planned_send::~nMessage_planned_send(){
3103
void nMessage_planned_send::execute(){
3104
if ( Val() < -killTimeout-10){
3106
mess.SetTemplateParameter(1, peer);
3107
mess << "$network_error_overflow";
3110
sn_DisconnectUser(peer, "$network_kill_overflow");
3113
m->SendImmediately(peer,ack);
3117
// **********************************************
3119
static REAL sn_SendPlanned1(){
3120
sn_OrderPriority = 0;
3122
// if possible, send waiting messages
3123
static double lastTime=-1;
3124
nTimeAbsolute time=tSysTimeFloat();
3128
if (time<lastTime-.01 || time>lastTime+1000)
3131
tERR_ERROR("Timer hickup!");
3135
tERR_WARN("Timer hickup!");
3139
REAL dt = time - lastTime;
3141
//for(int i=MAXCLIENTS+1;i>=0;i--){
3142
for(int i=0;i<=MAXCLIENTS+1;i++){
3143
nConnectionInfo & connection = sn_Connections[i];
3144
if ( !connection.socket )
3147
while (connection.ackPending<sn_maxNoAck &&
3148
connection.bandwidthControl_.CanSend() &&
3149
send_queue[i].Len())
3151
send_queue[i](0)->execute();
3152
if (send_queue[i].Len())
3153
delete send_queue[i](0);
3156
// make everything a little more urgent:
3157
for(int j=send_queue[i].Len()-1;j>=0;j--)
3158
send_queue[i](j)->add_to_priority(-dt);
3165
static void sn_SendPlanned2( REAL dt ){
3166
// empty the send buffers
3167
for(int i=0;i<=MAXCLIENTS+1;i++){
3168
nConnectionInfo & connection = sn_Connections[i];
3169
if ( connection.socket )
3171
if (connection.sendBuffer_.Len()>0 && connection.bandwidthControl_.CanSend() )
3172
nMessage::SendCollected(i);
3174
// update bandwidth usage and other time related data
3175
connection.Timestep( dt );
3180
void sn_SendPlanned()
3182
// propagate messages to buffers
3183
REAL dt = sn_SendPlanned1();
3185
// schedule the acks: send them if it's possible (bandwith limit) or if there already is a packet in the pipe.
3186
for(int i=0;i<=MAXCLIENTS+1;i++)
3187
if(sn_Connections[i].socket && sn_Connections[i].ackMess && !sn_Connections[i].ackMess->End()
3188
// && sn_ackAckPending[i] <= 1+sn_Connections[].ackMess[i]->DataLen()
3189
&& ( sn_Connections[i].bandwidthControl_.CanSend() || sn_Connections[i].sendBuffer_.Len() > 0 )
3191
sn_Connections[i].ackMess->SendImmediately(i, false);
3192
sn_Connections[i].ackMess=NULL;
3195
// schedule lost messages for resending
3196
nWaitForAck::Resend();
3198
// send everything out
3199
sn_SendPlanned2( dt );
3204
static bool reentry=false;
3210
netTime=tSysTimeFloat();
3212
sn_Connections[MAXCLIENTS+1].ping.Reset();
3214
// create the ack messages (not required, is done on demand later)
3217
for(i=0;i<=MAXCLIENTS+1;i++)
3218
if(sn_Connections[i].ackMess==NULL)
3219
sn_Connections[i].ackMess=new nAckMessage();
3223
switch (current_state){
3226
memset( &peers[0], 0, sizeof(sockaddr) );
3228
// listen on all sockets
3229
nSocketListener const & listener = sn_BasicNetworkSystem.GetListener();
3230
for ( nSocketListener::iterator i = listener.begin(); i != listener.end(); ++i )
3232
// clear peer info used for receiving
3233
memset( &peers[MAXCLIENTS+1], 0, sizeof(sockaddr) );
3235
// copy socket info over to [MAXCLIENTS+1] and receive. The copy
3236
// step is important, nAuthentication.cpp relies on the socket being set.
3237
if((sn_Connections[MAXCLIENTS+1].socket = (*i).CheckNewConnection() ) != NULL)
3239
rec_peer(MAXCLIENTS+1);
3243
// z-man: after much thought, the server does also need to listen to the
3244
// network control socket. .... Thinking again, it's only important for the master
3245
// servers, and they call rec_peer(0) separately.
3258
// scedule regular messages
3259
REAL dt = sn_SendPlanned1();
3261
// actually resend messages
3262
sn_SendPlanned2( dt );
3266
void sn_KickUser(int i, const tOutput& reason, REAL severity, nServerInfoBase * redirectTo )
3269
con << tOutput( "$network_kill_log", i, reason );
3274
nMachine::GetMachine(i).OnKick( severity );
3278
sn_DisconnectUser( i, reason, redirectTo );
3281
void sn_DisconnectUser(int i, const tOutput& reason, nServerInfoBase * redirectTo )
3283
// don't be daft and kill yourself, server!
3284
if ( i == 0 && sn_GetNetState() == nSERVER )
3286
tERR_WARN( "Server tried to disconnect from itself." );
3290
// clients can only disconnect from the server
3291
if ( i != 0 && sn_GetNetState() == nCLIENT )
3293
tERR_ERROR( "Client tried to disconnect from another client: impossible and a bad idea." );
3297
// anything to do at all?
3298
if (!sn_Connections[i].socket)
3303
sn_DisconnectUserNoWarn( i, reason, redirectTo );
3306
void sn_DisconnectUserNoWarn(int i, const tOutput& reason, nServerInfoBase * redirectTo )
3308
nCurrentSenderID senderID( i );
3310
nWaitForAck::AckAllPeer(i);
3312
static bool reentry=false;
3317
bool printMessage = false; // is it worth printing a message for this event?
3319
if (sn_Connections[i].socket)
3321
nMessage::SendCollected(i);
3322
printMessage = true;
3325
if ( i!=0 && i != MAXCLIENTS+2 && sn_GetNetState() == nSERVER ){
3326
for(int j=2;j>=0;j--){
3327
nMessage* mess = (new nMessage(login_deny));
3328
*mess << tString( reason );
3330
// write redirection
3331
tString redirection;
3335
redirection = redirectTo->GetConnectionName();
3336
port = redirectTo->GetPort();
3338
*mess << redirection;
3341
mess->SendImmediately(i, false);
3342
nMessage::SendCollected(i);
3347
nWaitForAck::AckAllPeer(i);
3349
sn_Connections[i].ackMess=NULL;
3351
if (i==0 && sn_GetNetState()==nCLIENT)
3352
sn_SetNetState(nSTANDALONE);
3356
// peers[i].sa_family=0;
3358
sn_Connections[i].ackPending=0;
3359
// sn_ackAckPending[i]=0;
3361
nCallbackLoginLogout::UserLoggedOut(i);
3365
con << tOutput( "$network_killuser", i, sn_Connections[i].ping.GetPing() );
3368
// clear address, socket and send queue
3369
sn_Connections[i].sendBuffer_.Clear();
3370
sn_Connections[i].socket=NULL;
3371
peers[i] = nAddress();
3372
sn_Connections[i].Clear();
3373
while (send_queue[i].Len())
3374
delete (send_queue[i](0));
3378
sn_UpdateCurrentVersion();
3382
int sn_QueueLen(int user){
3383
return send_queue[user].Len();
3387
static tCallback* s_loginoutAnchor=NULL;
3388
int nCallbackLoginLogout::user;
3389
bool nCallbackLoginLogout::login;
3391
nCallbackLoginLogout::nCallbackLoginLogout(VOIDFUNC *f)
3392
:tCallback(s_loginoutAnchor,f){}
3394
void nCallbackLoginLogout::UserLoggedIn(int u){
3397
Exec(s_loginoutAnchor);
3400
void nCallbackLoginLogout::UserLoggedOut(int u){
3403
Exec(s_loginoutAnchor);
3406
unsigned short nCallbackAcceptPackedWithoutConnection::descriptor=0; // the descriptor of the incoming packet
3407
static tCallbackOr* s_AcceptAnchor=NULL;
3409
nCallbackAcceptPackedWithoutConnection::nCallbackAcceptPackedWithoutConnection(BOOLRETFUNC *f)
3410
: tCallbackOr( s_AcceptAnchor, f )
3414
bool nCallbackAcceptPackedWithoutConnection::Accept( const nMessage& m )
3416
descriptor=m.Descriptor();
3417
return Exec( s_AcceptAnchor );
3420
static tCallback* s_ReceivedCompleteAnchor=NULL;
3422
nCallbackReceivedComplete::nCallbackReceivedComplete(VOIDFUNC *f)
3423
: tCallback( s_ReceivedCompleteAnchor, f )
3427
void nCallbackReceivedComplete::ReceivedComplete( )
3429
Exec( s_ReceivedCompleteAnchor );
3432
static bool net_Accept()
3435
nCallbackAcceptPackedWithoutConnection::Descriptor()==login_accept.ID() ||
3436
nCallbackAcceptPackedWithoutConnection::Descriptor()==login_deny.ID();
3439
static nCallbackAcceptPackedWithoutConnection net_acc( &net_Accept );
3441
static void net_exit(){
3442
for (int i=MAXCLIENTS+1;i>=0;i--)
3444
sn_Connections[i].ackMess = NULL;
3445
while (send_queue[i].Len())
3446
delete send_queue[i].Remove(0);
3450
static tInitExit net_ie(NULL, &net_exit);
3454
void sn_Statistics()
3456
nTimeRolling time = tSysTimeFloat();
3457
REAL dt = time - sn_StatsTime;
3458
sn_StatsTime = time;
3460
if (dt > 0 && (sn_SentPackets || sn_SentBytes))
3463
o.SetTemplateParameter(1,dt);
3464
o.SetTemplateParameter(2,sn_SentBytes);
3465
o.SetTemplateParameter(3,sn_SentPackets);
3466
o.SetTemplateParameter(4,sn_SentBytes/dt);
3467
o.SetTemplateParameter(5,sn_ReceivedBytes);
3468
o.SetTemplateParameter(6,sn_ReceivedPackets);
3469
o.SetTemplateParameter(7,sn_ReceivedBytes/dt);
3470
o << "$network_statistics1";
3471
o << "$network_statistics2";
3472
o << "$network_statistics3";
3479
sn_ReceivedPackets = 0;
3480
sn_ReceivedBytes = 0;
3488
nConnectionInfo::nConnectionInfo(){Clear();}
3489
nConnectionInfo::~nConnectionInfo(){}
3491
void nConnectionInfo::Clear(){
3497
supportedAuthenticationMethods_ = "";
3499
sendBuffer_.Clear();
3501
bandwidthControl_.Reset();
3505
// userName.SetLen(0);
3507
// start with 10% packet loss with low statistical weight
3508
packetLoss_.Reset();
3509
packetLoss_.Add(.1,10);
3512
void nConnectionInfo::Timestep( REAL dt ) //!< call whenever an an reliable message got sent
3515
ping.Timestep( dt );
3517
// update bandwidth control
3518
bandwidthControl_.Update( dt );
3520
// update packet loss; average about a minute
3521
packetLoss_.Timestep( .02 * dt );
3524
void nConnectionInfo::ReliableMessageSent() //!< call whenever an an reliable message got sent
3526
packetLoss_.Add( 1 );
3529
void nConnectionInfo::AckReceived() //!< call whenever an ackownledgement message arrives
3531
packetLoss_.Add( -1 );
3534
REAL nConnectionInfo::PacketLoss() const //!< returns the average packet loss ratio
3536
REAL ret = packetLoss_.GetAverage();
3537
return ret > 0 ? ret : 0;
3540
void sn_GetAdr(int user, tString& name)
3542
peers[user].ToString( name );
3545
unsigned int sn_GetPort(int user)
3547
return peers[user].GetPort();
3550
unsigned int sn_GetServerPort()
3552
return sn_serverPort;
3555
int sn_NumUsers( bool all )
3558
for (int i=MAXCLIENTS; i>0; i--)
3559
if (sn_Connections[i].socket && ( all || ( sn_allowSameIPCountSoft > CountSameIP( i ) ) ) )
3571
return sn_NumUsers( true );
3574
int sn_NumRealUsers()
3576
return sn_NumUsers( false );
3581
return sn_maxClients;
3584
int sn_MessagesPending(int user)
3586
return sn_Connections[user].ackPending + send_queue[user].Len();
3589
nBasicNetworkSystem sn_BasicNetworkSystem;
3591
// *******************************************************************************************
3595
// *******************************************************************************************
3598
// *******************************************************************************************
3600
nKillHim::nKillHim( void )
3604
// *******************************************************************************************
3608
// *******************************************************************************************
3611
// *******************************************************************************************
3613
nKillHim::~nKillHim( void )
3617
// *******************************************************************************************
3621
// *******************************************************************************************
3623
//! @return short name
3625
// *******************************************************************************************
3627
tString nKillHim::DoGetName( void ) const
3629
return tString( "Connektion kill request" );
3632
// *******************************************************************************************
3634
// * DoGetDescription
3636
// *******************************************************************************************
3638
//! @return description
3640
// *******************************************************************************************
3642
tString nKillHim::DoGetDescription( void ) const
3644
return tString( "The currently handled peer must have done something illegal, so it should be terminated." );
3647
// *******************************************************************************************
3651
// *******************************************************************************************
3654
// *******************************************************************************************
3656
nIgnore::nIgnore( void )
3660
// *******************************************************************************************
3664
// *******************************************************************************************
3667
// *******************************************************************************************
3669
nIgnore::~nIgnore( void )
3673
// *******************************************************************************************
3677
// *******************************************************************************************
3679
//! @return short name
3681
// *******************************************************************************************
3683
tString nIgnore::DoGetName( void ) const
3685
return tString( "Packet ignore request" );
3688
// *******************************************************************************************
3690
// * DoGetDescription
3692
// *******************************************************************************************
3694
//! @return description
3696
// *******************************************************************************************
3698
tString nIgnore::DoGetDescription( void ) const
3700
return tString( "An error that should lead to the current message getting ingored was detected." );
3703
// *******************************************************************************************
3707
// *******************************************************************************************
3710
// *******************************************************************************************
3712
nAverager::nAverager( void )
3713
: weight_(0), sum_(0), sumSquared_(0), weightSquared_(0)
3717
// *******************************************************************************************
3721
// *******************************************************************************************
3724
// *******************************************************************************************
3726
nAverager::~nAverager( void )
3730
// *******************************************************************************************
3734
// *******************************************************************************************
3736
//! @param decay decay factor 0 .. infinity; larger values lead to more decay.
3738
// *******************************************************************************************
3740
void nAverager::Timestep( REAL decay )
3742
REAL factor = 1/(1+decay);
3744
// pretend all data so far was collected with a weight of the original weight multiplied by factor
3747
sumSquared_ *= factor;
3748
weightSquared_ *= factor * factor;
3751
// *******************************************************************************************
3755
// *******************************************************************************************
3757
//! @param value the value to add
3758
//! @param weight its statistical weight (importance compared to other values)
3760
// *******************************************************************************************
3762
void nAverager::Add( REAL value, REAL weight )
3764
tASSERT( weight >= 0 );
3766
sum_ += weight * value;
3767
sumSquared_ += weight * value * value;
3768
weightSquared_ += weight * weight;
3771
// *******************************************************************************************
3775
// *******************************************************************************************
3778
// *******************************************************************************************
3780
void nAverager::Reset( void )
3782
weightSquared_ = weight_ = sum_ = sumSquared_ = 0.0f;
3785
// *******************************************************************************************
3789
// *******************************************************************************************
3791
//! @return the average value over the last time
3793
// *******************************************************************************************
3795
REAL nAverager::GetAverage( void ) const
3798
return sum_ / weight_;
3803
// *******************************************************************************************
3805
// * GetDataVariance
3807
// *******************************************************************************************
3809
//! @return the average recent variance in the incoming data
3811
// *******************************************************************************************
3813
REAL nAverager::GetDataVariance( void ) const
3817
REAL average = sum_ / weight_;
3818
REAL averageSquare = sumSquared_ / weight_;
3819
REAL ret = averageSquare - average * average;
3828
// *******************************************************************************************
3830
// * GetAverageVariance
3832
// *******************************************************************************************
3834
//! @return the expected variance of the return value of GetAverage()
3836
// *******************************************************************************************
3838
REAL nAverager::GetAverageVariance( void ) const
3842
REAL square = weight_ * weight_;
3844
REAL denominator = square - weightSquared_;
3845
REAL numerator = GetDataVariance() * weightSquared_;
3846
if ( denominator > numerator * 1E-30 )
3848
return numerator/denominator;
3857
// *******************************************************************************
3861
// *******************************************************************************
3863
//! @param stream stream to read from
3864
//! @return stream for chaining
3866
// *******************************************************************************
3868
std::istream & nAverager::operator <<( std::istream & stream )
3872
tASSERT( c == '(' );
3874
stream >> weight_ >> sum_ >> sumSquared_ >> weightSquared_;
3877
tASSERT( c == ')' );
3882
// *******************************************************************************
3886
// *******************************************************************************
3888
//! @param stream stream to write to
3889
//! @return stream for chaining
3891
// *******************************************************************************
3893
std::ostream & nAverager::operator >>( std::ostream & stream ) const
3895
stream << '(' << weight_ << ' ' << sum_ << ' ' << sumSquared_ << ' ' << weightSquared_ << ')';
3900
// *******************************************************************************
3904
// *******************************************************************************
3906
//! @param stream stream to read to
3907
//! @param averager averager to read
3908
//! @return stream for chaining
3910
// *******************************************************************************
3912
std::istream & operator >> ( std::istream & stream, nAverager & averager )
3914
return averager << stream;
3917
// *******************************************************************************
3921
// *******************************************************************************
3923
//! @param stream stream to write to
3924
//! @param averager averager to write
3925
//! @return stream for chaining
3927
// *******************************************************************************
3929
std::ostream & operator << ( std::ostream & stream, nAverager const & averager )
3931
return averager >> stream;
3935
// *******************************************************************************************
3939
// *******************************************************************************************
3942
// *******************************************************************************************
3944
nPingAverager::nPingAverager( void )
3949
// *******************************************************************************************
3953
// *******************************************************************************************
3956
// *******************************************************************************************
3958
nPingAverager::~nPingAverager( void )
3962
// *******************************************************************************************
3966
// *******************************************************************************************
3968
//! @return our best estimate for the ping
3970
// *******************************************************************************************
3972
REAL nPingAverager::GetPing( void ) const
3975
// determine the lowest guessed value for variance.
3976
// lag spikes should not contribute here too much.
3979
REAL snailVariance = this->snail_.GetDataVariance();
3980
REAL slowVariance = this->slow_.GetDataVariance();
3981
REAL fastVariance = this->fast_.GetDataVariance();
3982
variance = variance < snailVariance ? variance : snailVariance;
3983
variance = variance < slowVariance ? variance : slowVariance;
3984
variance = variance < fastVariance ? variance : fastVariance;
3987
REAL pingSnail = this->GetPingSnail();
3988
REAL pingSlow = this->GetPingSlow();
3989
REAL pingFast = this->GetPingFast();
3991
// the proposed return value: defaults to the snail ping, it flucuates the least
3992
REAL pingReturn = pingSnail;
3994
// return slow average if that differs from the snail one by at least one standard deviation
3995
if ( ( pingSlow - pingReturn ) * ( pingSlow - pingReturn ) > variance )
3997
// but clamp it to sane values
3998
if ( pingSlow > pingReturn * 2 )
3999
pingSlow = pingReturn * 2;
4001
pingReturn = pingSlow;
4004
// same for fast ping
4005
if ( ( pingFast - pingReturn ) * ( pingFast - pingReturn ) > variance )
4007
if ( pingFast > pingReturn * 2 )
4008
pingFast = pingReturn * 2;
4010
pingReturn = pingFast;
4013
// return best estimate plus expected variance with fudge factor. It's better to err to the big ping side.
4014
return pingReturn + sqrtf(variance) * 1.5;
4017
// *******************************************************************************************
4021
// *******************************************************************************************
4023
//! @return our best estimate for the ping
4025
// *******************************************************************************************
4027
nPingAverager::operator REAL( void ) const
4032
// *******************************************************************************************
4036
// *******************************************************************************************
4038
//! @return extremely longterm ping average
4040
// *******************************************************************************************
4042
REAL nPingAverager::GetPingSnail( void ) const
4044
return snail_.GetAverage();
4047
// *******************************************************************************************
4051
// *******************************************************************************************
4053
//! @return longterm ping average
4055
// *******************************************************************************************
4057
REAL nPingAverager::GetPingSlow( void ) const
4059
return slow_.GetAverage();
4062
// *******************************************************************************************
4066
// *******************************************************************************************
4068
//! @return shortterm ping average
4070
// *******************************************************************************************
4072
REAL nPingAverager::GetPingFast( void ) const
4074
return fast_.GetAverage();
4077
// *******************************************************************************************
4081
// *******************************************************************************************
4083
//! @return true if unusual high fluctuations exist in the ping
4085
// *******************************************************************************************
4087
bool nPingAverager::IsSpiking( void ) const
4089
REAL difference = slow_.GetAverage() - fast_.GetAverage();
4090
return slow_.GetAverageVariance() < difference * difference;
4093
// *******************************************************************************************
4097
// *******************************************************************************************
4099
//! @param decay time since last timestep
4101
// *******************************************************************************************
4103
void nPingAverager::Timestep( REAL decay )
4105
snail_.Timestep( decay * .02 );
4106
slow_.Timestep ( decay * .2 );
4107
fast_.Timestep ( decay * 2 );
4110
// *******************************************************************************************
4114
// *******************************************************************************************
4116
//! @param value the value to add
4117
//! @param weight the value's statistical weight
4119
// *******************************************************************************************
4121
void nPingAverager::Add( REAL value, REAL weight )
4123
// add value to both averagers
4124
snail_.Add( value, weight );
4125
slow_.Add ( value, weight );
4126
fast_.Add ( value, weight );
4129
// *******************************************************************************************
4133
// *******************************************************************************************
4135
//! @param value the value to add with default weight
4137
// *******************************************************************************************
4139
void nPingAverager::Add( REAL value )
4141
// add value to both averagers
4142
Add( value, weight_ );
4145
// *******************************************************************************************
4149
// *******************************************************************************************
4152
// *******************************************************************************************
4154
void nPingAverager::Reset( void )
4160
// fill in some low weight values
4164
// pin snail averager close to zero
4165
// snail_.Add(0,10);
4166
// not such a good idea after all. The above line caused massive resending of packets.
4169
REAL nPingAverager::weight_=1;
4175
// *******************************************************************************
4179
// *******************************************************************************
4182
// *******************************************************************************
4184
nMachine::nMachine( void )
4185
: lastUsed_(tSysTimeFloat())
4191
lastPlayerAction_ = lastUsed_;
4194
// *******************************************************************************
4198
// *******************************************************************************
4201
// *******************************************************************************
4203
nMachine::~nMachine( void )
4205
// destroy and remove the decorators
4206
while ( decorators_ )
4208
nMachineDecorator * decorator = decorators_;
4209
decorator->Remove();
4210
decorator->Destroy();
4214
// *******************************************************************************
4218
// *******************************************************************************
4220
//! @param other the machine to compare with
4221
//! @return true if they are equal
4223
// *******************************************************************************
4225
bool nMachine::operator == ( nMachine const & other ) const
4227
return this == &other;
4230
// *******************************************************************************
4234
// *******************************************************************************
4236
//! @param other the machine to compare with
4237
//! @return false if they are equal
4239
// *******************************************************************************
4241
bool nMachine::operator !=( nMachine const & other ) const
4243
return this != &other;
4246
// singleton machine map
4250
mutable nMachine * machine;
4251
nMachinePTR(): machine(tNEW(nMachine)()){};
4252
~nMachinePTR(){tDESTROY(machine);}
4253
nMachinePTR(nMachinePTR const & other): machine(other.machine){other.machine=0;}
4254
nMachinePTR & operator=(nMachinePTR const & other){ machine = other.machine; other.machine=0;return *this;}
4257
typedef std::map< tString, nMachinePTR > nMachineMap;
4258
static nMachineMap & sn_GetMachineMap()
4260
static nMachineMap map;
4264
static nMachine & sn_LookupMachine( tString const & address )
4266
// get map of all machines and look address up
4267
nMachineMap & map = sn_GetMachineMap();
4268
return map[ address ].machine->SetIP( address );
4271
// *******************************************************************************
4275
// *******************************************************************************
4277
//! @param userID the user ID to fetch the machine for
4278
//! @return the machine the user ID belongs to
4280
// *******************************************************************************
4282
nMachine & nMachine::GetMachine( unsigned short userID )
4284
// throw out old machines
4287
// hardcoding: the server itself
4288
if ( userID == 0 && sn_GetNetState() != nCLIENT )
4290
static nMachine server;
4294
tASSERT( userID <= MAXCLIENTS+1 );
4296
if( sn_GetNetState() != nSERVER )
4298
// invalid ID, return invalid machine (clients don't track machines)
4299
static nMachine invalid;
4304
tVERIFY( userID <= MAXCLIENTS+1 );
4305
if( !sn_Connections[userID].socket )
4307
// invalid ID, return invalid machine
4308
static nMachine invalid;
4312
peers[ userID ].GetAddress( address );
4315
// add client ID so multiple connects from one machine are distinguished
4317
newIP << address << " " << userID;
4322
return sn_LookupMachine( address );
4325
// safely delete iterator from map
4326
static void sn_Erase( nMachineMap & map, nMachineMap::iterator & iter )
4328
if ( iter != map.end() )
4335
// *******************************************************************************
4339
// *******************************************************************************
4342
// *******************************************************************************
4344
void nMachine::Expire( void )
4346
static double lastTime = tSysTimeFloat();
4347
double time = tSysTimeFloat();
4348
REAL dt = time - lastTime;
4353
// iterate over known machines
4354
nMachineMap & map = sn_GetMachineMap();
4355
nMachineMap::iterator toErase = map.end();
4356
for( nMachineMap::iterator iter = map.begin(); iter != map.end(); ++iter )
4358
// erase last deleted machine
4359
sn_Erase( map, toErase );
4361
nMachine & machine = *(*iter).second.machine;
4363
// advance the kick statistics if the user is not banned and has been active
4364
if ( time > machine.banned_ && ( machine.lastUsed_ > time - 300 || machine.players_ > 0 ) )
4366
machine.kph_.Add( 0, dt / 3600 );
4367
machine.kph_.Timestep( dt / 3600*24 );
4370
// if the machine is no longer in use, mark it for deletion
4371
if ( machine.players_ == 0 && machine.lastUsed_ < time - 300.0 && machine.banned_ < time && machine.kph_.GetAverage() < 0.5 )
4376
// erase last machine
4377
sn_Erase( map, toErase );
4380
// maximal time a client without players is tolerated
4381
static REAL sn_spectatorTime = 0;
4382
static tSettingItem< REAL > sn_spectatorTimeConf( "NETWORK_SPECTATOR_TIME", sn_spectatorTime );
4384
// *******************************************************************************
4388
// *******************************************************************************
4391
// *******************************************************************************
4393
void nMachine::KickSpectators( void )
4395
double time = tSysTimeFloat();
4398
if ( sn_GetNetState() == nSERVER && sn_spectatorTime > 0 )
4400
for ( int i = MAXCLIENTS; i >= 1; --i )
4402
if ( sn_Connections[i].socket )
4404
nMachine & machine = GetMachine( i );
4405
if ( machine.players_ == 0 && machine.lastPlayerAction_ + sn_spectatorTime < time )
4407
sn_KickUser( i, tOutput("$network_kill_spectator"), 0 );
4414
// settings for automatic banning
4415
static REAL sn_autobanOffset = 5; // bias that gets subtracted from the kills per hour
4416
static REAL sn_autobanFactor = 10; // factor that gets multiplied on top of it to determine the ban time in minutes
4417
static REAL sn_autobanMaxKPH = 30; // maximal value of kph
4419
static tSettingItem< REAL > sn_autobanOffsetSetting( "NETWORK_AUTOBAN_OFFSET", sn_autobanOffset );
4420
static tSettingItem< REAL > sn_autobanFactorSetting( "NETWORK_AUTOBAN_FACTOR", sn_autobanFactor );
4421
static tSettingItem< REAL > sn_autobanMaxKPHSetting( "NETWORK_AUTOBAN_MAX_KPH", sn_autobanMaxKPH );
4423
// *******************************************************************************
4427
// *******************************************************************************
4429
//! @param severity the severity of the offense; 1 is standard.
4431
// *******************************************************************************
4433
void nMachine::OnKick( REAL severity )
4435
// if the user is currently banned, don't count
4436
if ( banned_ > tSysTimeFloat() )
4439
// ban the user a bit, taking the kicks per hour into account
4440
REAL kph = kph_.GetAverage() - sn_autobanOffset;
4443
// the faster you get kicked when you turn up, the longer you get banned
4444
REAL banTime = 60 * kph * sn_autobanFactor;
4445
Ban( banTime, tString(tOutput( "$network_ban_kick" )) );
4448
// add it to the statistics
4449
if ( sn_autobanMaxKPH > 0 )
4450
kph_.Add( severity * sn_autobanMaxKPH, 2/sn_autobanMaxKPH );
4452
con << tOutput( "$network_ban_kph", GetIP(), GetKicksPerHour() );
4455
static bool sn_printBans = true;
4457
// *******************************************************************************
4461
// *******************************************************************************
4463
//! @param time time in seconds the ban should be in effect
4465
// *******************************************************************************
4467
void nMachine::Ban( REAL time )
4469
lastUsed_ = tSysTimeFloat();
4471
// set the banning timeout to the current time plus the given time
4472
banned_ = tSysTimeFloat() + time;
4477
con << tOutput( "$network_ban", GetIP(), int(time/60), banReason_.Len() > 1 ? banReason_ : tOutput( "$network_ban_noreason" ) );
4479
con << tOutput( "$network_noban", GetIP() );
4483
// *******************************************************************************
4487
// *******************************************************************************
4489
//! @param time time in seconds the ban should be in effect
4490
//! @param reason the reason for the ban
4492
// *******************************************************************************
4494
void nMachine::Ban( REAL time, tString const & reason )
4496
banReason_ = tString();
4497
if ( reason.Len() > 2 )
4498
banReason_ = reason;
4503
// *******************************************************************************
4507
// *******************************************************************************
4509
//! @return kick time left
4511
// *******************************************************************************
4513
REAL nMachine::IsBanned( void ) const
4516
double time = tSysTimeFloat();
4517
if ( time > banned_ )
4520
return banned_ - time;
4523
// *******************************************************************************
4527
// *******************************************************************************
4530
// *******************************************************************************
4532
void nMachine::AddPlayer( void )
4534
lastPlayerAction_ = lastUsed_ = tSysTimeFloat();
4539
// *******************************************************************************
4543
// *******************************************************************************
4546
// *******************************************************************************
4548
void nMachine::RemovePlayer( void )
4550
lastPlayerAction_ = lastUsed_ = tSysTimeFloat();
4557
// *******************************************************************************
4561
// *******************************************************************************
4563
//! @return the number of currently connected players
4565
// *******************************************************************************
4567
int nMachine::GetPlayerCount( void )
4573
static char const * sn_machinesFileName = "bans.txt";
4575
class nMachinePersistor
4578
// save ban info of machines
4579
static void SaveMachines()
4582
if (tDirectories::Var().Open( s, sn_machinesFileName ) )
4584
nMachineMap & map = sn_GetMachineMap();
4585
for( nMachineMap::iterator iter = map.begin(); iter != map.end(); ++iter )
4587
nMachine & machine = *(*iter).second.machine;
4588
// if ( machine.IsBanned() > 0 )
4590
s << (*iter).first << " " << machine.IsBanned() << " " << machine.kph_ << " " << machine.GetBanReason() << "\n";
4596
// load and enter ban info of machines
4597
static void LoadMachines()
4599
sn_printBans = false;
4601
tTextFileRecorder machines( tDirectories::Var(), sn_machinesFileName );
4602
while ( !machines.EndOfFile() )
4604
std::stringstream line( machines.GetLine() );
4606
// address and ban time left
4610
// read relevant info
4611
line >> address >> banTime;
4614
// read kph averager
4627
reason.ReadLine( line );
4629
if ( address.Len() > 2 )
4632
nMachine & machine = sn_LookupMachine( address );
4633
machine.Ban( banTime, reason );
4638
sn_printBans = true;
4642
// save ban info of machines
4643
static void sn_SaveMachines()
4645
nMachinePersistor::SaveMachines();
4648
// load and enter ban info of machines
4649
static void sn_LoadMachines()
4651
nMachinePersistor::LoadMachines();
4654
// *******************************************************************************
4656
// * GetKicksPerHour
4658
// *******************************************************************************
4660
//! @return averaged kicks per hour of players from this machine
4662
// *******************************************************************************
4664
REAL nMachine::GetKicksPerHour( void ) const
4666
return this->kph_.GetAverage();
4669
// *******************************************************************************
4671
// * GetKicksPerHour
4673
// *******************************************************************************
4675
//! @param kph averaged kicks per hour of players from this machine to fill
4676
//! @return A reference to this to allow chaining
4678
// *******************************************************************************
4680
nMachine const & nMachine::GetKicksPerHour( REAL & kph ) const
4682
kph = this->kph_.GetAverage();
4686
// *******************************************************************************
4690
// *******************************************************************************
4692
//! @return IP address of the machine
4694
// *******************************************************************************
4696
tString const & nMachine::GetIP( void ) const
4701
// *******************************************************************************
4705
// *******************************************************************************
4707
//! @param IP IP address of the machine to fill
4708
//! @return A reference to this to allow chaining
4710
// *******************************************************************************
4712
nMachine const & nMachine::GetIP( tString & IP ) const
4718
// *******************************************************************************
4722
// *******************************************************************************
4724
//! @param IP IP address of the machine to set
4725
//! @return A reference to this to allow chaining
4727
// *******************************************************************************
4729
nMachine & nMachine::SetIP( tString const & IP )
4731
lastUsed_ = tSysTimeFloat();
4737
// *******************************************************************************
4741
// *******************************************************************************
4743
//! @return Reason of the ban
4745
// *******************************************************************************
4747
tString const & nMachine::GetBanReason( void ) const
4749
return this->banReason_;
4752
// *******************************************************************************
4756
// *******************************************************************************
4758
//! @param reason Reason of the ban to fill
4759
//! @return A reference to this to allow chaining
4761
// *******************************************************************************
4763
nMachine const & nMachine::GetBanReason( tString & reason ) const
4765
reason = this->banReason_;
4769
// *******************************************************************************
4771
// * Banning and unbanning
4773
// *******************************************************************************
4776
static void sn_UnBanConf(std::istream &s)
4778
if ( !s.good() || s.eof() )
4780
con << "Usage: UNBAN_IP <ip>\n";
4788
if ( address.Len() < 8 )
4790
con << "Usage: UNBAN_IP <ip>, no or too short ip given.\n";
4795
sn_LookupMachine( address ).Ban( 0 );
4799
static tConfItemFunc sn_unBanConf("UNBAN_IP",&sn_UnBanConf);
4802
static void sn_BanConf(std::istream &s)
4808
if ( !s.good() && address.Len() < 7 )
4810
con << "Usage: BAN_IP <ip> <time in minutes (defaults to 60)> <reason>\n";
4826
if ( address.Len() > 4 )
4828
sn_LookupMachine( address ).Ban( duration * 60, reason );
4832
static tConfItemFunc sn_banConf("BAN_IP",&sn_BanConf);
4835
static void sn_ListBanConf(std::istream &s)
4837
nMachineMap & map = sn_GetMachineMap();
4838
for( nMachineMap::iterator iter = map.begin(); iter != map.end(); ++iter )
4840
nMachine & machine = *(*iter).second.machine;
4841
REAL banned = machine.IsBanned();
4844
con << tOutput( "$network_ban", machine.GetIP(), int(banned/60), machine.GetBanReason() );
4849
static tConfItemFunc sn_listBanConf("BAN_LIST",&sn_ListBanConf);
4851
// *******************************************************************************
4855
// *******************************************************************************
4858
// *******************************************************************************
4860
void nMachineDecorator::OnDestroy( void )
4864
// *******************************************************************************
4866
// * nMachineDecorator
4868
// *******************************************************************************
4871
// *******************************************************************************
4873
nMachineDecorator::nMachineDecorator( void )
4877
// *******************************************************************************
4879
// * ~nMachineDecorator
4881
// *******************************************************************************
4884
// *******************************************************************************
4886
nMachineDecorator::~nMachineDecorator( void )
4891
// *******************************************************************************
4893
// * nMachineDecorator
4895
// *******************************************************************************
4899
// *******************************************************************************
4901
nMachineDecorator::nMachineDecorator( nMachine & machine )
4903
Insert( machine.decorators_ );