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
/*
* SRT - Secure, Reliable, Transport
* Copyright (c) 2018 Haivision Systems Inc.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
*/
#ifndef INC_SRT_CONGCTL_H
#define INC_SRT_CONGCTL_H
#include <map>
#include <string>
#include <utility>
class CUDT;
class SrtCongestionControlBase;
typedef SrtCongestionControlBase* srtcc_create_t(CUDT* parent);
class SrtCongestion
{
// Temporarily changed to linear searching, until this is exposed
// for a user-defined controller.
// Note that this is a pointer to function :)
static const size_t N_CONTROLLERS = 2;
// The first/second is to mimic the map.
typedef struct { const char* first; srtcc_create_t* second; } NamePtr;
static NamePtr congctls[N_CONTROLLERS];
// This is a congctl container.
SrtCongestionControlBase* congctl;
size_t selector;
void Check();
public:
// If you predict to allow something to be done on controller also
// before it is configured, call this first. If you need it configured,
// you can rely on Check().
bool ready() { return congctl; }
SrtCongestionControlBase* operator->() { Check(); return congctl; }
// In the beginning it's uninitialized
SrtCongestion(): congctl(), selector(N_CONTROLLERS) {}
struct IsName
{
std::string n;
IsName(std::string nn): n(nn) {}
bool operator()(NamePtr np) { return n == np.first; }
};
// You can call select() multiple times, until finally
// the 'configure' method is called.
bool select(const std::string& name)
{
NamePtr* end = congctls+N_CONTROLLERS;
NamePtr* try_selector = std::find_if(congctls, end, IsName(name));
if (try_selector == end)
return false;
selector = try_selector - congctls;
return true;
}
std::string selected_name()
{
if (selector == N_CONTROLLERS)
return "";
return congctls[selector].first;
}
// Copy constructor - important when listener-spawning
// Things being done:
// 1. The congctl is individual, so don't copy it. Set NULL.
// 2. The selected name is copied so that it's configured correctly.
SrtCongestion(const SrtCongestion& source): congctl(), selector(source.selector) {}
void operator=(const SrtCongestion& source) { congctl = 0; selector = source.selector; }
// This function will be called by the parent CUDT
// in appropriate time. It should select appropriate
// congctl basing on the value in selector, then
// pin oneself in into CUDT for receiving event signals.
bool configure(CUDT* parent);
// This function will intentionally delete the contained object.
// This makes future calls to ready() return false. Calling
// configure on it again will create it again.
void dispose();
// Will delete the pinned in congctl object.
// This must be defined in *.cpp file due to virtual
// destruction.
~SrtCongestion();
enum RexmitMethod
{
SRM_LATEREXMIT,
SRM_FASTREXMIT
};
enum TransAPI
{
STA_MESSAGE = 0x1, // sendmsg/recvmsg functions
STA_BUFFER = 0x2, // send/recv functions
STA_FILE = 0x3, // sendfile/recvfile functions
};
enum TransDir
{
STAD_RECV = 0,
STAD_SEND = 1
};
};
class SrtCongestionControlBase
{
protected:
// Here can be some common fields
CUDT* m_parent;
double m_dPktSndPeriod;
double m_dCWndSize;
//int m_iBandwidth; // NOT REQUIRED. Use m_parent->bandwidth() instead.
double m_dMaxCWndSize;
//int m_iMSS; // NOT REQUIRED. Use m_parent->MSS() instead.
//int32_t m_iSndCurrSeqNo; // NOT REQUIRED. Use m_parent->sndSeqNo().
//int m_iRcvRate; // NOT REQUIRED. Use m_parent->deliveryRate() instead.
//int m_RTT; // NOT REQUIRED. Use m_parent->RTT() instead.
//char* m_pcParam; // Used to access m_llMaxBw. Use m_parent->maxBandwidth() instead.
// Constructor in protected section so that this class is semi-abstract.
SrtCongestionControlBase(CUDT* parent);
public:
// This could be also made abstract, but this causes a linkage
// problem in C++: this would constitute the first virtual method,
// and C++ compiler uses the location of the first virtual method as the
// file to which it also emits the virtual call table. When this is
// abstract, there would have to be simultaneously either defined
// an empty method in congctl.cpp file (obviously never called),
// or simply left empty body here.
virtual ~SrtCongestionControlBase() { }
// All these functions that return values interesting for processing
// by CUDT can be overridden. Normally they should refer to the fields
// and these fields should keep the values as a state.
virtual double pktSndPeriod_us() { return m_dPktSndPeriod; }
virtual double cgWindowSize() { return m_dCWndSize; }
virtual double cgWindowMaxSize() { return m_dMaxCWndSize; }
virtual int64_t sndBandwidth() { return 0; }
// If user-defined, will return nonzero value.
// If not, it will be internally calculated.
virtual int RTO() { return 0; }
// Maximum number of packets to trigger ACK sending.
// Specifies the number of packets to receive before sending the ACK.
// Used by CUDT together with ACKTimeout_us() to trigger ACK packet sending.
virtual int ACKMaxPackets() const { return 0; }
// Periodical interval to send an ACK, in microseconds.
// If user-defined, this value will be used to calculate
// the next ACK time every time ACK is considered to be sent (see CUDT::checkTimers).
// Otherwise this will be calculated internally in CUDT, normally taken
// from CUDT::COMM_SYN_INTERVAL_US.
virtual int ACKTimeout_us() const { return 0; }
// Called when the settings concerning m_llMaxBW were changed.
// Arg 1: value of CUDT::m_llMaxBW
// Arg 2: value calculated out of CUDT::m_llInputBW and CUDT::m_iOverheadBW.
virtual void updateBandwidth(int64_t, int64_t) {}
virtual bool needsQuickACK(const CPacket&)
{
return false;
}
// Particular controller is allowed to agree or disagree on the use of particular API.
virtual bool checkTransArgs(SrtCongestion::TransAPI , SrtCongestion::TransDir , const char* /*buffer*/, size_t /*size*/, int /*ttl*/, bool /*inorder*/)
{
return true;
}
virtual SrtCongestion::RexmitMethod rexmitMethod() = 0; // Implementation enforced.
virtual int64_t updateNAKInterval(int64_t nakint_us, int rcv_speed, size_t loss_length)
{
if (rcv_speed > 0)
nakint_us += (loss_length * int64_t(1000000) / rcv_speed);
return nakint_us;
}
virtual int64_t minNAKInterval()
{
return 0; // Leave default
}
};
#endif