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
|
/**
* @file llcircuit.h
* @brief Provides a method for tracking network circuit information
* for the UDP message system
*
* $LicenseInfo:firstyear=2001&license=viewergpl$
*
* Copyright (c) 2001-2007, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlife.com/developers/opensource/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at http://secondlife.com/developers/opensource/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
#ifndef LL_LLCIRCUIT_H
#define LL_LLCIRCUIT_H
#include <map>
#include <vector>
#include "llerror.h"
#include "lltimer.h"
#include "timing.h"
#include "net.h"
#include "llhost.h"
#include "llpacketack.h"
#include "lluuid.h"
#include "llthrottle.h"
//
// Constants
//
const F32 PING_INTERVAL_MAX = 100.f;
const F32 PING_INTERVAL_ALARM = 50.f;
const F32 LL_AVERAGED_PING_ALPHA = 0.2f; // relaxation constant on ping running average
const F32 LL_AVERAGED_PING_MAX = 2000; // msec
const F32 LL_AVERAGED_PING_MIN = 100; // msec // IW: increased to avoid retransmits when a process is slow
const U32 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;
// 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);
~LLCircuitData();
S32 resendUnackedPackets(const F64 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; }
U32 getPingDelay() const;
S32 getPingsInTransit() const { return mPingsInTransit; }
// ACCESSORS
BOOL isAlive() const;
BOOL isBlocked() const;
BOOL getAllowTimeout() const;
F32 getPingDelayAveraged();
F32 getPingInTransitTime();
U32 getPacketsIn() const;
S32 getBytesIn() const;
S32 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; }
F64 getNextPingSendTime() const { return mNextPingSendTime; }
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(U32 ping);
BOOL checkCircuitTimeout(); // Return FALSE if the circuit is dead and should be cleaned up
void addBytesIn(S32 bytes);
void addBytesOut(S32 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
F64 mPingTime; // Time at which a ping was sent.
F64 mLastPingSendTime; // Time we last sent a ping
F64 mLastPingReceivedTime; // Time we last received a ping
F64 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.
U32 mPingDelay; // raw ping delay
F32 mPingDelayAveraged; // averaged ping delay (fast attack/slow decay)
typedef std::map<TPACKETID, U64> 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;
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;
S32 mBytesIn;
S32 mBytesOut;
F32 mLastPeriodLength; // seconds
S32 mBytesInLastPeriod;
S32 mBytesOutLastPeriod;
S32 mBytesInThisPeriod;
S32 mBytesOutThisPeriod;
F32 mPeakBPSIn; // bits per second, max of all period bps
F32 mPeakBPSOut; // bits per second, max of all period bps
F64 mPeriodTime;
LLTimer mExistenceTimer; // initialized when circuit created, used to track bandwidth numbers
S32 mCurrentResendCount; // Number of resent packets since last spam
};
// Actually a singleton class -- the global messagesystem
// has a single LLCircuit member.
class LLCircuit
{
public:
// CREATORS
LLCircuit();
~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;
};
#endif
|