test
来源:互联网 发布:vivo手机一键锁屏软件 编辑:程序博客网 时间:2024/06/07 04:33
/* * Connect to a remote host. There is regrettably still a little * TCP 'magic' in here. */int inet_stream_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len, int flags){ struct sock *sk = sock->sk; int err; long timeo; lock_sock(sk); if (uaddr->sa_family == AF_UNSPEC) { err = sk->sk_prot->disconnect(sk, flags); sock->state = err ? SS_DISCONNECTING : SS_UNCONNECTED; goto out; } switch (sock->state) { default: err = -EINVAL; goto out; case SS_CONNECTED: err = -EISCONN; goto out; case SS_CONNECTING: err = -EALREADY; /* Fall out of switch with err, set for this state */ break; /* sock->state在inet_create时被设置为SS_UNCONNECTED */ case SS_UNCONNECTED: err = -EISCONN; /* 在inet_create中调用的sock_init_data函数中sk->sk_state被初始化为TCP_CLOSE */ /* 在inet_create中sk->sk_prot->init中同样会被初始化为TCP_CLOSE,init对应了tcp_v4_init_sock函数,初始化的动作重复了 */ if (sk->sk_state != TCP_CLOSE) goto out; /* 对应tcp_prot.connect,即tcp_v4_connect */ err = sk->sk_prot->connect(sk, uaddr, addr_len); if (err < 0) goto out; /× 更新当前状态为SS_CONNECTING ×/ sock->state = SS_CONNECTING; /* Just entered SS_CONNECTING state; the only * difference is that return value in non-blocking * case is EINPROGRESS, rather than EALREADY. */ err = -EINPROGRESS; break; } timeo = sock_sndtimeo(sk, flags & O_NONBLOCK); if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) { /* Error code is set above */ if (!timeo || !inet_wait_for_connect(sk, timeo)) goto out; err = sock_intr_errno(timeo); if (signal_pending(current)) goto out; } /* Connection was closed by RST, timeout, ICMP error * or another process disconnected us. */ if (sk->sk_state == TCP_CLOSE) goto sock_error; /* sk->sk_err may be not zero now, if RECVERR was ordered by user * and error was received after socket entered established state. * Hence, it is handled normally after connect() return successfully. */ sock->state = SS_CONNECTED; err = 0;out: release_sock(sk); return err;sock_error: err = sock_error(sk) ? : -ECONNABORTED; sock->state = SS_UNCONNECTED; if (sk->sk_prot->disconnect(sk, flags)) sock->state = SS_DISCONNECTING; goto out;
/* This will initiate an outgoing connection. */int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len){ struct inet_sock *inet = inet_sk(sk); struct tcp_sock *tp = tcp_sk(sk); struct sockaddr_in *usin = (struct sockaddr_in *)uaddr; struct rtable *rt; __be32 daddr, nexthop; int tmp; int err; struct ip_options *inet_opt; /* 检查一下地址长度和协议族类型 */ if (addr_len < sizeof(struct sockaddr_in)) return -EINVAL; if (usin->sin_family != AF_INET) return -EAFNOSUPPORT; /× 将nexthop和daddr暂时初始化为目标地址 ×/ nexthop = daddr = usin->sin_addr.s_addr; inet_opt = rcu_dereference(inet->opt); /× 如果指定了源路由选项,则按照指定的下一跳进行处理 ×/ if (inet_opt && inet_opt->srr) { if (!daddr) return -EINVAL; nexthop = inet_opt->faddr; } /× 本地发包需要确认源IP地址和源端口,如果没有提供源IP地址会通过路由查找过程中的inet_select_addr来选择源地址 ×/ /× 路由查找成功后会生成路由缓存项,可以加速后续报文的发送,下面函数返回路由缓存项,包含源IP地址 ×/ tmp = ip_route_connect(&rt, nexthop, inet->saddr, RT_CONN_FLAGS(sk), sk->sk_bound_dev_if, IPPROTO_TCP, inet->sport, usin->sin_port, sk, 1); if (tmp < 0) { if (tmp == -ENETUNREACH) IP_INC_STATS_BH(sock_net(sk), IPSTATS_MIB_OUTNOROUTES); return tmp; } /× 正常TCP连接查找到的都是单播路由 ×/ if (rt->rt_flags & (RTCF_MULTICAST | RTCF_BROADCAST)) { ip_rt_put(rt); return -ENETUNREACH; } /* 使用查完路由后的目的地址更新临时daddr,有可能与用户传入的目的地址不同 */ if (!inet_opt || !inet_opt->srr) daddr = rt->rt_dst; /* 如果没有指定源地址,则使用路由选择的源地址 */ if (!inet->saddr) inet->saddr = rt->rt_src; inet->rcv_saddr = inet->saddr; if (tp->rx_opt.ts_recent_stamp && inet->daddr != daddr) { /* Reset inherited state */ tp->rx_opt.ts_recent = 0; tp->rx_opt.ts_recent_stamp = 0; tp->write_seq = 0; } if (tcp_death_row.sysctl_tw_recycle && !tp->rx_opt.ts_recent_stamp && rt->rt_dst == daddr) { struct inet_peer *peer = rt_get_peer(rt); /* * VJ's idea. We save last timestamp seen from * the destination in peer table, when entering state * TIME-WAIT * and initialize rx_opt.ts_recent from it, * when trying new connection. */ if (peer != NULL && peer->tcp_ts_stamp + TCP_PAWS_MSL >= get_seconds()) { tp->rx_opt.ts_recent_stamp = peer->tcp_ts_stamp; tp->rx_opt.ts_recent = peer->tcp_ts; } } /* 记录目的端口和目的IP */ inet->dport = usin->sin_port; inet->daddr = daddr; /× 设置IP选项的长度 ×/ inet_csk(sk)->icsk_ext_hdr_len = 0; if (inet_opt) inet_csk(sk)->icsk_ext_hdr_len = inet_opt->optlen; /× 允许的最小MSS ×/ tp->rx_opt.mss_clamp = 536; /* Socket identity is still unknown (sport may be zero). * However we set state to SYN-SENT and not releasing socket * lock select source port, enter ourselves into the hash tables and * complete initialization after this. */ /× 马上要发送SYN了,所以可以更新sk->sk_state状态值了 ×/ tcp_set_state(sk, TCP_SYN_SENT); /× 进行端口选择,并与sk绑定,下面会重点分析一下 ×/ err = inet_hash_connect(&tcp_death_row, sk); if (err) goto failure; /× 使用sport更新路由缓存表 ×/ err = ip_route_newports(&rt, IPPROTO_TCP, inet->sport, inet->dport, sk); if (err) goto failure; /* OK, now commit destination to socket. */ /× 更新sock的路由缓存项,设置gso标签 ×/ sk->sk_gso_type = SKB_GSO_TCPV4; sk_setup_caps(sk, &rt->u.dst); /× 计算发送第一个报文的初始化序列号 ×/ if (!tp->write_seq) tp->write_seq = secure_tcp_sequence_number(inet->saddr, inet->daddr, inet->sport, usin->sin_port); /× 计算IP报文ID ×/ inet->id = tp->write_seq ^ jiffies; /× 发送SYN报文 ×/ err = tcp_connect(sk); rt = NULL; if (err) goto failure; return 0;failure: /* * This unhashes the socket and releases the local port, * if necessary. */ tcp_set_state(sk, TCP_CLOSE); ip_rt_put(rt); sk->sk_route_caps = 0; inet->dport = 0; return err;}
/* This will initiate an outgoing connection. */int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len){ struct inet_sock *inet = inet_sk(sk); struct tcp_sock *tp = tcp_sk(sk); struct sockaddr_in *usin = (struct sockaddr_in *)uaddr; struct rtable *rt; __be32 daddr, nexthop; int tmp; int err; struct ip_options *inet_opt; /* 检查一下地址长度和协议族类型 */ if (addr_len < sizeof(struct sockaddr_in)) return -EINVAL; if (usin->sin_family != AF_INET) return -EAFNOSUPPORT; /* 将nexthop和daddr暂时初始化为目标地址 */ nexthop = daddr = usin->sin_addr.s_addr; inet_opt = rcu_dereference(inet->opt); /* 如果指定了源路由选项,则按照指定的下一跳进行处理 */ if (inet_opt && inet_opt->srr) { if (!daddr) return -EINVAL; nexthop = inet_opt->faddr; } /* 本地发包需要确认源IP地址和源端口,如果没有提供源IP地址会通过路由查找过程中的inet_select_addr来选择源地址 */ /* 路由查找成功后会生成路由缓存项,可以加速后续报文的发送,下面函数返回路由缓存项,包含源IP地址 */ tmp = ip_route_connect(&rt, nexthop, inet->saddr, RT_CONN_FLAGS(sk), sk->sk_bound_dev_if, IPPROTO_TCP, inet->sport, usin->sin_port, sk, 1); if (tmp < 0) { if (tmp == -ENETUNREACH) IP_INC_STATS_BH(sock_net(sk), IPSTATS_MIB_OUTNOROUTES); return tmp; } /* 正常TCP连接查找到的都是单播路由 */ if (rt->rt_flags & (RTCF_MULTICAST | RTCF_BROADCAST)) { ip_rt_put(rt); return -ENETUNREACH; } /* 使用查完路由后的目的地址更新临时daddr,有可能与用户传入的目的地址不同 */ if (!inet_opt || !inet_opt->srr) daddr = rt->rt_dst; /* 如果没有指定源地址,则使用路由选择的源地址 */ if (!inet->saddr) inet->saddr = rt->rt_src; inet->rcv_saddr = inet->saddr; if (tp->rx_opt.ts_recent_stamp && inet->daddr != daddr) { /* Reset inherited state */ tp->rx_opt.ts_recent = 0; tp->rx_opt.ts_recent_stamp = 0; tp->write_seq = 0; } if (tcp_death_row.sysctl_tw_recycle && !tp->rx_opt.ts_recent_stamp && rt->rt_dst == daddr) { struct inet_peer *peer = rt_get_peer(rt); /* * VJ's idea. We save last timestamp seen from * the destination in peer table, when entering state * TIME-WAIT * and initialize rx_opt.ts_recent from it, * when trying new connection. */ if (peer != NULL && peer->tcp_ts_stamp + TCP_PAWS_MSL >= get_seconds()) { tp->rx_opt.ts_recent_stamp = peer->tcp_ts_stamp; tp->rx_opt.ts_recent = peer->tcp_ts; } } /* 记录目的端口和目的IP */ inet->dport = usin->sin_port; inet->daddr = daddr; /* 设置IP选项的长度 */ inet_csk(sk)->icsk_ext_hdr_len = 0; if (inet_opt) inet_csk(sk)->icsk_ext_hdr_len = inet_opt->optlen; /* 允许的最小MSS */ tp->rx_opt.mss_clamp = 536; /* Socket identity is still unknown (sport may be zero). * However we set state to SYN-SENT and not releasing socket * lock select source port, enter ourselves into the hash tables and * complete initialization after this. */ /* 马上要发送SYN了,所以可以更新sk->sk_state状态值了 */ tcp_set_state(sk, TCP_SYN_SENT); /* 进行端口选择,并与sk绑定,下面会重点分析一下 */ err = inet_hash_connect(&tcp_death_row, sk); if (err) goto failure; /* 使用sport更新路由缓存表 */ err = ip_route_newports(&rt, IPPROTO_TCP, inet->sport, inet->dport, sk); if (err) goto failure; /* OK, now commit destination to socket. */ /* 更新sock的路由缓存项,设置gso标签 */ sk->sk_gso_type = SKB_GSO_TCPV4; sk_setup_caps(sk, &rt->u.dst); /* 计算发送第一个报文的初始化序列号 */ if (!tp->write_seq) tp->write_seq = secure_tcp_sequence_number(inet->saddr, inet->daddr, inet->sport, usin->sin_port); /* 计算IP报文ID */ inet->id = tp->write_seq ^ jiffies; /* 发送SYN报文 */ err = tcp_connect(sk); rt = NULL; if (err) goto failure; return 0;failure: /* * This unhashes the socket and releases the local port, * if necessary. */ tcp_set_state(sk, TCP_CLOSE); ip_rt_put(rt); sk->sk_route_caps = 0; inet->dport = 0; return err;}
0 0
- test
- test
- test
- test
- test
- test
- test
- Test
- test
- Test
- test
- test
- test
- test
- test
- test
- test
- Test
- Faster RCNN代码理解(Python)
- Android 通过 style 设置状态栏,导航栏等的颜色
- websocket单聊与多聊的简单Demo
- 应用服务器性能优化 之 消息队列(MQ:Message Queue)
- javascript--2.导航条>>缓动效果
- test
- 趣味程序设计_抢n游戏
- fastq文件格式处理工具系列学习
- 关于webview 中使用https 链接 总是弹出认证ssl问题
- 算法提高 矩阵相乘
- JDBC(四)SQL 注入与 PreparedStatement
- 上传word文档
- Android MQTT实现消息推送
- 内存分析工具 MAT 的使用