Chinaunix首页 | 论坛 | 博客
  • 博客访问: 155887
  • 博文数量: 41
  • 博客积分: 2500
  • 博客等级: 少校
  • 技术积分: 425
  • 用 户 组: 普通用户
  • 注册时间: 2009-07-14 10:16
文章分类
文章存档

2011年(1)

2010年(5)

2009年(35)

我的朋友

分类: LINUX

2009-08-19 15:38:22

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,则表示函数的下半部分代码已经在执行,此时设置expires1秒并添加到计时器队列即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 结构的释放

阅读(1327) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~