Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1919579
  • 博文数量: 376
  • 博客积分: 2147
  • 博客等级: 大尉
  • 技术积分: 3642
  • 用 户 组: 普通用户
  • 注册时间: 2012-02-06 10:47
文章分类

全部博文(376)

文章存档

2019年(3)

2017年(28)

2016年(15)

2015年(17)

2014年(182)

2013年(16)

2012年(115)

我的朋友

分类: 嵌入式

2014-02-26 14:58:37

本文主要分析:三次握手中最后一个ACK段到达时,服务器端的处理路径。

内核版本:3.6

Author:zhangskd @ csdn blog

 

创建新sock

 

协议族相关的操作函数,我们要看的是TCP/IPv4的实例ipv4_specific。

  1. const struct inet_connection_sock_af_ops ipv4_specific = {  
  2.     ...  
  3.     .conn_request = tcp_v4_conn_request, /* 处理SYN段 */  
  4.     .syn_recv_sock = tcp_v4_syn_recv_sock, /* 创建和初始化一个新的sock */  
  5.     ...  
  6. };  

 

三次握手完成以后,要为新的连接创建一个传输控制块,并初始化传输控制块。

一个TCP传输控制块是由多层组成的,包括:

tcp_sock

inet_connection_sock

inet_sock

sock

sock_common

所以,初始化要做的工作比较多。

  1. /* The three way handshake has completed - we got a valid synack -  
  2.  * now create the new socket. 
  3.  */  
  4.   
  5. struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb, struct request_sock *req,  
  6.     struct dst_entry *dst)  
  7. {  
  8.     struct inet_request_sock *ireq;  
  9.     struct inet_sock *newinet;  
  10.     struct tcp_sock *newtp;  
  11.     struct sock *newsk;  
  12. #ifdef CONFIG_TCP_MD5SIG  
  13.     struct tcp_md5sig_key *key;  
  14. #endif  
  15.     struct ip_options_rcu *inet_opt;  
  16.   
  17.     /* 如果全连接队列满了,那么返回NULL */  
  18.     if (sk_acceptq_is_full(sk))  
  19.         goto exit_overflow;  
  20.   
  21.     /* 根据监听sock和req,为新连接创建一个传输控制块,并初始化 */  
  22.     newsk = tcp_create_openreq_child(sk, req, skb);  
  23.     if (! newsk)  
  24.         goto exit_nonewsk;  
  25.   
  26.     newsk->sk_gso_type = SKB_GSO_TCPV4;  
  27.     inet_sk_rx_dst_set(newsk, skb); /* 保存接收路由缓存 */  
  28.   
  29.     newtp = tcp_sk(newsk);  
  30.     newinet = inet_sk(newsk);  
  31.     ireq = inet_rsk(req);  
  32.     newinet->inet_daddr = ireq->rmt_addr; /* 目的IP */  
  33.     newinet->inet_rcv_saddr = ireq->loc_addr;  
  34.     newinet->inet_saddr = ireq->loc_addr; /* 源IP */  
  35.     inet_opt = ireq->opt;  
  36.     rcu_assign_pointer(newinet->inet_opt, inet_opt); /* IP选项 */  
  37.     ireq->opt = NULL;  
  38.   
  39.     newinet->mc_index = inet_iif(skb);  
  40.     newinet->mc_ttl = ip_hdr(skb)->ttl;  
  41.     newinet->rcv_tos = ip_hdr(skb)->tos;  
  42.     inet_csk(newsk)->icsk_ext_hdr_len = 0;  
  43.     if (inet_opt)  
  44.         inet_csk(newsk)->icsk_ext_hdr_len = inet_opt->opt.optlen;  
  45.     newinet->inet_id = newtp->write_seq ^ jiffies;  
  46.   
  47.     if (! dst) {  
  48.         dst = inet_csk_route_child_sock(sk, newsk, req);  
  49.         if (! dst)  
  50.             goto put_and_exit;  
  51.     } else {  
  52.         /* syncookie case: see end of cookie_v4_check() */  
  53.     }  
  54.     sk_setup_caps(newsk, dst);  
  55.   
  56.     tcp_mtup_init(newsk); /* MTU probe init */  
  57.     tcp_sync_mss(newsk, dst_mtu(dst));  
  58.     newtp->advmss = dst_metric_advmss(dst);  
  59.     if (tcp_sk(sk)->rx_opt.user_mss && tcp_sk(sk)->rx_opt.user_mss < newtp->advmss)  
  60.         newtp->advmss = tcp_sk(sk)->rx_opt.user_mss;  
  61.     tcp_initialize_rcv_mss(newsk);  
  62.   
  63.     if (tcp_rsk(req)->snt_synack) /* 第一个RTT样本 */  
  64.         tcp_valid_rtt_meas(newsk, tcp_time_stamp - tcp_rsk(req)->snt_synack);  
  65.     newtp->total_retrans = req->retrans;  
  66.   
  67. #ifdef CONFIG_TCP_MD5SIG  
  68.     /* Copy over the MD5 key from the original socket */  
  69.     key = tcp_md5_do_lookup(sk, (union tcp_md5_addr *) &newinet->inet_daddr, AF_INET);  
  70.     if (key != NULL) {  
  71.         /* We're using one, so create a matching key on the newsk structure. 
  72.          * If we fail to get memory, then we end up not copying the key across. Shucks. 
  73.          */  
  74.         tcp_md5_do_add(newsk, (union tcp_md5_addr *) &newinet->inet_daddr, AF_INET,  
  75.             key->key, key->keylen, GFP_ATOMIC);  
  76.         sk_nocaps_add(newsk, NETIF_F_GSO_MASK);  
  77.     }  
  78. #endif  
  79.   
  80.     /* 把newsk链入使用端口的哈希链表中,更新端口的统计信息 */  
  81.     if (__inet_inherit_port(sk, newsk) < 0)  
  82.         goto put_and_eixt;  
  83.   
  84.     /* 把newsk链入ESTABLISHED状态的哈希表中 */  
  85.     __inet_hash_nolisten(newsk, NULL);  
  86.   
  87.     return newsk;  
  88.   
  89. exit_overflow:  
  90.     NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS);  
  91. exit_nonewsk:  
  92.     dst_release(dst);  
  93. exit:  
  94.     NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS);  
  95.     return NULL;  
  96.   
  97. put_and_exit:  
  98.     tcp_clear_xmit_timers(newsk);  
  99.     tcp_cleanup_congestion_control(newsk);  
  100.     bh_unlock_sock(newsk);  
  101.     sock_put(newsk);  
  102.     goto exit;  
  103. }  

 

根据监听传输控制块sock、连接请求块req,为新的连接创建一个传输控制块sock。

初始化此传输控制块对应的inet_sock、inet_connection_sock、tcp_sock结构中的变量。

  1. struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req, struct sk_buff *skb)  
  2. {  
  3.     /* 克隆一个传输控制块,并对新的传输控制块上锁 */  
  4.     struct sock *newsk = inet_csk_clone_lock(sk, req, GFP_ATOMIC);  
  5.   
  6.     if (newsk != NULL) {  
  7.         cosnt struct inet_request_sock *ireq = inet_rsk(req);  
  8.         struct tcp_request_sock *treq = tcp_rsk(req);  
  9.         struct inet_connection_sock *newicsk = inet_csk(newsk);  
  10.         struct tcp_sock *newtp = tcp_sk(newsk);  
  11.         struct tcp_sock *oldtp = tcp_sk(sk);  
  12.         struct tcp_cookie_values *oldcvp = oldtp->cookie_values;  
  13.   
  14.         /* 由于TCPCT选项已被废弃,此处不做分析 */  
  15.         if (oldcvp != NULL) { ... }  
  16.   
  17.         /* Now setup tcp_sock,初始化tcp_sock实例 */  
  18.         newtp->pred_flags = 0;  
  19.   
  20.         /* 接收序号、发送序号相关变量初始化 */  
  21.         newtp->rcv_wup = newtp->copied_seq = newtp->rcv_nxt = treq->rcv_isn + 1;  
  22.         newtp->snd_sml = newtp->snd_una = newtp->snd_nxt = newtp->snd_up  
  23.                                         = treq->snt_isn + 1 + tcp_s_data_size(oldtp);  
  24.           
  25.         tcp_prequeue_init(newtp); /* prequeue队列初始化 */  
  26.         INIT_LIST_HEAD(&newtp->tsq_node);  
  27.         tcp_init_wl(newtp, treq->rcv_isn); /* 上次更新发送窗口的ACK段序号 */  
  28.   
  29.         /* 时延相关变量初始化 */  
  30.         newtp->srtt = 0;  
  31.         newtp->mdev = TCP_TIMEOUT_INIT;  
  32.         newicsk->icsk_rto = TCP_TIMEOUT_INIT;  
  33.   
  34.         /* 拥塞控制相关变量初始化 */  
  35.         newtp->packets_out = 0;  
  36.         newtp->retrans_out = 0;  
  37.         newtp->sacked_out = 0;  
  38.         newtp->fackets_out = 0;  
  39.         newtp->snd_ssthresh = TCP_INFINITE_SSTHRESH;  
  40.         tcp_enable_early_retrans(newtp);  
  41.   
  42.         newtp->snd_cwnd = TCP_INIT_CWND;  
  43.         newtp->snd_cwnd_cnt = 0;  
  44.         newtp->bytes_acked = 0;  
  45.         newtp->frto_counter = 0;  
  46.         newtp->frto_highmark = 0;  
  47.   
  48.         /* 如果拥塞控制算法不为Reno,则把使用的拥塞控制算法模块引用计数加1。 
  49.          * 如果该模块还没插入内核,则使用Reno。 
  50.          */  
  51.         if (newicsk->icsk_ca_ops != &tcp_init_congestion_ops &&   
  52.              ! try_module_get(newicsk->icsk_ca_ops->owner))  
  53.             newicsk->icsk_ca_ops = &tcp_init_congestion_ops;  
  54.   
  55.         tcp_set_ca_state(newsk, TCP_CA_Open);  
  56.         tcp_init_xmit_timers(newsk); /* 初始化几个定时器 */  
  57.         skb_queue_head_init(&newtp->out_of_order_queue);  
  58.         newtp->write_seq = newtp->pushed_seq = treq->snt_isn + 1 + tcp_s_data_size(oldtp);  
  59.   
  60.         /* TCP选项相关 */  
  61.         newtp->rx_opt.saw_tstamp = 0;  
  62.         newtp->rx_opt.dsack = 0;  
  63.         newtp->rx_opt.num_sacks = 0;  
  64.         newtp->urg_data = 0;  
  65.   
  66.         /* 如果用户设置了SO_KEEPALIVE选项 */  
  67.         if (sock_flag(newsk, SOCK_KEEPOPEN))  
  68.             inet_csk_reset_keepalive_timer(newsk, keepalive_time_when(newtp));  
  69.   
  70.         newtp->rx_opt.tstamp_ok = ireq->tstamp_ok;  
  71.         if ((newtp->rx_opt.sack_ok = ireq->sack_ok) != 0) {  
  72.             if (sysctl_tcp_fack)  
  73.                 tcp_enable_fack(newtp);  
  74.         }  
  75.   
  76.         newtp->window_clamp = req->window_clamp;  
  77.         newtp->rcv_ssthresh = req->rcv_wnd;  
  78.         newtp->rcv_wnd = req->rcv_wnd;  
  79.         newtp->rx_opt.wscale_ok = ireq->wscale_ok;  
  80.         if (newtp->rx_opt.wscale_ok) {  
  81.             newtp->rx_opt.snd_wscale = ireq->snd_wscale;  
  82.             newtp->rx_opt.rcv_wscale = ireq->rcv_wscale;  
  83.         } else {  
  84.             newtp->rx_opt.snd_wscale = newtp->rx_opt.rcv_wscale = 0;  
  85.             newtp->window_clamp = min(newtp->window_clamp, 65535U);  
  86.         }  
  87.   
  88.         newtp->snd_wnd = (ntohs(tcp_hdr(skb)->window) << newtp->rx_opt.snd_wscale);  
  89.         newtp->max_window = newtp->snd_wnd;  
  90.   
  91.         if (newtp->rx_opt.tstamp_ok) {  
  92.             newtp->rx_opt.ts_recent = req->ts_recent;  
  93.             newtp->rx_opt.ts_recent_stamp = get_seconds();  
  94.             newtp->tcp_header_len = sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED;  
  95.         } else {  
  96.             newtp->rx_opt.ts_recent_stamp = 0;  
  97.             newtp->tcp_header_len = sizeof(struct tcphdr);  
  98.         }  
  99.   
  100. #ifdef CONFIG_TCP_MD5SIG  
  101.         newtp->md5sig_info = NULL;  
  102.         if (newtp->af_specific->md5_lookup(sk, newsk))  
  103.             newtp->tcp_header_len += TCPOLEN_MD5SIG_ALIGNED;  
  104. #endif  
  105.   
  106.         if (skb->len >= TCP_MSS_DEFAULT + newtp->tcp_header_len)  
  107.             newicsk->icsk_ack.last_seg_size = skb->len - newtp->tcp_header_len;  
  108.   
  109.         newtp->rx_opt.mss_clamp = req->mss;  
  110.         TCP_ECN_openreq_child(newtp, req);  
  111.   
  112.         TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_PASSIVEOPENS);  
  113.     }  
  114.   
  115.     return newsk;  
  116. }  

 

克隆一个传输控制块,并对新的传输控制块上锁。

  1. /* inet_csk_clone_lock - clone an inet socket, and lock its clone. 
  2.  * @sk: the socket to clone 
  3.  * @req: request_sock 
  4.  * @priority: for allocation (%GFP_KERNEL, %GFP_ATOMIC, etc) 
  5.  * 
  6.  * Caller must unlock socket even in error path (bh_unlock_sock(newsk)) 
  7.  */  
  8. struct sock *inet_csk_clone_lock(cons struct sock *sk, const struct request_sock *req, const gfp_t priority)  
  9. {  
  10.     struct sock *newsk = sk_clone_lock(sk, priority); /* 从缓存中分配一个sock,并克隆sk */  
  11.   
  12.     if (newsk != NULL) {  
  13.         struct inet_connection_sock *newicsk = inet_csk(newsk);  
  14.         newsk->sk_state = TCP_SYN_RECV; /* 新sock的状态为SYN_RECV */  
  15.         newicsk->icsk_bind_hash = NULL;  /* 端口绑定的哈希桶 */  
  16.   
  17.         inet_sk(newsk)->inet_dport = inet_rsk(req)->rmt_port; /* 目的端口 */  
  18.         inet_sk(newsk)->inet_num = ntohs(inet_rsk(req)->loc_port); /* 源端口 */  
  19.         inet_sk(newsk)->inet_sport = inet_rsk(req)->loc_port; /* 源端口 */  
  20.         newsk->sk_write_space = sk_stream_write_space; /* write_space callback */  
  21.   
  22.         newicsk->icsk_retransmits = 0;  
  23.         newicsk->icsk_backoff = 0;  
  24.         newicsk->icsk_probes_out = 0;  
  25.   
  26.         memset(&newicsk->icsk_accept_queue, 0, sizeof(newicsk->icsk_accept_queue));  
  27.         security_inet_csk_clone(newsk, req);  
  28.     }  
  29.   
  30.     return newsk;  
  31. }  

 

把newsk链入使用端口的哈希链表中,更新端口的统计信息。

  1. int __inet_inherit_port(struct sock *sk, struct sock *child)  
  2. {  
  3.     struct inet_hashinfo *table = sk->sk_prot->h.hashinfo; /* 指向tcp_hashinfo */  
  4.     unsigned short port = inet_sk(child)->inet_num; /* 端口 */  
  5.     const int bhash = inet_bhashfn(sock_net(sk), port, table->bhash_size); /* 哈希值 */  
  6.     struct inet_bind_hashbucket *head = &table->bhash[bhash]; /* 哈希桶 */  
  7.     struct inet_bind_bucket *tb; /* 端口实例 */  
  8.   
  9.     spin_lock(&head->lock); /* 对哈希桶上锁 */  
  10.     tb = inet_csk(sk)->icsk_bind_hash;  
  11.   
  12.     if (tb->port != port) {  
  13.         /* NOTE: using tproxy and redirecting skbs to a proxy on a different listener port 
  14.          * breaks the assumption that the listener socket's icsk_bind_hash is the same 
  15.          * as that of the child socket. We have to look up or create a new bind bucket for 
  16.          * the child here. 
  17.          */  
  18.         struct hlist_node *node;  
  19.   
  20.         inet_bind_bucket_for_each(tb, node, &head->chain) {  
  21.             if (net_eq(ib_net(tb), sock_net(sk)) && tb->port == port)  
  22.                 break;  
  23.         }  
  24.   
  25.         if (! node) {  
  26.             /* 申请和初始化一个inet_bind_bucket */  
  27.             tb = inet_bind_bucket_create(table->bind_bucket_cachep, sock_net(sk), head, port);  
  28.             if (! tb) {  
  29.                 spin_unlock(&head->lock);  
  30.                 return -ENOMEM;  
  31.             }  
  32.         }  
  33.     }  
  34.   
  35.     inet_bind_hash(child, tb, port); /* 把child链入该端口的哈希链表中,更新相关变量 */  
  36.     spin_unlock(&head->lock);  
  37.   
  38.     return 0;  
  39. }  
  40.   
  41. void inet_bind_hash(struct sock *sk, struct inet_bind_bucket *tb, const unsigned short snum)  
  42. {  
  43.     struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo; /* 指向tcp_hashinfo */  
  44.     atomic_inc(&hashinfo->bsockets); /* 增加总的绑定次数 */  
  45.     inet_sk(sk)->inet_num = snum; /* 保存绑定的端口 */  
  46.     sk_add_bind_node(sk, &tb->owners); /* 把此sock链入tb->owners哈希链表中 */  
  47.     tb->num_owners++; /* 增加端口绑定次数 */  
  48.     inet_csk(sk)->icsk_bind_hash = tb; /* 把此tb作为icsk成员icsk_bind_hash */  
  49. }  

 

把newsk链入ESTABLISHED状态的哈希表中。

  1. int __inet_hash_nolisten(struct sock *sk, struct inet_timewait_sock *tw)  
  2. {  
  3.     struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo;  
  4.     struct hlist_nulls_head *list;  
  5.     spinlock_t *lock;  
  6.     struct inet_ehash_bucket *head;  
  7.     int twrefcnt = 0;  
  8.   
  9.     WARN_ON(! sk_unhashed(sk)); /* 要求sk不能已经链入哈希链表中 */  
  10.     sk->sk_hash = inet_sk_ehashfn(sk); /* 连接的哈希值 */  
  11.   
  12.     head = inet_ehash_bucket(hashinfo, sk->sk_hash); /* 哈希桶 */  
  13.     list = &head->chain;  
  14.     lock = inet_ehash_lockp(hashinfo, sk->sk_hash);  
  15.       
  16.     spin_lock(lock);  
  17.     __sk_nulls_add_node_rcu(sk, list); /* 把sk链入到哈希链表中 */  
  18.   
  19.     if (tw) {  
  20.         WARN_ON(sk->sk_hash != tw->tw_hash);  
  21.         twrefcnt = inet_twsk_unhash(tw);  
  22.     }  
  23.     spin_unlock(lock);  
  24.   
  25.     sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);  
  26.   
  27.     return twrefcnt;  
  28. }  
  29.   
  30. static inline int inet_sk_ehashfn(const struct sock *sk)  
  31. {  
  32.   
  33.     const struct inet_sock *inet = inet_sk(sk);  
  34.   
  35.     const __be32 laddr = inet->inet_rcv_saddr;  
  36.     const __u16 lport = inet->inet_num;  
  37.     const __be32 faddr = inet->inet_daddr;  
  38.     const __be16 fport = inet->inet_dport;  
  39.     struct net *net = sock_net(sk);  
  40.   
  41.     return inet_ehashfn(net, laddr, lport, faddr, fport);  
  42. }  

 

唤醒监听进程

 

调用tcp_child_process()来做最后的处理:

1. tcp_ack()处理接收到的ACK,更新child的状态为ESTABLISHED。

    唤醒child上的等待进程,初始化子传输控制块的一些字段。

2. 唤醒监听sock上的等待进程,以便监听进程执行accept()。

3. 如果child被用户进程占用,则先把ACK段添加到backlog队列中。

  1. /* Queue segment on the new socket if the new socket is active, 
  2.  * otherwise we just shortcircuit this and continue with the new socket. 
  3.  */  
  4.   
  5. int tcp_child_process(struct sock *parent, struct sock *child, sk_buff *skb)  
  6. {  
  7.     int ret = 0;  
  8.     int state = child->sk_state;  
  9.   
  10.     /* child没被用户进程占用 */  
  11.     if (! sock_owned_by_user(child)) {  
  12.         /* 调用tcp_ack()处理接收的ACK,设置新状态ESTABLISHED,唤醒child上的等待进程, 
  13.          * 初始化child的一些字段。 
  14.          */  
  15.         ret = tcp_rcv_state_process(child, skb, tcp_hdr(skb), skb->len);  
  16.           
  17.         /* Wakeup parent, send SIGIO. 
  18.          * 实例为sock_def_readable,唤醒调用accept()的进程。 
  19.          */  
  20.         if (state == TCP_SYN_RECV && child->sk_state != state)  
  21.             parent->sk_data_ready(parent, 0);  
  22.   
  23.     } else { /* 如果child被用户进程占用,则先把skb添加到backlog队列中 */  
  24.         __sk_add_backlog(child, skb);   
  25.     }  
  26.   
  27.     bh_unlock_sock(child);  
  28.     sock_put(child);  
  29.     return ret;  
  30. }  

把数据包添加到backlog队列中。

  1. static inline void __sk_add_backlog(struct sock *sk, struct sk_buff *skb)  
  2. {  
  3.     /* dont let skb not refcounted, we are going to leave rcu lock */  
  4.     skb_dst_force(skb);  
  5.   
  6.     /* backlog队列为空时 */  
  7.     if (! sk->sk_backlog.tail)  
  8.         sk->sk_backlog.head = skb;  
  9.     else  
  10.        sk->sk_backlog.tail->next = skb;  
  11.   
  12.     sk->sk_backlog.tail = skb;  
  13.     skb->next = NULL;  
  14. }  

 

子传输控制块调用tcp_ack()处理收到的ACK,把子传输控制块的状态从TCP_SYN_RECV更新为TCP_ESTABLISHED,

并唤醒子传输控制块上的等待进程,更新子传输控制块的一些字段。

  1. int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb, const struct tcphdr *th, unsigned int len)  
  2. {  
  3.     struct tcp_sock *tp = tcp_sk(sk);  
  4.     struct inet_connection_sock *icsk = inet_csk(sk);  
  5.     int queued = 0;  
  6.   
  7.     tp->rx_opt.saw_tstamp = 0;  
  8.   
  9.     switch(sk->sk_state) {  
  10.         ...  
  11.     }  
  12.   
  13.     if (! tcp_validate_incoming(sk, skb, th, 0))  
  14.         return 0;  
  15.   
  16.     /* step 5: check the ACK field */  
  17.     if (th->ack) {  
  18.         int acceptable = tcp_ack(sk, skb, FLAG_SLOWPATH) > 0/* 进入ACK处理路径 */  
  19.   
  20.         switch (sk->sk_state) {  
  21.             case TCP_SYN_RECV:  
  22.                 if (acceptable) {  
  23.                     tp->copied_seq = tp->rcv_nxt;  
  24.                     smp_mb();  
  25.   
  26.                     /* 在这里,才从TCP_SYN_RECV变为TCP_ESTABLISHED */  
  27.                     tcp_set_state(sk, TCP_ESTABLISHED);  
  28.   
  29.                     sk->sk_state_change(sk); /* 实例为sock_def_wakeup(),唤醒sk上的等待进程*/  
  30.   
  31.                     /* Note, that this wakeup is only for marginal crossed SYN case. 
  32.                      * Passively Open sockets are not waked up, because sk->sk_sleep == NULL 
  33.                      * and sk->sk_socket == NULL. 
  34.                      */  
  35.                     if (sk->sk_socket)  
  36.                         sk_wake_async(sk, SOCK_WAKE_IO, POLL_OUT);  
  37.   
  38.                     tp->snd_una = TCP_SKB_CB(skb)->ack_seq;  
  39.                     tp->snd_wnd = ntohs(th->window) << tp->rx_opt.snd_wscale;  
  40.                     tcp_init_wl(tp, TCP_SKB_CB(skb)->seq);  
  41.                     if (tp->rx_opt.tstamp_ok)  
  42.                         tp->advmss -= TCPOLEN_TSTAMP_ALIGNED;  
  43.   
  44.                     /* Make sure socket is routed, for correct metrics. */  
  45.                     icsk->icsk_af_ops->rebuild_header(sk);  
  46.   
  47.                     tcp_init_metrics(sk); /* 根据路由缓存信息初始化控制块 */  
  48.                     tcp_init_congestion_control(sk); /* 初始化拥塞控制算法 */  
  49.   
  50.                     /* Prevent spurious tcp_cwnd_restart() on first data packet. */  
  51.                     tp->lsndtime = tcp_time_stamp;  
  52.   
  53.                     tcp_mtup_init(sk);  
  54.                     tcp_initialize_rcv_mss(sk);  
  55.                     tcp_init_buffer_space(sk);  
  56.                     tcp_fast_path_on(tp);  
  57.                 } else  
  58.                     return 1;  
  59.   
  60.                 break;  
  61.                 ...  
  62.         }   
  63.     } else  
  64.         goto discard;  
  65.     ...  
  66. discard:  
  67.         __kfree_skb(skb);  
  68.     }  
  69.     return 0;  
  70. }  
  1. static void sock_def_wakeup(struct sock *sk)  
  2. {  
  3.     struct socket_wq *wq;  
  4.     rcu_read_lock();  
  5.   
  6.     wq = rcu_dereference(sk->sk_wq);  
  7.     if (wq_has_sleeper(wq)) /* 如果sock上有等待任务 */  
  8.         wake_up_interruptible_all(&wq->wait); /* 唤醒全部的等待任务 */  
  9.     rcu_read_unlock();  
  10. }  
  11.   
  12. /* check if there are any waiting processes. */  
  13. static inline bool wq_has_sleeper(struct socket_wq *wq)  
  14. {  
  15.     smp_mb();  
  16.     return wq && waitqueue_active(&wq->wait);  
  17. }  
  18.   
  19. static inline int waitqueue_active(wait_queue_head_t *q)  
  20. {  
  21.     return ! list_empty(&q->task_list);  
  22. }  
  23.   
  24. #define wake_up_interruptible_all(x) __wake_up(x, TASK_INTERRUPTIBLE, 0, NULL)  
  25.   
  26. void __wake_up(wait_queue_head_t *q, unsigned int mode, int nr_exclusive, void *key)  
  27. {  
  28.     unsigned long flags;  
  29.     spin_lock_irqsave(&q->lock, flags);  
  30.     __wake_up_common(q, mode, nr_exclusive, 0, key);  
  31.     spin_unlock_irqrestore(&q->lock, flags);  
  32. }  
  33.   
  34. static void __wake_up_common(wait_queue_head_t *q, unsigned int mode, int nr_exclusive,  
  35.     int wake_flags, void *key)  
  36. {  
  37.     wait_queue_t *curr, *next;  
  38.   
  39.     list_for_each_entry_safe(curr, next, &q->task_list, task_list) {  
  40.         unsigned flags = curr->flags;  
  41.   
  42.         if (curr->func(curr, mode, wake_flags, key) && (flags & WQ_FLAG_EXCLUSIVE) && !--nr_exclusive)  
  43.             break;  
  44.     }  

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