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系统调用的主要内容,如果未能解决你的问题,请参考以下文章