add .gitignore
[swift-upb.git] / send_control.cpp
index a49909f..130e9bd 100644 (file)
@@ -1,15 +1,15 @@
 /*
  *  send_control.cpp
- *  p2tp
+ *  congestion control logic for the swift protocol
  *
  *  Created by Victor Grishchenko on 12/10/09.
  *  Copyright 2009 Delft University of Technology. All rights reserved.
  *
  */
 
-#include "p2tp.h"
+#include "swift.h"
 
-using namespace p2tp;
+using namespace swift;
 using namespace std;
 
 tint Channel::MIN_DEV = 50*TINT_MSEC;
@@ -17,39 +17,48 @@ tint Channel::MAX_SEND_INTERVAL = TINT_SEC*58;
 tint Channel::LEDBAT_TARGET = TINT_MSEC*25;
 float Channel::LEDBAT_GAIN = 1.0/LEDBAT_TARGET;
 tint Channel::LEDBAT_DELAY_BIN = TINT_SEC*30;
+tint Channel::MAX_POSSIBLE_RTT = TINT_SEC*10;
 const char* Channel::SEND_CONTROL_MODES[] = {"keepalive", "pingpong",
-    "slowstart", "standard_aimd", "ledbat"};
+    "slowstart", "standard_aimd", "ledbat", "closing"};
 
 
 tint    Channel::NextSendTime () {
+    TimeoutDataOut(); // precaution to know free cwnd
     switch (send_control_) {
         case KEEP_ALIVE_CONTROL: return KeepAliveNextSendTime();
         case PING_PONG_CONTROL:  return PingPongNextSendTime();
         case SLOW_START_CONTROL: return SlowStartNextSendTime();
         case AIMD_CONTROL:       return AimdNextSendTime();
         case LEDBAT_CONTROL:     return LedbatNextSendTime();
+        case CLOSE_CONTROL:      return TINT_NEVER;
         default:                 assert(false);
     }
 }
 
 tint    Channel::SwitchSendControl (int control_mode) {
-    dprintf("%s #%u sendctrl %i->%i\n",tintstr(),id,send_control_,control_mode);
+    dprintf("%s #%u sendctrl switch %s->%s\n",tintstr(),id(),
+            SEND_CONTROL_MODES[send_control_],SEND_CONTROL_MODES[control_mode]);
     switch (control_mode) {
         case KEEP_ALIVE_CONTROL:
-            send_interval_ = max(TINT_SEC/10,rtt_avg_);
+            send_interval_ = rtt_avg_; //max(TINT_SEC/10,rtt_avg_);
             dev_avg_ = max(TINT_SEC,rtt_avg_);
+            data_out_cap_ = bin64_t::ALL;
             cwnd_ = 1;
             break;
         case PING_PONG_CONTROL:
             dev_avg_ = max(TINT_SEC,rtt_avg_);
+            data_out_cap_ = bin64_t::ALL;
             cwnd_ = 1;
             break;
         case SLOW_START_CONTROL:
+            cwnd_ = 1;
             break;
         case AIMD_CONTROL:
             break;
         case LEDBAT_CONTROL:
             break;
+        case CLOSE_CONTROL:
+            break;
         default: 
             assert(false);
     }
@@ -57,67 +66,69 @@ tint    Channel::SwitchSendControl (int control_mode) {
     return NextSendTime();
 }
 
-// TODO: transitions, consistently
-// TODO: may send data
 tint    Channel::KeepAliveNextSendTime () {
     if (sent_since_recv_>=3 && last_recv_time_<NOW-TINT_MIN)
-        return TINT_NEVER;
+        return SwitchSendControl(CLOSE_CONTROL);
     if (ack_rcvd_recent_)
         return SwitchSendControl(SLOW_START_CONTROL);
-    if (data_in_.bin!=bin64_t::NONE)
+    if (data_in_.time!=TINT_NEVER)
         return NOW;
-    send_interval_ <<= 1;
+    if (last_send_time_==NOW)
+        send_interval_ <<= 1;
     if (send_interval_>MAX_SEND_INTERVAL)
         send_interval_ = MAX_SEND_INTERVAL;
     return last_send_time_ + send_interval_;
 }
 
 tint    Channel::PingPongNextSendTime () { // FIXME INFINITE LOOP
-    if (last_recv_time_ < last_send_time_-TINT_SEC*3) {
-        // FIXME keepalive <-> pingpong (peers, transition)
-    } // last_data_out_time_ < last_send_time_ - TINT_SEC...
-    if (false)
+    if (dgrams_sent_>=10)
         return SwitchSendControl(KEEP_ALIVE_CONTROL);
     if (ack_rcvd_recent_)
         return SwitchSendControl(SLOW_START_CONTROL);
-    if (data_in_.bin!=bin64_t::NONE)
+    if (data_in_.time!=TINT_NEVER)
         return NOW;
     if (last_recv_time_>last_send_time_)
         return NOW;
-    else if (last_send_time_)
-        return last_send_time_ + ack_timeout();
-    else
+    if (!last_send_time_)
         return NOW;
+    return last_send_time_ + ack_timeout(); // timeout
 }
 
 tint    Channel::CwndRateNextSendTime () {
-    if (data_in_.bin!=bin64_t::NONE)
+    if (data_in_.time!=TINT_NEVER)
         return NOW; // TODO: delayed ACKs
+    //if (last_recv_time_<NOW-rtt_avg_*4)
+    //    return SwitchSendControl(KEEP_ALIVE_CONTROL);
     send_interval_ = rtt_avg_/cwnd_;
+    if (send_interval_>max(rtt_avg_,TINT_SEC)*4)
+        return SwitchSendControl(KEEP_ALIVE_CONTROL);
     if (data_out_.size()<cwnd_) {
+        dprintf("%s #%u sendctrl next in %llius (cwnd %.2f, data_out %i)\n",
+                tintstr(),id_,send_interval_,cwnd_,(int)data_out_.size());
         return last_data_out_time_ + send_interval_;
     } else {
-        tint next_timeout = data_out_.front().time + ack_timeout();
-        return last_data_out_time_ + next_timeout;
+        assert(data_out_.front().time!=TINT_NEVER);
+        return data_out_.front().time + ack_timeout();
     }
 }
 
-void    Channel::BackOffOnLosses () {
+void    Channel::BackOffOnLosses (float ratio) {
     ack_rcvd_recent_ = 0;
     ack_not_rcvd_recent_ =  0;
     if (last_loss_time_<NOW-rtt_avg_) {
-        cwnd_ /= 2;
+        cwnd_ *= ratio;
         last_loss_time_ = NOW;
+        dprintf("%s #%u sendctrl backoff %3.2f\n",tintstr(),id_,cwnd_);
     }
 }
 
 tint    Channel::SlowStartNextSendTime () {
     if (ack_not_rcvd_recent_) {
         BackOffOnLosses();
-        return SwitchSendControl(AIMD_CONTROL);
+        return SwitchSendControl(LEDBAT_CONTROL);//AIMD_CONTROL);
     } 
     if (rtt_avg_/cwnd_<TINT_SEC/10) 
-        return SwitchSendControl(AIMD_CONTROL);
+        return SwitchSendControl(LEDBAT_CONTROL);//AIMD_CONTROL);
     cwnd_+=ack_rcvd_recent_;
     ack_rcvd_recent_=0;
     return CwndRateNextSendTime();
@@ -126,7 +137,12 @@ tint    Channel::SlowStartNextSendTime () {
 tint    Channel::AimdNextSendTime () {
     if (ack_not_rcvd_recent_)
         BackOffOnLosses();
-    cwnd_ += ack_rcvd_recent_/cwnd_;
+    if (ack_rcvd_recent_) {
+        if (cwnd_>1)
+            cwnd_ += ack_rcvd_recent_/cwnd_;
+        else
+            cwnd_ *= 2;
+    }
     ack_rcvd_recent_=0;
     return CwndRateNextSendTime();
 }
@@ -140,11 +156,17 @@ tint Channel::LedbatNextSendTime () {
             owd_cur = owd_current_[i];
     }
     if (ack_not_rcvd_recent_)
-        BackOffOnLosses();
+        BackOffOnLosses(0.8);
     ack_rcvd_recent_ = 0;
     tint queueing_delay = owd_cur - owd_min;
     tint off_target = LEDBAT_TARGET - queueing_delay;
     cwnd_ += LEDBAT_GAIN * off_target / cwnd_;
+    if (cwnd_<1)
+        cwnd_ = 1;
+    if (owd_cur==TINT_NEVER || owd_min==TINT_NEVER)
+        cwnd_ = 1;
+    dprintf("%s #%u sendctrl ledbat %lli-%lli => %3.2f\n",
+            tintstr(),id_,owd_cur,owd_min,cwnd_);
     return CwndRateNextSendTime();
 }