现在开始新的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发送出去。