zoukankan      html  css  js  c++  java
  • linux内核之accept实现

    1. 用户态对accept的标准用法:  
    2. if ((client_fd = accept(sockfd, (struct sockaddr *)&remote_addr, &sin_size)) == -1)  
    3.   {  
    4.    //accept()函数让服务器接收客户的连接请求  
    5.    perror("accept Error ");  
    6.    continue;  
    7.   }  
    8. sockfd是通过socket系统调用,并且经过listen过的套接字:  
    9. sockfd = socket(AF_INET, SOCK_STREAM, 0)  
    10. listen(sockfd, 128)  
    11.   
    12. remote_addr将会存储远端设备的地址信息。 
     
    1. SYSCALL_DEFINE3(accept,int, fd,struct sockaddr __user *, upeer_sockaddr,
    2. int __user *, upeer_addrlen)
    3. {
    4. return sys_accept4(fd, upeer_sockaddr, upeer_addrlen,0);
    5. }
    1. SYSCALL_DEFINE4(accept4,int, fd,struct sockaddr __user *, upeer_sockaddr,
    2. int __user *, upeer_addrlen,int, flags)
    3. {
    4. struct socket *sock,*newsock;
    5. struct file *newfile;
    6. int err, len, newfd, fput_needed;
    7. struct sockaddr_storage address;
    8. if(flags &~(SOCK_CLOEXEC | SOCK_NONBLOCK))
    9. {
    10. return-EINVAL;
    11. }
    12. if(SOCK_NONBLOCK != O_NONBLOCK &&(flags & SOCK_NONBLOCK))
    13. {
    14. flags =(flags &~SOCK_NONBLOCK)| O_NONBLOCK;
    15. }
    16. sock = sockfd_lookup_light(fd,&err,&fput_needed);
    17. if(!sock)
    18. {
    19. goto out;
    20. }
    21. err =-ENFILE;
    22. newsock = sock_alloc();/*! 1.创建新的sock给新的连接 */
    23. if(!newsock)
    24. {
    25. goto out_put;
    26. }
    27. newsock->type = sock->type;
    28. newsock->ops = sock->ops;
    29. /*
    30. * We don't need try_module_get here, as the listening socket (sock)
    31. * has the protocol module (sock->ops->owner) held.
    32. */
    33. __module_get(newsock->ops->owner);
    34. newfd = get_unused_fd_flags(flags);/*! 2.分配一个fd给新的连接 */
    35. if(unlikely(newfd <0))
    36. {
    37. err = newfd;
    38. sock_release(newsock);
    39. goto out_put;
    40. }
    41. newfile = sock_alloc_file(newsock, flags, sock->sk->sk_prot_creator->name);/*! 3.为newsock创建一个对应的file结构 */
    42. if(unlikely(IS_ERR(newfile)))
    43. {
    44. err = PTR_ERR(newfile);
    45. put_unused_fd(newfd);
    46. sock_release(newsock);
    47. goto out_put;
    48. }
    49. err = security_socket_accept(sock, newsock);
    50. if(err)
    51. {
    52. goto out_fd;
    53. }
    54. err = sock->ops->accept(sock, newsock, sock->file->f_flags);/*! 4.调用Socket层操作函数inet_accept() */
    55. if(err <0)
    56. {
    57. goto out_fd;
    58. }
    59. if(upeer_sockaddr)
    60. {
    61. if(newsock->ops->getname(newsock,(struct sockaddr *)&address,
    62. &len,2)<0)
    63. {
    64. err =-ECONNABORTED;
    65. goto out_fd;
    66. }
    67. err = move_addr_to_user(&address,
    68. len, upeer_sockaddr, upeer_addrlen);
    69. if(err <0)
    70. {
    71. goto out_fd;
    72. }
    73. }
    74. /* File flags are not inherited via accept() unlike another OSes. */
    75. fd_install(newfd, newfile);
    76. err = newfd;
    77. out_put:
    78. fput_light(sock->file, fput_needed);
    79. out:
    80. return err;
    81. out_fd:
    82. fput(newfile);
    83. put_unused_fd(newfd);
    84. goto out_put;
    85. }
    3、sock_alloc_file()
    1. struct file *sock_alloc_file(struct socket *sock,int flags,constchar*dname)
    2. {
    3. struct qstr name ={.name =""};
    4. struct path path;
    5. struct file *file;
    6. if(dname)
    7. {
    8. name.name = dname;
    9. name.len = strlen(name.name);
    10. }
    11. elseif(sock->sk)
    12. {
    13. name.name = sock->sk->sk_prot_creator->name;
    14. name.len = strlen(name.name);
    15. }
    16. path.dentry = d_alloc_pseudo(sock_mnt->mnt_sb,&name);
    17. if(unlikely(!path.dentry))
    18. {
    19. return ERR_PTR(-ENOMEM);
    20. }
    21. path.mnt = mntget(sock_mnt);
    22. d_instantiate(path.dentry, SOCK_INODE(sock));
    23. file = alloc_file(&path, FMODE_READ | FMODE_WRITE,
    24. &socket_file_ops);
    25. if(unlikely(IS_ERR(file)))
    26. {
    27. /* drop dentry, keep inode */
    28. ihold(path.dentry->d_inode);
    29. path_put(&path);
    30. return file;
    31. }
    32. /*! 注意这里的属性设置 */
    33. sock->file = file;
    34. file->f_flags = O_RDWR |(flags & O_NONBLOCK);
    35. file->private_data = sock;
    36. return file;
    37. }
    4、inet_accept()
    1. /*
    2. * Accept a pending connection. The TCP layer now gives BSD semantics.
    3. */
    4. // <net/ipv4/af_inet.c>
    5. int inet_accept(struct socket *sock,struct socket *newsock,int flags)
    6. {
    7. struct sock *sk1 = sock->sk;
    8. int err =-EINVAL;
    9. /**
    10. * 如果使用的是TCP,则sk_prot为tcp_prot,accept为inet_csk_accept()
    11. * 获取新连接的sock。
    12. */
    13. struct sock *sk2 = sk1->sk_prot->accept(sk1, flags,&err);/*! 4.1.获取新连接的sock */
    14. if(!sk2)
    15. {
    16. goto do_err;
    17. }
    18. lock_sock(sk2);
    19. sock_rps_record_flow(sk2);
    20. WARN_ON(!((1<< sk2->sk_state)&
    21. (TCPF_ESTABLISHED | TCPF_SYN_RECV |
    22. TCPF_CLOSE_WAIT | TCPF_CLOSE)));
    23. sock_graft(sk2, newsock);/*! 4.2.把sock和socket嫁接起来,让它们能相互索引 */
    24. newsock->state = SS_CONNECTED;/*! 4.3.把新socket的状态设为已连接 */
    25. err =0;
    26. release_sock(sk2);
    27. do_err:
    28. return err;
    29. }
    4.2、sock_graft()
    1. // <net/Sock.h>
    2. staticinlinevoid sock_graft(struct sock *sk,struct socket *parent)
    3. {
    4. write_lock_bh(&sk->sk_callback_lock);
    5. sk->sk_wq = parent->wq;
    6. parent->sk = sk; /*! INET层的socket使用下层的sock服务 */
    7. sk_set_socket(sk, parent);
    8. security_sock_graft(sk, parent);
    9. write_unlock_bh(&sk->sk_callback_lock);
    10. }
    4.1、inet_csk_accept()
    /**
     * inet_csk_accept()用于从backlog队列(全连接队列)中取出一个ESTABLISHED状态的连接请求块,返回它所对应的连接sock。
     * 1. 非阻塞的,且当前没有已建立的连接,则直接退出,返回-EAGAIN。
     * 2. 阻塞的,且当前没有已建立的连接:
     *     2.1 用户没有设置超时时间,则无限期阻塞。
     *     2.2 用户设置了超时时间,超时后会退出。
     */
    1. // <net/ipv4/Inet_connection_sock.c>
    2. /*
    3. * This will accept the next outstanding connection.
    4. */
    5. struct sock *inet_csk_accept(struct sock *sk,int flags,int*err)
    6. {
    7. struct inet_connection_sock *icsk = inet_csk(sk);
    8. struct request_sock_queue *queue=&icsk->icsk_accept_queue;
    9. struct sock *newsk;
    10. struct request_sock *req;
    11. int error;
    12. lock_sock(sk);
    13. /* We need to make sure that this socket is listening,
    14. * and that it has something pending.
    15. */
    16. error =-EINVAL;
    17. if(sk->sk_state != TCP_LISTEN)
    18. {
    19. goto out_err;
    20. }
    21. /* Find already established connection */
    22. if(reqsk_queue_empty(queue))// 没有ESTABLISHED状态的连接请求块
    23. {
    24. long timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
    25. /* If this is a non blocking socket don't sleep */
    26. error =-EAGAIN;
    27. if(!timeo)
    28. {
    29. goto out_err;
    30. }
    31. /*! 4.1.1 阻塞等待,直到有全连接。如果用户设置有等待时间,超时后会退出 */
    32. error = inet_csk_wait_for_connect(sk, timeo);
    33. if(error)
    34. {
    35. goto out_err;
    36. }
    37. }
    38. /*! 从全连接队列中取出第一个established状态的连接请求块 */
    39. req = reqsk_queue_remove(queue);
    40. newsk = req->sk;
    41. sk_acceptq_removed(sk);
    42. if(sk->sk_protocol == IPPROTO_TCP &&queue->fastopenq != NULL)
    43. {
    44. spin_lock_bh(&queue->fastopenq->lock);
    45. if(tcp_rsk(req)->listener)
    46. {
    47. /* We are still waiting for the final ACK from 3WHS
    48. * so can't free req now. Instead, we set req->sk to
    49. * NULL to signify that the child socket is taken
    50. * so reqsk_fastopen_remove() will free the req
    51. * when 3WHS finishes (or is aborted).
    52. */
    53. req->sk = NULL;
    54. req = NULL;
    55. }
    56. spin_unlock_bh(&queue->fastopenq->lock);
    57. }
    58. out:
    59. release_sock(sk);
    60. if(req)
    61. {
    62. __reqsk_free(req);
    63. }
    64. return newsk;
    65. out_err:
    66. newsk = NULL;
    67. req = NULL;
    68. *err = error;
    69. goto out;
    70. }
    4.1.1 inet_csk_wait_for_connect()
    1. // <net/ipv4/Inet_connection_sock.c>
    2. /*
    3. * Wait for an incoming connection, avoid race conditions. This must be called
    4. * with the socket locked.
    5. */
    6. staticint inet_csk_wait_for_connect(struct sock *sk,long timeo)
    7. {
    8. struct inet_connection_sock *icsk = inet_csk(sk);
    9. DEFINE_WAIT(wait);
    10. int err;
    11. /*
    12. * True wake-one mechanism for incoming connections: only
    13. * one process gets woken up, not the 'whole herd'.
    14. * Since we do not 'race & poll' for established sockets
    15. * anymore, the common case will execute the loop only once.
    16. *
    17. * Subtle issue: "add_wait_queue_exclusive()" will be added
    18. * after any current non-exclusive waiters, and we know that
    19. * it will always _stay_ after any new non-exclusive waiters
    20. * because all non-exclusive waiters are added at the
    21. * beginning of the wait-queue. As such, it's ok to "drop"
    22. * our exclusiveness temporarily when we get woken up without
    23. * having to remove and re-insert us on the wait queue.
    24. */
    25. for(;;)
    26. {
    27. /*! 把自己加入到等待队列,并且设置自己的状态是可中断的 */
    28. prepare_to_wait_exclusive(sk_sleep(sk),&wait,
    29. TASK_INTERRUPTIBLE);
    30. release_sock(sk);
    31. if(reqsk_queue_empty(&icsk->icsk_accept_queue))
    32. {
    33. /**
    34. * 用户发起的accept操作就停schedule_timeout中
    35. * switch (timeout)
    36. * {
    37. * case MAX_SCHEDULE_TIMEOUT:
    38. * schedule();
    39. * goto out;
    40. * default:
    41. * }
    42. * 根据其实现代码,由于我们一般没有设置timeout值,所以是MAX_SCHEDULE_TIMEOUT的情况,这表示立即进入重新调度,
    43. * 而当前的进程可以处于睡眠,直到被其它事件唤醒。
    44. */
    45. timeo = schedule_timeout(timeo);
    46. }
    47. sched_annotate_sleep();
    48. lock_sock(sk);
    49. err =0;
    50. if(!reqsk_queue_empty(&icsk->icsk_accept_queue))
    51. {
    52. break;
    53. }
    54. err =-EINVAL;
    55. if(sk->sk_state != TCP_LISTEN)
    56. {
    57. break;
    58. }
    59. err = sock_intr_errno(timeo);
    60. if(signal_pending(current))
    61. {
    62. break;
    63. }
    64. err =-EAGAIN;
    65. if(!timeo)
    66. {
    67. break;
    68. }
    69. }
    70. /*! 下面把任务设置成TASK_RUNNING状态,然后把当前sock从等待队列中删除 */
    71. finish_wait(sk_sleep(sk),&wait);
    72. return err;
    73. }
     





  • 相关阅读:
    结对作业(测试版)
    回答自己的提问
    阅读一个程序员的生命周期有感
    阅读13到17章提出问题
    读8 9 10章提出问题
    5.2 5.3测试与封装
    5.1 四则运算单元测试j
    阅读5.5章6章7章提出疑问
    做汉堡
    阅读第1到第5章过程的疑问
  • 原文地址:https://www.cnblogs.com/fengkang1008/p/4688633.html
Copyright © 2011-2022 走看看