/* 每个struct sock的时钟函数 */ void net_timer (unsigned long data) { struct sock *sk = (struct sock*)data; /* 相当于获取时钟的类型吧, */ int why = sk->timeout; /* timeout is overwritten by 'delete_timer' and 'reset_timer' */ /* 判断sock是否已被其他进程使用,或者当前是否正在执行网络的下半部分, * 如果当前正在执行网络的下半部分,则重新设置sock的timer,同时添加到 * 内核时钟当中,等待下次执行 */ if (sk->inuse || in_inet_bh()) { sk->timer.expires = 10; add_timer(&sk->timer); return; } /* 设置sock为用 */ sk->inuse = 1; DPRINTF ((DBG_TMR, "net_timer: found sk=%X why = %d\n", sk, why)); if (sk->wfront && before(sk->window_seq, sk->wfront->h.seq) && sk->send_head == NULL && sk->ack_backlog == 0 && sk->state != TCP_TIME_WAIT) reset_timer(sk, TIME_PROBE0, sk->rto); else if (sk->keepopen) reset_timer (sk, TIME_KEEPOPEN, TCP_TIMEOUT_LEN); /* Always see if we need to send an ack. */ /* 看看还有没有收到的数据包没有应答 */ if (sk->ack_backlog) { /* sock发送确认数据包*/ sk->prot->read_wakeup (sk); if (! sk->dead) wake_up_interruptible (sk->sleep); } /* Now we need to figure out why the socket was on the timer. */ switch (why) { case TIME_DONE: if (! sk->dead || sk->state != TCP_CLOSE) { printk ("non dead socket in time_done\n"); release_sock (sk); break; } destroy_sock (sk); break; case TIME_DESTROY: /* We've waited for a while for all the memory associated with * the socket to be freed. We need to print an error message. */ /* 如果sock的发送缓冲区和接收缓冲区都为空,则直接在后面的语句当中释放 */ if(sk->wmem_alloc!=0 || sk->rmem_alloc!=0) { DPRINTF ((DBG_TMR, "possible memory leak. sk = %X\n", sk)); sk->wmem_alloc++; /* So it DOESNT go away */ destroy_sock (sk); sk->wmem_alloc--; /* Might now have hit 0 - fall through and do it again if so */ sk->inuse = 0; /* This will be ok, the destroy won't totally work */ } if(sk->wmem_alloc==0 && sk->rmem_alloc==0) destroy_sock(sk); /* Socket gone, DONT update sk->inuse! */ break; case TIME_CLOSE: /* We've waited long enough, close the socket. */ sk->state = TCP_CLOSE; delete_timer (sk); /* Kill the ARP entry in case the hardware has changed. */ arp_destroy_maybe (sk->daddr); if (!sk->dead) wake_up_interruptible (sk->sleep); sk->shutdown = SHUTDOWN_MASK; reset_timer (sk, TIME_DESTROY, TCP_DONE_TIME); release_sock (sk); break; case TIME_PROBE0: /* 窗口探测定时器,也被称为坚持定时器 */ tcp_send_probe0(sk); release_sock (sk); break; case TIME_WRITE: /* 超时重传定时器 */ /* try to retransmit. */ /* It could be we got here because we needed to send an ack. * So we need to check for that. */ if (sk->send_head) { if (jiffies < (sk->send_head->when + sk->rto)) { reset_timer (sk, TIME_WRITE, (sk->send_head->when + sk->rto - jiffies)); release_sock (sk); break; } /* printk("timer: seq %d retrans %d out %d cong %d\n", sk->send_head->h.seq, sk->retransmits, sk->packets_out, sk->cong_window); */ DPRINTF ((DBG_TMR, "retransmitting.\n")); /* 调用tcp协议的超时重传函数 */ sk->prot->retransmit (sk, 0); if ((sk->state == TCP_ESTABLISHED && sk->retransmits && !(sk->retransmits & 7)) || (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR1)) { DPRINTF ((DBG_TMR, "timer.c TIME_WRITE time-out 1\n")); arp_destroy_maybe (sk->daddr); ip_route_check (sk->daddr); } if (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR2) { DPRINTF ((DBG_TMR, "timer.c TIME_WRITE time-out 2\n")); sk->err = ETIMEDOUT; if (sk->state == TCP_FIN_WAIT1 || sk->state == TCP_FIN_WAIT2 || sk->state == TCP_LAST_ACK) { sk->state = TCP_TIME_WAIT; reset_timer (sk, TIME_CLOSE, TCP_TIMEWAIT_LEN); } else { sk->prot->close (sk, 1); break; } } } release_sock (sk); break; case TIME_KEEPOPEN: /* 保活定时器 */ /* Send something to keep the connection open. */ if (sk->prot->write_wakeup) sk->prot->write_wakeup (sk); sk->retransmits++; /* 因为是重发定时,所以会增加超时重发次数 */ if (sk->shutdown == SHUTDOWN_MASK) { sk->prot->close (sk, 1); sk->state = TCP_CLOSE; } if ((sk->state == TCP_ESTABLISHED && sk->retransmits && !(sk->retransmits & 7)) || (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR1)) { DPRINTF ((DBG_TMR, "timer.c TIME_KEEPOPEN time-out 1\n")); arp_destroy_maybe (sk->daddr); ip_route_check (sk->daddr); release_sock (sk); break; } if (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR2) { DPRINTF ((DBG_TMR, "timer.c TIME_KEEPOPEN time-out 2\n")); arp_destroy_maybe (sk->daddr); sk->err = ETIMEDOUT; if (sk->state == TCP_FIN_WAIT1 || sk->state == TCP_FIN_WAIT2) { sk->state = TCP_TIME_WAIT; if (!sk->dead) wake_up_interruptible (sk->sleep); release_sock (sk); } else { sk->prot->close (sk, 1); } break; } release_sock (sk); break; default: printk ("net timer expired - reason unknown, sk=%08X\n", (int)sk); release_sock (sk); break; } }
void tcp_retransmit_timer(unsigned long data) { struct sock *sk = (struct sock*)data; int why = sk->ip_xmit_timeout; /* * We are reset. We will send no more retransmits. */ if(sk->zapped) return; /* * Only process if socket is not in use */ if (sk->users) { /* Try again in 1 second */ sk->retransmit_timer.expires = jiffies+HZ; add_timer(&sk->retransmit_timer); return; } if (sk->ack_backlog && !sk->dead) sk->data_ready(sk,0); /* Now we need to figure out why the socket was on the timer. */ switch (why) { /* Window probing */ case TIME_PROBE0: tcp_send_probe0(sk); tcp_write_timeout(sk); break; /* Retransmitting */ case TIME_WRITE: tcp_time_write_timeout(sk); break; /* Sending Keepalives */ case TIME_KEEPOPEN: /* * this reset_timer() call is a hack, this is not * how KEEPOPEN is supposed to work. */ tcp_reset_xmit_timer (sk, TIME_KEEPOPEN, TCP_TIMEOUT_LEN); /* Send something to keep the connection open. */ if (sk->prot->write_wakeup) sk->prot->write_wakeup (sk); sk->retransmits++; sk->prot->retransmits++; tcp_write_timeout(sk); break; default: printk (KERN_ERR "rexmit_timer: timer expired - reason unknown\n"); break; } }