accept系统调用

Posted Alex

tags:

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

 

  1 /*
  2  *    For accept, we attempt to create a new socket, set up the link
  3  *    with the client, wake up the client, then return the new
  4  *    connected fd. We collect the address of the connector in kernel
  5  *    space and move it to user at the very end. This is unclean because
  6  *    we open the socket then return an error.
  7  *
  8  *    1003.1g adds the ability to recvmsg() to query connection pending
  9  *    status to recvmsg. We need to add that support in a way thats
 10  *    clean when we restucture accept also.
 11  */
 12 
 13 SYSCALL_DEFINE4(accept4, int, fd, struct sockaddr __user *, upeer_sockaddr,
 14         int __user *, upeer_addrlen, int, flags)
 15 {
 16     struct socket *sock, *newsock;
 17     struct file *newfile;
 18     int err, len, newfd, fput_needed;
 19     struct sockaddr_storage address;
 20 
 21     /* 只支持cloexec和nonblock */
 22     if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
 23         return -EINVAL;
 24 
 25     /* 如果阻塞标记不等&& 有阻塞标记,则替换为O_NONBLOCK */
 26     if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK))
 27         flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK;
 28 
 29     /* 找到socket */
 30     sock = sockfd_lookup_light(fd, &err, &fput_needed);
 31     if (!sock)
 32         goto out;
 33 
 34     err = -ENFILE;
 35 
 36     /* 分配一个新socket */
 37     newsock = sock_alloc();
 38     if (!newsock)
 39         goto out_put;
 40 
 41     /* 类型和操作与本端socket相同 */
 42     newsock->type = sock->type;
 43     newsock->ops = sock->ops;
 44 
 45     /*
 46      * We don‘t need try_module_get here, as the listening socket (sock)
 47      * has the protocol module (sock->ops->owner) held.
 48      */
 49     /* 增加模块引用 */
 50     __module_get(newsock->ops->owner);
 51 
 52     /* 获取新的文件描述符 */
 53     newfd = get_unused_fd_flags(flags);
 54     if (unlikely(newfd < 0)) {
 55         err = newfd;
 56         sock_release(newsock);
 57         goto out_put;
 58     }
 59 
 60     /* 分配新的文件 */
 61     newfile = sock_alloc_file(newsock, flags, sock->sk->sk_prot_creator->name);
 62     if (IS_ERR(newfile)) {
 63         err = PTR_ERR(newfile);
 64         put_unused_fd(newfd);
 65         sock_release(newsock);
 66         goto out_put;
 67     }
 68 
 69     /* accept检查 */
 70     err = security_socket_accept(sock, newsock);
 71     if (err)
 72         goto out_fd;
 73 
 74     /* 执行具体的accept操作 */
 75     err = sock->ops->accept(sock, newsock, sock->file->f_flags, false);
 76     if (err < 0)
 77         goto out_fd;
 78 
 79     /* 指定了获取对端信息 */
 80     if (upeer_sockaddr) {
 81         if (newsock->ops->getname(newsock, (struct sockaddr *)&address,
 82                       &len, 2) < 0) {
 83             err = -ECONNABORTED;
 84             goto out_fd;
 85         }
 86 
 87         /* 拷贝对端地址到用户空间结构 */
 88         err = move_addr_to_user(&address,
 89                     len, upeer_sockaddr, upeer_addrlen);
 90         if (err < 0)
 91             goto out_fd;
 92     }
 93 
 94     /* File flags are not inherited via accept() unlike another OSes. */
 95 
 96     /* 绑定描述符和文件 */
 97     fd_install(newfd, newfile);
 98     err = newfd;
 99 
100 out_put:
101     fput_light(sock->file, fput_needed);
102 out:
103     return err;
104 out_fd:
105     fput(newfile);
106     put_unused_fd(newfd);
107     goto out_put;
108 }
109 
110 SYSCALL_DEFINE3(accept, int, fd, struct sockaddr __user *, upeer_sockaddr,
111         int __user *, upeer_addrlen)
112 {
113     return sys_accept4(fd, upeer_sockaddr, upeer_addrlen, 0);
114 }

 

 

 1 /*
 2  *    Accept a pending connection. The TCP layer now gives BSD semantics.
 3  */
 4 
 5 int inet_accept(struct socket *sock, struct socket *newsock, int flags,
 6         bool kern)
 7 {
 8     struct sock *sk1 = sock->sk;
 9     int err = -EINVAL;
10 
11     /* 执行传输层的accept操作 */
12     struct sock *sk2 = sk1->sk_prot->accept(sk1, flags, &err, kern);
13 
14     if (!sk2)
15         goto do_err;
16 
17     lock_sock(sk2);
18 
19     /* rps处理 */
20     sock_rps_record_flow(sk2);
21     WARN_ON(!((1 << sk2->sk_state) &
22           (TCPF_ESTABLISHED | TCPF_SYN_RECV |
23           TCPF_CLOSE_WAIT | TCPF_CLOSE)));
24 
25     /* 控制块连接到新的socket */
26     sock_graft(sk2, newsock);
27 
28     /* 设置新socket的状态为连接 */
29     newsock->state = SS_CONNECTED;
30     err = 0;
31     release_sock(sk2);
32 do_err:
33     return err;
34 }
35 EXPORT_SYMBOL(inet_accept);

 

红色部分的传输层accept实现在tcp代码阅读时再做分析;

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

TCP层accept系统调用的实现分析

如何在 gen_tcp:accept 上调用(和睡眠)并同时处理系统消息?

linux 内核中accept实现

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

h5 input 调用摄像头或者相册

accept接受连接