176404edcSAsim Jamshed #include "timer.h" 276404edcSAsim Jamshed #include "tcp_in.h" 376404edcSAsim Jamshed #include "tcp_out.h" 476404edcSAsim Jamshed #include "stat.h" 576404edcSAsim Jamshed #include "debug.h" 676404edcSAsim Jamshed #include "memory_mgt.h" 776404edcSAsim Jamshed #include "config.h" 876404edcSAsim Jamshed 976404edcSAsim Jamshed #define MAX(a, b) ((a)>(b)?(a):(b)) 1076404edcSAsim Jamshed #define MIN(a, b) ((a)<(b)?(a):(b)) 1176404edcSAsim Jamshed 1276404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 1376404edcSAsim Jamshed struct rto_hashstore* 1476404edcSAsim Jamshed InitRTOHashstore() 1576404edcSAsim Jamshed { 1676404edcSAsim Jamshed int i; 1776404edcSAsim Jamshed struct rto_hashstore* hs = calloc(1, sizeof(struct rto_hashstore)); 1876404edcSAsim Jamshed if (!hs) { 1976404edcSAsim Jamshed TRACE_ERROR("calloc: InitHashStore"); 2076404edcSAsim Jamshed return 0; 2176404edcSAsim Jamshed } 2276404edcSAsim Jamshed 2376404edcSAsim Jamshed for (i = 0; i < RTO_HASH; i++) 2476404edcSAsim Jamshed TAILQ_INIT(&hs->rto_list[i]); 2576404edcSAsim Jamshed 2676404edcSAsim Jamshed TAILQ_INIT(&hs->rto_list[RTO_HASH]); 2776404edcSAsim Jamshed 2876404edcSAsim Jamshed return hs; 2976404edcSAsim Jamshed } 3076404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 3176404edcSAsim Jamshed inline void 3276404edcSAsim Jamshed AddtoRTOList(mtcp_manager_t mtcp, tcp_stream *cur_stream) 3376404edcSAsim Jamshed { 3476404edcSAsim Jamshed if (!mtcp->rto_list_cnt) { 3576404edcSAsim Jamshed mtcp->rto_store->rto_now_idx = 0; 3676404edcSAsim Jamshed mtcp->rto_store->rto_now_ts = cur_stream->sndvar->ts_rto; 3776404edcSAsim Jamshed } 3876404edcSAsim Jamshed 3976404edcSAsim Jamshed if (cur_stream->on_rto_idx < 0 ) { 4076404edcSAsim Jamshed if (cur_stream->on_timewait_list) { 4176404edcSAsim Jamshed TRACE_ERROR("Stream %u: cannot be in both " 4276404edcSAsim Jamshed "rto and timewait list.\n", cur_stream->id); 4376404edcSAsim Jamshed #ifdef DUMP_STREAM 4476404edcSAsim Jamshed DumpStream(mtcp, cur_stream); 4576404edcSAsim Jamshed #endif 4676404edcSAsim Jamshed return; 4776404edcSAsim Jamshed } 4876404edcSAsim Jamshed 4976404edcSAsim Jamshed int diff = (int32_t)(cur_stream->sndvar->ts_rto - mtcp->rto_store->rto_now_ts); 5076404edcSAsim Jamshed #if 0 5176404edcSAsim Jamshed if (diff < RTO_HASH) { 5276404edcSAsim Jamshed #else 5376404edcSAsim Jamshed int offset= ((diff + mtcp->rto_store->rto_now_idx) & (RTO_HASH - 1)); 5476404edcSAsim Jamshed cur_stream->on_rto_idx = offset; 5576404edcSAsim Jamshed TAILQ_INSERT_TAIL(&(mtcp->rto_store->rto_list[offset]), 5676404edcSAsim Jamshed cur_stream, sndvar->timer_link); 5776404edcSAsim Jamshed #endif 5876404edcSAsim Jamshed #if 0 5976404edcSAsim Jamshed } else { 6076404edcSAsim Jamshed cur_stream->on_rto_idx = RTO_HASH; 6176404edcSAsim Jamshed TAILQ_INSERT_TAIL(&(mtcp->rto_store->rto_list[RTO_HASH]), 6276404edcSAsim Jamshed cur_stream, sndvar->timer_link); 6376404edcSAsim Jamshed } 6476404edcSAsim Jamshed #endif 6576404edcSAsim Jamshed mtcp->rto_list_cnt++; 6676404edcSAsim Jamshed } 6776404edcSAsim Jamshed } 6876404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 6976404edcSAsim Jamshed inline void 7076404edcSAsim Jamshed RemoveFromRTOList(mtcp_manager_t mtcp, tcp_stream *cur_stream) 7176404edcSAsim Jamshed { 7276404edcSAsim Jamshed if (cur_stream->on_rto_idx < 0) { 7376404edcSAsim Jamshed // assert(0); 7476404edcSAsim Jamshed return; 7576404edcSAsim Jamshed } 7676404edcSAsim Jamshed 7776404edcSAsim Jamshed TAILQ_REMOVE(&mtcp->rto_store->rto_list[cur_stream->on_rto_idx], 7876404edcSAsim Jamshed cur_stream, sndvar->timer_link); 7976404edcSAsim Jamshed cur_stream->on_rto_idx = -1; 8076404edcSAsim Jamshed 8176404edcSAsim Jamshed mtcp->rto_list_cnt--; 8276404edcSAsim Jamshed } 8376404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 8476404edcSAsim Jamshed inline void 8576404edcSAsim Jamshed AddtoTimewaitList(mtcp_manager_t mtcp, tcp_stream *cur_stream, uint32_t cur_ts) 8676404edcSAsim Jamshed { 8776404edcSAsim Jamshed cur_stream->rcvvar->ts_tw_expire = cur_ts + g_config.mos->tcp_tw_interval; 8876404edcSAsim Jamshed 8976404edcSAsim Jamshed if (cur_stream->on_timewait_list) { 9076404edcSAsim Jamshed // Update list in sorted way by ts_tw_expire 9176404edcSAsim Jamshed TAILQ_REMOVE(&mtcp->timewait_list, cur_stream, sndvar->timer_link); 9276404edcSAsim Jamshed TAILQ_INSERT_TAIL(&mtcp->timewait_list, cur_stream, sndvar->timer_link); 9376404edcSAsim Jamshed } else { 9476404edcSAsim Jamshed if (cur_stream->on_rto_idx >= 0) { 9576404edcSAsim Jamshed TRACE_DBG("Stream %u: cannot be in both " 9676404edcSAsim Jamshed "timewait and rto list.\n", cur_stream->id); 9776404edcSAsim Jamshed //assert(0); 9876404edcSAsim Jamshed #ifdef DUMP_STREAM 9976404edcSAsim Jamshed DumpStream(mtcp, cur_stream); 10076404edcSAsim Jamshed #endif 10176404edcSAsim Jamshed RemoveFromRTOList(mtcp, cur_stream); 10276404edcSAsim Jamshed } 10376404edcSAsim Jamshed 10476404edcSAsim Jamshed cur_stream->on_timewait_list = TRUE; 10576404edcSAsim Jamshed TAILQ_INSERT_TAIL(&mtcp->timewait_list, cur_stream, sndvar->timer_link); 10676404edcSAsim Jamshed mtcp->timewait_list_cnt++; 10776404edcSAsim Jamshed } 10876404edcSAsim Jamshed } 10976404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 11076404edcSAsim Jamshed inline void 11176404edcSAsim Jamshed RemoveFromTimewaitList(mtcp_manager_t mtcp, tcp_stream *cur_stream) 11276404edcSAsim Jamshed { 11376404edcSAsim Jamshed if (!cur_stream->on_timewait_list) { 11476404edcSAsim Jamshed //assert(0); 11576404edcSAsim Jamshed return; 11676404edcSAsim Jamshed } 11776404edcSAsim Jamshed 11876404edcSAsim Jamshed TAILQ_REMOVE(&mtcp->timewait_list, cur_stream, sndvar->timer_link); 11976404edcSAsim Jamshed cur_stream->on_timewait_list = FALSE; 12076404edcSAsim Jamshed mtcp->timewait_list_cnt--; 12176404edcSAsim Jamshed } 12276404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 12376404edcSAsim Jamshed inline void 12476404edcSAsim Jamshed AddtoTimeoutList(mtcp_manager_t mtcp, tcp_stream *cur_stream) 12576404edcSAsim Jamshed { 12676404edcSAsim Jamshed if (cur_stream->on_timeout_list) { 12776404edcSAsim Jamshed //assert(0); 12876404edcSAsim Jamshed return; 12976404edcSAsim Jamshed } 13076404edcSAsim Jamshed 13176404edcSAsim Jamshed cur_stream->on_timeout_list = TRUE; 13276404edcSAsim Jamshed TAILQ_INSERT_TAIL(&mtcp->timeout_list, cur_stream, sndvar->timeout_link); 13376404edcSAsim Jamshed mtcp->timeout_list_cnt++; 13476404edcSAsim Jamshed } 13576404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 13676404edcSAsim Jamshed inline void 13776404edcSAsim Jamshed RemoveFromTimeoutList(mtcp_manager_t mtcp, tcp_stream *cur_stream) 13876404edcSAsim Jamshed { 13976404edcSAsim Jamshed if (cur_stream->on_timeout_list) { 14076404edcSAsim Jamshed cur_stream->on_timeout_list = FALSE; 14176404edcSAsim Jamshed TAILQ_REMOVE(&mtcp->timeout_list, cur_stream, sndvar->timeout_link); 14276404edcSAsim Jamshed mtcp->timeout_list_cnt--; 14376404edcSAsim Jamshed } 14476404edcSAsim Jamshed } 14576404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 14676404edcSAsim Jamshed inline void 14776404edcSAsim Jamshed UpdateTimeoutList(mtcp_manager_t mtcp, tcp_stream *cur_stream) 14876404edcSAsim Jamshed { 14976404edcSAsim Jamshed if (cur_stream->on_timeout_list) { 15076404edcSAsim Jamshed TAILQ_REMOVE(&mtcp->timeout_list, cur_stream, sndvar->timeout_link); 15176404edcSAsim Jamshed TAILQ_INSERT_TAIL(&mtcp->timeout_list, cur_stream, sndvar->timeout_link); 15276404edcSAsim Jamshed } 15376404edcSAsim Jamshed } 15476404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 15576404edcSAsim Jamshed inline void 15676404edcSAsim Jamshed UpdateRetransmissionTimer(mtcp_manager_t mtcp, 15776404edcSAsim Jamshed tcp_stream *cur_stream, uint32_t cur_ts) 15876404edcSAsim Jamshed { 15976404edcSAsim Jamshed /* Update the retransmission timer */ 16076404edcSAsim Jamshed assert(cur_stream->sndvar->rto > 0); 16176404edcSAsim Jamshed cur_stream->sndvar->nrtx = 0; 16276404edcSAsim Jamshed 16376404edcSAsim Jamshed /* if in rto list, remove it */ 16476404edcSAsim Jamshed if (cur_stream->on_rto_idx >= 0) { 16576404edcSAsim Jamshed RemoveFromRTOList(mtcp, cur_stream); 16676404edcSAsim Jamshed } 16776404edcSAsim Jamshed 16876404edcSAsim Jamshed /* Reset retransmission timeout */ 16976404edcSAsim Jamshed if (TCP_SEQ_GT(cur_stream->snd_nxt, cur_stream->sndvar->snd_una)) { 17076404edcSAsim Jamshed /* there are packets sent but not acked */ 17176404edcSAsim Jamshed /* update rto timestamp */ 17276404edcSAsim Jamshed cur_stream->sndvar->ts_rto = cur_ts + cur_stream->sndvar->rto; 17376404edcSAsim Jamshed AddtoRTOList(mtcp, cur_stream); 17476404edcSAsim Jamshed 17576404edcSAsim Jamshed } else { 17676404edcSAsim Jamshed /* all packets are acked */ 17776404edcSAsim Jamshed TRACE_RTO("All packets are acked. snd_una: %u, snd_nxt: %u\n", 17876404edcSAsim Jamshed cur_stream->sndvar->snd_una, cur_stream->snd_nxt); 17976404edcSAsim Jamshed } 18076404edcSAsim Jamshed } 18176404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 18276404edcSAsim Jamshed static inline int 18376404edcSAsim Jamshed HandleRTO(mtcp_manager_t mtcp, uint32_t cur_ts, tcp_stream *cur_stream) 18476404edcSAsim Jamshed { 18576404edcSAsim Jamshed uint8_t backoff; 18676404edcSAsim Jamshed 18776404edcSAsim Jamshed TRACE_RTO("Stream %d Timeout! rto: %u (%ums), snd_una: %u, snd_nxt: %u\n", 18876404edcSAsim Jamshed cur_stream->id, cur_stream->sndvar->rto, TS_TO_MSEC(cur_stream->sndvar->rto), 18976404edcSAsim Jamshed cur_stream->sndvar->snd_una, cur_stream->snd_nxt); 19076404edcSAsim Jamshed assert(cur_stream->sndvar->rto > 0); 19176404edcSAsim Jamshed 19276404edcSAsim Jamshed /* count number of retransmissions */ 19376404edcSAsim Jamshed if (cur_stream->sndvar->nrtx < TCP_MAX_RTX) { 19476404edcSAsim Jamshed cur_stream->sndvar->nrtx++; 19576404edcSAsim Jamshed } else { 19676404edcSAsim Jamshed /* if it exceeds the threshold, destroy and notify to application */ 19776404edcSAsim Jamshed TRACE_RTO("Stream %d: Exceed MAX_RTX\n", cur_stream->id); 19876404edcSAsim Jamshed if (cur_stream->state < TCP_ST_ESTABLISHED) { 19976404edcSAsim Jamshed cur_stream->state = TCP_ST_CLOSED_RSVD; 20076404edcSAsim Jamshed cur_stream->close_reason = TCP_CONN_FAIL; 20176404edcSAsim Jamshed cur_stream->cb_events |= MOS_ON_TCP_STATE_CHANGE; 20276404edcSAsim Jamshed DestroyTCPStream(mtcp, cur_stream); 20376404edcSAsim Jamshed } else { 20476404edcSAsim Jamshed cur_stream->state = TCP_ST_CLOSED_RSVD; 20576404edcSAsim Jamshed cur_stream->close_reason = TCP_CONN_LOST; 20676404edcSAsim Jamshed cur_stream->cb_events |= MOS_ON_TCP_STATE_CHANGE; 20776404edcSAsim Jamshed if (cur_stream->socket) { 20876404edcSAsim Jamshed RaiseErrorEvent(mtcp, cur_stream); 20976404edcSAsim Jamshed } else { 21076404edcSAsim Jamshed DestroyTCPStream(mtcp, cur_stream); 21176404edcSAsim Jamshed } 21276404edcSAsim Jamshed } 21376404edcSAsim Jamshed return 0; 21476404edcSAsim Jamshed } 21576404edcSAsim Jamshed if (cur_stream->sndvar->nrtx > cur_stream->sndvar->max_nrtx) { 21676404edcSAsim Jamshed cur_stream->sndvar->max_nrtx = cur_stream->sndvar->nrtx; 21776404edcSAsim Jamshed } 21876404edcSAsim Jamshed 21976404edcSAsim Jamshed /* update rto timestamp */ 22076404edcSAsim Jamshed if (cur_stream->state >= TCP_ST_ESTABLISHED) { 22176404edcSAsim Jamshed uint32_t rto_prev; 22276404edcSAsim Jamshed backoff = MIN(cur_stream->sndvar->nrtx, TCP_MAX_BACKOFF); 22376404edcSAsim Jamshed 22476404edcSAsim Jamshed rto_prev = cur_stream->sndvar->rto; 22576404edcSAsim Jamshed cur_stream->sndvar->rto = 22676404edcSAsim Jamshed ((cur_stream->rcvvar->srtt >> 3) + cur_stream->rcvvar->rttvar) << backoff; 22776404edcSAsim Jamshed if (cur_stream->sndvar->rto <= 0) { 22876404edcSAsim Jamshed TRACE_RTO("Stream %d current rto: %u, prev: %u, state: %s\n", 22976404edcSAsim Jamshed cur_stream->id, cur_stream->sndvar->rto, rto_prev, 23076404edcSAsim Jamshed TCPStateToString(cur_stream)); 23176404edcSAsim Jamshed cur_stream->sndvar->rto = rto_prev; 23276404edcSAsim Jamshed } 23376404edcSAsim Jamshed } else if (cur_stream->state >= TCP_ST_SYN_SENT) { 23476404edcSAsim Jamshed /* if there is no rtt measured, update rto based on the previous one */ 23576404edcSAsim Jamshed if (cur_stream->sndvar->nrtx < TCP_MAX_BACKOFF) { 23676404edcSAsim Jamshed cur_stream->sndvar->rto <<= 1; 23776404edcSAsim Jamshed } 23876404edcSAsim Jamshed } 23976404edcSAsim Jamshed //cur_stream->sndvar->ts_rto = cur_ts + cur_stream->sndvar->rto; 24076404edcSAsim Jamshed 24176404edcSAsim Jamshed /* reduce congestion window and ssthresh */ 24276404edcSAsim Jamshed cur_stream->sndvar->ssthresh = MIN(cur_stream->sndvar->cwnd, cur_stream->sndvar->peer_wnd) / 2; 24376404edcSAsim Jamshed if (cur_stream->sndvar->ssthresh < (2 * cur_stream->sndvar->mss)) { 24476404edcSAsim Jamshed cur_stream->sndvar->ssthresh = cur_stream->sndvar->mss * 2; 24576404edcSAsim Jamshed } 24676404edcSAsim Jamshed cur_stream->sndvar->cwnd = cur_stream->sndvar->mss; 24776404edcSAsim Jamshed TRACE_CONG("Stream %d Timeout. cwnd: %u, ssthresh: %u\n", 24876404edcSAsim Jamshed cur_stream->id, cur_stream->sndvar->cwnd, cur_stream->sndvar->ssthresh); 24976404edcSAsim Jamshed 25076404edcSAsim Jamshed #if RTM_STAT 25176404edcSAsim Jamshed /* update retransmission stats */ 25276404edcSAsim Jamshed cur_stream->sndvar->rstat.rto_cnt++; 25376404edcSAsim Jamshed cur_stream->sndvar->rstat.rto_bytes += (cur_stream->snd_nxt - cur_stream->sndvar->snd_una); 25476404edcSAsim Jamshed #endif 25576404edcSAsim Jamshed 25676404edcSAsim Jamshed if (cur_stream->on_rto_idx >= 0) 25776404edcSAsim Jamshed RemoveFromRTOList(mtcp, cur_stream); 25876404edcSAsim Jamshed 25976404edcSAsim Jamshed /* Retransmission */ 26076404edcSAsim Jamshed if (cur_stream->state == TCP_ST_SYN_SENT) { 26176404edcSAsim Jamshed /* SYN lost */ 26276404edcSAsim Jamshed if (cur_stream->sndvar->nrtx > TCP_MAX_SYN_RETRY) { 26376404edcSAsim Jamshed cur_stream->state = TCP_ST_CLOSED_RSVD; 26476404edcSAsim Jamshed cur_stream->close_reason = TCP_CONN_FAIL; 26576404edcSAsim Jamshed cur_stream->cb_events |= MOS_ON_TCP_STATE_CHANGE; 26676404edcSAsim Jamshed TRACE_RTO("Stream %d: SYN retries exceed maximum retries.\n", 26776404edcSAsim Jamshed cur_stream->id); 26876404edcSAsim Jamshed if (cur_stream->socket) { 26976404edcSAsim Jamshed RaiseErrorEvent(mtcp, cur_stream); 27076404edcSAsim Jamshed } else { 27176404edcSAsim Jamshed DestroyTCPStream(mtcp, cur_stream); 27276404edcSAsim Jamshed } 27376404edcSAsim Jamshed 27476404edcSAsim Jamshed return 0; 27576404edcSAsim Jamshed } 27676404edcSAsim Jamshed TRACE_RTO("Stream %d Retransmit SYN. snd_nxt: %u, snd_una: %u\n", 27776404edcSAsim Jamshed cur_stream->id, cur_stream->snd_nxt, cur_stream->sndvar->snd_una); 27876404edcSAsim Jamshed 27976404edcSAsim Jamshed } else if (cur_stream->state == TCP_ST_SYN_RCVD) { 28076404edcSAsim Jamshed /* SYN/ACK lost */ 28176404edcSAsim Jamshed TRACE_RTO("Stream %d: Retransmit SYN/ACK. snd_nxt: %u, snd_una: %u\n", 28276404edcSAsim Jamshed cur_stream->id, cur_stream->snd_nxt, cur_stream->sndvar->snd_una); 28376404edcSAsim Jamshed 28476404edcSAsim Jamshed } else if (cur_stream->state == TCP_ST_ESTABLISHED) { 28576404edcSAsim Jamshed /* Data lost */ 28676404edcSAsim Jamshed TRACE_RTO("Stream %d: Retransmit data. snd_nxt: %u, snd_una: %u\n", 28776404edcSAsim Jamshed cur_stream->id, cur_stream->snd_nxt, cur_stream->sndvar->snd_una); 28876404edcSAsim Jamshed 28976404edcSAsim Jamshed } else if (cur_stream->state == TCP_ST_CLOSE_WAIT) { 29076404edcSAsim Jamshed /* Data lost */ 29176404edcSAsim Jamshed TRACE_RTO("Stream %d: Retransmit data. snd_nxt: %u, snd_una: %u\n", 29276404edcSAsim Jamshed cur_stream->id, cur_stream->snd_nxt, cur_stream->sndvar->snd_una); 29376404edcSAsim Jamshed 29476404edcSAsim Jamshed } else if (cur_stream->state == TCP_ST_LAST_ACK) { 29576404edcSAsim Jamshed /* FIN/ACK lost */ 29676404edcSAsim Jamshed TRACE_RTO("Stream %d: Retransmit FIN/ACK. " 29776404edcSAsim Jamshed "snd_nxt: %u, snd_una: %u\n", 29876404edcSAsim Jamshed cur_stream->id, cur_stream->snd_nxt, cur_stream->sndvar->snd_una); 29976404edcSAsim Jamshed 30076404edcSAsim Jamshed } else if (cur_stream->state == TCP_ST_FIN_WAIT_1) { 30176404edcSAsim Jamshed /* FIN lost */ 30276404edcSAsim Jamshed TRACE_RTO("Stream %d: Retransmit FIN. snd_nxt: %u, snd_una: %u\n", 30376404edcSAsim Jamshed cur_stream->id, cur_stream->snd_nxt, cur_stream->sndvar->snd_una); 30476404edcSAsim Jamshed } else if (cur_stream->state == TCP_ST_CLOSING) { 30576404edcSAsim Jamshed TRACE_RTO("Stream %d: Retransmit ACK. snd_nxt: %u, snd_una: %u\n", 30676404edcSAsim Jamshed cur_stream->id, cur_stream->snd_nxt, cur_stream->sndvar->snd_una); 30776404edcSAsim Jamshed //TRACE_DBG("Stream %d: Retransmitting at CLOSING\n", cur_stream->id); 30876404edcSAsim Jamshed 30976404edcSAsim Jamshed } else if (cur_stream->state == TCP_ST_FIN_WAIT_2) { 31076404edcSAsim Jamshed TRACE_RTO("Stream %d: Retransmit ACK. snd_nxt: %u, snd_una: %u\n", 31176404edcSAsim Jamshed cur_stream->id, cur_stream->snd_nxt, cur_stream->sndvar->snd_una); 31276404edcSAsim Jamshed } else { 31376404edcSAsim Jamshed TRACE_ERROR("Stream %d: not implemented state! state: %s, rto: %u\n", 31476404edcSAsim Jamshed cur_stream->id, 31576404edcSAsim Jamshed TCPStateToString(cur_stream), cur_stream->sndvar->rto); 31676404edcSAsim Jamshed assert(0); 31776404edcSAsim Jamshed return 0; 31876404edcSAsim Jamshed } 31976404edcSAsim Jamshed 32076404edcSAsim Jamshed cur_stream->snd_nxt = cur_stream->sndvar->snd_una; 32176404edcSAsim Jamshed if (cur_stream->state == TCP_ST_ESTABLISHED || 32276404edcSAsim Jamshed cur_stream->state == TCP_ST_CLOSE_WAIT) { 32376404edcSAsim Jamshed /* retransmit data at ESTABLISHED state */ 32476404edcSAsim Jamshed AddtoSendList(mtcp, cur_stream); 32576404edcSAsim Jamshed 32676404edcSAsim Jamshed } else if (cur_stream->state == TCP_ST_FIN_WAIT_1 || 32776404edcSAsim Jamshed cur_stream->state == TCP_ST_CLOSING || 32876404edcSAsim Jamshed cur_stream->state == TCP_ST_LAST_ACK) { 32976404edcSAsim Jamshed 33076404edcSAsim Jamshed if (cur_stream->sndvar->fss == 0) { 33176404edcSAsim Jamshed TRACE_ERROR("Stream %u: fss not set.\n", cur_stream->id); 33276404edcSAsim Jamshed } 33376404edcSAsim Jamshed /* decide to retransmit data or control packet */ 33476404edcSAsim Jamshed if (TCP_SEQ_LT(cur_stream->snd_nxt, cur_stream->sndvar->fss)) { 33576404edcSAsim Jamshed /* need to retransmit data */ 33676404edcSAsim Jamshed if (cur_stream->sndvar->on_control_list) { 33776404edcSAsim Jamshed RemoveFromControlList(mtcp, cur_stream); 33876404edcSAsim Jamshed } 33976404edcSAsim Jamshed cur_stream->control_list_waiting = TRUE; 34076404edcSAsim Jamshed AddtoSendList(mtcp, cur_stream); 34176404edcSAsim Jamshed 34276404edcSAsim Jamshed } else { 34376404edcSAsim Jamshed /* need to retransmit control packet */ 34476404edcSAsim Jamshed AddtoControlList(mtcp, cur_stream, cur_ts); 34576404edcSAsim Jamshed } 34676404edcSAsim Jamshed 34776404edcSAsim Jamshed } else { 34876404edcSAsim Jamshed AddtoControlList(mtcp, cur_stream, cur_ts); 34976404edcSAsim Jamshed } 35076404edcSAsim Jamshed 35176404edcSAsim Jamshed return 1; 35276404edcSAsim Jamshed } 35376404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 35476404edcSAsim Jamshed static inline void 35576404edcSAsim Jamshed RearrangeRTOStore(mtcp_manager_t mtcp) { 35676404edcSAsim Jamshed tcp_stream *walk, *next; 35776404edcSAsim Jamshed struct rto_head* rto_list = &mtcp->rto_store->rto_list[RTO_HASH]; 35876404edcSAsim Jamshed int cnt = 0; 35976404edcSAsim Jamshed 36076404edcSAsim Jamshed for (walk = TAILQ_FIRST(rto_list); 36176404edcSAsim Jamshed walk != NULL; walk = next) { 36276404edcSAsim Jamshed next = TAILQ_NEXT(walk, sndvar->timer_link); 36376404edcSAsim Jamshed 36476404edcSAsim Jamshed int diff = (int32_t)(mtcp->rto_store->rto_now_ts - walk->sndvar->ts_rto); 36576404edcSAsim Jamshed if (diff < RTO_HASH) { 36676404edcSAsim Jamshed //int offset = (diff + mtcp->rto_store->rto_now_idx) % RTO_HASH; 36776404edcSAsim Jamshed int offset = ((diff + mtcp->rto_store->rto_now_idx) & (RTO_HASH - 1)); 36876404edcSAsim Jamshed if (!TAILQ_EMPTY(&mtcp->rto_store->rto_list[RTO_HASH])) { 36976404edcSAsim Jamshed TAILQ_REMOVE(&mtcp->rto_store->rto_list[RTO_HASH], 37076404edcSAsim Jamshed walk, sndvar->timer_link); 37176404edcSAsim Jamshed walk->on_rto_idx = offset; 37276404edcSAsim Jamshed TAILQ_INSERT_TAIL(&(mtcp->rto_store->rto_list[offset]), 37376404edcSAsim Jamshed walk, sndvar->timer_link); 37476404edcSAsim Jamshed } 37576404edcSAsim Jamshed } 37676404edcSAsim Jamshed cnt++; 37776404edcSAsim Jamshed } 37876404edcSAsim Jamshed } 37976404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 38076404edcSAsim Jamshed void 38176404edcSAsim Jamshed CheckRtmTimeout(mtcp_manager_t mtcp, uint32_t cur_ts, int thresh) 38276404edcSAsim Jamshed { 38376404edcSAsim Jamshed tcp_stream *walk, *next; 38476404edcSAsim Jamshed struct rto_head* rto_list; 38576404edcSAsim Jamshed int cnt; 38676404edcSAsim Jamshed 38776404edcSAsim Jamshed if (!mtcp->rto_list_cnt) { 38876404edcSAsim Jamshed return; 38976404edcSAsim Jamshed } 39076404edcSAsim Jamshed 39176404edcSAsim Jamshed STAT_COUNT(mtcp->runstat.rounds_rtocheck); 39276404edcSAsim Jamshed 39376404edcSAsim Jamshed cnt = 0; 39476404edcSAsim Jamshed 39576404edcSAsim Jamshed while (1) { 39676404edcSAsim Jamshed 39776404edcSAsim Jamshed rto_list = &mtcp->rto_store->rto_list[mtcp->rto_store->rto_now_idx]; 39876404edcSAsim Jamshed if ((int32_t)(cur_ts - mtcp->rto_store->rto_now_ts) < 0) { 39976404edcSAsim Jamshed break; 40076404edcSAsim Jamshed } 40176404edcSAsim Jamshed 40276404edcSAsim Jamshed for (walk = TAILQ_FIRST(rto_list); 40376404edcSAsim Jamshed walk != NULL; walk = next) { 40476404edcSAsim Jamshed if (++cnt > thresh) { 40576404edcSAsim Jamshed break; 40676404edcSAsim Jamshed } 40776404edcSAsim Jamshed next = TAILQ_NEXT(walk, sndvar->timer_link); 40876404edcSAsim Jamshed 40976404edcSAsim Jamshed TRACE_LOOP("Inside rto list. cnt: %u, stream: %d\n", 41076404edcSAsim Jamshed cnt, walk->s_id); 41176404edcSAsim Jamshed 41276404edcSAsim Jamshed if (walk->on_rto_idx >= 0) { 41376404edcSAsim Jamshed TAILQ_REMOVE(rto_list, walk, sndvar->timer_link); 41476404edcSAsim Jamshed mtcp->rto_list_cnt--; 41576404edcSAsim Jamshed walk->on_rto_idx = -1; 41676404edcSAsim Jamshed HandleRTO(mtcp, cur_ts, walk); 41776404edcSAsim Jamshed } else { 41876404edcSAsim Jamshed TRACE_ERROR("Stream %d: not on rto list.\n", walk->id); 41976404edcSAsim Jamshed #ifdef DUMP_STREAM 42076404edcSAsim Jamshed DumpStream(mtcp, walk); 42176404edcSAsim Jamshed #endif 42276404edcSAsim Jamshed } 42376404edcSAsim Jamshed } 42476404edcSAsim Jamshed 42576404edcSAsim Jamshed if (cnt > thresh) { 42676404edcSAsim Jamshed break; 42776404edcSAsim Jamshed } else { 42876404edcSAsim Jamshed mtcp->rto_store->rto_now_idx = ((mtcp->rto_store->rto_now_idx + 1) & (RTO_HASH - 1)); 42976404edcSAsim Jamshed mtcp->rto_store->rto_now_ts++; 43076404edcSAsim Jamshed if (!((mtcp->rto_store->rto_now_idx & (1024 - 1)))) { 43176404edcSAsim Jamshed RearrangeRTOStore(mtcp); 43276404edcSAsim Jamshed } 43376404edcSAsim Jamshed } 43476404edcSAsim Jamshed 43576404edcSAsim Jamshed } 43676404edcSAsim Jamshed 43776404edcSAsim Jamshed TRACE_ROUND("Checking retransmission timeout. cnt: %d\n", cnt); 43876404edcSAsim Jamshed } 43976404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 44076404edcSAsim Jamshed void 44176404edcSAsim Jamshed CheckTimewaitExpire(mtcp_manager_t mtcp, uint32_t cur_ts, int thresh) 44276404edcSAsim Jamshed { 44376404edcSAsim Jamshed tcp_stream *walk, *next; 44476404edcSAsim Jamshed int cnt; 44576404edcSAsim Jamshed 44676404edcSAsim Jamshed STAT_COUNT(mtcp->runstat.rounds_twcheck); 44776404edcSAsim Jamshed 44876404edcSAsim Jamshed cnt = 0; 44976404edcSAsim Jamshed 45076404edcSAsim Jamshed for (walk = TAILQ_FIRST(&mtcp->timewait_list); 45176404edcSAsim Jamshed walk != NULL; walk = next) { 45276404edcSAsim Jamshed if (++cnt > thresh) 45376404edcSAsim Jamshed break; 45476404edcSAsim Jamshed next = TAILQ_NEXT(walk, sndvar->timer_link); 45576404edcSAsim Jamshed 45676404edcSAsim Jamshed TRACE_LOOP("Inside timewait list. cnt: %u, stream: %d\n", 45776404edcSAsim Jamshed cnt, walk->s_id); 45876404edcSAsim Jamshed 45976404edcSAsim Jamshed if (walk->on_timewait_list) { 46076404edcSAsim Jamshed if ((int32_t)(cur_ts - walk->rcvvar->ts_tw_expire) >= 0) { 46176404edcSAsim Jamshed if (!walk->sndvar->on_control_list) { 46276404edcSAsim Jamshed 46376404edcSAsim Jamshed TAILQ_REMOVE(&mtcp->timewait_list, walk, sndvar->timer_link); 46476404edcSAsim Jamshed walk->on_timewait_list = FALSE; 46576404edcSAsim Jamshed mtcp->timewait_list_cnt--; 46676404edcSAsim Jamshed 46776404edcSAsim Jamshed walk->state = TCP_ST_CLOSED_RSVD; 46876404edcSAsim Jamshed walk->close_reason = TCP_ACTIVE_CLOSE; 46976404edcSAsim Jamshed walk->cb_events |= MOS_ON_TCP_STATE_CHANGE; 47076404edcSAsim Jamshed TRACE_STATE("Stream %d: TCP_ST_CLOSED_RSVD\n", walk->id); 47176404edcSAsim Jamshed DestroyTCPStream(mtcp, walk); 47276404edcSAsim Jamshed } 47376404edcSAsim Jamshed } else { 47476404edcSAsim Jamshed break; 47576404edcSAsim Jamshed } 47676404edcSAsim Jamshed } else { 47776404edcSAsim Jamshed TRACE_ERROR("Stream %d: not on timewait list.\n", walk->id); 47876404edcSAsim Jamshed #ifdef DUMP_STREAM 47976404edcSAsim Jamshed DumpStream(mtcp, walk); 48076404edcSAsim Jamshed #endif 48176404edcSAsim Jamshed } 48276404edcSAsim Jamshed } 48376404edcSAsim Jamshed 48476404edcSAsim Jamshed TRACE_ROUND("Checking timewait timeout. cnt: %d\n", cnt); 48576404edcSAsim Jamshed } 48676404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 48776404edcSAsim Jamshed void 48876404edcSAsim Jamshed CheckConnectionTimeout(mtcp_manager_t mtcp, uint32_t cur_ts, int thresh) 48976404edcSAsim Jamshed { 49076404edcSAsim Jamshed tcp_stream *walk, *next; 49176404edcSAsim Jamshed int cnt; 49276404edcSAsim Jamshed 49376404edcSAsim Jamshed STAT_COUNT(mtcp->runstat.rounds_tocheck); 49476404edcSAsim Jamshed 49576404edcSAsim Jamshed cnt = 0; 49676404edcSAsim Jamshed for (walk = TAILQ_FIRST(&mtcp->timeout_list); 49776404edcSAsim Jamshed walk != NULL; walk = next) { 49876404edcSAsim Jamshed if (++cnt > thresh) 49976404edcSAsim Jamshed break; 50076404edcSAsim Jamshed next = TAILQ_NEXT(walk, sndvar->timeout_link); 50176404edcSAsim Jamshed 50276404edcSAsim Jamshed if ((int32_t)(cur_ts - walk->last_active_ts) >= 50376404edcSAsim Jamshed g_config.mos->tcp_timeout) { 50476404edcSAsim Jamshed 505*cafe7743SAsim Jamshed TRACE_DBG("stream-state: %s, streampair-state: %s\n", 50676404edcSAsim Jamshed TCPStateToString(walk), 50776404edcSAsim Jamshed TCPStateToString(walk->pair_stream)); 50876404edcSAsim Jamshed 50976404edcSAsim Jamshed walk->on_timeout_list = FALSE; 51076404edcSAsim Jamshed TAILQ_REMOVE(&mtcp->timeout_list, walk, sndvar->timeout_link); 51176404edcSAsim Jamshed mtcp->timeout_list_cnt--; 51276404edcSAsim Jamshed walk->state = TCP_ST_CLOSED_RSVD; 51376404edcSAsim Jamshed walk->close_reason = TCP_TIMEDOUT; 51476404edcSAsim Jamshed walk->cb_events |= MOS_ON_TCP_STATE_CHANGE; 51576404edcSAsim Jamshed if (walk->socket && HAS_STREAM_TYPE(walk, MOS_SOCK_STREAM)) { 51676404edcSAsim Jamshed RaiseErrorEvent(mtcp, walk); 51776404edcSAsim Jamshed } else { 51876404edcSAsim Jamshed DestroyTCPStream(mtcp, walk); 51976404edcSAsim Jamshed } 52076404edcSAsim Jamshed } else { 52176404edcSAsim Jamshed break; 52276404edcSAsim Jamshed } 52376404edcSAsim Jamshed 52476404edcSAsim Jamshed } 52576404edcSAsim Jamshed } 52676404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 52776404edcSAsim Jamshed #define TIMEVAL_ADD(a, b) \ 52876404edcSAsim Jamshed do { (a)->tv_sec += (b)->tv_sec; \ 52976404edcSAsim Jamshed if (((a)->tv_usec += (b)->tv_usec) > 1000000) { \ 53076404edcSAsim Jamshed (a)->tv_sec++; (a)->tv_usec -= 1000000; } \ 53176404edcSAsim Jamshed } while (0) 53276404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 53376404edcSAsim Jamshed static int 53476404edcSAsim Jamshed RegTimer(mtcp_manager_t mtcp, struct timer *timer) 53576404edcSAsim Jamshed { 53676404edcSAsim Jamshed /* NOTE: This code assumes that the new timer expires later than existing 53776404edcSAsim Jamshed * timers with high probability. */ 53876404edcSAsim Jamshed struct timer *walk; 53976404edcSAsim Jamshed 54076404edcSAsim Jamshed TAILQ_FOREACH_REVERSE(walk, &mtcp->timer_list, timer_head, timer_link) { 54176404edcSAsim Jamshed if (TIMEVAL_LT(&walk->exp, &timer->exp)) { 54276404edcSAsim Jamshed TAILQ_INSERT_AFTER(&mtcp->timer_list, walk, timer, timer_link); 54376404edcSAsim Jamshed return 0; 54476404edcSAsim Jamshed } 54576404edcSAsim Jamshed } 54676404edcSAsim Jamshed 54776404edcSAsim Jamshed assert(!walk); 54876404edcSAsim Jamshed 54976404edcSAsim Jamshed TAILQ_INSERT_HEAD(&mtcp->timer_list, timer, timer_link); 55076404edcSAsim Jamshed return 0; 55176404edcSAsim Jamshed } 55276404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 55376404edcSAsim Jamshed static struct timer * 55476404edcSAsim Jamshed NewTimer(mtcp_manager_t mtcp, int id, struct timeval *timeout, callback_t cb) 55576404edcSAsim Jamshed { 55676404edcSAsim Jamshed #ifdef USE_TIMER_POOL 55776404edcSAsim Jamshed struct timer *t = MPAllocateChunk(mtcp->timer_pool); 55876404edcSAsim Jamshed #else 55976404edcSAsim Jamshed struct timer *t = calloc(1, sizeof(struct timer)); 56076404edcSAsim Jamshed #endif 56176404edcSAsim Jamshed if (!t) 56276404edcSAsim Jamshed return NULL; 56376404edcSAsim Jamshed 56476404edcSAsim Jamshed t->id = id; 56576404edcSAsim Jamshed t->cb = cb; 56676404edcSAsim Jamshed gettimeofday(&t->exp, NULL); 56776404edcSAsim Jamshed TIMEVAL_ADD(&t->exp, timeout); 56876404edcSAsim Jamshed 56976404edcSAsim Jamshed return t; 57076404edcSAsim Jamshed } 57176404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 57276404edcSAsim Jamshed void 57376404edcSAsim Jamshed DelTimer(mtcp_manager_t mtcp, struct timer *timer) 57476404edcSAsim Jamshed { 57576404edcSAsim Jamshed TAILQ_REMOVE(&mtcp->timer_list, timer, timer_link); 57676404edcSAsim Jamshed #ifdef USE_TIMER_POOL 57776404edcSAsim Jamshed MPFreeChunk(mtcp->timer_pool, timer); 57876404edcSAsim Jamshed #else 57976404edcSAsim Jamshed free(timer); 58076404edcSAsim Jamshed #endif 58176404edcSAsim Jamshed } 58276404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 58376404edcSAsim Jamshed int 58476404edcSAsim Jamshed mtcp_settimer(mctx_t mctx, int id, struct timeval *timeout, callback_t cb) 58576404edcSAsim Jamshed { 58676404edcSAsim Jamshed mtcp_manager_t mtcp = GetMTCPManager(mctx); 58776404edcSAsim Jamshed if (!mtcp) 58876404edcSAsim Jamshed return -1; 58976404edcSAsim Jamshed 59076404edcSAsim Jamshed struct timer *t = NewTimer(mtcp, id, timeout, cb); 59176404edcSAsim Jamshed if (!t) 59276404edcSAsim Jamshed return -1; 59376404edcSAsim Jamshed 59476404edcSAsim Jamshed RegTimer(mtcp, t); 59576404edcSAsim Jamshed 59676404edcSAsim Jamshed return 0; 59776404edcSAsim Jamshed } 59876404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 599