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*
InitRTOHashstore()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
AddtoRTOList(mtcp_manager_t mtcp,tcp_stream * cur_stream)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
RemoveFromRTOList(mtcp_manager_t mtcp,tcp_stream * cur_stream)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
AddtoTimewaitList(mtcp_manager_t mtcp,tcp_stream * cur_stream,uint32_t cur_ts)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
RemoveFromTimewaitList(mtcp_manager_t mtcp,tcp_stream * cur_stream)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
AddtoTimeoutList(mtcp_manager_t mtcp,tcp_stream * cur_stream)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
RemoveFromTimeoutList(mtcp_manager_t mtcp,tcp_stream * cur_stream)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
UpdateTimeoutList(mtcp_manager_t mtcp,tcp_stream * cur_stream)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
UpdateRetransmissionTimer(mtcp_manager_t mtcp,tcp_stream * cur_stream,uint32_t cur_ts)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
HandleRTO(mtcp_manager_t mtcp,uint32_t cur_ts,tcp_stream * cur_stream)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
RearrangeRTOStore(mtcp_manager_t mtcp)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
CheckRtmTimeout(mtcp_manager_t mtcp,uint32_t cur_ts,int thresh)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
CheckTimewaitExpire(mtcp_manager_t mtcp,uint32_t cur_ts,int thresh)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) {
4608c9e1184SAsim Jamshed /* wait until the other end is finished in monitoring socket */
4618c9e1184SAsim Jamshed if ((walk->pair_stream != NULL)
4628c9e1184SAsim Jamshed && (walk->pair_stream->state != TCP_ST_CLOSED_RSVD)
4638c9e1184SAsim Jamshed && (walk->pair_stream->state != TCP_ST_TIME_WAIT))
4648c9e1184SAsim Jamshed continue;
4658c9e1184SAsim Jamshed
46676404edcSAsim Jamshed if ((int32_t)(cur_ts - walk->rcvvar->ts_tw_expire) >= 0) {
46776404edcSAsim Jamshed if (!walk->sndvar->on_control_list) {
46876404edcSAsim Jamshed
46976404edcSAsim Jamshed TAILQ_REMOVE(&mtcp->timewait_list, walk, sndvar->timer_link);
47076404edcSAsim Jamshed walk->on_timewait_list = FALSE;
47176404edcSAsim Jamshed mtcp->timewait_list_cnt--;
47276404edcSAsim Jamshed
47376404edcSAsim Jamshed walk->state = TCP_ST_CLOSED_RSVD;
47476404edcSAsim Jamshed walk->close_reason = TCP_ACTIVE_CLOSE;
47576404edcSAsim Jamshed walk->cb_events |= MOS_ON_TCP_STATE_CHANGE;
47676404edcSAsim Jamshed TRACE_STATE("Stream %d: TCP_ST_CLOSED_RSVD\n", walk->id);
47776404edcSAsim Jamshed DestroyTCPStream(mtcp, walk);
47876404edcSAsim Jamshed }
47976404edcSAsim Jamshed } else {
48076404edcSAsim Jamshed break;
48176404edcSAsim Jamshed }
48276404edcSAsim Jamshed } else {
48376404edcSAsim Jamshed TRACE_ERROR("Stream %d: not on timewait list.\n", walk->id);
48476404edcSAsim Jamshed #ifdef DUMP_STREAM
48576404edcSAsim Jamshed DumpStream(mtcp, walk);
48676404edcSAsim Jamshed #endif
48776404edcSAsim Jamshed }
48876404edcSAsim Jamshed }
48976404edcSAsim Jamshed
49076404edcSAsim Jamshed TRACE_ROUND("Checking timewait timeout. cnt: %d\n", cnt);
49176404edcSAsim Jamshed }
49276404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
49376404edcSAsim Jamshed void
CheckConnectionTimeout(mtcp_manager_t mtcp,uint32_t cur_ts,int thresh)49476404edcSAsim Jamshed CheckConnectionTimeout(mtcp_manager_t mtcp, uint32_t cur_ts, int thresh)
49576404edcSAsim Jamshed {
49676404edcSAsim Jamshed tcp_stream *walk, *next;
49776404edcSAsim Jamshed int cnt;
49876404edcSAsim Jamshed
49976404edcSAsim Jamshed STAT_COUNT(mtcp->runstat.rounds_tocheck);
50076404edcSAsim Jamshed
50176404edcSAsim Jamshed cnt = 0;
50276404edcSAsim Jamshed for (walk = TAILQ_FIRST(&mtcp->timeout_list);
50376404edcSAsim Jamshed walk != NULL; walk = next) {
50476404edcSAsim Jamshed if (++cnt > thresh)
50576404edcSAsim Jamshed break;
50676404edcSAsim Jamshed next = TAILQ_NEXT(walk, sndvar->timeout_link);
50776404edcSAsim Jamshed
50876404edcSAsim Jamshed if ((int32_t)(cur_ts - walk->last_active_ts) >=
50976404edcSAsim Jamshed g_config.mos->tcp_timeout) {
51076404edcSAsim Jamshed
511cafe7743SAsim Jamshed TRACE_DBG("stream-state: %s, streampair-state: %s\n",
51276404edcSAsim Jamshed TCPStateToString(walk),
51376404edcSAsim Jamshed TCPStateToString(walk->pair_stream));
51476404edcSAsim Jamshed
51576404edcSAsim Jamshed walk->on_timeout_list = FALSE;
51676404edcSAsim Jamshed TAILQ_REMOVE(&mtcp->timeout_list, walk, sndvar->timeout_link);
51776404edcSAsim Jamshed mtcp->timeout_list_cnt--;
51876404edcSAsim Jamshed walk->state = TCP_ST_CLOSED_RSVD;
51976404edcSAsim Jamshed walk->close_reason = TCP_TIMEDOUT;
52076404edcSAsim Jamshed walk->cb_events |= MOS_ON_TCP_STATE_CHANGE;
52176404edcSAsim Jamshed if (walk->socket && HAS_STREAM_TYPE(walk, MOS_SOCK_STREAM)) {
52276404edcSAsim Jamshed RaiseErrorEvent(mtcp, walk);
52376404edcSAsim Jamshed } else {
52476404edcSAsim Jamshed DestroyTCPStream(mtcp, walk);
52576404edcSAsim Jamshed }
52676404edcSAsim Jamshed } else {
52776404edcSAsim Jamshed break;
52876404edcSAsim Jamshed }
52976404edcSAsim Jamshed
53076404edcSAsim Jamshed }
53176404edcSAsim Jamshed }
53276404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
53376404edcSAsim Jamshed static int
RegTimer(mtcp_manager_t mtcp,struct timer * timer)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 *
NewTimer(mtcp_manager_t mtcp,int id,struct timeval * timeout,callback_t cb)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
DelTimer(mtcp_manager_t mtcp,struct timer * timer)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
mtcp_settimer(mctx_t mctx,int id,struct timeval * timeout,callback_t cb)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);
587*05e3289cSYoungGyoun if (!mtcp || !timeout || !cb)
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