📄 2_4网络代码阅读笔记(5) - china linux forum.htm
字号:
EALREADY. <BR>*/ <BR>err = -EINPROGRESS; <BR>break; <BR>}
<BR>>>>>return flags&O_NONBLOCK ? 0 :
sk->sndtimeo;
<BR>>>>>sk->sndtimeo在创建socket的时候,在函数sock_init_data里赋值
<BR>>>>>sk->sndtimeo=MAX_SCHEDULE_TIMEOUT;可以通过setsockopt修改
<BR>timeo = sock_sndtimeo(sk, flags&O_NONBLOCK);
<BR>>>>>判断TCP状态机是不是TCPF_SYN_SENT或者TCPF_SYN_RECV <BR>if
((1<<SK->state)&(TCPF_SYN_SENT|TCPF_SYN_RECV)) { <BR>/* Error
code is set above */
<BR>>>>>如果为非阻塞,或者(inet_wait_for_connect好象不会返回0,除非time0=0.
<BR>>>>>看看后面的代码) <BR>if (!timeo ||
!inet_wait_for_connect(sk, timeo)) <BR>goto out; <BR>err =
sock_intr_errno(timeo); <BR>if (signal_pending(current)) <BR>goto
out; <BR>} <BR>/* Connection was closed by RST, timeout, ICMP error
<BR>* or another process disconnected us. <BR>*/ <BR>if
(sk->state == TCP_CLOSE) <BR>goto sock_error; <BR>/* sk->err
may be not zero now, if RECVERR was ordered by user <BR>* and error
was received after socket entered established state. <BR>* Hence, it
is handled normally after connect() return successfully. <BR>*/
<BR>>>>>将socket的状态置为SS_CONNECTED <BR>sock->state =
SS_CONNECTED; <BR>err = 0; <BR>out: <BR>release_sock(sk); <BR>return
err; <BR>sock_error: <BR>err = sock_error(sk) ? : -ECONNABORTED;
<BR>sock->state = SS_UNCONNECTED; <BR>if
(sk->prot->disconnect(sk, flags)) <BR>sock->state =
SS_DISCONNECTING; <BR>goto out; <BR>}
<BR><BR><BR>>>>>当syn数据报发送出去后,等待连接建立 <BR>static long
inet_wait_for_connect(struct sock *sk, long timeo) <BR>{
<BR>DECLARE_WAITQUEUE(wait, current); <BR>>>>>当前进程为可中断
<BR>__set_current_state(TASK_INTERRUPTIBLE);
<BR>add_wait_queue(sk->sleep, &wait); <BR>/* Basic
assumption: if someone sets sk->err, he _must_ <BR>* change state
of the socket from TCP_SYN_*. <BR>* Connect() does not allow to get
error notifications <BR>* without closing the socket. <BR>*/
<BR>>>>>如果状态机仍为TCP_SYN_SEND或者TCP_SYN_RECV,则睡眠等待状态变化
<BR>while ((1<<SK->state)&(TCPF_SYN_SENT|TCPF_SYN_RECV)) {
<BR>release_sock(sk); <BR>timeo = schedule_timeout(timeo);
<BR>lock_sock(sk); <BR>if (signal_pending(current) || !timeo)
<BR>break; <BR>set_current_state(TASK_INTERRUPTIBLE); <BR>}
<BR>__set_current_state(TASK_RUNNING);
<BR>remove_wait_queue(sk->sleep, &wait); <BR>return timeo;
<BR>} <BR><BR>下面是tcp_v4_connect: <BR><BR>/* This will initiate an
outgoing connection. */ <BR>int tcp_v4_connect(struct sock *sk,
struct sockaddr *uaddr, int addr_len) <BR>{ <BR>struct tcp_opt *tp =
&(sk->tp_pinfo.af_tcp); <BR>struct sockaddr_in *usin =
(struct sockaddr_in *) uaddr; <BR>struct sk_buff *buff; <BR>struct
rtable *rt; <BR>u32 daddr, nexthop; <BR>int tmp; <BR>int err;
<BR>................... <BR>>>>>uaddr是用户传入的服务器的地址
<BR>nexthop = daddr = usin->sin_addr.s_addr; <BR>if
(sk->protinfo.af_inet.opt &&
sk->protinfo.af_inet.opt->srr) { <BR>if (daddr == 0)
<BR>return -EINVAL; <BR>nexthop =
sk->protinfo.af_inet.opt->faddr; <BR>}
<BR>>>>>根据源地址、目的地址、TOS以及出口网络设备选择一条路由 <BR>tmp =
ip_route_connect(&rt, nexthop, sk->saddr,
<BR>RT_TOS(sk->protinfo.af_inet.tos)|RTO_CONN|sk->localroute,
sk->bound_d <BR>ev_if); <BR>if (tmp < 0) <BR>return tmp;
<BR>if (rt->rt_flags&(RTCF_MULTICAST|RTCF_BROADCAST)) {
<BR>ip_rt_put(rt); <BR>return -ENETUNREACH; <BR>}
<BR>>>>>old_dst = sk->dst_cache;
<BR>>>>>sk->dst_cache = dst;
<BR>>>>>dst_release(old_dst); <BR>__sk_dst_set(sk,
&rt->u.dst); <BR>sk->route_caps =
rt->u.dst.dev->features; <BR>if (!sk->protinfo.af_inet.opt
|| !sk->protinfo.af_inet.opt->srr) <BR>daddr = rt->rt_dst;
<BR>err = -ENOBUFS; <BR>>>>>分配syn数据报文sk_buff <BR>buff =
alloc_skb(MAX_TCP_HEADER + 15, GFP_KERNEL); <BR>if (buff == NULL)
<BR>goto failure; <BR>>>>>源地址 <BR>if (!sk->saddr)
<BR>sk->saddr = rt->rt_src; <BR>sk->rcv_saddr =
sk->saddr; <BR>if (tp->ts_recent_stamp && sk->daddr
!= daddr) { <BR>/* Reset inherited state */ <BR>tp->ts_recent =
0; <BR>tp->ts_recent_stamp = 0; <BR>tp->write_seq = 0; <BR>}
<BR>if (sysctl_tcp_tw_recycle && <BR>!tp->ts_recent_stamp
&& <BR>rt->rt_dst == daddr) { <BR>struct inet_peer *peer
= rt_get_peer(rt); <BR>/* VJ's idea. We save last timestamp seen
from <BR>* the destination in peer table, when entering state
TIME-WAIT <BR>* and initialize ts_recent from it, when trying new
connection. <BR>*/ <BR>if (peer && peer->tcp_ts_stamp +
TCP_PAWS_MSL >= xtime.tv_sec) { <BR>tp->ts_recent_stamp =
peer->tcp_ts_stamp; <BR>tp->ts_recent = peer->tcp_ts; <BR>}
<BR>} <BR>sk->dport = usin->sin_port; <BR>sk->daddr =
daddr; <BR>if (!tp->write_seq) <BR>>>>>获取初始序列号
<BR>tp->write_seq = secure_tcp_sequence_number(sk->saddr,
sk->daddr, <BR>sk->sport, usin->sin_port);
<BR>tp->ext_header_len = 0; <BR>if (sk->protinfo.af_inet.opt)
<BR>tp->ext_header_len = sk->protinfo.af_inet.opt->optlen;
<BR>sk->protinfo.af_inet.id = tp->write_seq^jiffies;
<BR>>>>>初始MSS=536 <BR>tp->mss_clamp = 536;
<BR>>>>>发送syn数据报文 <BR>err = tcp_connect(sk, buff);
<BR>if (err == 0) <BR>return 0; <BR>failure: <BR>__sk_dst_reset(sk);
<BR>sk->route_caps = 0; <BR>sk->dport = 0; <BR>return err;
<BR>}
<BR><BR>ip_route_connect调用ip_route_output,它先在路由高速缓冲(由rt_hash_table哈希
<BR>链表表示)中查找,如果没有找到,则调用ip_route_output_slow,它调用fib_lookup
<BR>到转发信息表fib_tables(结构structfib_table)中去查找,此时找到正确的的路由 <BR>后:
<BR>rth = dst_alloc(&ipv4_dst_ops);
<BR>atomic_set(&rth->u.dst.__refcnt, 1);
<BR>rth->u.dst.flags= DST_HOST; <BR>rth->key.dst =
oldkey->dst; <BR>rth->key.tos = tos; <BR>rth->key.src =
oldkey->src; <BR>rth->key.iif = 0; <BR>rth->key.oif =
oldkey->oif; <BR>rth->rt_dst = key.dst; <BR>rth->rt_src =
key.src; <BR>rth->rt_iif = oldkey->oif ? :
dev_out->ifindex; <BR>rth->u.dst.dev = dev_out;
<BR>dev_hold(dev_out); <BR>rth->rt_gateway = key.dst;
<BR>rth->rt_spec_dst= key.src; <BR>>>>>发包例程
<BR>rth->u.dst.output=ip_output; <BR>if (flags&RTCF_LOCAL) {
<BR>>>>>收包例程 <BR>rth->u.dst.input = ip_local_deliver;
<BR>rth->rt_spec_dst = key.dst; <BR>} <BR>if
(flags&(RTCF_BROADCAST|RTCF_MULTICAST)) {
<BR>rth->rt_spec_dst = key.src; <BR>if (flags&RTCF_LOCAL
&& !(dev_out->flags&IFF_LOOPBACK))
<BR>rth->u.dst.output = ip_mc_output;
<BR>................................................... <BR>}
<BR>rt_set_nexthop(rth, &res, 0); <BR>rth->rt_flags = flags;
<BR>hash = rt_hash_code(oldkey->dst,
oldkey->src^(oldkey->oif<<5), tos);
<BR><BR>>>>>对可能的arp做准备,并将得到的路由信息添加到路由高速缓冲中。 <BR>err =
rt_intern_hash(hash, rth, rp); <BR><BR><BR><BR>下面就是tcp_connect:
<BR>int tcp_connect(struct sock *sk, struct sk_buff *buff) <BR>{
<BR>>>>>路由信息 <BR>struct dst_entry *dst =
__sk_dst_get(sk); <BR>struct tcp_opt *tp =
&(sk->tp_pinfo.af_tcp); <BR>/* Reserve space for headers. */
<BR>skb_reserve(buff, MAX_TCP_HEADER); <BR>/* We'll fix this up when
we get a response from the other end. <BR>* See
tcp_input.c:tcp_rcv_state_process case TCP_SYN_SENT. <BR>*/
<BR>>>>>tcp报头长度 <BR>tp->tcp_header_len =
sizeof(struct tcphdr) + <BR>(sysctl_tcp_timestamps ?
TCPOLEN_TSTAMP_ALIGNED : 0); <BR>/* If user gave his TCP_MAXSEG,
record it to clamp */ <BR>>>>>将用户给定的mss赋给mss_clamp
<BR>if (tp->user_mss) <BR>tp->mss_clamp = tp->user_mss;
<BR>tp->max_window = 0; <BR>>>>>计算几个TCB的几个与mss相关的域
<BR>>>>> tp->user_mss is mss set by user by
TCP_MAXSEG. It does NOT counts <BR>>>>> for TCP options,
but includes only bare TCP header. <BR>>>>>
tp->mss_clamp is mss negotiated at connection setup.
<BR>>>>> It is minumum of user_mss and mss received with
SYN. <BR>>>>> It also does not include TCP options.
<BR>>>>> tp->pmtu_cookie is last pmtu, seen by this
function. <BR>>>>> tp->mss_cache is current effective
sending mss, including <BR>>>>> all tcp options except
for SACKs. It is evaluated, <BR>>>>> taking into account
current pmtu, but never exceeds <BR>>>>>
tp->mss_clamp. <BR>tcp_sync_mss(sk, dst->pmtu); <BR>if
(!tp->window_clamp) <BR>tp->window_clamp = dst->window;
<BR>tp->advmss = dst->advmss;
<BR>>>>>计算tp->ack.rcv_mss的值 <BR>>>>>
RCV_MSS is an our guess about MSS used by the peer.
<BR>>>>> We haven't any direct information about the
MSS. <BR>>>>> It's better to underestimate the RCV_MSS
rather than overestimate. <BR>>>>> Overestimations make
us ACKing less frequently than needed. <BR>>>>>
Underestimations are more easy to detect and fix by
tcp_measure_rcv_ms <BR>>>>> s().
<BR>tcp_initialize_rcv_mss(sk);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -