天天看点

内核中的UDP socket流程(6)——sendto

内核中的UDP socket流程(6)——sendto作者:[email protected]

现在开始新的API sendto,那么就重新回到了socket.c文件。

SYSCALL_DEFINE6(sendto, int, fd, void __user *, buff, size_t, len,

          unsigned, flags, struct sockaddr __user *, addr,

          int, addr_len)

{

     struct socket *sock;

     struct sockaddr_storage address;

     int err;

     struct msghdr msg;

     struct iovec iov;

     int fput_needed;

     sock = sockfd_lookup_light(fd, &err, &fput_needed);

     if (!sock)

          goto out;

通过函数sockfd_lookup_light和参数fd,来得到对应的sock。sockfd_lookup_light的实现比较简单,fd就是进程的fdtable的索引。通过这个fd索引就可以得到对应的file指针,然后在从file指针中,得到sock的地址。

     iov.iov_base = buff;

     iov.iov_len = len;

     msg.msg_name = NULL;

     msg.msg_iov = &iov;

     msg.msg_iovlen = 1;

     msg.msg_control = NULL;

     msg.msg_controllen = 0;

     msg.msg_namelen = 0;

初始化iov和msg,因为这里的消息传递方式采用的是4.4 BSD的消息传递方式。

struct msghdr {

     void * msg_name; /* Socket name */

     int msg_namelen; /* Length of name */

     struct iovec * msg_iov; /* Data blocks */

     __kernel_size_t msg_iovlen; /* Number of blocks */

     void * msg_control; /* Per protocol magic (eg BSD file descriptor passing) */

     __kernel_size_t msg_controllen; /* Length of cmsg list */

     unsigned msg_flags;

};

通过查看msghdr结构体的定义,可以很容易的理解上述代码。

    if (addr) {

          err = move_addr_to_kernel(addr, addr_len, (struct sockaddr *)&address);

          if (err 0)

               goto out_put;

          msg.msg_name = (struct sockaddr *)&address;

          msg.msg_namelen = addr_len;

     }

     if (sock->file->f_flags & O_NONBLOCK)

          flags |= MSG_DONTWAIT;

     msg.msg_flags = flags;

如果sendto指定了addr,那么首先将用户空间的地址addr复制到kernel空间的address中,并用内核空间的address来初始化msg;如果该socket指定了O_NONBLOCK,那么将flags设置上MSG_DONTWAIT,并将flags赋给msg.msg_flags。

err = sock_sendmsg(sock, &msg, len);

最后调用sock_sendmsg,将msg发送出去。

今天的sendto比较简单,就这么几行代码。明天学习sock_sendmsg。

继续阅读