sys_socketcall() --> sys_sendto()
asmlinkage long sys_sendto(
int fd,
void __user *buff, size_t len,
unsigned flags,
struct sockaddr __user *addr, int addr_len)
{
struct socket *sock;
char address[MAX_SOCK_ADDR];
int err;
struct msghdr msg;
struct iovec iov;
int fput_needed;
struct file *sock_file;
sock_file = fget_light(fd, &fput_needed);
err = -EBADF;
if (!sock_file)
goto out;
sock = sock_from_file(sock_file, &err);
if (!sock)
goto out_put;
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;
if (addr) {
err = move_addr_to_kernel(addr, addr_len, address);
if (err < 0)
goto out_put;
msg.msg_name = address;
msg.msg_namelen = addr_len;
}
if (sock->file->f_flags & O_NONBLOCK)
flags |= MSG_DONTWAIT;
msg.msg_flags = flags;
err =
sock_sendmsg(sock, &msg, len);
out_put:
fput_light(sock_file, fput_needed);
out:
return err;
}
在内核的实现中,send和sendto系统调用最终都会调用到内核函数:
asmlinkage long sys_sendto(
int fd,
void __user *buff, size_t len,
unsigned flags,
struct sockaddr __user *addr, int addr_len)
fd socket文件描述符
buff 指向需要发送的数据
len 需要发送的数据的长度
flags 标志位
addr 数据报文要发送的对方端点的地址信息
addr_len 地址信息的长度
在send系统调用中,参数addr被置为NULL,addr_len为0。sys_sendto首先根据传入的描述符fd,找到对应的struct socket结构体。然后构建内核的消息结构struct msghdr:
内核的消息结构struct--msghdr:
struct
msghdr {
void *msg_name;
int msg_namelen;
struct iovec *msg_iov;
__kernel_size_t -msg_iovlen;
void *msg_control;
__kernel_size_t -msg_controllen;
unsigned msg_flags;
};
msghdr->msg_name
msghdr->msg_namelen
-----------------------------------
msg_name和msg_namelen就是数据报文要发向的对端的地址信息(即sendto系统调用中的addr和addr_len)。当使用send时,它们的值为NULL和0。
msghdr->msg_iov
-----------------------------------
msg_iov的定义如下:
struct--iovec {
void __user *iov_base;
__kernel_size_t iov_len;
};
表示存放待发送数据的一个缓冲区,iov_base是缓冲区的起始地址,指向message, iov_len是缓冲区的长度,指向length。
msghdr->msg_iovlen
-----------------------------------
msg_iovlen是缓冲区的数量,对于sendto和send来讲,msg_iovlen都是1。
msghdr->msg_flags
msghdr->msg_control
msghdr->msg_controllen
-----------------------------------
msg_flags即为传入的参数flags,现在暂时不过多的关注flags的应用。
msg_control和msg_controllen暂时不关注。
sys_sendto构建完这些后,调用sock_sendmsg继续执行发送流程,传入参数为struct msghdr和数据的长度。忽略中间的一些不重要的细节,sock_sendmsg继续调用__sock_sendmsg(),__sock_sendmsg()最后调用struct socket->ops->sendmsg,即对应套接字类型的sendmsg()函数,所有的套接字类型的sendmsg()函数都是
inet_sendmsg(),该函数首先检查本地端口是否已绑定,无绑定则执行自动绑定,而后调用具体协议的sendmsg函数。
send、sendto与sys_sendto之间的关系
最新推荐文章于 2023-10-07 23:16:05 发布