start_retransmit_timer(c);
}
+ if(is_reliable(c) && !timerisset(&c->conn_timeout)) {
+ gettimeofday(&c->conn_timeout, NULL);
+ c->conn_timeout.tv_sec += c->utcp->timeout;
+ }
+
return len;
}
// 4. Update timers
if(advanced) {
- timerclear(&c->conn_timeout); // It will be set anew in utcp_timeout() if c->snd.una != c->snd.nxt.
-
if(c->snd.una == c->snd.last) {
stop_retransmit_timer(c);
+ timerclear(&c->conn_timeout);
} else if(is_reliable(c)) {
start_retransmit_timer(c);
+ gettimeofday(&c->conn_timeout, NULL);
+ c->conn_timeout.tv_sec += utcp->timeout;
}
}
c->recv(c, NULL, 0);
}
+ if(c->poll) {
+ c->poll(c, 0);
+ }
+
continue;
}
then.tv_sec += utcp->timeout;
for(int i = 0; i < utcp->nconnections; i++) {
- utcp->connections[i]->rtrx_timeout = now;
- utcp->connections[i]->conn_timeout = then;
- utcp->connections[i]->rtt_start.tv_sec = 0;
+ struct utcp_connection *c = utcp->connections[i];
+
+ if(c->reapable) {
+ continue;
+ }
+
+ c->rtrx_timeout = now;
+ c->conn_timeout = then;
+ c->rtt_start.tv_sec = 0;
}
if(utcp->rto > START_RTO) {
}
}
+size_t utcp_get_sendq(struct utcp_connection *c) {
+ return c->sndbuf.used;
+}
+
+size_t utcp_get_recvq(struct utcp_connection *c) {
+ return c->rcvbuf.used;
+}
+
bool utcp_get_nodelay(struct utcp_connection *c) {
return c ? c->nodelay : false;
}
utcp->pre_accept = pre_accept;
}
}
+
+void utcp_expect_data(struct utcp_connection *c, bool expect) {
+ if(!c || c->reapable) {
+ return;
+ }
+
+ if(!(c->state == ESTABLISHED || c->state == FIN_WAIT_1 || c->state == FIN_WAIT_2)) {
+ return;
+ }
+
+ if(expect) {
+ // If we expect data, start the connection timer.
+ if(!timerisset(&c->conn_timeout)) {
+ gettimeofday(&c->conn_timeout, NULL);
+ c->conn_timeout.tv_sec += c->utcp->timeout;
+ }
+ } else {
+ // If we want to cancel expecting data, only clear the timer when there is no unACKed data.
+ if(c->snd.una == c->snd.last) {
+ timerclear(&c->conn_timeout);
+ }
+ }
+}
+
+void utcp_offline(struct utcp *utcp, bool offline) {
+ for(int i = 0; i < utcp->nconnections; i++) {
+ struct utcp_connection *c = utcp->connections[i];
+
+ if(!c->reapable) {
+ utcp_expect_data(c, offline);
+
+ // If we are online again, reset the retransmission timers, but keep the connection timeout as it is,
+ // to prevent peers toggling online/offline state frequently from keeping connections alive
+ // if there is no progress in sending actual data.
+ if(!offline) {
+ gettimeofday(&utcp->connections[i]->rtrx_timeout, NULL);
+ utcp->connections[i]->rtt_start.tv_sec = 0;
+ }
+ }
+ }
+
+ if(!offline && utcp->rto > START_RTO) {
+ utcp->rto = START_RTO;
+ }
+}