您的位置:首页 > 理论基础 > 计算机网络

TCP/IP工作流5 connect 3

2017-02-06 23:26 423 查看

继续TCP connect

如下,来到252行。

252 err = inet_hash_connect(&tcp_death_row, sk);
253     if (err)
254         goto failure;
256     err = ip_route_newports(&rt, IPPROTO_TCP,
257                 inet->sport, inet->dport, sk);
258     if (err)
259         goto failure;
262     sk->sk_gso_type = SKB_GSO_TCPV4;
263     sk_setup_caps(sk, &rt->u.dst);
265     if (!tp->write_seq)
266         tp->write_seq = secure_tcp_sequence_number(inet->saddr,
267                                inet->daddr,
268                                inet->sport,
269                                usin->sin_port);
271     inet->id = tp->write_seq ^ jiffies;
273     err = tcp_connect(sk);
274     rt = NULL;
275     if (err)
276         goto failure;
278     return 0;
280 failure:
285     tcp_set_state(sk, TCP_CLOSE);
286     ip_rt_put(rt);
287     sk->sk_route_caps = 0;
288     inet->dport = 0;
289     return err;
290 }


252:一个函数调用,传入的参数tcp_death_row,变更类型为struct inet_timewait_death_row。定义在net/ipv4/tcp_minisocks.c中。它的作用现在猜测可能是用来记录出现连接失败时,把此TCP socket加入到记录中。另外一个变量sk则是TCP连接的主要数据实例。

函数定义在net/ipv4/inet_hashtables.c中。

这个函数也很长,分两部分来说下。

273 int inet_hash_connect(struct inet_timewait_death_row *death_row,
274               struct sock *sk)
275 {
276     struct inet_hashinfo *hinfo = death_row->hashinfo;
277     const unsigned short snum = inet_sk(sk)->num;
278     struct inet_bind_hashbucket *head;
279     struct inet_bind_bucket *tb;
280     int ret;
282     if (!snum) {
283         int i, remaining, low, high, port;
284         static u32 hint;
285         u32 offset = hint + inet_sk_port_offset(sk);
286         struct hlist_node *node;
287         struct inet_timewait_sock *tw = NULL;
289         inet_get_local_port_range(&low, &high);
290         remaining = (high - low) + 1;
292         local_bh_disable();
293         for (i = 1; i <= remaining; i++) {
294             port = low + (i + offset) % remaining;
295             head = &hinfo->bhash[inet_bhashfn(port, hinfo->bhash_size)];
296             spin_lock(&head->lock);
302             inet_bind_bucket_for_each(tb, node, &head->chain) {
303                 if (tb->port == port) {
304                     BUG_TRAP(!hlist_empty(&tb->owners));
305                     if (tb->fastreuse >= 0)
306                         goto next_port;
307                     if (!__inet_check_established(death_row,
308                                       sk, port,
309                                       &tw))
310                         goto ok;
311                     goto next_port;
312                 }
313             }
315             tb = inet_bind_bucket_create(hinfo->bind_bucket_cachep, head, port);
316             if (!tb) {
317                 spin_unlock(&head->lock);
318                 break;
319             }
320             tb->fastreuse = -1;
321             goto ok;
323         next_port:
324             spin_unlock(&head->lock);
325         }
326         local_bh_enable();
328         return -EADDRNOTAVAIL;


276-280:变量声明。hinfo是struct inet_hashinfo类型,用来记录已经散列的socket和正在监听的socket。

snum:在初始化socket时写入的源端口。当我们发起一个连接时,可以指定一个没有被占用的端口。

head:与hinfo中的成员bhash同样类型,指向一个散列表的表头。

tb:一个散列表项。是head->chain所指向的散列表的元素,从名称可以看出来。bucket就是桶的意思。

ret: return, 与retval一样,是linux系统里的返回值。虽然linux源码格式高度统一,但还是会出现一些不一样的地方。比如这里,跟之前用retval的代码段,应该不是一个人维护的。

282-328:在一个if里面。记得在socket创建时没有指定本地要使用的端口,所以这里传入的端口是0。这个0是在什么时候设置的呢?通过分析socket创建时的代码可以知道,只有当socket类型为RAW_SOCK时,这个端口号才不为0。而我们正在创建的是TCP类型的socket所以是0。代码还是要看下

这段代码是根据本地配置的许可端口范围里,一个个试,直到找到一个可以用的端口。假设每一个端口都有一大堆socket绑定着,如果符合了端口重用的规则的话,说明这个端口我们也可以用。说明找到了就可以跳出循环了。goto ok中的ok标签在下面。这里我们也看到了,可以用goto跳出循环体。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  workflow tcp-ip linux
相关文章推荐