核心中的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。