summaryrefslogtreecommitdiff
path: root/indra/llmessage/llcircuit.h
blob: ba38849f70d8f4091d4a5f72c467dd2d672abb21 (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
348
349
350
/**
 * @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);

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