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