| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672 |
- /*
- ** Command & Conquer Renegade(tm)
- ** Copyright 2025 Electronic Arts Inc.
- **
- ** This program is free software: you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation, either version 3 of the License, or
- ** (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- //
- // Filename: connect.cpp
- // Project: wwnet
- // Author: Tom Spencer-Smith
- // Date: June 1998
- // Description:
- //
- //------------------------------------------------------------------------------------
- #include "always.h"
- // Disable warning about exception handling not being enabled. It's used as part of STL - in a part of STL we don't use.
- #pragma warning(disable : 4530)
- #include "connect.h" // I WANNA BE FIRST!
- //#include <stdlib.h>
- #include "systimer.h"
- #include "systimer.h"
- #include "miscutil.h"
- #include "netutil.h"
- #include "singlepl.h"
- #include "mathutil.h"
- #include "wwdebug.h"
- #include "wwmath.h"
- #include "fromaddress.h"
- #include "crc.h"
- #include "msgstatlist.h"
- #include "wwprofile.h"
- #include "commando\nat.h"
- #include "commando\natter.h"
- #include "packetmgr.h"
- #include "bwbalance.h"
- #ifdef WWDEBUG
- #include "combat\crandom.h"
- int cConnection::LatencyAddLow = 0;
- int cConnection::LatencyAddHigh = 0;
- int cConnection::CurrentLatencyAdd = 0;
- unsigned long cConnection::LastLatencyChange = 0;
- #endif //WWDEBUG
- //
- // class statics
- //
- BOOL cConnection::IsFlowControlEnabled = true;
- UINT cConnection::TotalCompressedBytesSent = 0;
- UINT cConnection::TotalUncompressedBytesSent = 0;
- static const int INVALID_RHOST_ID = -1;
- //#ifdef WWDEBUG
- /***********************************************************************************************
- * Addr_As_String -- Get a human readable internet address *
- * *
- * *
- * *
- * INPUT: Address ptr *
- * *
- * OUTPUT: String representation *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 8/31/2001 3:48PM ST : Created *
- *=============================================================================================*/
- char * Addr_As_String(sockaddr_in *addr)
- {
- static char _string[128];
- sprintf(_string, "%d.%d.%d.%d ; %d", (int)(addr->sin_addr.S_un.S_un_b.s_b1),
- (int)(addr->sin_addr.S_un.S_un_b.s_b2),
- (int)(addr->sin_addr.S_un.S_un_b.s_b3),
- (int)(addr->sin_addr.S_un.S_un_b.s_b4),
- htonl((int)(addr->sin_port)));
- return(_string);
- }
- //#endif //WWDEBUG
- //------------------------------------------------------------------------------------
- cConnection::cConnection() :
- NumRHosts(0),
- RefusalPacketSendId(0),
- HighestRefusalPacketRcvId(-1),
- MinRHost(-1), // should be altered if IsServer
- //MaxRHost(0), // should be altered if IsServer
- MaxRHost(-2), // should be altered if IsServer
- InitDone(false),
- IsServer(false),
- IsDedicatedServer(false),
- SimulatedPacketLossPerRANDMAX(0),
- SimulatedPacketDuplicationPerRANDMAX(0),
- MaxAcceptablePacketlossPc(0),
- MinimumLatencyMs(0),
- MaximumLatencyMs(0),
- BandwidthBudgetOut(0),
- ServiceCount(0),
- ThisFrameTimeMs(TIMEGETTIME()),
- IsDestroy(false),
- PRHost(NULL),
- AcceptHandler(NULL),
- RefusalHandler(NULL),
- ServerBrokenConnectionHandler(NULL),
- ClientBrokenConnectionHandler(NULL),
- EvictionHandler(NULL),
- ConnHandler(NULL),
- ApplicationAcceptanceHandler(NULL),
- ServerPacketHandler(NULL),
- ClientPacketHandler(NULL),
- IsBadConnection(false),
- ExtraTimeoutTime(0),
- ExtraTimeoutTimeStarted(0),
- CanProcess(true)
- {
- WWDEBUG_SAY(("cConnection::cConnection\n"));
- //
- // All this stuff is common to C & S
- //
- if (!cSinglePlayerData::Is_Single_Player()) {
- cNetUtil::Create_Unbound_Socket(Sock);
- //
- // Make socket non-blocking
- //
- u_long arg = 1L;
- WSA_CHECK(ioctlsocket(Sock, FIONBIO, (u_long *) &arg));
- //
- // Increase the send and rcv buffer sizes a bit
- //
- cNetUtil::Set_Socket_Buffer_Sizes(Sock);
- }
- /*
- for (int rhost_id = 0; rhost_id < MAX_RHOSTS; rhost_id++) {
- PRHost[rhost_id] = NULL;
- }
- */
- //Init_Stats();
- PStatList = new cMsgStatList;
- WWASSERT(PStatList != NULL);
- PStatList->Init(PACKETTYPE_COUNT);
- for (int i = 0; i < PStatList->Get_Num_Stats(); i++) {
- //PStatList->Set_Name(i, Type_Translation(i));
- char message_trans[200];
- ::strcpy(message_trans, Type_Translation(i));
- PStatList->Set_Name(i, &message_trans[11]);
- }
- }
- //------------------------------------------------------------------------------------
- cConnection::~cConnection()
- {
- WWDEBUG_SAY(("cConnection::~cConnection\n"));
- //Remove_All();
- if (!cSinglePlayerData::Is_Single_Player()) {
- //
- // Abortively shut down the socket
- //
- WSA_CHECK(shutdown(Sock, 2)); // SD_BOTH
- WSA_CHECK(::closesocket(Sock));
- }
- //for (int rhost_id = 0; rhost_id < MAX_RHOSTS; rhost_id++) {
- //for (int rhost_id = 0; rhost_id < MaxRHost; rhost_id++) {
- for (int rhost_id = MinRHost; rhost_id <= MaxRHost; rhost_id++) {
- if (PRHost[rhost_id] != NULL) {
- Destroy_Connection(rhost_id);
- }
- }
- delete [] PRHost;
- PRHost = NULL;
- delete PStatList;
- PStatList = NULL;
- #ifdef WWDEBUG
- while (LaggedPackets.Count()) {
- delete LaggedPackets[0];
- LaggedPackets.Delete(0);
- }
- LaggedPacketTimes.Delete_All();
- #endif //WWDEBUG
- }
- //------------------------------------------------------------------------------------
- void cConnection::Init_Stats()
- {
- CombinedStats.Init_Net_Stats();
- AveragedStats.Init_Net_Stats();
- for (int rhost_id = MinRHost; rhost_id <= MaxRHost; rhost_id++) {
- if (PRHost[rhost_id] != NULL) {
- PRHost[rhost_id]->Init_Stats();
- }
- }
- ThisFrameTimeMs = TIMEGETTIME();
- }
- //------------------------------------------------------------------------------------
- void cConnection::Init_As_Client(LPSOCKADDR_IN p_server_address, unsigned short my_port)
- {
- WWASSERT(p_server_address != NULL);
- WWASSERT(!InitDone);
- IsServer = false;
- IsDedicatedServer = false;
- LocalId = ID_UNKNOWN;
- //
- // Now the port is supplied by the firewall negotiation code. We have to use the same port here that the firewall code
- // was bound to.
- //
- // The server address and port are supplied by the firewall code too.
- //
- if (!cSinglePlayerData::Is_Single_Player()) {
- bool is_bound;
- is_bound = Bind(my_port);
- WWASSERT(is_bound);
- }
- //
- // Create rhost for server
- //
- MinRHost = 0;
- MaxRHost = 0;
- typedef cRemoteHost * PcRemoteHost;
- PRHost = new PcRemoteHost[1];
- WWASSERT(PRHost != NULL);
- PRHost[0] = new cRemoteHost();
- WWASSERT(PRHost[0] != NULL);
- PRHost[0]->Set_Id(0);//TSS2001
- NumRHosts++;
- WWASSERT(NumRHosts == 1);
- if (!cSinglePlayerData::Is_Single_Player()) {
- PRHost[0]->Set_Address(*p_server_address);
- WWASSERT(cNetUtil::Is_Same_Address(&PRHost[0]->Get_Address(), p_server_address));
- }
- Init_Stats();
- InitDone = true;
- }
- //------------------------------------------------------------------------------------
- void cConnection::Init_As_Client(ULONG server_ip, USHORT server_port, unsigned short my_port)
- {
- WWDEBUG_SAY(("cConnection::Init_As_Client(%s, %d, %d)\n",
- cNetUtil::Address_To_String(server_ip), server_port, my_port));
- WWASSERT(!InitDone);
- WWASSERT(server_port >= MIN_SERVER_PORT && server_port <= MAX_SERVER_PORT);
- SOCKADDR_IN server_address;
- ZeroMemory(&server_address, sizeof(server_address));
- if (!cSinglePlayerData::Is_Single_Player()) {
- server_address.sin_family = AF_INET;
- server_address.sin_addr.s_addr = server_ip;
- server_address.sin_port = ::htons(server_port);
- }
- Init_As_Client(&server_address, my_port);
- }
- //------------------------------------------------------------------------------------
- void cConnection::Init_As_Server(USHORT server_port, int max_players,
- bool is_dedicated_server, ULONG addr)
- {
- WWDEBUG_SAY(("cConnection::Init_As_Server\n"));
- WWASSERT(!InitDone);
- WWASSERT(server_port >= MIN_SERVER_PORT && server_port <= MAX_SERVER_PORT);
- WWASSERT(max_players >= 1);
- //WWASSERT(max_players < MAX_RHOSTS); // because MAX_RHOSTS is an array bound
- MinRHost = 1;
- MaxRHost = max_players;
- typedef cRemoteHost * PcRemoteHost;
- PRHost = new PcRemoteHost[max_players + 1];
- WWASSERT(PRHost != NULL);
- //ZeroMemory(PRHost, sizeof(PRHost));
- for (int rhost_id = MinRHost; rhost_id <= MaxRHost; rhost_id++) {
- PRHost[rhost_id] = NULL;
- }
- Init_Stats();
- IsServer = true;
- IsDedicatedServer = is_dedicated_server;
- LocalId = 0;
- if (cSinglePlayerData::Is_Single_Player()) {
- IsFlowControlEnabled = false;
- } else {
- //
- // The server has to ::bind to his well-known port... or the nearest he can get
- // to it...
- //
- bool is_bound;
- int num_tries = 0;
- do {
- is_bound = Bind(server_port, addr);
- if (!is_bound) {
- WWDEBUG_SAY(("Failed to Bind to local port %d.\n", server_port));
- server_port++;
- num_tries++;
- }
- } while (!is_bound && num_tries < 50 && server_port <= MAX_SERVER_PORT);
- WWASSERT(num_tries < 50 && server_port <= MAX_SERVER_PORT);
- // Tell the firewall code that we started a new local server.
- WOLNATInterface.Set_Server(true);
- }
- InitDone = true;
- }
- //------------------------------------------------------------------------------------
- bool cConnection::Bind(USHORT port, ULONG addr)
- {
- WWASSERT(!cSinglePlayerData::Is_Single_Player());
- WWASSERT(!InitDone);
- //WWASSERT((!IsServer && port == 0) ||
- WWASSERT((!IsServer) ||
- (IsServer && port >= MIN_SERVER_PORT && port <= MAX_SERVER_PORT));
- SOCKADDR_IN address;
- cNetUtil::Create_Local_Address(&address, port);
- if (addr) address.sin_addr.s_addr = htonl(addr);
- if (::bind(Sock, (LPSOCKADDR) &address, sizeof(SOCKADDR_IN)) != SOCKET_ERROR) {
- LocalPort = port;
- WWDEBUG_SAY(("Bound to local port %d.\n", LocalPort));
- return true;
- } else {
- //
- // Any excuse other than address/port already used, is fatal.
- //
- if (::WSAGetLastError() != WSAEADDRINUSE) {
- WSA_ERROR;
- }
- return false;
- }
- //DIE; // won't get here
- }
- //------------------------------------------------------------------------------------
- #define ADD_CASE(exp) case exp: return #exp;
- LPCSTR cConnection::Type_Translation(int type)
- {
- switch (type) {
- ADD_CASE(PACKETTYPE_UNRELIABLE);
- ADD_CASE(PACKETTYPE_RELIABLE);
- ADD_CASE(PACKETTYPE_ACK);
- ADD_CASE(PACKETTYPE_KEEPALIVE);
- ADD_CASE(PACKETTYPE_CONNECT_CS);
- ADD_CASE(PACKETTYPE_ACCEPT_SC);
- ADD_CASE(PACKETTYPE_REFUSAL_SC);
- ADD_CASE(PACKETTYPE_FIREWALL_PROBE);
- default:
- DIE;
- return ""; // to avoid warning
- }
- }
- //------------------------------------------------------------------------------------
- bool cConnection::Sender_Id_Tests(cPacket & packet)
- {
- WWASSERT(InitDone);
- int sender_id = packet.Get_Sender_Id();
- //
- // Clients should only receive packets from sender_id 0
- //
- if (!IsServer && sender_id != SERVER_RHOST_ID) {
- WWDEBUG_SAY(("Warning: Client received packet from non-server id %d\n", sender_id));
- CombinedStats.Increment_Stat_Sample(STAT_DiscardCount, 1);
- return false;
- }
- WWASSERT(sender_id >= MinRHost && sender_id <= MaxRHost);
- if (sender_id < MinRHost || sender_id > MaxRHost) {
- WWDEBUG_SAY(("Warning: Packet with bad sender_id %d\n", sender_id));
- return(false);
- }
- if (PRHost[sender_id] == NULL) {
- //
- // This can happen when the connection is broken... packets in-the-air
- // may still arrive
- //
- BYTE packet_type;
- packet_type = packet.Get_Type();
- WWASSERT(packet_type >= PACKETTYPE_FIRST && packet_type <= PACKETTYPE_LAST);
- WWDEBUG_SAY(("Packet from broken connection discarded: type %d, id %d, sender %d\n",
- packet_type, packet.Get_Id(), sender_id));
- CombinedStats.StatSample[STAT_DiscardCount]++;
- return false;
- }
- if (!cSinglePlayerData::Is_Single_Player() &&
- !cNetUtil::Is_Same_Address(&(PRHost[sender_id]->Get_Address()),
- &packet.Get_From_Address_Wrapper()->FromAddress)) {
- //
- // This can happen under 2 known conditions:
- // 1. A new player reuses an id and old packets from the previous player
- // are still on the wire.
- // 2. The client has hacked the internal id field
- //
- // At this point we will just discard the packet.
- //
- WWDEBUG_SAY(("Warning: Packet sender id (%d) conflicts with actual send address\n", sender_id));
- CombinedStats.StatSample[STAT_DiscardCount]++;
- return false;
- }
- return true;
- }
- //------------------------------------------------------------------------------------
- USHORT cConnection::Calculate_Packet_Bits(USHORT app_bytes)
- {
- //USHORT packet_bits = 0;
- //
- // From the app bytes, work out an approximate expected number
- // of bits. Assume modem and PPP.
- //
- // 1. Add header bytes
- // 2. Assume worst case of PPP byte escaping: all of 0x00-0x1F and 0x7d, 0x7e
- // = 34 bytes, so multiply by (256 + 34) / 256
- // 3. Multiple by 10 bits/byte for modem traffic (assume serial connection,
- // 1 start bit and 1 stop bit)
- //
- // So we have (app bytes + header bytes) * (256 + 34) / 256 * 10
- //
- // Assumption: no IP fragmentation occurs because we are keeping the
- // total packet size small (less than the IP MTU of 576).
- //
- // Our application will probably be targeting a client average inbound bps
- // of 28800 or less.
- //
- //
- // Header (assuming PPP):
- //
- // IP 4.0 : 20 Bytes
- // UDP : 8 Bytes
- // PPP : 5 Bytes (typical value after negotiation)
- // ---------
- // 33 bytes
- //
- //HeaderBytes = 33;
- USHORT packet_bits = (USHORT)((app_bytes + 33) * 11.328125);
- return packet_bits;
- }
- //------------------------------------------------------------------------------------
- void cConnection::Set_Packet_Loss(double percent_lost)
- {
- //
- // This sets simultedpacketloss to a common value for all rhosts
- // as well as for non-established connections
- //
- WWASSERT(percent_lost >= 0 && percent_lost <= 100);
- SimulatedPacketLossPerRANDMAX = (UINT) cMathUtil::Round(
- percent_lost / 100.0 * RAND_MAX);
- WWDEBUG_SAY(("cConnection::Set_Packet_Loss: %d / %d\n", SimulatedPacketLossPerRANDMAX, RAND_MAX));
- }
- //------------------------------------------------------------------------------------
- void cConnection::Set_Packet_Duplication(double percent_duplicated)
- {
- //
- // This sets simultedpacketloss to a common value for all rhosts
- // as well as for non-established connections
- //
- WWASSERT(percent_duplicated >= -WWMATH_EPSILON &&
- percent_duplicated <= 100 + WWMATH_EPSILON);
- //
- // Globally:
- //
- SimulatedPacketDuplicationPerRANDMAX = (UINT) cMathUtil::Round(
- percent_duplicated / 100.0 * RAND_MAX);
- WWDEBUG_SAY(("cConnection::Set_Packet_Duplication: %d / %d\n", SimulatedPacketDuplicationPerRANDMAX, RAND_MAX));
- }
- //------------------------------------------------------------------------------------
- void cConnection::Set_Packet_Latency_Range(int minimum_latency_ms, int maximum_latency_ms)
- {
- WWASSERT(minimum_latency_ms >= 0);
- WWASSERT(maximum_latency_ms >= 0);
- WWASSERT(maximum_latency_ms >= minimum_latency_ms);
- MinimumLatencyMs = minimum_latency_ms;
- MaximumLatencyMs = maximum_latency_ms;
- }
- //------------------------------------------------------------------------------------
- int cConnection::Single_Player_recvfrom(char * data)
- {
- //WWDEBUG_SAY(("cConnection::Single_Player_recvfrom\n"));
- //
- // TSS - this relies on doing all recvs in one shot
- //
- WWASSERT(cSinglePlayerData::Is_Single_Player());
- int ret_code;
- SList<cPacket> * p_packet_list;
- if (IsServer) {
- p_packet_list = cSinglePlayerData::Get_Input_Packet_List(SERVER_LIST);
- } else {
- p_packet_list = cSinglePlayerData::Get_Input_Packet_List(CLIENT_LIST);
- }
- WWASSERT(p_packet_list != NULL);
- SLNode<cPacket> * objnode = p_packet_list->Head();
- if (objnode == NULL) {
- WSASetLastError(WSAEWOULDBLOCK);
- ret_code = SOCKET_ERROR; // no data received
- } else {
- cPacket * p_packet = objnode->Data();
- WWASSERT(p_packet != NULL);
- memcpy(data, p_packet->Get_Data(), p_packet->Get_Max_Size());
- ret_code = p_packet->Get_Compressed_Size_Bytes();
- p_packet->Flush();
- p_packet_list->Remove(p_packet);
- delete p_packet;
- }
- return ret_code;
- }
- //------------------------------------------------------------------------------------
- //
- // Return true if we receive a valid packet on this call
- //
- bool cConnection::Receive_Packet()
- {
- //WWDEBUG_SAY(("cConnection::Receive_Packet start\n"));
- WWASSERT(InitDone);
- cPacket packet;
- int ret_code = 0;
- #ifdef WWDEBUG
- //
- // See if there are any old packets with simulated lag whos time has come.
- //
- if (LaggedPacketTimes.Count()) {
- unsigned long time_now = TIMEGETTIME();
- for (int p=0 ; p<LaggedPacketTimes.Count() ; p++) {
- if (LaggedPacketTimes[p] <= time_now) {
- packet = *LaggedPackets[p];
- delete LaggedPackets[p];
- LaggedPackets.Delete(p);
- LaggedPacketTimes.Delete(p);
- ret_code = LaggedPacketRetCodes[p];
- LaggedPacketRetCodes.Delete(p);
- break;
- }
- }
- }
- #endif //WWDEBUG
- if (ret_code == 0) {
- ret_code = Receive_Wrapper(packet);
- if (ret_code == 0) {
- return(false);
- }
- if (cSinglePlayerData::Is_Single_Player() && ret_code == SOCKET_ERROR) {
- return(false);
- }
- #ifndef WRAPPER_CRC
- if (!packet.Is_Crc_Correct()) {
- #ifdef WWDEBUG
- sockaddr_in *addr_ptr = (LPSOCKADDR_IN) &packet.Get_From_Address_Wrapper()->FromAddress;
- #endif //WWDEBUG
- WWDEBUG_SAY(("*** CRC FAILURE: PACKET DISCARDED ***\n"));
- WWDEBUG_SAY(("*** CRC FAILURE: Packet from %s\n", Addr_As_String(addr_ptr)));
- packet.Flush();
- return true;
- }
- #endif //WRAPPER_CRC
- #ifdef WWDEBUG
- //
- // Add simulated latency if required.
- //
- if (LatencyAddLow || LatencyAddHigh) {
- cPacket *new_packet = new cPacket;
- *new_packet = packet;
- unsigned long time = TIMEGETTIME();
- const int latency_adjust_delay = 1000 * 10;
- if (time - LastLatencyChange > latency_adjust_delay) {
- LastLatencyChange = time;
- if (LatencyAddLow == LatencyAddHigh) {
- CurrentLatencyAdd = LatencyAddLow;
- } else {
- CurrentLatencyAdd = FreeRandom.Get_Int(LatencyAddLow, LatencyAddHigh);
- }
- }
- time += CurrentLatencyAdd;
- LaggedPackets.Add(new_packet);
- LaggedPacketTimes.Add(time);
- LaggedPacketRetCodes.Add(ret_code);
- packet.Flush();
- return(true);
- }
- #endif //WWDEBUG
- }
- //
- // Intercept packets intended for the firewall negotiation code.
- //
- if (packet.Get_Type() == PACKETTYPE_FIREWALL_PROBE) {
- WOLNATInterface.Intercept_Game_Packet(packet);
- packet.Flush();
- WWDEBUG_SAY(("cConnection:: Packet transferred to WOLNAT interface\n"));
- return(true);
- };
- //
- // A ret_code of zero indicates either:
- // 1. A graceful closure of the socket, or
- // 2. A zero-data packet.
- //
- // We are never going to attempt to recv after we have closed it, and
- // we never send zero-length packets, so assert this.
- //
- WWASSERT(ret_code > 0);
- //
- // Measurement stats
- //
- USHORT packet_bits = Calculate_Packet_Bits(ret_code);
- int addressee = Address_To_Rhostid(&packet.Get_From_Address_Wrapper()->FromAddress);
- if (addressee != INVALID_RHOST_ID) {
- PRHost[addressee]->Get_Stats().StatSample[STAT_PktRcv]++;
- PRHost[addressee]->Get_Stats().StatSample[STAT_AppByteRcv] += ret_code;
- //PRHost[addressee]->Get_Stats().StatSample[STAT_HdrByteRcv] += cNetUtil::Get_Header_Bytes();
- PRHost[addressee]->Get_Stats().StatSample[STAT_BitsRcv] += packet_bits;
- PRHost[addressee]->Set_Last_Contact_Time(TIMEGETTIME());
- }
- //
- // Aliases
- //
- const int packet_id = packet.Get_Id();
- const int sender_id = packet.Get_Sender_Id();
- SOCKADDR_IN * p_from_address = &packet.Get_From_Address_Wrapper()->FromAddress;
- WWASSERT(p_from_address != NULL);
- cRemoteHost * p_sender_rhost = NULL;
- if (sender_id != cPacket::UNDEFINED_ID) {
- p_sender_rhost = PRHost[sender_id];
- //WWASSERT(p_sender_rhost != NULL);
- if (p_sender_rhost == NULL) {
- packet.Flush();
- WWDEBUG_SAY(("Packet from null rhost (%d) discarded.\n", sender_id));
- return true;
- }
- }
- switch (packet.Get_Type()) {
- case PACKETTYPE_KEEPALIVE: {
- //WWDEBUG_SAY(("CONNECT: PACKETTYPE_KEEPALIVE received\n"));
- if (!Sender_Id_Tests(packet)) {
- WWDEBUG_SAY(("PACKETTYPE_KEEPALIVE flushed due to Sender_Id_Tests. Packet id = %d\n", packet_id));
- packet.Flush();
- return true;
- }
- //
- // TSS110201
- //
- if ( LocalId == ID_UNKNOWN) {
- WWDEBUG_SAY(("PACKETTYPE_KEEPALIVE flushed due to LocalId == ID_UNKNOWN. Packet id = %d\n", packet_id));
- packet.Flush();
- return true;
- }
- //
- // The main purpose of the keepalive is to stimulate this ack.
- //
- Send_Ack(p_from_address, packet_id);
- float packetloss_pc = packet.Get(packetloss_pc);
- WWASSERT(p_sender_rhost != NULL);
- cNetStats & sender_stats = p_sender_rhost->Get_Stats();
- sender_stats.Set_Pc_Packetloss_Sent(packetloss_pc);
- int remote_service_count = packet.Get(remote_service_count);
- sender_stats.Set_Remote_Service_Count(remote_service_count);
- //
- // We still have to process the keepalive in the rcv list so that
- // we step past it's reliable id. It will be discarded at that
- // point, and not passed up to the application level.
- //
- WWASSERT(packet.Is_Flushed());
- p_sender_rhost->Add_Packet(packet, RELIABLE_RCV_LIST);
- return true;
- }
- case PACKETTYPE_CONNECT_CS: {
- WWDEBUG_SAY(("CONNECT: PACKETTYPE_CONNECT_CS received\n"));
- WWASSERT(IsServer);
- WWASSERT(sender_id == ID_UNKNOWN);
- //
- // Reliable message, ack it.
- //
- Send_Ack(p_from_address, packet_id);
- Process_Connection_Request(packet);
- return true;
- }
- case PACKETTYPE_ACCEPT_SC: {
- //WWDEBUG_SAY(("cConnection::Receive_Packet : PACKETTYPE_ACCEPT_SC received\n"));
- WWDEBUG_SAY(("CONNECT: PACKETTYPE_ACCEPT_SC received\n"));
- WWASSERT(!IsServer);
- if (LocalId != ID_UNKNOWN) {
- //
- // This is a duplicate packet... discard here.
- //
- CombinedStats.StatSample[STAT_DiscardCount]++;
- WWDEBUG_SAY(("PACKETTYPE_ACCEPT_SC flushed due to LocalId != ID_UNKNOWN. Packet id = %d\n", packet_id));
- Send_Ack(p_from_address, packet_id);
- packet.Flush();
- } else {
- WWASSERT(sender_id == SERVER_RHOST_ID);
- packet.Get(LocalId); // This is where we learn our id
- WWDEBUG_SAY((" Received LocalId:%d\n", LocalId));
- Send_Ack(p_from_address, packet_id);
- //
- // Now, client may do something if he wants
- //
- //Accept_Handler();
- WWASSERT(AcceptHandler != NULL);
- AcceptHandler();
- //
- // We still have to process the accept in the rcv list so that
- // we step past it's reliable id. It will be discarded at that point
- // and not passed up to the application level.
- //
- WWASSERT(packet.Is_Flushed());
- WWASSERT(p_sender_rhost != NULL);
- p_sender_rhost->Add_Packet(packet, RELIABLE_RCV_LIST);
- }
- return true;
- }
- case PACKETTYPE_REFUSAL_SC: {
- WWDEBUG_SAY(("cConnection::Receive_Packet : PACKETTYPE_REFUSAL_SC received\n"));
- WWASSERT(!IsServer);
- if (LocalId == ID_UNKNOWN) {
- WWASSERT(sender_id == SERVER_RHOST_ID);
- if (packet_id > HighestRefusalPacketRcvId) {
- HighestRefusalPacketRcvId = packet_id;
- int refusal_code = packet.Get(refusal_code);
- //Refusal_Handler(refusal_code);
- WWASSERT(RefusalHandler != NULL);
- RefusalHandler((REFUSAL_CODE)refusal_code);
- IsDestroy = true;
- } else {
- //
- // It's a duplicate
- //
- packet.Flush();
- }
- } else {
- //
- // This is an inappropriate packet... discard here.
- // TSS - bug - duplicates not handled properly - sent * 5
- //
- CombinedStats.StatSample[STAT_DiscardCount]++;
- packet.Flush();
- }
- return true;
- }
- case PACKETTYPE_UNRELIABLE: {
- //WWDEBUG_SAY(("CONNECT: PACKETTYPE_UNRELIABLE received\n"));
- //
- // Discard all unreliable packets until we have an id.
- //
- if (LocalId == ID_UNKNOWN) {
- packet.Flush();
- WWDEBUG_SAY(("Unreliable packet flushed due to unknown id.\n"));
- return true;
- }
- //
- // Discard data with an address mismatch.
- //
- if (!Sender_Id_Tests(packet)) {
- packet.Flush();
- WWDEBUG_SAY(("Unreliable packet flushed due to address mismatch.\n"));
- return true;
- }
- //
- // Discard out-of-date data.
- //
- WWASSERT(p_sender_rhost != NULL);
- if (packet_id < p_sender_rhost->Get_Unreliable_Packet_Rcv_Id()) {
- packet.Flush();
- //WWDEBUG_SAY(("Unreliable packet flushed due to being out-of-date.\n"));
- return true;
- }
- //
- // Keep track of how many of each packet is received
- //
- cNetStats & sender_stats = p_sender_rhost->Get_Stats();
- sender_stats.StatSample[STAT_MsgRcv]++;
- sender_stats.StatSample[STAT_UPktRcv]++;
- sender_stats.StatSample[STAT_UByteRcv] += ret_code;
- if (packet_id > sender_stats.Get_Freeze_Packet_Id()) {
- sender_stats.StatSample[STAT_UPktRcv2]++;
- sender_stats.Increment_Unreliable_Count();
- }
- if (packet_id > sender_stats.Get_Last_Unreliable_Packet_Id()) {
- sender_stats.Set_Last_Unreliable_Packet_Id(packet_id);
- }
- p_sender_rhost->Add_Packet(packet, UNRELIABLE_RCV_LIST);
- return true;
- }
- case PACKETTYPE_RELIABLE: {
- //WWDEBUG_SAY(("CONNECT: PACKETTYPE_RELIABLE received\n"));
- //
- // Discard all reliable packets until we have an id.
- // We still don't have LocalId, therefore we can't Ack this.
- //
- if (LocalId == ID_UNKNOWN) {
- packet.Flush();
- WWDEBUG_SAY(("Reliable packet %d flushed due to unknown id.\n", packet_id));
- return true;
- }
- //
- // Discard data with an address mismatch.
- //
- if (!Sender_Id_Tests(packet)) {
- packet.Flush();
- WWDEBUG_SAY(("Reliable packet %d flushed due to address mismatch.\n", packet_id));
- return true;
- }
- Send_Ack(p_from_address, packet_id);
- //
- // Keep track of how many of each packet is received
- //
- WWASSERT(p_sender_rhost != NULL);
- cNetStats & sender_stats = p_sender_rhost->Get_Stats();
- sender_stats.StatSample[STAT_MsgRcv]++;
- sender_stats.StatSample[STAT_RPktRcv]++;
- sender_stats.StatSample[STAT_RByteRcv] += ret_code;
- p_sender_rhost->Add_Packet(packet, RELIABLE_RCV_LIST);
- return true;
- }
- case PACKETTYPE_ACK: {
- //WWDEBUG_SAY(("CONNECT: PACKETTYPE_ACK received\n"));
- //WWDEBUG_SAY(("(Received Ack for packet %d)\n", packet_id));
- if (!Sender_Id_Tests(packet)) {
- return true;
- }
- WWASSERT(p_sender_rhost != NULL);
- cNetStats & sender_stats = p_sender_rhost->Get_Stats();
- sender_stats.StatSample[STAT_AckCountRcv]++;
- p_sender_rhost->Remove_Packet(packet_id, RELIABLE_SEND_LIST);
- return true;
- }
- default:
- DIE;
- break;
- }
- DIE; // shouldn't get here
- return true;
- }
- //-----------------------------------------------------------------------------
- void cConnection::Process_Connection_Request(cPacket & packet)
- {
- LPSOCKADDR_IN p_address = &packet.Get_From_Address_Wrapper()->FromAddress;
- WWASSERT(InitDone);
- WWASSERT(IsServer);
- int new_rhost_id = ID_UNKNOWN;
- //
- // Make sure we don't already know him, and find him a slot
- //
- for (int player_id = MinRHost; player_id <= MaxRHost; player_id++) {
- if (PRHost[player_id] != NULL) {
- if (!cSinglePlayerData::Is_Single_Player() &&
- cNetUtil::Is_Same_Address(&(PRHost[player_id]->Get_Address()),
- p_address)) {
- //
- // He already has an id. This must be a resend or duplicate.
- //
- return;
- }
- } else if (new_rhost_id == ID_UNKNOWN) {
- new_rhost_id = player_id;
- }
- }
- if (new_rhost_id == ID_UNKNOWN) {
- WWDEBUG_SAY((" Warning: server cannot accept this client; no free slots\n"));
- Send_Refusal_Sc(p_address, REFUSAL_GAME_FULL);
- } else {
- WWASSERT(ApplicationAcceptanceHandler != NULL);
- REFUSAL_CODE refusal = ApplicationAcceptanceHandler(packet);
- if (refusal != REFUSAL_CLIENT_ACCEPTED) {
- packet.Flush();
- Send_Refusal_Sc(p_address, refusal);
- return;
- }
- //
- // TSS091701
- //
- int bbo = packet.Get(bbo);
- WWDEBUG_SAY(("New clients BBO is %d\n", bbo));
- WWASSERT(PRHost[new_rhost_id] == NULL);
- PRHost[new_rhost_id] = new cRemoteHost();
- WWASSERT(PRHost[new_rhost_id] != NULL);
- PRHost[new_rhost_id]->Set_Id(new_rhost_id);//TSS2001
- NumRHosts++;
- WWASSERT(NumRHosts <= MaxRHost - MinRHost + 1);
- PRHost[new_rhost_id]->Set_Address(*p_address);
- PRHost[new_rhost_id]->Set_Maximum_Bps(bbo);
- Send_Accept_Sc(new_rhost_id);
- //Connection_Handler(new_rhost_id);
- WWASSERT(ConnHandler != NULL);
- ConnHandler(new_rhost_id);
- //
- // Although processed individually, PACKETTYPE_CONNECT_CS
- // is essentially reliable, and we must track the id appropriately.
- //
- PRHost[new_rhost_id]->Get_Reliable_Packet_Rcv_Id();
- PRHost[new_rhost_id]->Increment_Reliable_Packet_Rcv_Id();
- }
- }
- //------------------------------------------------------------------------------------
- int cConnection::Single_Player_sendto(cPacket & packet)
- {
- //WWDEBUG_SAY(("cConnection::Single_Player_sendto\n"));
- WWASSERT(cSinglePlayerData::Is_Single_Player());
- SList<cPacket> * p_packet_list;
- if (IsServer) {
- p_packet_list = cSinglePlayerData::Get_Input_Packet_List(CLIENT_LIST);
- } else {
- p_packet_list = cSinglePlayerData::Get_Input_Packet_List(SERVER_LIST);
- }
- WWASSERT(p_packet_list != NULL);
- cPacket * p_packet = new cPacket;
- WWASSERT(p_packet != NULL);
- *p_packet = packet;
- p_packet_list->Add_Tail(p_packet);
- return packet.Get_Compressed_Size_Bytes();
- }
- //------------------------------------------------------------------------------------
- int cConnection::Address_To_Rhostid(const SOCKADDR_IN* p_address)
- {
- WWASSERT(p_address != NULL);
- if (cSinglePlayerData::Is_Single_Player()) {
- return INVALID_RHOST_ID;
- }
- //
- // TSS - this searching is very inefficient.
- //
- for (int rhost_id = MinRHost; rhost_id <= MaxRHost; rhost_id++) {
- if (PRHost[rhost_id] != NULL &&
- cNetUtil::Is_Same_Address(&(PRHost[rhost_id]->Get_Address()), p_address)) {
- return rhost_id;
- }
- }
- return INVALID_RHOST_ID;
- }
- //#include "packetmgr.h"
- //unsigned char last_packet[1024];
- //unsigned char delta_packet[1024];
- //unsigned char fixed_packet[1024];
- //int last_packet_len = 0;
- //------------------------------------------------------------------------------------
- int cConnection::Low_Level_Send_Wrapper(cPacket & packet, LPSOCKADDR_IN p_address)
- {
- WWASSERT(p_address != NULL);
- int ret_code = 0;
- #if (0)
- if (last_packet_len == (int)packet.Get_Compressed_Size_Bytes()) {
- int delta_size = PacketManagerClass::Build_Delta_Packet_Patch(last_packet, (unsigned char*)packet.Get_Data(), delta_packet, last_packet_len, last_packet_len);
- if (delta_size != -1) {
- WWDEBUG_SAY(("Packet size = %d, last packet delta = %d\n", last_packet_len, delta_size));
- }
- int bytes = PacketManagerClass::Reconstruct_From_Delta(last_packet, fixed_packet, delta_packet, last_packet_len);
- assert(bytes == last_packet_len);
- assert(memcmp(packet.Get_Data(), fixed_packet, last_packet_len) == 0);
- }
- last_packet_len = (int)packet.Get_Compressed_Size_Bytes();
- memcpy(last_packet, packet.Get_Data(), last_packet_len);
- #endif (0)
- if (cSinglePlayerData::Is_Single_Player()) {
- ret_code = Single_Player_sendto(packet);
- } else {
- //WWDEBUG_SAY(("cConnection: sendto %s\n", Addr_As_String(p_address)));
- //
- // Just pass the packet to the packet manager for deltaing and coagulation.
- //
- bool took = PacketManager.Take_Packet((unsigned char *)packet.Get_Data(), packet.Get_Compressed_Size_Bytes(), (unsigned char*)&p_address->sin_addr.s_addr, p_address->sin_port, Sock);
- if (!took) {
- WWDEBUG_SAY(("Low_Level_Send_Wrapper - Failed to pass packet to packet manager\n"));
- return(0);
- //ret_code = sendto(Sock, packet.Get_Data(),
- // packet.Get_Compressed_Size_Bytes(), 0,
- // (LPSOCKADDR) p_address, sizeof(SOCKADDR_IN));
- } else {
- PacketManager.Flush();
- ret_code = packet.Get_Compressed_Size_Bytes();
- if (ret_code < 0) {
- ret_code = 0;
- }
- }
- //unsigned long bytes;
- //int result = ioctlsocket(Sock, FIONREAD, &bytes);
- //if (result == 0 && bytes != 0) {
- // WWDEBUG_SAY(("ioctlsocket - bytes left to read = %d\n", bytes));
- //}
- }
- return ret_code;
- }
- //------------------------------------------------------------------------------------
- int cConnection::Send_Wrapper(cPacket & packet, LPSOCKADDR_IN p_address)
- {
- WWASSERT(p_address != NULL);
- cPacket full_packet;
- cPacket::Construct_Full_Packet(full_packet, packet);
- //
- // Update stats
- //
- BYTE packet_type = packet.Get_Type();
- WWASSERT(packet_type >= PACKETTYPE_FIRST && packet_type <= PACKETTYPE_LAST);
- PStatList->Increment_Num_Msg_Sent(packet_type);
- PStatList->Increment_Num_Byte_Sent(packet_type, full_packet.Get_Compressed_Size_Bytes());
- bool is_lost = false;
- #ifdef WWDEBUG
- is_lost = (rand() < SimulatedPacketLossPerRANDMAX);
- #endif
- int ret_code = 0;
- if (is_lost) {
- ret_code = full_packet.Get_Compressed_Size_Bytes(); // just don't send !
- } else {
- ret_code = Low_Level_Send_Wrapper(full_packet, p_address);
- }
- return ret_code;
- }
- //------------------------------------------------------------------------------------
- int cConnection::Send_Wrapper(cPacket & packet, int addressee)
- {
- WWASSERT(addressee >= 0);
- WWASSERT(addressee != ID_UNKNOWN);
- WWASSERT(PRHost[addressee] != NULL);
- return Send_Wrapper(packet, &(PRHost[addressee]->Get_Address()));//, addressee);
- }
- //------------------------------------------------------------------------------------
- int cConnection::Low_Level_Receive_Wrapper(cPacket & packet)
- {
- int ret_code = 0;
- if (cSinglePlayerData::Is_Single_Player()) {
- ret_code = Single_Player_recvfrom(packet.Get_Data());
- } else {
- const int max_errors = 250;
- int error_count = 0;
- int bytes = 0;
- //
- // Try getting a packet from the packet manager. Keep trying for a number of times if we get a socket error. If we don't
- // do this and just fail then we fall out of the receive packet loop and no more packets are received this frame. 15 of
- // these a second and we don't get any packets in at all.
- //
- unsigned char ip_address[4];
- unsigned short port = 0;
- while (error_count < max_errors) {
- bytes = PacketManager.Get_Packet(Sock, (unsigned char *)packet.Get_Data(), packet.Get_Max_Size(), ip_address, port);
- //
- // A return value of less than 0 indicates a fatal socket error. Try and ditch the offending client.
- //
- if (bytes < 0) {
- bytes = 0;
- error_count++;
- bool found_bad = false;
- if (IsServer) {
- //
- // If we try to invoke the broken connection handler when loading a level it will access the player list
- // which will cause a DataSafe access from the wrong (main) thread with potentially catastrophic effects.
- // ST - 1/17/2002 11:18AM
- //
- if (CanProcess) {
- WWASSERT(ServerBrokenConnectionHandler != NULL);
- for (int i=MinRHost ; i<MaxRHost ; i++) {
- cRemoteHost *rhost_ptr = PRHost[i];
- if (rhost_ptr) {
- SOCKADDR_IN rhost_addr = rhost_ptr->Get_Address();
- if (memcmp(ip_address, &rhost_addr.sin_addr.s_addr, 4) == 0) {
- if (rhost_addr.sin_port == port) {
- int rhost_id = rhost_ptr->Get_Id();
- Destroy_Connection(rhost_id);
- ServerBrokenConnectionHandler(rhost_id);
- found_bad = true;
- break;
- }
- }
- }
- }
- if (!found_bad) {
- WWDEBUG_SAY(("WSAECONNRESET address not in host list\n"));
- }
- }
- }
- } else {
- break;
- }
- }
- if (bytes) {
- sockaddr_in *addr_ptr = (LPSOCKADDR_IN) &packet.Get_From_Address_Wrapper()->FromAddress;
- memcpy(&addr_ptr->sin_addr.s_addr, ip_address, 4);
- addr_ptr->sin_port = port;
- }
- ret_code = bytes;
- #if (0)
- int address_size = sizeof(SOCKADDR_IN);
- ret_code = recvfrom(Sock, packet.Get_Data(),
- packet.Get_Max_Size(), 0,
- (LPSOCKADDR) &packet.Get_From_Address_Wrapper()->FromAddress, &address_size);
- if (ret_code > 0) {
- //WWDEBUG_SAY(("cConnection: recvfrom %s\n", Addr_As_String((LPSOCKADDR_IN) &packet.Get_From_Address_Wrapper()->FromAddress)));
- }
- #endif //(0)
- /*
- //
- // diagnostic
- //
- if (ret_code > 0) {
- ULONG ip = packet.Get_From_Address_Wrapper()->FromAddress.sin_addr.s_addr;
- WWDEBUG_SAY(("cConnection::Low_Level_Receive_Wrapper: %s\n",
- cNetUtil::Address_To_String(ip)));
- }
- /**/
- }
- return ret_code;
- }
- //------------------------------------------------------------------------------------
- int cConnection::Receive_Wrapper(cPacket & packet)
- {
- cPacket full_packet;
- int ret_code = Low_Level_Receive_Wrapper(full_packet);
- if (ret_code > 0) {
- //
- // We won't be able to read the header from the full packet unless we
- // set the bit length (approximately).
- // The returned packet object will have the exact bit length set correctly.
- //
- full_packet.Set_Bit_Length(ret_code * 8);
- cPacket::Construct_App_Packet(packet, full_packet);
- #ifndef WRAPPER_CRC
- if (packet.Is_Crc_Correct()) {
- #endif //WRAPPER_CRC
- //
- // Update receive stats
- //
- BYTE packet_type = packet.Get_Type();
- WWASSERT(packet_type >= PACKETTYPE_FIRST && packet_type <= PACKETTYPE_LAST);
- PStatList->Increment_Num_Msg_Recd(packet_type);
- PStatList->Increment_Num_Byte_Recd(packet_type, ret_code);
- #ifndef WRAPPER_CRC
- }
- #endif //WRAPPER_CRC
- }
- return ret_code;
- }
- /*
- //------------------------------------------------------------------------------------
- void cConnection::Handle_Send_Resource_Failure(int rhost_id)
- {
- if (rhost_id != INVALID_RHOST_ID) {
- WWASSERT(PRHost[rhost_id] != NULL);
- PRHost[rhost_id]->Get_Stats().StatSample[STAT_SendFailureCount]++;
- }
- int orgbuffersize;
- int newbuffersize;
- int len;
- len = sizeof(int);
- WSA_CHECK(::getsockopt(Sock, SOL_SOCKET, SO_SNDBUF,
- (char *)&orgbuffersize, &len));
- static int time_of_last_reset = 0;
- int time_now = TIMEGETTIME();
- Clear_Resend_Counts();
- if (time_now - time_of_last_reset > 5000) {
- failcount++;
- float failure_ratio;
- if (succcount == 0) {
- failure_ratio = 1;
- } else {
- failure_ratio = failcount / (float) succcount;
- }
- succcount = 0;
- failcount = 0;
- extern int g_c_wouldblock;
- extern int g_c_nobufs;
- g_c_wouldblock = 0;
- g_c_nobufs = 0;
- if (orgbuffersize < 1000000) {
- //
- // 2-pronged approach. Firstly, increase send buffer size.
- // Secondly, if it was a significant failure, immediately
- // reduce bw out.
- //
- newbuffersize = 4 * orgbuffersize;
- len = sizeof(int);
- WSA_CHECK(setsockopt(Sock, SOL_SOCKET, SO_SNDBUF,
- (char *)&newbuffersize, len));
- len = sizeof(int);
- WSA_CHECK(::getsockopt(Sock, SOL_SOCKET, SO_SNDBUF,
- (char *)&newbuffersize, &len));
- WWDEBUG_SAY(("SO_SNDBUF %d -> %d\n",
- orgbuffersize, newbuffersize));
- if (failure_ratio > 0.05f) {
- time_of_last_reset = time_now;
- }
- } else {
- //
- // If we max out the send buffer and are still getting fails here
- // then we need to throttle back our output through this socket.
- //
- if (failure_ratio > 0.05f) {
- time_of_last_reset = time_now;
- }
- }
- }
- }
- */
- //------------------------------------------------------------------------------------
- void cConnection::Send_Packet_To_Address(cPacket & packet, LPSOCKADDR_IN p_address)
- {
- WWASSERT(p_address != NULL);
- WWASSERT(InitDone);
- // TSS - need reverse lookup of addressee from address
- int rhost_id = Address_To_Rhostid(p_address);
- if (rhost_id != INVALID_RHOST_ID) {
- WWASSERT(PRHost[rhost_id] != NULL);
- }
- if (rand() < SimulatedPacketDuplicationPerRANDMAX) {
- //
- // we'll send a duplicate
- //
- packet.Set_Num_Sends(packet.Get_Num_Sends() + 1);
- }
- //static int succcount = 0;
- //static int failcount = 0;
- for (int i = 0; i < packet.Get_Num_Sends(); i++) {
- int ret_code;
- if (rhost_id == INVALID_RHOST_ID) {
- ret_code = Send_Wrapper(packet, p_address);
- } else {
- ret_code = Send_Wrapper(packet, rhost_id);
- }
- if (SEND_RESOURCE_FAILURE(ret_code)) {
- //Handle_Send_Resource_Failure(rhost_id);
- WWDEBUG_SAY(("WARNING: cConnection::Send_Packet_To_Address : SEND_RESOURCE_FAILURE\n"));
- } else {
- //succcount++;
- TotalCompressedBytesSent += packet.Get_Compressed_Size_Bytes();
- TotalUncompressedBytesSent += packet.Get_Uncompressed_Size_Bytes();
- USHORT bits_sent = Calculate_Packet_Bits(packet.Get_Compressed_Size_Bytes());
- if (rhost_id != INVALID_RHOST_ID) {
- PRHost[rhost_id]->Get_Stats().StatSample[STAT_PktSent]++;
- PRHost[rhost_id]->Get_Stats().StatSample[STAT_AppByteSent] += packet.Get_Compressed_Size_Bytes();
- //PRHost[rhost_id]->Get_Stats().StatSample[STAT_HdrByteSent] += cNetUtil::Get_Header_Bytes();
- PRHost[rhost_id]->Get_Stats().StatSample[STAT_BitsSent] += bits_sent;
- }
- }
- }
- }
- //------------------------------------------------------------------------------------
- void cConnection::Set_R_And_U_Packet_Id(cPacket & packet, int addressee, BYTE send_type)
- {
- WWASSERT(PRHost[addressee] != NULL);
- if (send_type == PACKETTYPE_RELIABLE) {
- packet.Set_Id(PRHost[addressee]->Get_Reliable_Packet_Send_Id());
- PRHost[addressee]->Increment_Reliable_Packet_Send_Id();
- } else {
- WWASSERT(send_type == PACKETTYPE_UNRELIABLE);
- packet.Set_Id(PRHost[addressee]->Get_Unreliable_Packet_Send_Id());
- PRHost[addressee]->Increment_Unreliable_Packet_Send_Id();
- }
- }
- //------------------------------------------------------------------------------------
- void cConnection::R_And_U_Send(
- cPacket & packet,
- int addressee)
- {
- WWASSERT(PRHost[addressee] != NULL);
- if (packet.Get_Type() == PACKETTYPE_RELIABLE) {
- PRHost[addressee]->Add_Packet(packet, RELIABLE_SEND_LIST);
- } else {
- WWASSERT(packet.Get_Type() == PACKETTYPE_UNRELIABLE);
- PRHost[addressee]->Add_Packet(packet, UNRELIABLE_SEND_LIST);
- }
- }
- //------------------------------------------------------------------------------------
- void cConnection::Send_Packet_To_Individual(cPacket & packet, int addressee, BYTE send_flags)
- {
- WWASSERT(InitDone);
- //
- // Validate inputs
- //
- WWASSERT(packet.Get_Compressed_Size_Bytes() > 0);
- WWASSERT(addressee >= MinRHost && addressee <= MaxRHost);
- WWASSERT(PRHost[addressee] != NULL);
- WWASSERT(
- send_flags == SEND_RELIABLE ||
- send_flags == SEND_UNRELIABLE ||
- send_flags == (SEND_UNRELIABLE | SEND_MULTI));
- int num_sends = 1;
- if (send_flags & SEND_MULTI) {
- num_sends = cNetUtil::MULTI_SENDS;
- }
- packet.Set_Num_Sends(num_sends);
- if (send_flags & SEND_RELIABLE) {
- packet.Set_Type(PACKETTYPE_RELIABLE);
- } else {
- packet.Set_Type(PACKETTYPE_UNRELIABLE);
- }
- Set_R_And_U_Packet_Id(packet, addressee, packet.Get_Type());
- packet.Set_Sender_Id(LocalId);
- //
- // Keep track of how many of each packet is sent.
- //
- PRHost[addressee]->Get_Stats().StatSample[STAT_MsgSent] += num_sends;
- R_And_U_Send(packet, addressee);
- }
- /*
- //------------------------------------------------------------------------------------
- void cConnection::Send_Packet_To_All(cPacket & packet, BYTE send_flags)
- {
- WWASSERT(InitDone);
- //
- // Validate inputs
- //
- WWASSERT(packet.Get_Compressed_Size_Bytes() > 0);
- WWASSERT(
- send_flags == SEND_RELIABLE ||
- send_flags == SEND_UNRELIABLE ||
- send_flags == (SEND_UNRELIABLE | SEND_MULTI));
- if (NumRHosts == 0) {
- return;
- }
- //int num_sends = 0;
- for (int rhost_id = MinRHost; rhost_id <= MaxRHost; rhost_id++) {
- if (PRHost[rhost_id] != NULL) {
- //if (IsServer && !PRHost[rhost_id]->Is_Ready_For_All_Data()) {
- // continue;
- //}
- Send_Packet_To_Individual(packet, rhost_id, send_flags);
- //num_sends++;
- }
- }
- //return num_sends;
- }
- */
- //------------------------------------------------------------------------------------
- bool cConnection::Is_Established() const
- {
- bool is_established = true;
- if (!IsServer) {
- is_established = (LocalId != ID_UNKNOWN) && (PRHost[SERVER_RHOST_ID] != NULL);
- }
- return is_established;
- }
- //------------------------------------------------------------------------------------
- void cConnection::Connect_Cs(cPacket & packet)
- {
- WWASSERT(InitDone);
- WWASSERT(!IsServer);
- WWASSERT(PRHost[SERVER_RHOST_ID] != NULL);
- WWASSERT(LocalId == ID_UNKNOWN);
- //WWDEBUG_SAY(("Connect_Cs at time %s\n", cMiscUtil::Get_Text_Time()));
- int packet_id = PRHost[SERVER_RHOST_ID]->Get_Reliable_Packet_Send_Id();
- PRHost[SERVER_RHOST_ID]->Increment_Reliable_Packet_Send_Id();
- WWASSERT(packet_id == 0);
- //WWDEBUG_SAY(("cConnection::Connect_Cs : Sending PACKETTYPE_CONNECT_CS\n"));
- WWDEBUG_SAY(("CONNECT: PACKETTYPE_CONNECT_CS sent\n"));
- packet.Set_Type(PACKETTYPE_CONNECT_CS);
- packet.Set_Id(packet_id);
- //packet.Set_Sender_Id(LocalId);//NEW
- PRHost[SERVER_RHOST_ID]->Add_Packet(packet, RELIABLE_SEND_LIST);
- }
- //-----------------------------------------------------------------------------
- void cConnection::Send_Accept_Sc(int new_rhost_id)
- {
- WWASSERT(new_rhost_id >= 0);
- WWASSERT(InitDone);
- WWASSERT(IsServer);
- WWASSERT(new_rhost_id >= MinRHost && new_rhost_id <= MaxRHost);
- //WWDEBUG_SAY(("cConnection::Send_Accept_Sc(%d)\n", new_rhost_id));
- WWDEBUG_SAY(("CONNECT: PACKETTYPE_ACCEPT_SC (%d) sent\n", new_rhost_id));
- int packet_id = PRHost[new_rhost_id]->Get_Reliable_Packet_Send_Id();
- PRHost[new_rhost_id]->Increment_Reliable_Packet_Send_Id();
- cPacket packet;
- packet.Add(new_rhost_id);
- packet.Set_Type(PACKETTYPE_ACCEPT_SC);
- packet.Set_Id(packet_id);
- packet.Set_Sender_Id(LocalId);
- PRHost[new_rhost_id]->Add_Packet(packet, RELIABLE_SEND_LIST);
- }
- //-----------------------------------------------------------------------------
- void cConnection::Send_Refusal_Sc(LPSOCKADDR_IN p_address, REFUSAL_CODE refusal_code)
- {
- WWASSERT(p_address != NULL);
- //
- // This is a refusal originating from the wwnet layer
- //
- WWDEBUG_SAY(("cConnection::Send_Refusal_Sc (%d)\n", refusal_code));
- WWASSERT(InitDone);
- WWASSERT(IsServer);
- //
- // The id is not per-client... because we don't hold per client information
- // for this guy.
- //
- int packet_id = RefusalPacketSendId++;
- cPacket packet;
- packet.Add((int)refusal_code);
- packet.Set_Type(PACKETTYPE_REFUSAL_SC);
- packet.Set_Id(packet_id);
- packet.Set_Sender_Id(LocalId);
- //
- // Send redundantly, because it's unreliable
- //
- packet.Set_Num_Sends(cNetUtil::MULTI_SENDS);
- Send_Packet_To_Address(packet, p_address);
- }
- //-----------------------------------------------------------------------------
- void cConnection::Send_Ack(LPSOCKADDR_IN p_address, int packet_id)
- {
- WWASSERT(p_address != NULL);
- WWASSERT(InitDone);
- WWASSERT(packet_id >= 0);
- WWASSERT(LocalId != ID_UNKNOWN); //TSS - bug - asserted here when 50% packet loss or crc failures
- //WWDEBUG_SAY(("Ack reply for packet is %d\n", packet_id));
- //WWDEBUG_SAY(("Sending ack for packet %d to %s\n", packet_id, Addr_As_String(p_address)));
- cPacket packet;
- packet.Set_Type(PACKETTYPE_ACK);
- packet.Set_Id(packet_id);
- packet.Set_Sender_Id(LocalId);
- //
- // Acks are unreliable
- //
- int addressee = Address_To_Rhostid(p_address);
- if (addressee != INVALID_RHOST_ID) {
- WWASSERT(PRHost[addressee] != NULL);
- PRHost[addressee]->Get_Stats().StatSample[STAT_AckCountSent]++;
- PRHost[addressee]->Get_Stats().StatSample[STAT_UPktSent]++;
- PRHost[addressee]->Get_Stats().StatSample[STAT_UByteSent] += packet.Get_Compressed_Size_Bytes();
- }
- //unsigned long time = TIMEGETTIME() / 1000;
- //WWDEBUG_SAY(("Sending ack at %d\n", time));
- Send_Packet_To_Address(packet, p_address);
- }
- //-----------------------------------------------------------------------------
- void cConnection::Destroy_Connection(int rhost_id)
- {
- WWASSERT(rhost_id >= 0);
- WWASSERT(InitDone);
- WWASSERT(rhost_id >= MinRHost && rhost_id <= MaxRHost);
- if (PRHost[rhost_id] != NULL) {
- delete PRHost[rhost_id];
- PRHost[rhost_id] = NULL;
- NumRHosts--;
- WWASSERT(NumRHosts >= 0);
- }
- }
- //-----------------------------------------------------------------------------
- void cConnection::Send_Keepalives()
- {
- //
- /////// Keepalives are only sent when we have heard nothing from the rhost for a while.
- //
- WWASSERT(InitDone);
- if (LocalId != ID_UNKNOWN) {
- for (int rhost_id = MinRHost; rhost_id <= MaxRHost; rhost_id++) {
- if (PRHost[rhost_id] != NULL && ThisFrameTimeMs -
- PRHost[rhost_id]->Get_Last_Keepalive_Time_Ms() > cNetUtil::KEEPALIVE_TIMEOUT_MS) {
- int service_rate = (int)(1000 *
- (ServiceCount - PRHost[rhost_id]->Get_Last_Service_Count()) / (ThisFrameTimeMs -
- PRHost[rhost_id]->Get_Last_Keepalive_Time_Ms()));
- PRHost[rhost_id]->Set_Last_Service_Count(ServiceCount);
- PRHost[rhost_id]->Set_Last_Keepalive_Time_Ms(ThisFrameTimeMs);
- //WWDEBUG_SAY(("Sending keepalive to rhost %d at time %d\n", rhost_id, TIMEGETTIME()));
- //
- // Keepalive is a reliable message
- //
- int packet_id = PRHost[rhost_id]->Get_Reliable_Packet_Send_Id();
- PRHost[rhost_id]->Increment_Reliable_Packet_Send_Id();
- cPacket packet;
- packet.Add((float) PRHost[rhost_id]->Get_Stats().Get_Pc_Packetloss_Received());
- packet.Add(service_rate);
- packet.Set_Type(PACKETTYPE_KEEPALIVE);
- packet.Set_Id(packet_id);
- packet.Set_Sender_Id(LocalId);
- PRHost[rhost_id]->Add_Packet(packet, RELIABLE_SEND_LIST);
- }
- }
- }
- }
- //-----------------------------------------------------------------------------
- double cConnection::Get_Threshold_Priority(int rhost_id)
- {
- WWASSERT(rhost_id >= 0);
- WWASSERT(PRHost[rhost_id] != NULL);
- return PRHost[rhost_id]->Get_Threshold_Priority();
- }
- //-----------------------------------------------------------------------------
- void cConnection::Set_Max_Acceptable_Packetloss_Pc(double max_packetloss_pc)
- {
- WWASSERT(max_packetloss_pc >= 0 && max_packetloss_pc <= 100);
- //WWDEBUG_SAY(("cConnection::Set_Max_Acceptable_Packetloss_Pc: %5.2f\n",
- // MaxAcceptablePacketlossPc));
- MaxAcceptablePacketlossPc = max_packetloss_pc;
- }
- //-----------------------------------------------------------------------------
- bool cConnection::Demultiplex_R_Or_U_Packet(cPacket * p_packet, int rhost_id)
- {
- WWASSERT(p_packet != NULL);
- WWASSERT(rhost_id >= 0);
- bool is_aborted;
- WWASSERT(PRHost[rhost_id] != NULL);
- if (IsServer) {
- //WWPROFILE("cConnection::Server_Packet_Handler");
- //Server_Packet_Handler(*p_packet, rhost_id);
- WWASSERT(ServerPacketHandler != NULL);
- ServerPacketHandler(*p_packet, rhost_id);
- } else {
- //WWPROFILE("cConnection::Client_Packet_Handler");
- //Client_Packet_Handler(*p_packet);
- WWASSERT(ClientPacketHandler != NULL);
- ClientPacketHandler(*p_packet);
- }
- if (PRHost[rhost_id] == NULL) {
- is_aborted = true;
- } else {
- //WWASSERT(p_packet->Is_Flushed());
- is_aborted = false;
- }
- return is_aborted;
- }
- //-----------------------------------------------------------------------------
- //
- // Service_Read() should be called once per frame on both C & S
- //
- void cConnection::Service_Read()
- {
- //WWDEBUG_SAY(("cConnection::Service_Read\n"));
- WWASSERT(InitDone);
- CombinedStats.StatSample[STAT_ServiceCount]++;
- ThisFrameTimeMs = TIMEGETTIME();
- if (ExtraTimeoutTime && (ThisFrameTimeMs - ExtraTimeoutTimeStarted) > (ExtraTimeoutTime * 2)) {
- ExtraTimeoutTime = 0;
- ExtraTimeoutTimeStarted = 0;
- }
- //
- // Receive as many packets as are available
- //
- //int start_time;
- //start_time = TIMEGETTIME();
- /*
- if (Is_Packet_Latency_Simulation_Active()) {
- Buffer_Packets();
- }
- */
- {
- WWPROFILE("Receive Packets");
- while (Receive_Packet());
- }
- /*
- int time_spent = (int) TIMEGETTIME() - start_time;
- if (time_spent > cNetUtil::Get_Max_Receive_Time_Ms()) {
- WWDEBUG_SAY(("*** WWNET: Too much time spent (%d ms)) receiving packets.\n",
- time_spent));
- }
- */
- if (!CanProcess) {
- return;
- }
- int rhost_id;
- //
- // Process as many reliable packets as are available in sequence
- //
- //start_time = (int) TIMEGETTIME();
- {
- WWPROFILE("Process R Packets");
- for (rhost_id = MinRHost; rhost_id <= MaxRHost; rhost_id++) {
- if (PRHost[rhost_id] != NULL) {
- PRHost[rhost_id]->Compute_List_Max(RELIABLE_RCV_LIST);
- for (SLNode<cPacket> * objnode = PRHost[rhost_id]->Get_Packet_List(RELIABLE_RCV_LIST).Head();
- objnode != NULL;) {
- cPacket * p_packet = objnode->Data();
- WWASSERT(p_packet != NULL);
- objnode = objnode->Next();
- int comparison = p_packet->Get_Id() - PRHost[rhost_id]->Get_Reliable_Packet_Rcv_Id();
- if (comparison < 0) {
- //
- // Duplicate packet, discard
- //
- CombinedStats.StatSample[STAT_DiscardCount]++;
- /*
- WWDEBUG_SAY(("%s removing duplicate reliable packet (id %d)) [ReliablePacketRcvId is %d]\n",
- IsServer ? "Server" : "Client",
- p_packet->Get_Id(),
- PRHost[rhost_id]->Get_Reliable_Packet_Rcv_Id()));
- */
- PRHost[rhost_id]->Get_Packet_List(RELIABLE_RCV_LIST).Remove_Head();
- p_packet->Flush();
- delete p_packet;
- } else if (comparison == 0) {
- /*
- bool need_abort = false;
- switch (p_packet->Get_Type()) {
- case PACKETTYPE_KEEPALIVE:
- case PACKETTYPE_ACCEPT_SC:
- //
- // Don't pass on reliable system packets... they are in
- // the list solely to maintain packet sequencing.
- //
- p_packet->Flush();// is this necessary?
- break;
- case PACKETTYPE_RELIABLE:
- need_abort = Demultiplex_R_Or_U_Packet(p_packet, rhost_id);
- break;
- default:
- DIE;
- }
- if (need_abort) {
- break;
- }
- */
- WWASSERT(p_packet->Get_Type() >= PACKETTYPE_FIRST && p_packet->Get_Type() <= PACKETTYPE_LAST);
- if (p_packet->Get_Type() == PACKETTYPE_RELIABLE) {
- bool abort = Demultiplex_R_Or_U_Packet(p_packet, rhost_id);
- if (abort) {
- break;
- }
- }
- //
- // This may help detect if the packet got deallocated or something bad...
- //
- WWASSERT(p_packet->Get_Type() >= PACKETTYPE_FIRST && p_packet->Get_Type() <= PACKETTYPE_LAST);
- PRHost[rhost_id]->Get_Packet_List(RELIABLE_RCV_LIST).Remove_Head();
- p_packet->Flush();
- delete p_packet;
- PRHost[rhost_id]->Increment_Reliable_Packet_Rcv_Id();
- } else {
- WWASSERT(comparison > 0);
- //
- // We are done... we cannot process the next packet in the list yet.
- //
- break;
- }
- }
- }
- }
- }
- /*
- time_spent = (int) TIMEGETTIME() - start_time;
- if (time_spent > cNetUtil::Get_Max_Receive_Time_Ms()) {
- WWDEBUG_SAY(("*** WWNET: Too much time (%d ms)) spent receiving reliable queued packets.\n",
- time_spent));
- }
- */
- //
- // Process all unreliable packets.
- //
- //start_time = (int) TIMEGETTIME();
- {
- WWPROFILE("Process U Packets");
- for (rhost_id = MinRHost; rhost_id <= MaxRHost; rhost_id++) {
- if (PRHost[rhost_id] != NULL) {
- PRHost[rhost_id]->Compute_List_Max(UNRELIABLE_RCV_LIST);
- //broken PRHost[rhost_id]->Set_List_Packet_Size(UNRELIABLE_RCV_LIST, 0);
- unsigned long list_processing_start = TIMEGETTIME();
- for (SLNode<cPacket> * objnode = PRHost[rhost_id]->Get_Packet_List(UNRELIABLE_RCV_LIST).Head();
- objnode != NULL; objnode = objnode->Next()) {
- cPacket * p_packet = objnode->Data();
- WWASSERT(p_packet != NULL);
- WWASSERT(p_packet->Get_Id() >= 0);
- if (p_packet->Get_Id() < PRHost[rhost_id]->Get_Unreliable_Packet_Rcv_Id()) {
- //
- // Duplicate packet, discard
- //
- CombinedStats.StatSample[STAT_DiscardCount]++;
- /*
- WWDEBUG_SAY(("Ignoring duplicate unreliable packet (id %d)) [UnreliablePacketRcvId is %d]\n",
- p_packet->Id, PRHost[rhost_id]->UnreliablePacketRcvId));
- */
- } else {
- //WWASSERT(p_packet->Get_Type() == (BYTE) PACKETTYPE_UNRELIABLE);
- {
- //WWPROFILE("Demultiplex_R_Or_U_Packet");
- bool abort = Demultiplex_R_Or_U_Packet(p_packet, rhost_id);
- if (abort) {
- break;
- }
- }
- PRHost[rhost_id]->Set_Unreliable_Packet_Rcv_Id(p_packet->Get_Id());
- }
- }
- if (PRHost[rhost_id] != NULL) {
- PRHost[rhost_id]->Set_List_Processing_Time(UNRELIABLE_RCV_LIST, TIMEGETTIME() - list_processing_start);
- }
- if (PRHost[rhost_id] != NULL) {
- //
- // Destroy list
- //
- for (SLNode<cPacket> * objnode = PRHost[rhost_id]->Get_Packet_List(UNRELIABLE_RCV_LIST).Head();
- objnode != NULL; objnode = objnode->Next()) {
- cPacket * p_packet = objnode->Data();
- p_packet->Flush();
- WWASSERT(p_packet != NULL);
- delete p_packet;
- }
- PRHost[rhost_id]->Get_Packet_List(UNRELIABLE_RCV_LIST).Remove_All();
- }
- }
- }
- }
- /*
- time_spent = (int) TIMEGETTIME() - start_time;
- if (time_spent > cNetUtil::Get_Max_Receive_Time_Ms()) {
- WWDEBUG_SAY(("*** WWNET: Too much time (%d ms)) spent receiving unreliable queued packets.\n",
- time_spent));
- }
- */
- if (IsServer) {
- //
- // Notify Server of recommended evictions
- //
- for (rhost_id = MinRHost; rhost_id <= MaxRHost; rhost_id++) {
- if (PRHost[rhost_id] != NULL && PRHost[rhost_id]->Must_Evict()) {
- PRHost[rhost_id]->Set_Must_Evict(false);
- //Eviction_Handler(rhost_id);
- WWASSERT(EvictionHandler != NULL);
- EvictionHandler(rhost_id);
- }
- }
- }
- }
- //-----------------------------------------------------------------------------
- void cConnection::Set_Bandwidth_Budget_Out(ULONG bw_budget)
- {
- //WWASSERT(bw_budget >= 0);
- BandwidthBudgetOut = bw_budget;
- //
- // If we only have very limited bandwidth available then it's silly to have huge send buffers since that can mask
- // problems with outgoing packets until it's too late to recover. ST - 10/17/2001 12:51PM
- //
- if (!cSinglePlayerData::Is_Single_Player()) {
- if (Sock != INVALID_SOCKET) {
- // make the buffers big enough for 3 seconds of data.
- int new_buffer_size = (bw_budget / 8) * 3;
- new_buffer_size = min(new_buffer_size, 250000);
- cNetUtil::Set_Socket_Buffer_Sizes(Sock, new_buffer_size);
- }
- }
- }
- //-----------------------------------------------------------------------------
- void cConnection::Clear_Resend_Counts()
- {
- //WWDEBUG_SAY(("cConnection::Clear_Resend_Counts()\n"));
- SLNode<cPacket> * objnode;
- cPacket * p_packet;
- for (int rhost_id = MinRHost; rhost_id <= MaxRHost; rhost_id++) {
- if (PRHost[rhost_id] != NULL) {
- for (objnode = PRHost[rhost_id]->Get_Packet_List(RELIABLE_SEND_LIST).Head();
- objnode != NULL; objnode = objnode->Next()) {
- p_packet = objnode->Data();
- WWASSERT(p_packet != NULL);
- if (p_packet->Get_Resend_Count() > 0) {
- p_packet->Clear_Resend_Count();
- }
- }
- }
- }
- }
- //-----------------------------------------------------------------------------
- cRemoteHost * cConnection::Get_Remote_Host(int rhost)
- {
- WWASSERT(rhost >= MinRHost && rhost <= MaxRHost);
- /*
- if (rhost < MinRHost || rhost > MaxRHost) {
- WWDEBUG_SAY((">>> %d: %d,%d IS:%d\n", rhost, MinRHost, MaxRHost,
- IsServer));
- DIE;
- }
- */
- return PRHost[rhost];
- }
- //-----------------------------------------------------------------------------
- //
- // Service_Send() should be called once per frame on both C & S
- //
- void cConnection::Service_Send(bool is_urgent)
- {
- WWASSERT(InitDone);
- ServiceCount++;
- //
- // Set TargetBps for all rhosts
- //
- int num_real_remote_hosts = NumRHosts;
- if (IsServer && !IsDedicatedServer) {
- num_real_remote_hosts--;
- if (PRHost[1] != NULL) {
- PRHost[1]->Set_Target_Bps(10000000);//TSS - won't this just be overwritten below???
- }
- }
- if (num_real_remote_hosts > 0) { // necessary?
- if (IsServer && BandwidthBalancer.IsEnabled) {
- BandwidthBalancer.Adjust(this, IsDedicatedServer);
- } else {
- ULONG bps_per_rhost = (ULONG) (BandwidthBudgetOut / (float) num_real_remote_hosts);
- for (int rhost_id = MinRHost; rhost_id <= MaxRHost; rhost_id++) {
- if (PRHost[rhost_id] != NULL) {
- //
- // Do not exceed the max bps set by the client.
- //
- int bps = bps_per_rhost;
- int max_bps = PRHost[rhost_id]->Get_Maximum_Bps();
- if (max_bps != 0 && max_bps < bps) {
- bps = max_bps;
- }
- PRHost[rhost_id]->Set_Target_Bps(bps);
- //WWDEBUG_SAY(("Compressed bandwidth out to client = %d bps\n", PacketManager.Get_Compressed_Bandwidth_Out(&(PRHost[rhost_id]->Get_Address()))));
- }
- }
- }
- }
- int rhost_id;
- //
- // Reliable sends and resends
- //
- bool any_bad = false;
- for (rhost_id = MinRHost; rhost_id <= MaxRHost; rhost_id++) {
- cRemoteHost * p_rhost = PRHost[rhost_id];
- if (p_rhost != NULL) {
- p_rhost->Compute_List_Max(RELIABLE_SEND_LIST);
- /*
- //
- // Send any reliable combined-packet
- //
- cPacket * & p_packet_rs = p_rhost->Get_P_Comb_Rel_Packet();
- if (p_packet_rs != NULL) {
- Internal_Send_Packet_To_Individual(*p_packet_rs, rhost_id, PACKETTYPE_RELIABLE);
- p_packet_rs->Flush();
- delete p_packet_rs;
- p_packet_rs = NULL;
- }
- */
- int resent_packets = 0;
- //
- // Send any appropriate reliable queued packets
- //
- for (SLNode<cPacket> * objnode = p_rhost->Get_Packet_List(RELIABLE_SEND_LIST).Head();
- objnode != NULL;) {
- cPacket * p_packet = objnode->Data();
- objnode = objnode->Next();
- WWASSERT(p_packet != NULL);
- if (p_packet->Get_Resend_Count() > 1) {
- resent_packets++;
- if (ThisFrameTimeMs - p_packet->Get_First_Send_Time() > 5000) {
- any_bad = true;
- }
- }
- if (Is_Time_To_Resend_Packet_To_Remote_Host(p_packet, p_rhost)) {
- //
- // This will hold true for new packets because Sendtime is set high negative
- //
- //
- // Resends are reliable
- //
- p_rhost->Get_Stats().StatSample[STAT_RPktSent]++;
- p_rhost->Get_Stats().StatSample[STAT_RByteSent] += p_packet->Get_Compressed_Size_Bytes();
- //
- // Send!
- //
- //if (p_packet->Get_Resend_Count() > 0) {
- //if (p_packet->Get_Resend_Count() > 0 && p_packet->Get_Resend_Count() % 10 == 0) {
- //WWDEBUG_SAY(("Resending packet %d to %s after %dms. Resent %d times\n", p_packet->Get_Id(), Addr_As_String(&(p_rhost->Get_Address())), ThisFrameTimeMs - p_packet->Get_First_Send_Time(), p_packet->Get_Resend_Count()));
- //}
- Send_Packet_To_Address(*p_packet, &(p_rhost->Get_Address()));
- p_packet->Set_Send_Time();
- /*
- if (p_rhost->Is_Ready_For_All_Data()) {
- p_packet->Increment_Resend_Count();
- }
- */
- p_packet->Increment_Resend_Count();
- if (p_packet->Get_Resend_Count() > 0) {
- p_rhost->Get_Stats().StatSample[STAT_ResendCount]++;
- p_rhost->Increment_Resends();
- }
- // In a LAN game, if resend time is low. Say 4 ms, and we only resend 50 times, thats 200ms total before the game
- // craps out. Any kind of network or machine hiccup could cause the game to quit. This is an experimant to see if that's
- // what is causing our disconnect at game start.
- //
- // As it happens, the main thread can get lost loading textures for several seconds at the end of a game load
- // so some sort of overall timeout is neccessary.
- //
- // TSS 09/24/01 - new loading lags worse than 10 seconds... bumping it up
- // to 20s.
- //
- // ST 1/24/2002 2:16PM. Can't time out players when we are loading or we get DataSafe access from the wrong
- // thread.
- //
- if (Is_Packet_Too_Old(p_packet, p_rhost) && CanProcess) {
- WWDEBUG_SAY(("*** WWNET: Connection timed out - assuming connection to rhost %d is broken.\n", rhost_id));
- WWDEBUG_SAY(("*** WWNET: ThisFrameTimeMs - p_packet->Get_First_Send_Time() == %d\n", ThisFrameTimeMs - p_packet->Get_First_Send_Time()));
- //
- // Define the connection as broken
- //
- WWDEBUG_SAY(("*** Breaking connection on packet %d ... internal ping = %d/%d/%d ms, ResendTimeoutMs = %d ms\n",
- p_packet->Get_Id(),
- p_rhost->Get_Min_Internal_Pingtime_Ms(),
- p_rhost->Get_Average_Internal_Pingtime_Ms(),
- p_rhost->Get_Max_Internal_Pingtime_Ms(),
- p_rhost->Get_Resend_Timeout_Ms()));
- Destroy_Connection(rhost_id);
- //WWDEBUG_SAY(("*** WWNET: Exceeded maximum resends (%d)) - assuming connection to rhost %d is broken.\n",
- // cNetUtil::MAX_RESENDS, rhost_id));
- if (IsServer) {
- //Server_Broken_Connection_Handler(rhost_id); // Inform app level of this disaster
- WWASSERT(ServerBrokenConnectionHandler != NULL);
- ServerBrokenConnectionHandler(rhost_id);
- } else {
- //Client_Broken_Connection_Handler(); // Inform app level of this disaster
- WWASSERT(ClientBrokenConnectionHandler != NULL);
- ClientBrokenConnectionHandler();
- }
- break;
- }
- }
- }
- // Keep track of how many packets in the queue are waiting on late acks.
- p_rhost->Set_Total_Resent_Packets_In_Queue(resent_packets);
- }
- }
- IsBadConnection = any_bad;
- //
- // Unreliable sends and resends
- //
- for (rhost_id = MinRHost; rhost_id <= MaxRHost; rhost_id++) {
- cRemoteHost * p_rhost = PRHost[rhost_id];
- if (p_rhost != NULL) {
- p_rhost->Compute_List_Max(UNRELIABLE_SEND_LIST);
- /*
- //
- // Send any unreliable combined-packet
- //
- cPacket * & p_packet_u = p_rhost->Get_P_Comb_Unrel_Packet();
- if (p_packet_u != NULL) {
- Internal_Send_Packet_To_Individual(*p_packet_u, rhost_id, PACKETTYPE_UNRELIABLE);
- p_packet_u->Flush();
- delete p_packet_u;
- p_packet_u = NULL;
- }
- */
- //
- // Send any appropriate queued packets
- //
- for (SLNode<cPacket> * objnode = p_rhost->Get_Packet_List(UNRELIABLE_SEND_LIST).Head();
- objnode != NULL; objnode = objnode->Next()) {
- cPacket * p_packet = objnode->Data();
- WWASSERT(p_packet != NULL);
- p_rhost->Get_Stats().StatSample[STAT_UPktSent]++;
- p_rhost->Get_Stats().StatSample[STAT_UByteSent] += p_packet->Get_Compressed_Size_Bytes();
- //
- // Send!
- //
- Send_Packet_To_Address(*p_packet, &(p_rhost->Get_Address()));
- }
- // destroy all
- for (objnode = p_rhost->Get_Packet_List(UNRELIABLE_SEND_LIST).Head();
- objnode != NULL; objnode = objnode->Next()) {
- cPacket * p_packet = objnode->Data();
- WWASSERT(p_packet != NULL);
- p_packet->Flush();
- delete p_packet;
- }
- p_rhost->Get_Packet_List(UNRELIABLE_SEND_LIST).Remove_All();
- }
- }
- //
- // Send keepalives if necessary
- //
- Send_Keepalives();
- //
- // Monkey with the stats for a while
- //
- float sample_time_ms = ThisFrameTimeMs - CombinedStats.Get_Sample_Start_Time();
- if (IsServer && NumRHosts > 0 &&
- sample_time_ms > cNetUtil::NETSTATS_SAMPLE_TIME_MS) {
- for (int statistic = 0; statistic < STAT_COUNT; statistic++) {
- for (rhost_id = MinRHost; rhost_id <= MaxRHost; rhost_id++) {
- if (PRHost[rhost_id] != NULL) {
- CombinedStats.StatSample[statistic] += PRHost[rhost_id]->Get_Stats().StatSnapshot[statistic];
- }
- }
- AveragedStats.StatSample[statistic] = cMathUtil::Round(
- CombinedStats.StatSample[statistic] / (double) NumRHosts);
- }
- AveragedStats.Update_If_Sample_Done(ThisFrameTimeMs);
- }
- CombinedStats.Update_If_Sample_Done(ThisFrameTimeMs);
- for (rhost_id = MinRHost; rhost_id <= MaxRHost; rhost_id++) {
- if (PRHost[rhost_id] != NULL) {
- bool is_updated = PRHost[rhost_id]->Get_Stats().Update_If_Sample_Done(
- ThisFrameTimeMs, false);
- if (is_updated) {
- PRHost[rhost_id]->Adjust_Resend_Timeout();
- PRHost[rhost_id]->Adjust_Flow_If_Necessary(sample_time_ms);
- }
- }
- }
- //
- // Service the packet manager
- //
- PacketManager.Flush(is_urgent);
- }
- //-----------------------------------------------------------------------------
- void cConnection::Install_Accept_Handler(Accept_Handler handler)
- {
- WWASSERT(handler != NULL);
- AcceptHandler = handler;
- }
- //-----------------------------------------------------------------------------
- void cConnection::Install_Refusal_Handler(Refusal_Handler handler)
- {
- WWASSERT(handler != NULL);
- RefusalHandler = handler;
- }
- //-----------------------------------------------------------------------------
- void cConnection::Install_Server_Broken_Connection_Handler(Server_Broken_Connection_Handler handler)
- {
- WWASSERT(handler != NULL);
- ServerBrokenConnectionHandler = handler;
- }
- //-----------------------------------------------------------------------------
- void cConnection::Install_Client_Broken_Connection_Handler(Client_Broken_Connection_Handler handler)
- {
- WWASSERT(handler != NULL);
- ClientBrokenConnectionHandler = handler;
- }
- //-----------------------------------------------------------------------------
- void cConnection::Install_Eviction_Handler(Eviction_Handler handler)
- {
- WWASSERT(handler != NULL);
- EvictionHandler = handler;
- }
- //-----------------------------------------------------------------------------
- void cConnection::Install_Conn_Handler(Conn_Handler handler)
- {
- WWASSERT(handler != NULL);
- ConnHandler = handler;
- }
- //-----------------------------------------------------------------------------
- void cConnection::Install_Application_Acceptance_Handler(Application_Acceptance_Handler handler)
- {
- WWASSERT(handler != NULL);
- ApplicationAcceptanceHandler = handler;
- }
- //-----------------------------------------------------------------------------
- void cConnection::Install_Server_Packet_Handler(Server_Packet_Handler handler)
- {
- WWASSERT(handler != NULL);
- ServerPacketHandler = handler;
- }
- //-----------------------------------------------------------------------------
- void cConnection::Install_Client_Packet_Handler(Client_Packet_Handler handler)
- {
- WWASSERT(handler != NULL);
- ClientPacketHandler = handler;
- }
- //-----------------------------------------------------------------------------
- void cConnection::Set_Rhost_Is_In_Game(int id, bool state)
- {
- if (IsServer) {
- for (int i = MinRHost; i <= MaxRHost; i++) {
- if (PRHost[i] && PRHost[i]->Get_Id() == id) {
- PRHost[i]->Set_Is_Loading(!state);
- break;
- }
- }
- }
- }
- void cConnection::Set_Rhost_Expect_Packet_Flood(int id, bool state)
- {
- if (IsServer) {
- for (int i = MinRHost; i <= MaxRHost; i++) {
- if (PRHost[i] && PRHost[i]->Get_Id() == id) {
- PRHost[i]->Set_Flood(state);
- break;
- }
- }
- }
- }
- //-----------------------------------------------------------------------------
- bool cConnection::Is_Time_To_Resend_Packet_To_Remote_Host(const cPacket *packet, cRemoteHost *rhost)
- {
- WWASSERT(ThisFrameTimeMs >= 0);
- WWASSERT(packet);
- WWASSERT(rhost);
- if (!packet || !rhost) {
- return(false);
- }
- unsigned long last_send_time = packet->Get_Send_Time();
- if (last_send_time == cPacket::Get_Default_Send_Time()) {
- return(true);
- }
- //
- // Basically this slows down the resend rate each time we resend
- //
- float resend_timeout = (float) rhost->Get_Resend_Timeout_Ms();
- WWASSERT(resend_timeout != 0);
- float resend_count = (float) packet->Get_Resend_Count();
- float timeout_multiplier = 0.5f;
- float total_timeout = resend_timeout;
- if (IsServer) {
- bool loading = rhost->Get_Is_Loading();
- //
- // Slow down resend rate if remote host is loading. He might not be able to respond anyway.
- //
- if (loading) {
- timeout_multiplier = timeout_multiplier * 2.0f;
- }
- }
- total_timeout = resend_timeout + (resend_timeout * resend_count * timeout_multiplier);
- //
- // Max resend timeout of 3 secs.
- //
- total_timeout = min(total_timeout, 3000.0f);
- if (ThisFrameTimeMs - packet->Get_Send_Time() >= (unsigned long)total_timeout) {
- //WWDEBUG_SAY(("Time to resend packet %d, age = %d, timeout = %d, resend count = %d\n", packet->Get_Id(), (int)(ThisFrameTimeMs - packet->Get_Send_Time()), (int)total_timeout, packet->Get_Resend_Count()));
- return(true);
- }
- return(false);
- }
- //-----------------------------------------------------------------------------
- bool cConnection::Is_Packet_Too_Old(const cPacket *packet, cRemoteHost *rhost)
- {
- WWASSERT(ThisFrameTimeMs >= 0);
- WWASSERT(packet);
- WWASSERT(rhost);
- if (!packet || !rhost) {
- return(false);
- }
- if (packet->Get_Send_Time() == cPacket::Get_Default_Send_Time()) {
- return(false);
- }
- unsigned long timeout = 0;
- if (IsServer) {
- timeout = cNetUtil::SERVER_CONNECTION_LOSS_TIMEOUT;
- //
- // Server needs to allow more time for players entering the game.
- //
- if (rhost->Get_Is_Loading() || rhost->Was_Recently_Loading(ThisFrameTimeMs)) {
- timeout += cNetUtil::SERVER_CONNECTION_LOSS_TIMEOUT_LOADING_ALLOWANCE;
- } else {
- int num_remote_hosts = Get_Num_RHosts();
- if (!IsDedicatedServer) {
- num_remote_hosts--;
- }
- if (num_remote_hosts < 1) {
- timeout += cNetUtil::SERVER_CONNECTION_LOSS_TIMEOUT_LOADING_ALLOWANCE;
- }
- }
- } else {
- //
- // Client just uses a constant value.
- //
- timeout = cNetUtil::CLIENT_CONNECTION_LOSS_TIMEOUT;
- //
- // Modified when server is potentially loading.
- //
- timeout += ExtraTimeoutTime;
- }
- if (ThisFrameTimeMs > packet->Get_First_Send_Time()) {
- if (ThisFrameTimeMs - packet->Get_First_Send_Time() > timeout) {
- return(true);
- }
- }
- return(false);
- }
- //-----------------------------------------------------------------------------
- void cConnection::Allow_Extra_Timeout_For_Loading(void)
- {
- ExtraTimeoutTime = cNetUtil::SERVER_CONNECTION_LOSS_TIMEOUT_LOADING_ALLOWANCE;
- ExtraTimeoutTimeStarted = TIMEGETTIME();
- }
- #ifdef WWDEBUG
- void cConnection::Set_Latency(int low, int high)
- {
- LatencyAddLow = low;
- LatencyAddHigh = high;
- CurrentLatencyAdd = LatencyAddLow + ((LatencyAddHigh - LatencyAddLow) / 2);
- }
- void cConnection::Get_Latency(int &low, int &high, int ¤t)
- {
- low = LatencyAddLow;
- high = LatencyAddHigh;
- current = CurrentLatencyAdd;
- }
- #endif //WWDEBUG
- //KEEPALIVE_TIMEOUT_MS(cNetUtil::Get_Default_Keepalive_Timeout_Ms()),
- //MAX_RESENDS(cNetUtil::Get_Default_Max_Resends()),
- //MULTI_SENDS(cNetUtil::Get_Default_Multi_Sends()), //if (!Application_Acceptance_Handler(packet)) {
|