v whether sending is limited by cwnd or app
* actually: whether packets are ACKed faster than sent
* uproot DATA NONE: complicates and deceives
+ * r735 goes to github
if (peak==bin64_t::NONE)
return false;
- if (!OfferHash(pos, Sha1Hash(data,length)))
+ Sha1Hash data_hash(data,length);
+ if (!OfferHash(pos, data_hash)) {
+ printf("invalid hash for %s: %s\n",pos.str(),data_hash.hex().c_str());
return false;
+ }
//printf("g %lli %s\n",(uint64_t)pos,hash.hex().c_str());
ack_out_.set(pos,bins::FILLED);
AIMD_CONTROL,
LEDBAT_CONTROL
} send_control_t;
+
+ static const char* SEND_CONTROL_MODES[];
static Channel*
RecvDatagram (int socket);
/** Channel id: index in the channel array. */
uint32_t id;
/** Socket address of the peer. */
- Address peer_;
+ Address peer_;
/** The UDP socket fd. */
- int socket_;
+ int socket_;
/** Descriptor of the file in question. */
FileTransfer* transfer_;
/** Peer channel id; zero if we are trying to open a channel. */
/** Peer's progress, based on acknowledgements. */
bins ack_in_;
/** Last data received; needs to be acked immediately. */
- tintbin data_in_;
+ tintbin data_in_;
bin64_t data_in_dbl_;
/** The history of data sent and still unacknowledged. */
tbqueue data_out_;
tint Channel::LEDBAT_TARGET = TINT_MSEC*25;
float Channel::LEDBAT_GAIN = 1.0/LEDBAT_TARGET;
tint Channel::LEDBAT_DELAY_BIN = TINT_SEC*30;
+const char* Channel::SEND_CONTROL_MODES[] = {"keepalive", "pingpong",
+ "slowstart", "standard_aimd", "ledbat"};
tint Channel::NextSendTime () {
return TINT_NEVER;
if (ack_rcvd_recent_)
return SwitchSendControl(SLOW_START_CONTROL);
+ if (data_in_.bin!=bin64_t::NONE)
+ return NOW;
send_interval_ <<= 1;
if (send_interval_>MAX_SEND_INTERVAL)
send_interval_ = MAX_SEND_INTERVAL;
return last_send_time_ + send_interval_;
}
-tint Channel::PingPongNextSendTime () {
+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...
return SwitchSendControl(KEEP_ALIVE_CONTROL);
if (ack_rcvd_recent_)
return SwitchSendControl(SLOW_START_CONTROL);
+ if (data_in_.bin!=bin64_t::NONE)
+ return NOW;
if (last_recv_time_>last_send_time_)
return NOW;
else if (last_send_time_)
}
tint Channel::CwndRateNextSendTime () {
+ if (data_in_.bin!=bin64_t::NONE)
+ return NOW; // TODO: delayed ACKs
send_interval_ = rtt_avg_/cwnd_;
if (data_out_.size()<cwnd_) {
return last_data_out_time_ + send_interval_;
BackOffOnLosses();
return SwitchSendControl(AIMD_CONTROL);
}
+ if (rtt_avg_/cwnd_<TINT_SEC/10)
+ return SwitchSendControl(AIMD_CONTROL);
cwnd_+=ack_rcvd_recent_;
ack_rcvd_recent_=0;
return CwndRateNextSendTime();
dgram.Push8(P2TP_HANDSHAKE);
int encoded = EncodeID(id);
dgram.Push32(encoded);
- dprintf("%s #%u +hs %i\n",tintstr(),id,encoded);
+ dprintf("%s #%u +hs %x\n",tintstr(),id,encoded);
ack_out_.clear();
AddAck(dgram);
}
AddHandshake(dgram);
AddAck(dgram);
}
- dprintf("%s #%u sent %ib %s:%u\n",
+ dprintf("%s #%u sent %ib %s:%x\n",
tintstr(),id,dgram.size(),peer().str(),peer_channel_id_);
if (dgram.size()==4) {// only the channel id; bare keep-alive
data = bin64_t::ALL;
- if (send_control_!=KEEP_ALIVE_CONTROL) // we did our best
- SwitchSendControl(KEEP_ALIVE_CONTROL);
- if (NOW<last_send_time_+MAX_SEND_INTERVAL) // no need for keepalive
- return; // don't send empty dgram
+ if (send_control_!=KEEP_ALIVE_CONTROL) {
+ if ( (cwnd_/=2) < 1 )
+ SwitchSendControl(KEEP_ALIVE_CONTROL);
+ }
+ //if (data_out_.empty() && send_control_!=KEEP_ALIVE_CONTROL)
+ // SwitchSendControl(KEEP_ALIVE_CONTROL);// we did our best
+ //if (NOW<last_send_time_+MAX_SEND_INTERVAL) // no need for keepalive
+ // return; // don't send empty dgram
}
if (dgram.Send()==-1)
print_error("can't send datagram");
}
dprintf("%s #%u -ack %s\n",tintstr(),id,ackd_pos.str());
ack_in_.set(ackd_pos);
- CleanDataOut(ackd_pos);
+ CleanDataOut(ackd_pos); // FIXME do AFTER all ACKs
}
void Channel::OnHandshake (Datagram& dgram) {
peer_channel_id_ = dgram.Pull32();
- dprintf("%s #%u -hs %i\n",tintstr(),id,peer_channel_id_);
+ dprintf("%s #%u -hs %x\n",tintstr(),id,peer_channel_id_);
// FUTURE: channel forking
}
tint send_time(TINT_NEVER);
Channel* sender(NULL);
while (!sender && !send_queue.is_empty()) { // dequeue
- send_time = send_queue.peek().time;
- sender = channel((int)send_queue.peek().bin);
- send_queue.pop();
+ tintbin next = send_queue.pop();
+ send_time = next.time;
+ sender = channel((int)next.bin);
if (sender && sender->next_send_time_!=send_time &&
sender->next_send_time_!=TINT_NEVER )
sender = NULL; // it was a stale entry
}
- if ( sender && send_time <= NOW ) { // it's time
+ if ( sender!=NULL && send_time<=NOW ) { // it's time
if (sender->next_send_time_<NOW+TINT_MIN) { // either send
dprintf("%s #%u sch_send %s\n",tintstr(),sender->id,
}
- } while (Datagram::Time()<limit);
+ } while (NOW<limit);
}