mirror of
https://github.com/skywind3000/kcp.git
synced 2026-08-19 06:03:28 +08:00
congestion control: basically finish
This commit is contained in:
114
ikcp.c
114
ikcp.c
@@ -973,14 +973,22 @@ void ikcp_flush(ikcpcb *kcp)
|
||||
int count, size, i;
|
||||
IUINT32 resent, cwnd;
|
||||
IUINT32 rtomin;
|
||||
IUINT32 prior_cwnd;
|
||||
IUINT32 eff_cwnd, cur_inflight;
|
||||
struct IQUEUEHEAD *p;
|
||||
int change = 0;
|
||||
int lost = 0;
|
||||
IKCPSEG seg;
|
||||
|
||||
// 'ikcp_update' haven't been called.
|
||||
// 'ikcp_update' hasn't been called yet.
|
||||
if (kcp->updated == 0) return;
|
||||
|
||||
if (kcp->ccops && kcp->ccops->on_tick) {
|
||||
kcp->ccops->on_tick(kcp);
|
||||
}
|
||||
|
||||
prior_cwnd = kcp->cwnd;
|
||||
|
||||
seg.conv = kcp->conv;
|
||||
seg.cmd = IKCP_CMD_ACK;
|
||||
seg.frg = 0;
|
||||
@@ -1052,7 +1060,7 @@ void ikcp_flush(ikcpcb *kcp)
|
||||
|
||||
// calculate window size
|
||||
cwnd = _imin_(kcp->snd_wnd, kcp->rmt_wnd);
|
||||
if (kcp->nocwnd == 0) cwnd = _imin_(kcp->cwnd, cwnd);
|
||||
if (kcp->ccops != NULL || kcp->nocwnd == 0) cwnd = _imin_(kcp->cwnd, cwnd);
|
||||
|
||||
// move data from snd_queue to snd_buf
|
||||
while (_itimediff(kcp->snd_nxt, kcp->snd_una + cwnd) < 0) {
|
||||
@@ -1076,6 +1084,22 @@ void ikcp_flush(ikcpcb *kcp)
|
||||
newseg->rto = kcp->rx_rto;
|
||||
newseg->fastack = 0;
|
||||
newseg->xmit = 0;
|
||||
|
||||
if (kcp->ccops && kcp->ccops->on_pkt_sent) {
|
||||
kcp->ccops->on_pkt_sent(kcp, newseg->sn, current, newseg->len, kcp->nsnd_buf - 1);
|
||||
}
|
||||
}
|
||||
|
||||
// check on_app_limited
|
||||
if (kcp->ccops && kcp->ccops->on_app_limited) {
|
||||
if (iqueue_is_empty(&kcp->snd_queue)) {
|
||||
eff_cwnd = _imin_(kcp->snd_wnd, kcp->rmt_wnd);
|
||||
eff_cwnd = _imin_(kcp->cwnd, eff_cwnd);
|
||||
cur_inflight = kcp->nsnd_buf;
|
||||
if (cur_inflight < eff_cwnd) {
|
||||
kcp->ccops->on_app_limited(kcp, cur_inflight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// calculate resent
|
||||
@@ -1144,7 +1168,7 @@ void ikcp_flush(ikcpcb *kcp)
|
||||
}
|
||||
}
|
||||
|
||||
// flash remain segments
|
||||
// flash remaining segments
|
||||
size = (int)(ptr - buffer);
|
||||
if (size > 0) {
|
||||
ikcp_output(kcp, buffer, size);
|
||||
@@ -1152,20 +1176,30 @@ void ikcp_flush(ikcpcb *kcp)
|
||||
|
||||
// update ssthresh
|
||||
if (change) {
|
||||
IUINT32 inflight = kcp->snd_nxt - kcp->snd_una;
|
||||
kcp->ssthresh = inflight / 2;
|
||||
if (kcp->ssthresh < IKCP_THRESH_MIN)
|
||||
kcp->ssthresh = IKCP_THRESH_MIN;
|
||||
kcp->cwnd = kcp->ssthresh + resent;
|
||||
kcp->incr = kcp->cwnd * kcp->mss;
|
||||
if (kcp->ccops && kcp->ccops->on_fast_retransmit) {
|
||||
kcp->ccops->on_fast_retransmit(kcp, (IUINT32)change, kcp->nsnd_buf, prior_cwnd);
|
||||
}
|
||||
else {
|
||||
IUINT32 inflight = kcp->snd_nxt - kcp->snd_una;
|
||||
kcp->ssthresh = inflight / 2;
|
||||
if (kcp->ssthresh < IKCP_THRESH_MIN)
|
||||
kcp->ssthresh = IKCP_THRESH_MIN;
|
||||
kcp->cwnd = kcp->ssthresh + resent;
|
||||
kcp->incr = kcp->cwnd * kcp->mss;
|
||||
}
|
||||
}
|
||||
|
||||
if (lost) {
|
||||
kcp->ssthresh = cwnd / 2;
|
||||
if (kcp->ssthresh < IKCP_THRESH_MIN)
|
||||
kcp->ssthresh = IKCP_THRESH_MIN;
|
||||
kcp->cwnd = 1;
|
||||
kcp->incr = kcp->mss;
|
||||
if (kcp->ccops && kcp->ccops->on_timeout) {
|
||||
kcp->ccops->on_timeout(kcp, prior_cwnd);
|
||||
}
|
||||
else {
|
||||
kcp->ssthresh = cwnd / 2;
|
||||
if (kcp->ssthresh < IKCP_THRESH_MIN)
|
||||
kcp->ssthresh = IKCP_THRESH_MIN;
|
||||
kcp->cwnd = 1;
|
||||
kcp->incr = kcp->mss;
|
||||
}
|
||||
}
|
||||
|
||||
if (kcp->cwnd < 1) {
|
||||
@@ -1176,9 +1210,9 @@ void ikcp_flush(ikcpcb *kcp)
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// update state (call it repeatedly, every 10ms-100ms), or you can ask
|
||||
// ikcp_check when to call it again (without ikcp_input/_send calling).
|
||||
// 'current' - current timestamp in millisec.
|
||||
// update state (call it repeatedly, every 10ms-100ms), or you can ask
|
||||
// ikcp_check when to call it again (if no ikcp_input/_send calls occur).
|
||||
// 'current' - current timestamp in milliseconds.
|
||||
//---------------------------------------------------------------------
|
||||
void ikcp_update(ikcpcb *kcp, IUINT32 current)
|
||||
{
|
||||
@@ -1209,13 +1243,13 @@ void ikcp_update(ikcpcb *kcp, IUINT32 current)
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Determine when should you invoke ikcp_update:
|
||||
// returns when you should invoke ikcp_update in millisec, if there
|
||||
// is no ikcp_input/_send calling. you can call ikcp_update in that
|
||||
// time, instead of call update repeatly.
|
||||
// Important to reduce unnacessary ikcp_update invoking. use it to
|
||||
// schedule ikcp_update (eg. implementing an epoll-like mechanism,
|
||||
// or optimize ikcp_update when handling massive kcp connections)
|
||||
// Determines when you should invoke ikcp_update next:
|
||||
// returns the timestamp (in milliseconds) at which you should call
|
||||
// ikcp_update, assuming no ikcp_input/_send calls occur in between.
|
||||
// You can call ikcp_update at that time instead of calling it repeatedly.
|
||||
// Important for reducing unnecessary ikcp_update invocations. Use it to
|
||||
// schedule ikcp_update (e.g., implementing an epoll-like mechanism,
|
||||
// or optimizing ikcp_update when handling massive kcp connections).
|
||||
//---------------------------------------------------------------------
|
||||
IUINT32 ikcp_check(const ikcpcb *kcp, IUINT32 current)
|
||||
{
|
||||
@@ -1334,3 +1368,35 @@ IUINT32 ikcp_getconv(const void *ptr)
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// install congestion control
|
||||
//---------------------------------------------------------------------
|
||||
int ikcp_setcc(ikcpcb *kcp, const struct IKCPOPS *ops)
|
||||
{
|
||||
assert(kcp);
|
||||
if (kcp->ccops && kcp->ccops->release) {
|
||||
kcp->ccops->release(kcp);
|
||||
}
|
||||
kcp->congest = NULL;
|
||||
kcp->ccops = ops;
|
||||
if (ops) {
|
||||
if (ops->init) {
|
||||
if (ops->init(kcp) < 0) {
|
||||
kcp->ccops = NULL;
|
||||
kcp->congest = NULL;
|
||||
if (kcp->cwnd < 1) kcp->cwnd = 1;
|
||||
kcp->incr = kcp->cwnd * kcp->mss;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (kcp->cwnd < 1) kcp->cwnd = 1;
|
||||
kcp->incr = kcp->cwnd * kcp->mss;
|
||||
if (kcp->incr < kcp->mss) kcp->incr = kcp->mss;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user