354 lines
11 KiB
C++
354 lines
11 KiB
C++
/**
|
|
* @file llcircuit.h
|
|
* @brief Provides a method for tracking network circuit information
|
|
* for the UDP message system
|
|
*
|
|
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
|
* Second Life Viewer Source Code
|
|
* Copyright (C) 2010, Linden Research, Inc.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation;
|
|
* version 2.1 of the License only.
|
|
*
|
|
* This library 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
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*
|
|
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
|
* $/LicenseInfo$
|
|
*/
|
|
|
|
#ifndef LL_LLCIRCUIT_H
|
|
#define LL_LLCIRCUIT_H
|
|
|
|
#include <map>
|
|
#include <vector>
|
|
|
|
#include "llerror.h"
|
|
|
|
#include "lltimer.h"
|
|
#include "net.h"
|
|
#include "llhost.h"
|
|
#include "llpacketack.h"
|
|
#include "lluuid.h"
|
|
#include "llthrottle.h"
|
|
|
|
//
|
|
// Constants
|
|
//
|
|
const F32 LL_AVERAGED_PING_ALPHA = 0.2f; // relaxation constant on ping running average
|
|
const F32Milliseconds LL_AVERAGED_PING_MAX(2000);
|
|
const F32Milliseconds LL_AVERAGED_PING_MIN(100); // increased to avoid retransmits when a process is slow
|
|
|
|
const U32Milliseconds INITIAL_PING_VALUE_MSEC(1000); // initial value for the ping delay, or for ping delay for an unknown circuit
|
|
|
|
const TPACKETID LL_MAX_OUT_PACKET_ID = 0x01000000;
|
|
const int LL_ERR_CIRCUIT_GONE = -23017;
|
|
const int LL_ERR_TCP_TIMEOUT = -23016;
|
|
|
|
// 0 - flags
|
|
// [1,4] - packetid
|
|
// 5 - data offset (after message name)
|
|
const U8 LL_PACKET_ID_SIZE = 6;
|
|
|
|
const S32 LL_MAX_RESENT_PACKETS_PER_FRAME = 100;
|
|
const S32 LL_MAX_ACKED_PACKETS_PER_FRAME = 200;
|
|
const F32 LL_COLLECT_ACK_TIME_MAX = 2.f;
|
|
|
|
//
|
|
// Prototypes and Predefines
|
|
//
|
|
class LLMessageSystem;
|
|
class LLEncodedDatagramService;
|
|
class LLSD;
|
|
|
|
//
|
|
// Classes
|
|
//
|
|
|
|
|
|
class LLCircuitData
|
|
{
|
|
public:
|
|
LLCircuitData(const LLHost &host, TPACKETID in_id,
|
|
const F32Seconds circuit_heartbeat_interval, const F32Seconds circuit_timeout);
|
|
~LLCircuitData();
|
|
|
|
S32 resendUnackedPackets(const F64Seconds now);
|
|
void clearDuplicateList(TPACKETID oldest_id);
|
|
|
|
|
|
void dumpResendCountAndReset(); // Used for tracking how many resends are being done on a circuit.
|
|
|
|
|
|
|
|
// Public because stupid message system callbacks uses it.
|
|
void pingTimerStart();
|
|
void pingTimerStop(const U8 ping_id);
|
|
void ackReliablePacket(TPACKETID packet_num);
|
|
|
|
// remote computer information
|
|
const LLUUID& getRemoteID() const { return mRemoteID; }
|
|
const LLUUID& getRemoteSessionID() const { return mRemoteSessionID; }
|
|
void setRemoteID(const LLUUID& id) { mRemoteID = id; }
|
|
void setRemoteSessionID(const LLUUID& id) { mRemoteSessionID = id; }
|
|
|
|
void setTrusted(BOOL t);
|
|
|
|
// The local end point ID is used when establishing a trusted circuit.
|
|
// no matching set function for getLocalEndPointID()
|
|
// mLocalEndPointID should only ever be setup in the LLCircuitData constructor
|
|
const LLUUID& getLocalEndPointID() const { return mLocalEndPointID; }
|
|
|
|
U32Milliseconds getPingDelay() const;
|
|
S32 getPingsInTransit() const { return mPingsInTransit; }
|
|
|
|
// ACCESSORS
|
|
BOOL isAlive() const;
|
|
BOOL isBlocked() const;
|
|
BOOL getAllowTimeout() const;
|
|
F32Milliseconds getPingDelayAveraged();
|
|
F32Milliseconds getPingInTransitTime();
|
|
U32 getPacketsIn() const;
|
|
S32Bytes getBytesIn() const;
|
|
S32Bytes getBytesOut() const;
|
|
U32 getPacketsOut() const;
|
|
U32 getPacketsLost() const;
|
|
TPACKETID getPacketOutID() const;
|
|
BOOL getTrusted() const;
|
|
F32 getAgeInSeconds() const;
|
|
S32 getUnackedPacketCount() const { return mUnackedPacketCount; }
|
|
S32 getUnackedPacketBytes() const { return mUnackedPacketBytes; }
|
|
F64Seconds getNextPingSendTime() const { return mNextPingSendTime; }
|
|
U32 getLastPacketGap() const { return mLastPacketGap; }
|
|
LLHost getHost() const { return mHost; }
|
|
F64Seconds getLastPacketInTime() const { return mLastPacketInTime; }
|
|
|
|
LLThrottleGroup &getThrottleGroup() { return mThrottles; }
|
|
|
|
class less
|
|
{
|
|
public:
|
|
bool operator()(const LLCircuitData* lhs, const LLCircuitData* rhs) const
|
|
{
|
|
if (lhs->getNextPingSendTime() < rhs->getNextPingSendTime())
|
|
{
|
|
return true;
|
|
}
|
|
else if (lhs->getNextPingSendTime() > rhs->getNextPingSendTime())
|
|
{
|
|
return false;
|
|
}
|
|
else return lhs > rhs;
|
|
}
|
|
};
|
|
|
|
//
|
|
// Debugging stuff (not necessary for operation)
|
|
//
|
|
void checkPeriodTime(); // Reset per-period counters if necessary.
|
|
friend std::ostream& operator<<(std::ostream& s, LLCircuitData &circuit);
|
|
void getInfo(LLSD& info) const;
|
|
|
|
friend class LLCircuit;
|
|
friend class LLMessageSystem;
|
|
friend class LLEncodedDatagramService;
|
|
friend void crash_on_spaceserver_timeout (const LLHost &host, void *); // HACK, so it has access to setAlive() so it can send a final shutdown message.
|
|
protected:
|
|
TPACKETID nextPacketOutID();
|
|
void setPacketInID(TPACKETID id);
|
|
void checkPacketInID(TPACKETID id, BOOL receive_resent);
|
|
void setPingDelay(U32Milliseconds ping);
|
|
BOOL checkCircuitTimeout(); // Return FALSE if the circuit is dead and should be cleaned up
|
|
|
|
void addBytesIn(S32Bytes bytes);
|
|
void addBytesOut(S32Bytes bytes);
|
|
|
|
U8 nextPingID() { mLastPingID++; return mLastPingID; }
|
|
|
|
BOOL updateWatchDogTimers(LLMessageSystem *msgsys); // Return FALSE if the circuit is dead and should be cleaned up
|
|
|
|
void addReliablePacket(S32 mSocket, U8 *buf_ptr, S32 buf_len, LLReliablePacketParams *params);
|
|
BOOL isDuplicateResend(TPACKETID packetnum);
|
|
// Call this method when a reliable message comes in - this will
|
|
// correctly place the packet in the correct list to be acked
|
|
// later. RAack = requested ack
|
|
BOOL collectRAck(TPACKETID packet_num);
|
|
|
|
|
|
void setTimeoutCallback(void (*callback_func)(const LLHost &host, void *user_data), void *user_data);
|
|
|
|
|
|
|
|
void setAlive(BOOL b_alive);
|
|
void setAllowTimeout(BOOL allow);
|
|
|
|
protected:
|
|
// Identification for this circuit.
|
|
LLHost mHost;
|
|
LLUUID mRemoteID;
|
|
LLUUID mRemoteSessionID;
|
|
|
|
LLThrottleGroup mThrottles;
|
|
|
|
TPACKETID mWrapID;
|
|
|
|
// Current packet IDs of incoming/outgoing packets
|
|
// Used for packet sequencing/packet loss detection.
|
|
TPACKETID mPacketsOutID;
|
|
TPACKETID mPacketsInID;
|
|
TPACKETID mHighestPacketID;
|
|
|
|
|
|
// Callback and data to run in the case of a circuit timeout.
|
|
// Used primarily to try and reconnect to servers if they crash/die.
|
|
void (*mTimeoutCallback)(const LLHost &host, void *user_data);
|
|
void *mTimeoutUserData;
|
|
|
|
BOOL mTrusted; // Is this circuit trusted?
|
|
BOOL mbAllowTimeout; // Machines can "pause" circuits, forcing them not to be dropped
|
|
|
|
BOOL mbAlive; // Indicates whether a circuit is "alive", i.e. responded to pings
|
|
|
|
BOOL mBlocked; // Blocked is true if the circuit is hosed, i.e. far behind on pings
|
|
|
|
// Not sure what the difference between this and mLastPingSendTime is
|
|
F64Seconds mPingTime; // Time at which a ping was sent.
|
|
|
|
F64Seconds mLastPingSendTime; // Time we last sent a ping
|
|
F64Seconds mLastPingReceivedTime; // Time we last received a ping
|
|
F64Seconds mNextPingSendTime; // Time to try and send the next ping
|
|
S32 mPingsInTransit; // Number of pings in transit
|
|
U8 mLastPingID; // ID of the last ping that we sent out
|
|
|
|
|
|
// Used for determining the resend time for reliable resends.
|
|
U32Milliseconds mPingDelay; // raw ping delay
|
|
F32Milliseconds mPingDelayAveraged; // averaged ping delay (fast attack/slow decay)
|
|
|
|
typedef std::map<TPACKETID, U64Microseconds> packet_time_map;
|
|
|
|
packet_time_map mPotentialLostPackets;
|
|
packet_time_map mRecentlyReceivedReliablePackets;
|
|
std::vector<TPACKETID> mAcks;
|
|
F32 mAckCreationTime; // first ack creation time
|
|
|
|
typedef std::map<TPACKETID, LLReliablePacket *> reliable_map;
|
|
typedef reliable_map::iterator reliable_iter;
|
|
|
|
reliable_map mUnackedPackets;
|
|
reliable_map mFinalRetryPackets;
|
|
|
|
S32 mUnackedPacketCount;
|
|
S32 mUnackedPacketBytes;
|
|
|
|
F64Seconds mLastPacketInTime; // Time of last packet arrival
|
|
|
|
LLUUID mLocalEndPointID;
|
|
|
|
//
|
|
// These variables are being used for statistical and debugging purpose ONLY,
|
|
// as far as I can tell.
|
|
//
|
|
|
|
U32 mPacketsOut;
|
|
U32 mPacketsIn;
|
|
S32 mPacketsLost;
|
|
S32Bytes mBytesIn,
|
|
mBytesOut;
|
|
|
|
F32Seconds mLastPeriodLength;
|
|
S32Bytes mBytesInLastPeriod;
|
|
S32Bytes mBytesOutLastPeriod;
|
|
S32Bytes mBytesInThisPeriod;
|
|
S32Bytes mBytesOutThisPeriod;
|
|
F32 mPeakBPSIn; // bits per second, max of all period bps
|
|
F32 mPeakBPSOut; // bits per second, max of all period bps
|
|
F64Seconds mPeriodTime;
|
|
LLTimer mExistenceTimer; // initialized when circuit created, used to track bandwidth numbers
|
|
|
|
S32 mCurrentResendCount; // Number of resent packets since last spam
|
|
U32 mLastPacketGap; // Gap in sequence number of last packet.
|
|
|
|
const F32Seconds mHeartbeatInterval;
|
|
const F32Seconds mHeartbeatTimeout;
|
|
};
|
|
|
|
|
|
// Actually a singleton class -- the global messagesystem
|
|
// has a single LLCircuit member.
|
|
class LLCircuit
|
|
{
|
|
public:
|
|
// CREATORS
|
|
LLCircuit(const F32Seconds circuit_heartbeat_interval, const F32Seconds circuit_timeout);
|
|
~LLCircuit();
|
|
|
|
// ACCESSORS
|
|
LLCircuitData* findCircuit(const LLHost& host) const;
|
|
BOOL isCircuitAlive(const LLHost& host) const;
|
|
|
|
// MANIPULATORS
|
|
LLCircuitData *addCircuitData(const LLHost &host, TPACKETID in_id);
|
|
void removeCircuitData(const LLHost &host);
|
|
|
|
void updateWatchDogTimers(LLMessageSystem *msgsys);
|
|
void resendUnackedPackets(S32& unacked_list_length, S32& unacked_list_size);
|
|
|
|
// this method is called during the message system processAcks()
|
|
// to send out any acks that did not get sent already.
|
|
void sendAcks(F32 collect_time);
|
|
|
|
friend std::ostream& operator<<(std::ostream& s, LLCircuit &circuit);
|
|
void getInfo(LLSD& info) const;
|
|
|
|
void dumpResends();
|
|
|
|
typedef std::map<LLHost, LLCircuitData*> circuit_data_map;
|
|
|
|
/**
|
|
* @brief This method gets an iterator range starting after key in
|
|
* the circuit data map.
|
|
*
|
|
* @param key The the host before first.
|
|
* @param first[out] The first matching value after key. This
|
|
* value will equal end if there are no entries.
|
|
* @param end[out] The end of the iteration sequence.
|
|
*/
|
|
void getCircuitRange(
|
|
const LLHost& key,
|
|
circuit_data_map::iterator& first,
|
|
circuit_data_map::iterator& end);
|
|
|
|
// <edit>
|
|
std::vector<LLCircuitData*> getCircuitDataList();
|
|
// </edit>
|
|
|
|
// Lists that optimize how many circuits we need to traverse a frame
|
|
// HACK - this should become protected eventually, but stupid !@$@# message system/circuit classes are jumbling things up.
|
|
circuit_data_map mUnackedCircuitMap; // Map of circuits with unacked data
|
|
circuit_data_map mSendAckMap; // Map of circuits which need to send acks
|
|
protected:
|
|
circuit_data_map mCircuitData;
|
|
|
|
typedef std::set<LLCircuitData *, LLCircuitData::less> ping_set_t; // Circuits sorted by next ping time
|
|
ping_set_t mPingSet;
|
|
|
|
// This variable points to the last circuit data we found to
|
|
// optimize the many, many times we call findCircuit. This may be
|
|
// set in otherwise const methods, so it is declared mutable.
|
|
mutable LLCircuitData* mLastCircuit;
|
|
|
|
private:
|
|
const F32Seconds mHeartbeatInterval;
|
|
const F32Seconds mHeartbeatTimeout;
|
|
};
|
|
#endif
|