summaryrefslogtreecommitdiff
path: root/indra/llmessage/llcircuit.h
blob: 5b109fc2182bb9f897fa2fb1b88c9773af410ec2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
/** 
 * @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;

//
// 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;

	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();

	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);

	// 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