/receive-data-from-socket.md

https://github.com/huy/linux_kernel_study · Markdown · 147 lines · 111 code · 36 blank · 0 comment · 0 complexity · c1f4b020610868f0cef959d6871cd87c MD5 · raw file

  1. # Receive data from socket
  2. asmlinkage long sys_recvfrom(int fd, void __user * ubuf, size_t size, unsigned flags,
  3. struct sockaddr __user *addr, int __user *addr_len)
  4. {
  5. sock_file = fget_light(fd, &fput_needed);
  6. if (!sock_file)
  7. return -EBADF;
  8. ...
  9. sock = sock_from_file(sock_file, &err);
  10. if (!sock)
  11. goto out;
  12. err=sock_recvmsg(sock, &msg, size, flags);
  13. The syscall first look for a socket from file descriptor and call relevent function using the socket data structure
  14. int sock_recvmsg(struct socket *sock, struct msghdr *msg,
  15. size_t size, int flags)
  16. {
  17. ...
  18. ret = __sock_recvmsg(&iocb, sock, msg, size, flags);
  19. ...
  20. }
  21. static inline int __sock_recvmsg(struct kiocb *iocb, struct socket *sock,
  22. struct msghdr *msg, size_t size, int flags)
  23. {
  24. ...
  25. err = sock->ops->recvmsg(iocb, sock, msg, size, flags);
  26. ops is protocol operation struct holding pointers to functions operating on socket file descriptor.
  27. When creating socket this field is filled depending mostly on domain/family and type
  28. int sock_common_recvmsg(struct kiocb *iocb, struct socket *sock,
  29. struct msghdr *msg, size_t size, int flags)
  30. {
  31. struct sock *sk = sock->sk;
  32. int addr_len = 0;
  33. int err;
  34. /* this will delegate its work to internal sock*/
  35. err = sk->sk_prot->recvmsg(iocb, sk, msg, size, flags & MSG_DONTWAIT,
  36. flags & ~MSG_DONTWAIT, &addr_len);
  37. if (err >= 0)
  38. msg->msg_namelen = addr_len;
  39. return err;
  40. }
  41. static int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
  42. size_t len, int noblock, int flags, int *addr_len)
  43. {
  44. struct inet_sock *inet = inet_sk(sk);
  45. struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name;
  46. struct sk_buff *skb;
  47. int copied, err;
  48. int peeked;
  49. /*
  50. * Check any passed addresses
  51. */
  52. if (addr_len)
  53. *addr_len=sizeof(*sin);
  54. if (flags & MSG_ERRQUEUE)
  55. return ip_recv_error(sk, msg, len);
  56. try_again:
  57. skb = __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0),
  58. &peeked, &err);
  59. ...
  60. struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned flags,
  61. int *peeked, int *err)
  62. {
  63. ...
  64. timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
  65. do {
  66. /* Again only user level code calls this function, so nothing
  67. * interrupt level will suddenly eat the receive_queue.
  68. *
  69. * Look at current nfs client by the way...
  70. * However, this function was corrent in any case. 8)
  71. */
  72. unsigned long cpu_flags;
  73. if (flags & MSG_PEEK) {
  74. spin_lock_irqsave(&sk->sk_receive_queue.lock,
  75. cpu_flags);
  76. skb = skb_peek(&sk->sk_receive_queue);
  77. if (skb) {
  78. *peeked = skb->peeked;
  79. skb->peeked = 1;
  80. atomic_inc(&skb->users);
  81. }
  82. spin_unlock_irqrestore(&sk->sk_receive_queue.lock,
  83. cpu_flags);
  84. } else {
  85. skb = skb_dequeue(&sk->sk_receive_queue);
  86. if (skb)
  87. *peeked = skb->peeked;
  88. }
  89. if (skb)
  90. return skb;
  91. /* User doesn't want to wait */
  92. error = -EAGAIN;
  93. if (!timeo)
  94. goto no_packet;
  95. } while (!wait_for_packet(sk, err, &timeo));
  96. static int wait_for_packet(struct sock *sk, int *err, long *timeo_p)
  97. {
  98. int error;
  99. DEFINE_WAIT(wait);
  100. prepare_to_wait_exclusive(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
  101. ...
  102. *timeo_p = schedule_timeout(*timeo_p);
  103. References
  104. 1. http://www.ibm.com/developerworks/linux/library/l-hisock/index.html
  105. 2. http://www.haifux.org/lectures/217/netLec5.pdf