tcp.c文件的retransmit_timer函数(11) - TCP-IP - 978...

来源:百度文库 编辑:神马文学网 时间:2024/07/03 12:40:19
tcp.c文件的retransmit_timer函数(11) tcp.c文件的retransmit_timer函数
978计划工作组 2009-8-18
1函数源码
/*
*    The TCP retransmit timer. This lacks a few small details.
*
*    1.    An initial rtt timeout on the probe0 should cause what we can
*           of the first write queue buffer to be split and sent.
*    2.    On a 'major timeout' as defined by RFC1122 we shouldn't report
*           ETIMEDOUT if we know an additional 'soft' error caused this.
*           tcp_err should save a 'soft error' for us.
*/
static void retransmit_timer(unsigned long data)
{
struct sock *sk = (struct sock*)data;
int why = sk->ip_xmit_timeout;
/*
* only process if socket is not in use
*/
cli();
if (sk->inuse || in_bh)
{
/* Try again in 1 second */
sk->retransmit_timer.expires = HZ;
add_timer(&sk->retransmit_timer);
sti();
return;
}
sk->inuse = 1;
sti();
/* Always see if we need to send an ack. */
if (sk->ack_backlog && !sk->zapped)
{
sk->prot->read_wakeup (sk);
if (! 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:
/* It could be we got here because we needed to send an ack.
* So we need to check for that.
*/
{
struct sk_buff *skb;
unsigned long flags;
save_flags(flags);
cli();
skb = sk->send_head;
if (!skb)
{
restore_flags(flags);
}
else
{
/*
*    Kicked by a delayed ack. Reset timer
*    correctly now
*/
if (jiffies < skb->when + sk->rto)
{
reset_xmit_timer (sk, TIME_WRITE, skb->when + sk->rto - jiffies);
restore_flags(flags);
break;
}
restore_flags(flags);
/*
*    Retransmission
*/
sk->prot->retransmit (sk, 0);
tcp_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.
*/
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++;
tcp_write_timeout(sk);
break;
default:
printk ("rexmit_timer: timer expired - reason unknown\n");
break;
}
release_sock(sk);
}
}2函数用途
重传定时器到期执行函数,根据重传定时器具体超时原因进行相应处理。
3调用关系
4语句注释
4.1 if (sk->inuse || in_bh)
in_bh:如果该变量已经设置为1,则表示函数的下半部分代码已经在执行,此时设置expires为1秒并添加到计时器队列即1秒后重试,然后返回,这样做的目的是因为该函数不允许重入。
sk->inuse:值为1表示其它进程正在使用该套接字,本进程需要等待。
4.2 if (sk->ack_backlog && !sk->zapped)
{
sk->prot->read_wakeup (sk);
if (! sk->dead)
sk->data_ready(sk,0);
}
sk->ack_backlog:计算目前累计的应发送而未发送的应答数据包的个数。
sk->ack_zapped:用于标识本地是否接收到远端发送的RESET复位数据包,zapped=1表示对方发送了复位数据包进行了连接复位,所以在发送任何数据包(包括应答数据包)之前必须重新进行连接,换句话说,如果zapped=1,此处不必发送应答数据包。
read_wakeup:该函数指针指向tcp_read_wakeup函数,实现发送应答数据包的功能 。
sk->dead:如果套接字仍在使用则值为0,如值为1表示套接字处于相关结构释放状态 。
sk->data_ready:该函数指针指向def_callback2函数,唤醒睡眠在该侦听套接字睡眠队列中的进程 。
4.3 case TIME_PROBE0:
case TIME_WRITE:
case TIME_KEEPOPEN:
TIME_PROBEO:是常数6,窗口探测计时器。
TIME_WRITE:是常数1,超时重传。
TIME_KEEPOPEN:是常数3,保活。
4.4  tcp_send_probe0(sk);
tcp_write_timeout(sk);
tcp_send_probe0:发送窗口探测数据包。其一方面发送窗口探测数据包,另一方面采用指数退避算法更新超时间隔时间后,重新设置窗口探测定时器,以便在对方未响应的情况下,继续进行窗口探测。
tcp_write_timeout:进行超时处理,具体参见《tcp.c文件的tcp_write_timeout函数(10).doc》。
4.5  if (jiffies < skb->when + sk->rto)
{
reset_xmit_timer (sk, TIME_WRITE, skb->when + sk->rto - jiffies);
restore_flags(flags);
break;
}
skb->when:该数据包的发送时间。
sk->rto:延迟时间。
reset_xmit_timer:重新设置重传计时器。具体参见《tcp.c文件的reset_xmit_timer函数(7).doc》
4.6 if (sk->prot->write_wakeup)
sk->prot->write_wakeup (sk);
sk->retransmits++;
write_wakeup:此函数指针指向tcp_write_wakeup函数,实现向远端发送保活数据包。
4.6 release_sock(sk);
此函数功能是将sock 结构中缓存的数据包送给应用程序读取,并在检测套接字已处于关闭且等待销毁时,设置一定时器,在定时器到期时,进行sock 结构的释放
发表于: 2009-08-19,修改于: 2009-08-19 15:38 已浏览73次,有评论0条推荐投诉