1 #include "timer.h"
2 #include "tcp_in.h"
3 #include "tcp_out.h"
4 #include "stat.h"
5 #include "debug.h"
6 #include "memory_mgt.h"
7 #include "config.h"
8
9 #define MAX(a, b) ((a)>(b)?(a):(b))
10 #define MIN(a, b) ((a)<(b)?(a):(b))
11
12 /*----------------------------------------------------------------------------*/
13 struct rto_hashstore*
InitRTOHashstore()14 InitRTOHashstore()
15 {
16 int i;
17 struct rto_hashstore* hs = calloc(1, sizeof(struct rto_hashstore));
18 if (!hs) {
19 TRACE_ERROR("calloc: InitHashStore");
20 return 0;
21 }
22
23 for (i = 0; i < RTO_HASH; i++)
24 TAILQ_INIT(&hs->rto_list[i]);
25
26 TAILQ_INIT(&hs->rto_list[RTO_HASH]);
27
28 return hs;
29 }
30 /*----------------------------------------------------------------------------*/
31 inline void
AddtoRTOList(mtcp_manager_t mtcp,tcp_stream * cur_stream)32 AddtoRTOList(mtcp_manager_t mtcp, tcp_stream *cur_stream)
33 {
34 if (!mtcp->rto_list_cnt) {
35 mtcp->rto_store->rto_now_idx = 0;
36 mtcp->rto_store->rto_now_ts = cur_stream->sndvar->ts_rto;
37 }
38
39 if (cur_stream->on_rto_idx < 0 ) {
40 if (cur_stream->on_timewait_list) {
41 TRACE_ERROR("Stream %u: cannot be in both "
42 "rto and timewait list.\n", cur_stream->id);
43 #ifdef DUMP_STREAM
44 DumpStream(mtcp, cur_stream);
45 #endif
46 return;
47 }
48
49 int diff = (int32_t)(cur_stream->sndvar->ts_rto - mtcp->rto_store->rto_now_ts);
50 #if 0
51 if (diff < RTO_HASH) {
52 #else
53 int offset= ((diff + mtcp->rto_store->rto_now_idx) & (RTO_HASH - 1));
54 cur_stream->on_rto_idx = offset;
55 TAILQ_INSERT_TAIL(&(mtcp->rto_store->rto_list[offset]),
56 cur_stream, sndvar->timer_link);
57 #endif
58 #if 0
59 } else {
60 cur_stream->on_rto_idx = RTO_HASH;
61 TAILQ_INSERT_TAIL(&(mtcp->rto_store->rto_list[RTO_HASH]),
62 cur_stream, sndvar->timer_link);
63 }
64 #endif
65 mtcp->rto_list_cnt++;
66 }
67 }
68 /*----------------------------------------------------------------------------*/
69 inline void
RemoveFromRTOList(mtcp_manager_t mtcp,tcp_stream * cur_stream)70 RemoveFromRTOList(mtcp_manager_t mtcp, tcp_stream *cur_stream)
71 {
72 if (cur_stream->on_rto_idx < 0) {
73 // assert(0);
74 return;
75 }
76
77 TAILQ_REMOVE(&mtcp->rto_store->rto_list[cur_stream->on_rto_idx],
78 cur_stream, sndvar->timer_link);
79 cur_stream->on_rto_idx = -1;
80
81 mtcp->rto_list_cnt--;
82 }
83 /*----------------------------------------------------------------------------*/
84 inline void
AddtoTimewaitList(mtcp_manager_t mtcp,tcp_stream * cur_stream,uint32_t cur_ts)85 AddtoTimewaitList(mtcp_manager_t mtcp, tcp_stream *cur_stream, uint32_t cur_ts)
86 {
87 cur_stream->rcvvar->ts_tw_expire = cur_ts + g_config.mos->tcp_tw_interval;
88
89 if (cur_stream->on_timewait_list) {
90 // Update list in sorted way by ts_tw_expire
91 TAILQ_REMOVE(&mtcp->timewait_list, cur_stream, sndvar->timer_link);
92 TAILQ_INSERT_TAIL(&mtcp->timewait_list, cur_stream, sndvar->timer_link);
93 } else {
94 if (cur_stream->on_rto_idx >= 0) {
95 TRACE_DBG("Stream %u: cannot be in both "
96 "timewait and rto list.\n", cur_stream->id);
97 //assert(0);
98 #ifdef DUMP_STREAM
99 DumpStream(mtcp, cur_stream);
100 #endif
101 RemoveFromRTOList(mtcp, cur_stream);
102 }
103
104 cur_stream->on_timewait_list = TRUE;
105 TAILQ_INSERT_TAIL(&mtcp->timewait_list, cur_stream, sndvar->timer_link);
106 mtcp->timewait_list_cnt++;
107 }
108 }
109 /*----------------------------------------------------------------------------*/
110 inline void
RemoveFromTimewaitList(mtcp_manager_t mtcp,tcp_stream * cur_stream)111 RemoveFromTimewaitList(mtcp_manager_t mtcp, tcp_stream *cur_stream)
112 {
113 if (!cur_stream->on_timewait_list) {
114 //assert(0);
115 return;
116 }
117
118 TAILQ_REMOVE(&mtcp->timewait_list, cur_stream, sndvar->timer_link);
119 cur_stream->on_timewait_list = FALSE;
120 mtcp->timewait_list_cnt--;
121 }
122 /*----------------------------------------------------------------------------*/
123 inline void
AddtoTimeoutList(mtcp_manager_t mtcp,tcp_stream * cur_stream)124 AddtoTimeoutList(mtcp_manager_t mtcp, tcp_stream *cur_stream)
125 {
126 if (cur_stream->on_timeout_list) {
127 //assert(0);
128 return;
129 }
130
131 cur_stream->on_timeout_list = TRUE;
132 TAILQ_INSERT_TAIL(&mtcp->timeout_list, cur_stream, sndvar->timeout_link);
133 mtcp->timeout_list_cnt++;
134 }
135 /*----------------------------------------------------------------------------*/
136 inline void
RemoveFromTimeoutList(mtcp_manager_t mtcp,tcp_stream * cur_stream)137 RemoveFromTimeoutList(mtcp_manager_t mtcp, tcp_stream *cur_stream)
138 {
139 if (cur_stream->on_timeout_list) {
140 cur_stream->on_timeout_list = FALSE;
141 TAILQ_REMOVE(&mtcp->timeout_list, cur_stream, sndvar->timeout_link);
142 mtcp->timeout_list_cnt--;
143 }
144 }
145 /*----------------------------------------------------------------------------*/
146 inline void
UpdateTimeoutList(mtcp_manager_t mtcp,tcp_stream * cur_stream)147 UpdateTimeoutList(mtcp_manager_t mtcp, tcp_stream *cur_stream)
148 {
149 if (cur_stream->on_timeout_list) {
150 TAILQ_REMOVE(&mtcp->timeout_list, cur_stream, sndvar->timeout_link);
151 TAILQ_INSERT_TAIL(&mtcp->timeout_list, cur_stream, sndvar->timeout_link);
152 }
153 }
154 /*----------------------------------------------------------------------------*/
155 inline void
UpdateRetransmissionTimer(mtcp_manager_t mtcp,tcp_stream * cur_stream,uint32_t cur_ts)156 UpdateRetransmissionTimer(mtcp_manager_t mtcp,
157 tcp_stream *cur_stream, uint32_t cur_ts)
158 {
159 /* Update the retransmission timer */
160 assert(cur_stream->sndvar->rto > 0);
161 cur_stream->sndvar->nrtx = 0;
162
163 /* if in rto list, remove it */
164 if (cur_stream->on_rto_idx >= 0) {
165 RemoveFromRTOList(mtcp, cur_stream);
166 }
167
168 /* Reset retransmission timeout */
169 if (TCP_SEQ_GT(cur_stream->snd_nxt, cur_stream->sndvar->snd_una)) {
170 /* there are packets sent but not acked */
171 /* update rto timestamp */
172 cur_stream->sndvar->ts_rto = cur_ts + cur_stream->sndvar->rto;
173 AddtoRTOList(mtcp, cur_stream);
174
175 } else {
176 /* all packets are acked */
177 TRACE_RTO("All packets are acked. snd_una: %u, snd_nxt: %u\n",
178 cur_stream->sndvar->snd_una, cur_stream->snd_nxt);
179 }
180 }
181 /*----------------------------------------------------------------------------*/
182 static inline int
HandleRTO(mtcp_manager_t mtcp,uint32_t cur_ts,tcp_stream * cur_stream)183 HandleRTO(mtcp_manager_t mtcp, uint32_t cur_ts, tcp_stream *cur_stream)
184 {
185 uint8_t backoff;
186
187 TRACE_RTO("Stream %d Timeout! rto: %u (%ums), snd_una: %u, snd_nxt: %u\n",
188 cur_stream->id, cur_stream->sndvar->rto, TS_TO_MSEC(cur_stream->sndvar->rto),
189 cur_stream->sndvar->snd_una, cur_stream->snd_nxt);
190 assert(cur_stream->sndvar->rto > 0);
191
192 /* count number of retransmissions */
193 if (cur_stream->sndvar->nrtx < TCP_MAX_RTX) {
194 cur_stream->sndvar->nrtx++;
195 } else {
196 /* if it exceeds the threshold, destroy and notify to application */
197 TRACE_RTO("Stream %d: Exceed MAX_RTX\n", cur_stream->id);
198 if (cur_stream->state < TCP_ST_ESTABLISHED) {
199 cur_stream->state = TCP_ST_CLOSED_RSVD;
200 cur_stream->close_reason = TCP_CONN_FAIL;
201 cur_stream->cb_events |= MOS_ON_TCP_STATE_CHANGE;
202 DestroyTCPStream(mtcp, cur_stream);
203 } else {
204 cur_stream->state = TCP_ST_CLOSED_RSVD;
205 cur_stream->close_reason = TCP_CONN_LOST;
206 cur_stream->cb_events |= MOS_ON_TCP_STATE_CHANGE;
207 if (cur_stream->socket) {
208 RaiseErrorEvent(mtcp, cur_stream);
209 } else {
210 DestroyTCPStream(mtcp, cur_stream);
211 }
212 }
213 return 0;
214 }
215 if (cur_stream->sndvar->nrtx > cur_stream->sndvar->max_nrtx) {
216 cur_stream->sndvar->max_nrtx = cur_stream->sndvar->nrtx;
217 }
218
219 /* update rto timestamp */
220 if (cur_stream->state >= TCP_ST_ESTABLISHED) {
221 uint32_t rto_prev;
222 backoff = MIN(cur_stream->sndvar->nrtx, TCP_MAX_BACKOFF);
223
224 rto_prev = cur_stream->sndvar->rto;
225 cur_stream->sndvar->rto =
226 ((cur_stream->rcvvar->srtt >> 3) + cur_stream->rcvvar->rttvar) << backoff;
227 if (cur_stream->sndvar->rto <= 0) {
228 TRACE_RTO("Stream %d current rto: %u, prev: %u, state: %s\n",
229 cur_stream->id, cur_stream->sndvar->rto, rto_prev,
230 TCPStateToString(cur_stream));
231 cur_stream->sndvar->rto = rto_prev;
232 }
233 } else if (cur_stream->state >= TCP_ST_SYN_SENT) {
234 /* if there is no rtt measured, update rto based on the previous one */
235 if (cur_stream->sndvar->nrtx < TCP_MAX_BACKOFF) {
236 cur_stream->sndvar->rto <<= 1;
237 }
238 }
239 //cur_stream->sndvar->ts_rto = cur_ts + cur_stream->sndvar->rto;
240
241 /* reduce congestion window and ssthresh */
242 cur_stream->sndvar->ssthresh = MIN(cur_stream->sndvar->cwnd, cur_stream->sndvar->peer_wnd) / 2;
243 if (cur_stream->sndvar->ssthresh < (2 * cur_stream->sndvar->mss)) {
244 cur_stream->sndvar->ssthresh = cur_stream->sndvar->mss * 2;
245 }
246 cur_stream->sndvar->cwnd = cur_stream->sndvar->mss;
247 TRACE_CONG("Stream %d Timeout. cwnd: %u, ssthresh: %u\n",
248 cur_stream->id, cur_stream->sndvar->cwnd, cur_stream->sndvar->ssthresh);
249
250 #if RTM_STAT
251 /* update retransmission stats */
252 cur_stream->sndvar->rstat.rto_cnt++;
253 cur_stream->sndvar->rstat.rto_bytes += (cur_stream->snd_nxt - cur_stream->sndvar->snd_una);
254 #endif
255
256 if (cur_stream->on_rto_idx >= 0)
257 RemoveFromRTOList(mtcp, cur_stream);
258
259 /* Retransmission */
260 if (cur_stream->state == TCP_ST_SYN_SENT) {
261 /* SYN lost */
262 if (cur_stream->sndvar->nrtx > TCP_MAX_SYN_RETRY) {
263 cur_stream->state = TCP_ST_CLOSED_RSVD;
264 cur_stream->close_reason = TCP_CONN_FAIL;
265 cur_stream->cb_events |= MOS_ON_TCP_STATE_CHANGE;
266 TRACE_RTO("Stream %d: SYN retries exceed maximum retries.\n",
267 cur_stream->id);
268 if (cur_stream->socket) {
269 RaiseErrorEvent(mtcp, cur_stream);
270 } else {
271 DestroyTCPStream(mtcp, cur_stream);
272 }
273
274 return 0;
275 }
276 TRACE_RTO("Stream %d Retransmit SYN. snd_nxt: %u, snd_una: %u\n",
277 cur_stream->id, cur_stream->snd_nxt, cur_stream->sndvar->snd_una);
278
279 } else if (cur_stream->state == TCP_ST_SYN_RCVD) {
280 /* SYN/ACK lost */
281 TRACE_RTO("Stream %d: Retransmit SYN/ACK. snd_nxt: %u, snd_una: %u\n",
282 cur_stream->id, cur_stream->snd_nxt, cur_stream->sndvar->snd_una);
283
284 } else if (cur_stream->state == TCP_ST_ESTABLISHED) {
285 /* Data lost */
286 TRACE_RTO("Stream %d: Retransmit data. snd_nxt: %u, snd_una: %u\n",
287 cur_stream->id, cur_stream->snd_nxt, cur_stream->sndvar->snd_una);
288
289 } else if (cur_stream->state == TCP_ST_CLOSE_WAIT) {
290 /* Data lost */
291 TRACE_RTO("Stream %d: Retransmit data. snd_nxt: %u, snd_una: %u\n",
292 cur_stream->id, cur_stream->snd_nxt, cur_stream->sndvar->snd_una);
293
294 } else if (cur_stream->state == TCP_ST_LAST_ACK) {
295 /* FIN/ACK lost */
296 TRACE_RTO("Stream %d: Retransmit FIN/ACK. "
297 "snd_nxt: %u, snd_una: %u\n",
298 cur_stream->id, cur_stream->snd_nxt, cur_stream->sndvar->snd_una);
299
300 } else if (cur_stream->state == TCP_ST_FIN_WAIT_1) {
301 /* FIN lost */
302 TRACE_RTO("Stream %d: Retransmit FIN. snd_nxt: %u, snd_una: %u\n",
303 cur_stream->id, cur_stream->snd_nxt, cur_stream->sndvar->snd_una);
304 } else if (cur_stream->state == TCP_ST_CLOSING) {
305 TRACE_RTO("Stream %d: Retransmit ACK. snd_nxt: %u, snd_una: %u\n",
306 cur_stream->id, cur_stream->snd_nxt, cur_stream->sndvar->snd_una);
307 //TRACE_DBG("Stream %d: Retransmitting at CLOSING\n", cur_stream->id);
308
309 } else if (cur_stream->state == TCP_ST_FIN_WAIT_2) {
310 TRACE_RTO("Stream %d: Retransmit ACK. snd_nxt: %u, snd_una: %u\n",
311 cur_stream->id, cur_stream->snd_nxt, cur_stream->sndvar->snd_una);
312 } else {
313 TRACE_ERROR("Stream %d: not implemented state! state: %s, rto: %u\n",
314 cur_stream->id,
315 TCPStateToString(cur_stream), cur_stream->sndvar->rto);
316 assert(0);
317 return 0;
318 }
319
320 cur_stream->snd_nxt = cur_stream->sndvar->snd_una;
321 if (cur_stream->state == TCP_ST_ESTABLISHED ||
322 cur_stream->state == TCP_ST_CLOSE_WAIT) {
323 /* retransmit data at ESTABLISHED state */
324 AddtoSendList(mtcp, cur_stream);
325
326 } else if (cur_stream->state == TCP_ST_FIN_WAIT_1 ||
327 cur_stream->state == TCP_ST_CLOSING ||
328 cur_stream->state == TCP_ST_LAST_ACK) {
329
330 if (cur_stream->sndvar->fss == 0) {
331 TRACE_ERROR("Stream %u: fss not set.\n", cur_stream->id);
332 }
333 /* decide to retransmit data or control packet */
334 if (TCP_SEQ_LT(cur_stream->snd_nxt, cur_stream->sndvar->fss)) {
335 /* need to retransmit data */
336 if (cur_stream->sndvar->on_control_list) {
337 RemoveFromControlList(mtcp, cur_stream);
338 }
339 cur_stream->control_list_waiting = TRUE;
340 AddtoSendList(mtcp, cur_stream);
341
342 } else {
343 /* need to retransmit control packet */
344 AddtoControlList(mtcp, cur_stream, cur_ts);
345 }
346
347 } else {
348 AddtoControlList(mtcp, cur_stream, cur_ts);
349 }
350
351 return 1;
352 }
353 /*----------------------------------------------------------------------------*/
354 static inline void
RearrangeRTOStore(mtcp_manager_t mtcp)355 RearrangeRTOStore(mtcp_manager_t mtcp) {
356 tcp_stream *walk, *next;
357 struct rto_head* rto_list = &mtcp->rto_store->rto_list[RTO_HASH];
358 int cnt = 0;
359
360 for (walk = TAILQ_FIRST(rto_list);
361 walk != NULL; walk = next) {
362 next = TAILQ_NEXT(walk, sndvar->timer_link);
363
364 int diff = (int32_t)(mtcp->rto_store->rto_now_ts - walk->sndvar->ts_rto);
365 if (diff < RTO_HASH) {
366 //int offset = (diff + mtcp->rto_store->rto_now_idx) % RTO_HASH;
367 int offset = ((diff + mtcp->rto_store->rto_now_idx) & (RTO_HASH - 1));
368 if (!TAILQ_EMPTY(&mtcp->rto_store->rto_list[RTO_HASH])) {
369 TAILQ_REMOVE(&mtcp->rto_store->rto_list[RTO_HASH],
370 walk, sndvar->timer_link);
371 walk->on_rto_idx = offset;
372 TAILQ_INSERT_TAIL(&(mtcp->rto_store->rto_list[offset]),
373 walk, sndvar->timer_link);
374 }
375 }
376 cnt++;
377 }
378 }
379 /*----------------------------------------------------------------------------*/
380 void
CheckRtmTimeout(mtcp_manager_t mtcp,uint32_t cur_ts,int thresh)381 CheckRtmTimeout(mtcp_manager_t mtcp, uint32_t cur_ts, int thresh)
382 {
383 tcp_stream *walk, *next;
384 struct rto_head* rto_list;
385 int cnt;
386
387 if (!mtcp->rto_list_cnt) {
388 return;
389 }
390
391 STAT_COUNT(mtcp->runstat.rounds_rtocheck);
392
393 cnt = 0;
394
395 while (1) {
396
397 rto_list = &mtcp->rto_store->rto_list[mtcp->rto_store->rto_now_idx];
398 if ((int32_t)(cur_ts - mtcp->rto_store->rto_now_ts) < 0) {
399 break;
400 }
401
402 for (walk = TAILQ_FIRST(rto_list);
403 walk != NULL; walk = next) {
404 if (++cnt > thresh) {
405 break;
406 }
407 next = TAILQ_NEXT(walk, sndvar->timer_link);
408
409 TRACE_LOOP("Inside rto list. cnt: %u, stream: %d\n",
410 cnt, walk->s_id);
411
412 if (walk->on_rto_idx >= 0) {
413 TAILQ_REMOVE(rto_list, walk, sndvar->timer_link);
414 mtcp->rto_list_cnt--;
415 walk->on_rto_idx = -1;
416 HandleRTO(mtcp, cur_ts, walk);
417 } else {
418 TRACE_ERROR("Stream %d: not on rto list.\n", walk->id);
419 #ifdef DUMP_STREAM
420 DumpStream(mtcp, walk);
421 #endif
422 }
423 }
424
425 if (cnt > thresh) {
426 break;
427 } else {
428 mtcp->rto_store->rto_now_idx = ((mtcp->rto_store->rto_now_idx + 1) & (RTO_HASH - 1));
429 mtcp->rto_store->rto_now_ts++;
430 if (!((mtcp->rto_store->rto_now_idx & (1024 - 1)))) {
431 RearrangeRTOStore(mtcp);
432 }
433 }
434
435 }
436
437 TRACE_ROUND("Checking retransmission timeout. cnt: %d\n", cnt);
438 }
439 /*----------------------------------------------------------------------------*/
440 void
CheckTimewaitExpire(mtcp_manager_t mtcp,uint32_t cur_ts,int thresh)441 CheckTimewaitExpire(mtcp_manager_t mtcp, uint32_t cur_ts, int thresh)
442 {
443 tcp_stream *walk, *next;
444 int cnt;
445
446 STAT_COUNT(mtcp->runstat.rounds_twcheck);
447
448 cnt = 0;
449
450 for (walk = TAILQ_FIRST(&mtcp->timewait_list);
451 walk != NULL; walk = next) {
452 if (++cnt > thresh)
453 break;
454 next = TAILQ_NEXT(walk, sndvar->timer_link);
455
456 TRACE_LOOP("Inside timewait list. cnt: %u, stream: %d\n",
457 cnt, walk->s_id);
458
459 if (walk->on_timewait_list) {
460 /* wait until the other end is finished in monitoring socket */
461 if ((walk->pair_stream != NULL)
462 && (walk->pair_stream->state != TCP_ST_CLOSED_RSVD)
463 && (walk->pair_stream->state != TCP_ST_TIME_WAIT))
464 continue;
465
466 if ((int32_t)(cur_ts - walk->rcvvar->ts_tw_expire) >= 0) {
467 if (!walk->sndvar->on_control_list) {
468
469 TAILQ_REMOVE(&mtcp->timewait_list, walk, sndvar->timer_link);
470 walk->on_timewait_list = FALSE;
471 mtcp->timewait_list_cnt--;
472
473 walk->state = TCP_ST_CLOSED_RSVD;
474 walk->close_reason = TCP_ACTIVE_CLOSE;
475 walk->cb_events |= MOS_ON_TCP_STATE_CHANGE;
476 TRACE_STATE("Stream %d: TCP_ST_CLOSED_RSVD\n", walk->id);
477 DestroyTCPStream(mtcp, walk);
478 }
479 } else {
480 break;
481 }
482 } else {
483 TRACE_ERROR("Stream %d: not on timewait list.\n", walk->id);
484 #ifdef DUMP_STREAM
485 DumpStream(mtcp, walk);
486 #endif
487 }
488 }
489
490 TRACE_ROUND("Checking timewait timeout. cnt: %d\n", cnt);
491 }
492 /*----------------------------------------------------------------------------*/
493 void
CheckConnectionTimeout(mtcp_manager_t mtcp,uint32_t cur_ts,int thresh)494 CheckConnectionTimeout(mtcp_manager_t mtcp, uint32_t cur_ts, int thresh)
495 {
496 tcp_stream *walk, *next;
497 int cnt;
498
499 STAT_COUNT(mtcp->runstat.rounds_tocheck);
500
501 cnt = 0;
502 for (walk = TAILQ_FIRST(&mtcp->timeout_list);
503 walk != NULL; walk = next) {
504 if (++cnt > thresh)
505 break;
506 next = TAILQ_NEXT(walk, sndvar->timeout_link);
507
508 if ((int32_t)(cur_ts - walk->last_active_ts) >=
509 g_config.mos->tcp_timeout) {
510
511 TRACE_DBG("stream-state: %s, streampair-state: %s\n",
512 TCPStateToString(walk),
513 TCPStateToString(walk->pair_stream));
514
515 walk->on_timeout_list = FALSE;
516 TAILQ_REMOVE(&mtcp->timeout_list, walk, sndvar->timeout_link);
517 mtcp->timeout_list_cnt--;
518 walk->state = TCP_ST_CLOSED_RSVD;
519 walk->close_reason = TCP_TIMEDOUT;
520 walk->cb_events |= MOS_ON_TCP_STATE_CHANGE;
521 if (walk->socket && HAS_STREAM_TYPE(walk, MOS_SOCK_STREAM)) {
522 RaiseErrorEvent(mtcp, walk);
523 } else {
524 DestroyTCPStream(mtcp, walk);
525 }
526 } else {
527 break;
528 }
529
530 }
531 }
532 /*----------------------------------------------------------------------------*/
533 static int
RegTimer(mtcp_manager_t mtcp,struct timer * timer)534 RegTimer(mtcp_manager_t mtcp, struct timer *timer)
535 {
536 /* NOTE: This code assumes that the new timer expires later than existing
537 * timers with high probability. */
538 struct timer *walk;
539
540 TAILQ_FOREACH_REVERSE(walk, &mtcp->timer_list, timer_head, timer_link) {
541 if (TIMEVAL_LT(&walk->exp, &timer->exp)) {
542 TAILQ_INSERT_AFTER(&mtcp->timer_list, walk, timer, timer_link);
543 return 0;
544 }
545 }
546
547 assert(!walk);
548
549 TAILQ_INSERT_HEAD(&mtcp->timer_list, timer, timer_link);
550 return 0;
551 }
552 /*----------------------------------------------------------------------------*/
553 static struct timer *
NewTimer(mtcp_manager_t mtcp,int id,struct timeval * timeout,callback_t cb)554 NewTimer(mtcp_manager_t mtcp, int id, struct timeval *timeout, callback_t cb)
555 {
556 #ifdef USE_TIMER_POOL
557 struct timer *t = MPAllocateChunk(mtcp->timer_pool);
558 #else
559 struct timer *t = calloc(1, sizeof(struct timer));
560 #endif
561 if (!t)
562 return NULL;
563
564 t->id = id;
565 t->cb = cb;
566 gettimeofday(&t->exp, NULL);
567 TIMEVAL_ADD(&t->exp, timeout);
568
569 return t;
570 }
571 /*----------------------------------------------------------------------------*/
572 void
DelTimer(mtcp_manager_t mtcp,struct timer * timer)573 DelTimer(mtcp_manager_t mtcp, struct timer *timer)
574 {
575 TAILQ_REMOVE(&mtcp->timer_list, timer, timer_link);
576 #ifdef USE_TIMER_POOL
577 MPFreeChunk(mtcp->timer_pool, timer);
578 #else
579 free(timer);
580 #endif
581 }
582 /*----------------------------------------------------------------------------*/
583 int
mtcp_settimer(mctx_t mctx,int id,struct timeval * timeout,callback_t cb)584 mtcp_settimer(mctx_t mctx, int id, struct timeval *timeout, callback_t cb)
585 {
586 mtcp_manager_t mtcp = GetMTCPManager(mctx);
587 if (!mtcp || !timeout || !cb)
588 return -1;
589
590 struct timer *t = NewTimer(mtcp, id, timeout, cb);
591 if (!t)
592 return -1;
593
594 RegTimer(mtcp, t);
595
596 return 0;
597 }
598 /*----------------------------------------------------------------------------*/
599