5 * Created by Victor Grishchenko on 12/10/09.
6 * Copyright 2009 Delft University of Technology. All rights reserved.
15 tint Channel::MIN_DEV = 50*TINT_MSEC;
16 tint Channel::MAX_SEND_INTERVAL = TINT_SEC*58;
17 tint Channel::LEDBAT_TARGET = TINT_MSEC*25;
18 float Channel::LEDBAT_GAIN = 1.0/LEDBAT_TARGET;
19 tint Channel::LEDBAT_DELAY_BIN = TINT_SEC*30;
22 tint Channel::NextSendTime () {
23 switch (send_control_) {
24 case KEEP_ALIVE_CONTROL: return KeepAliveNextSendTime();
25 case PING_PONG_CONTROL: return PingPongNextSendTime();
26 case SLOW_START_CONTROL: return SlowStartNextSendTime();
27 case AIMD_CONTROL: return AimdNextSendTime();
28 case LEDBAT_CONTROL: return LedbatNextSendTime();
29 default: assert(false);
33 tint Channel::SwitchSendControl (int control_mode) {
34 dprintf("%s #%u sendctrl %i->%i\n",tintstr(),id,send_control_,control_mode);
35 switch (control_mode) {
36 case KEEP_ALIVE_CONTROL:
37 send_interval_ = max(TINT_SEC/10,rtt_avg_);
38 dev_avg_ = max(TINT_SEC,rtt_avg_);
41 case PING_PONG_CONTROL:
42 dev_avg_ = max(TINT_SEC,rtt_avg_);
45 case SLOW_START_CONTROL:
54 send_control_ = control_mode;
55 return NextSendTime();
58 // TODO: transitions, consistently
59 // TODO: may send data
60 tint Channel::KeepAliveNextSendTime () {
61 if (sent_since_recv_>=3 && last_recv_time_<NOW-TINT_MIN)
64 return SwitchSendControl(SLOW_START_CONTROL);
66 if (send_interval_>MAX_SEND_INTERVAL)
67 send_interval_ = MAX_SEND_INTERVAL;
68 return last_send_time_ + send_interval_;
71 tint Channel::PingPongNextSendTime () {
72 if (last_recv_time_ < last_send_time_-TINT_SEC*3) {
73 // FIXME keepalive <-> pingpong (peers, transition)
74 } // last_data_out_time_ < last_send_time_ - TINT_SEC...
76 return SwitchSendControl(KEEP_ALIVE_CONTROL);
78 return SwitchSendControl(SLOW_START_CONTROL);
79 if (last_recv_time_>last_send_time_)
81 else if (last_send_time_)
82 return last_send_time_ + ack_timeout();
87 tint Channel::CwndRateNextSendTime () {
88 send_interval_ = rtt_avg_/cwnd_;
89 if (data_out_.size()<cwnd_) {
90 dprintf("%s #%u sendctrl next in %llius\n",tintstr(),id,send_interval_);
91 return last_data_out_time_ + send_interval_;
93 tint next_timeout = data_out_.front().time + ack_timeout();
94 return last_data_out_time_ + next_timeout;
98 void Channel::BackOffOnLosses () {
100 ack_not_rcvd_recent_ = 0;
101 if (last_loss_time_<NOW-rtt_avg_) {
103 last_loss_time_ = NOW;
104 dprintf("%s #%u sendctrl backoff %3.2f\n",tintstr(),id,cwnd_);
108 tint Channel::SlowStartNextSendTime () {
109 if (ack_not_rcvd_recent_) {
111 return SwitchSendControl(AIMD_CONTROL);
113 if (send_interval_<TINT_SEC/10)
114 return SwitchSendControl(AIMD_CONTROL);
115 cwnd_+=ack_rcvd_recent_;
117 return CwndRateNextSendTime();
120 tint Channel::AimdNextSendTime () {
121 if (ack_not_rcvd_recent_)
123 cwnd_ += ack_rcvd_recent_/cwnd_;
125 return CwndRateNextSendTime();
128 tint Channel::LedbatNextSendTime () {
129 tint owd_cur(TINT_NEVER), owd_min(TINT_NEVER);
130 for(int i=0; i<4; i++) {
131 if (owd_min>owd_min_bins_[i])
132 owd_min = owd_min_bins_[i];
133 if (owd_cur>owd_current_[i])
134 owd_cur = owd_current_[i];
136 if (ack_not_rcvd_recent_)
138 ack_rcvd_recent_ = 0;
139 tint queueing_delay = owd_cur - owd_min;
140 tint off_target = LEDBAT_TARGET - queueing_delay;
141 cwnd_ += LEDBAT_GAIN * off_target / cwnd_;
142 return CwndRateNextSendTime();