connect系统调用

Posted Alex

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了connect系统调用相关的知识,希望对你有一定的参考价值。

 

 1 /*
 2  *    Attempt to connect to a socket with the server address.  The address
 3  *    is in user space so we verify it is OK and move it to kernel space.
 4  *
 5  *    For 1003.1g we need to add clean support for a bind to AF_UNSPEC to
 6  *    break bindings
 7  *
 8  *    NOTE: 1003.1g draft 6.3 is broken with respect to AX.25/NetROM and
 9  *    other SEQPACKET protocols that take time to connect() as it doesn‘t
10  *    include the -EINPROGRESS status for such sockets.
11  */
12 
13 SYSCALL_DEFINE3(connect, int, fd, struct sockaddr __user *, uservaddr,
14         int, addrlen)
15 {
16     struct socket *sock;
17     struct sockaddr_storage address;
18     int err, fput_needed;
19 
20     /* 找到socket */
21     sock = sockfd_lookup_light(fd, &err, &fput_needed);
22     if (!sock)
23         goto out;
24 
25     /* 地址复制到内核 */
26     err = move_addr_to_kernel(uservaddr, addrlen, &address);
27     if (err < 0)
28         goto out_put;
29 
30     /* 安全检查 */
31     err =
32         security_socket_connect(sock, (struct sockaddr *)&address, addrlen);
33     if (err)
34         goto out_put;
35 
36     /* 调用对应协议族的connect */
37     err = sock->ops->connect(sock, (struct sockaddr *)&address, addrlen,
38                  sock->file->f_flags);
39 out_put:
40     fput_light(sock->file, fput_needed);
41 out:
42     return err;
43 }

 

 1 int inet_stream_connect(struct socket *sock, struct sockaddr *uaddr,
 2             int addr_len, int flags)
 3 {
 4     int err;
 5 
 6     lock_sock(sock->sk);
 7     err = __inet_stream_connect(sock, uaddr, addr_len, flags, 0);
 8     release_sock(sock->sk);
 9     return err;
10 }

 

  1 /*
  2  *    Connect to a remote host. There is regrettably still a little
  3  *    TCP ‘magic‘ in here.
  4  */
  5 int __inet_stream_connect(struct socket *sock, struct sockaddr *uaddr,
  6               int addr_len, int flags, int is_sendmsg)
  7 {
  8     struct sock *sk = sock->sk;
  9     int err;
 10     long timeo;
 11 
 12     /*
 13      * uaddr can be NULL and addr_len can be 0 if:
 14      * sk is a TCP fastopen active socket and
 15      * TCP_FASTOPEN_CONNECT sockopt is set and
 16      * we already have a valid cookie for this socket.
 17      * In this case, user can call write() after connect().
 18      * write() will invoke tcp_sendmsg_fastopen() which calls
 19      * __inet_stream_connect().
 20      */
 21     /* 地址存在 */
 22     if (uaddr) {
 23 
 24         /* 检查地址长度 */
 25         if (addr_len < sizeof(uaddr->sa_family))
 26             return -EINVAL;
 27 
 28         /* 对unspec的特殊处理 */
 29         if (uaddr->sa_family == AF_UNSPEC) {
 30             err = sk->sk_prot->disconnect(sk, flags);
 31             sock->state = err ? SS_DISCONNECTING : SS_UNCONNECTED;
 32             goto out;
 33         }
 34     }
 35 
 36     /* 根据socket状态对应处理 */
 37     switch (sock->state) {
 38     default:
 39         err = -EINVAL;
 40         goto out;
 41         /* 已连接 */
 42     case SS_CONNECTED:
 43         err = -EISCONN;
 44         goto out;
 45         /* 正在连接 */
 46     case SS_CONNECTING:
 47         /* 对是否发消息做不同处理,fastopen*/
 48         if (inet_sk(sk)->defer_connect)
 49             err = is_sendmsg ? -EINPROGRESS : -EISCONN;
 50         else
 51             err = -EALREADY;
 52         /* Fall out of switch with err, set for this state */
 53         break;
 54         /* 未连接 */
 55     case SS_UNCONNECTED:
 56         err = -EISCONN;
 57         /* 需要为closed状态 */
 58         if (sk->sk_state != TCP_CLOSE)
 59             goto out;
 60 
 61         /* 传输层协议的connect */
 62         err = sk->sk_prot->connect(sk, uaddr, addr_len);
 63         if (err < 0)
 64             goto out;
 65 
 66         /* 标记状态为正在连接 */
 67         sock->state = SS_CONNECTING;
 68 
 69         /* fastopen */
 70         if (!err && inet_sk(sk)->defer_connect)
 71             goto out;
 72 
 73         /* Just entered SS_CONNECTING state; the only
 74          * difference is that return value in non-blocking
 75          * case is EINPROGRESS, rather than EALREADY.
 76          */
 77         /* 非阻塞情况返回inprogress,阻塞返回already */
 78         err = -EINPROGRESS;
 79         break;
 80     }
 81 
 82     /* 阻塞情况下需要获取超时时间,非阻塞为0 */
 83     timeo = sock_sndtimeo(sk, flags & O_NONBLOCK);
 84 
 85     /* 已发送或者已收到syn */
 86     if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) {
 87         int writebias = (sk->sk_protocol == IPPROTO_TCP) &&
 88                 tcp_sk(sk)->fastopen_req &&
 89                 tcp_sk(sk)->fastopen_req->data ? 1 : 0;
 90 
 91         /* Error code is set above */
 92         /* 非阻塞退出,阻塞则等待连接,等待剩余时间为0,退出 */
 93         if (!timeo || !inet_wait_for_connect(sk, timeo, writebias))
 94             goto out;
 95 
 96         /* 处理信号,达到最大调度时间或者被打断 */
 97         err = sock_intr_errno(timeo);
 98         if (signal_pending(current))
 99             goto out;
100     }
101 
102     /* Connection was closed by RST, timeout, ICMP error
103      * or another process disconnected us.
104      */
105     /* 状态为关闭 */
106     if (sk->sk_state == TCP_CLOSE)
107         goto sock_error;
108 
109     /* sk->sk_err may be not zero now, if RECVERR was ordered by user
110      * and error was received after socket entered established state.
111      * Hence, it is handled normally after connect() return successfully.
112      */
113 
114     /* 设置为连接状态 */
115     sock->state = SS_CONNECTED;
116     err = 0;
117 out:
118     return err;
119 
120 sock_error:
121     err = sock_error(sk) ? : -ECONNABORTED;
122     /* 设置未连接状态 */
123     sock->state = SS_UNCONNECTED;
124     if (sk->sk_prot->disconnect(sk, flags))
125         sock->state = SS_DISCONNECTING;
126     goto out;
127 }

 

 1 /* 阻塞等待连接 */
 2 static long inet_wait_for_connect(struct sock *sk, long timeo, int writebias)
 3 {
 4     DEFINE_WAIT_FUNC(wait, woken_wake_function);
 5 
 6     /* 添加到等待队列 */
 7     add_wait_queue(sk_sleep(sk), &wait);
 8     sk->sk_write_pending += writebias;
 9 
10     /* Basic assumption: if someone sets sk->sk_err, he _must_
11      * change state of the socket from TCP_SYN_*.
12      * Connect() does not allow to get error notifications
13      * without closing the socket.
14      */
15     /* 等待连接状态改变 */
16     while ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) {
17         release_sock(sk);
18         timeo = wait_woken(&wait, TASK_INTERRUPTIBLE, timeo);
19         lock_sock(sk);
20         if (signal_pending(current) || !timeo)
21             break;
22     }
23 
24     /* 从等待队列移除 */
25     remove_wait_queue(sk_sleep(sk), &wait);
26     sk->sk_write_pending -= writebias;
27     return timeo;
28 }

 

以上是关于connect系统调用的主要内容,如果未能解决你的问题,请参考以下文章

RPC 服务器不可用。调用 ManagementScope.Connect 时

如何测量代码片段的调用次数和经过时间

如何从片段中调用 getSupportFragmentManager()?

如何从片段 KOTLIN 中调用意图 [重复]

connect系统调用

如何减少 TCP connect() 系统调用超时?