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