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* 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 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 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