套接字之sendmsg系统调用
sendmsg系统调用允许在用户空间构造消息头和控制信息,用此函数可以发送多个数据缓冲区的数据,并支持控制信息;当调用进入内核后,会将用户端的user_msghdr对应拷贝到内核的msghdr中,然后进行数据发送;
SYSCALL_DEFINE3(sendmsg, int, fd, struct user_msghdr __user *, msg, unsigned int, flags)
{
/* 不支持64位采用32位兼容标记 */
if (flags & MSG_CMSG_COMPAT)
return -EINVAL; /* 调用__sys_sendmsg */
return __sys_sendmsg(fd, msg, flags);
}
/*
* BSD sendmsg interface
*/ long __sys_sendmsg(int fd, struct user_msghdr __user *msg, unsigned flags)
{
int fput_needed, err;
struct msghdr msg_sys;
struct socket *sock; /* 查找socket */
sock = sockfd_lookup_light(fd, &err, &fput_needed);
if (!sock)
goto out; /* 发送数据 */
err = ___sys_sendmsg(sock, msg, &msg_sys, flags, NULL, ); fput_light(sock->file, fput_needed);
out:
return err;
}
static int ___sys_sendmsg(struct socket *sock, struct user_msghdr __user *msg,
struct msghdr *msg_sys, unsigned int flags,
struct used_address *used_address,
unsigned int allowed_msghdr_flags)
{
struct compat_msghdr __user *msg_compat =
(struct compat_msghdr __user *)msg;
struct sockaddr_storage address;
struct iovec iovstack[UIO_FASTIOV], *iov = iovstack;
unsigned char ctl[sizeof(struct cmsghdr) + ]
__aligned(sizeof(__kernel_size_t));
/* 20 is size of ipv6_pktinfo */
unsigned char *ctl_buf = ctl;
int ctl_len;
ssize_t err; msg_sys->msg_name = &address; /* 需要做64位采用32位兼容 */
if (MSG_CMSG_COMPAT & flags)
/* 从64位消息头拷贝数据到32位消息头 */
err = get_compat_msghdr(msg_sys, msg_compat, NULL, &iov);
else
/* 从用户空间拷贝消息数据到消息头 */
err = copy_msghdr_from_user(msg_sys, msg, NULL, &iov);
if (err < )
return err; err = -ENOBUFS; /* 控制信息长度错误 */
if (msg_sys->msg_controllen > INT_MAX)
goto out_freeiov; /* 拷贝控制信息 */
flags |= (msg_sys->msg_flags & allowed_msghdr_flags);
ctl_len = msg_sys->msg_controllen;
if ((MSG_CMSG_COMPAT & flags) && ctl_len) {
err =
cmsghdr_from_user_compat_to_kern(msg_sys, sock->sk, ctl,
sizeof(ctl));
if (err)
goto out_freeiov;
ctl_buf = msg_sys->msg_control;
ctl_len = msg_sys->msg_controllen;
} else if (ctl_len) {
BUILD_BUG_ON(sizeof(struct cmsghdr) !=
CMSG_ALIGN(sizeof(struct cmsghdr)));
if (ctl_len > sizeof(ctl)) {
ctl_buf = sock_kmalloc(sock->sk, ctl_len, GFP_KERNEL);
if (ctl_buf == NULL)
goto out_freeiov;
}
err = -EFAULT;
/*
* Careful! Before this, msg_sys->msg_control contains a user pointer.
* Afterwards, it will be a kernel pointer. Thus the compiler-assisted
* checking falls down on this.
*/
if (copy_from_user(ctl_buf,
(void __user __force *)msg_sys->msg_control,
ctl_len))
goto out_freectl;
msg_sys->msg_control = ctl_buf;
} /* 设置发送标记 */
msg_sys->msg_flags = flags; /* 设置非阻塞标记 */
if (sock->file->f_flags & O_NONBLOCK)
msg_sys->msg_flags |= MSG_DONTWAIT;
/*
* If this is sendmmsg() and current destination address is same as
* previously succeeded address, omit asking LSM's decision.
* used_address->name_len is initialized to UINT_MAX so that the first
* destination address never matches.
*/
/* 如果这次发送的地址跟上次成功发送的一致 */
if (used_address && msg_sys->msg_name &&
used_address->name_len == msg_sys->msg_namelen &&
!memcmp(&used_address->name, msg_sys->msg_name,
used_address->name_len)) {
/* 无需进行检查,直接发送 */
err = sock_sendmsg_nosec(sock, msg_sys);
goto out_freectl;
} /* 进行安全模块检查后发送 */
err = sock_sendmsg(sock, msg_sys);
/*
* If this is sendmmsg() and sending to current destination address was
* successful, remember it.
*/ /* 发送成功需要更新成功地址记录 */
if (used_address && err >= ) {
used_address->name_len = msg_sys->msg_namelen;
if (msg_sys->msg_name)
memcpy(&used_address->name, msg_sys->msg_name,
used_address->name_len);
} out_freectl:
if (ctl_buf != ctl)
sock_kfree_s(sock->sk, ctl_buf, ctl_len);
out_freeiov:
kfree(iov);
return err;
}
TCP层的sendmsg实现为tcp_sendmsg,详情请移步<TCP层sendmsg系统调用的实现分析>;
套接字之sendmsg系统调用的更多相关文章
- 套接字之recv系统调用
recv系统调用对sys_recvfrom进行了简单的封装,只是其中不包含地址信息,其只需要从建立连接的另一端接收信息: /* * Receive a datagram from a socket. ...
- 套接字之send系统调用
send系统调用只是对sendto系统调用进行了封装,传递的参数不包含目的地址信息,数据会发送到已经建立连接的另一端的地址: /* * Send a datagram down a socket. * ...
- 套接字之close系统调用
close系统调用用于关闭文件描述符,其系统调用实现如下所示: / * Careful here! We test whether the file pointer is NULL before * ...
- 套接字之sendto系统调用
sendto系统调用用于向指定的目的地址发送数据,其系统调用的流程比较容易理解,如下面所示,其主要完成 (1)将用户数据组织成msghdr,(2)而后调用socket操作的sendmsg:ipv4对应 ...
- 套接字之recvmsg系统调用
recvmsg系统调用允许用户指定msghdr结构来接收数据,可以将数据接收到多个缓冲区中,并且可以接收控制信息:接收信息过程与其他接收系统调用核心一致,都是调用传输层的接收函数进行数据接收: SYS ...
- 套接字之recvfrom系统调用
recvfrom系统调用通过用户传入的接收空间构造msghdr,并且调用sock_recvmsg,该函数调用socket操作的recvmsg函数sock->ops->recvmsg,ipv ...
- 套接字之select系统调用
select是IO多路复用的一种方式,用来等待一个列表中的多个描述符的可读可写状态: SYSCALL_DEFINE5(select, int, n, fd_set __user *, inp, fd_ ...
- 套接字之msghdr结构
用户端在使用sendmsg/recvmsg发送或者接收数据时,会使用msghdr来构造消息,其对应的内核结构为user_msghdr:其中msg_iov向量指向了多个数据区,msg_iovlen标识了 ...
- 【 Linux 】Linux套接字简要说明
Linux套接字 源IP地址和目的IP地址以及源端口和目标端口号的组合称为套接字.其作用于标识客户端请求的服务器和服务. 套接字,支持TCP/IP的网络通信的基本操作单元,可以看做是不同主机之间 ...
随机推荐
- node-images Windows 64-bit with Unsupported runtime 错误解决办法 及 node 历史版本下载
在做项目的时候下载的最新的10.16[2019.6.12]版本,出现了模块不兼容的问题[node-images]. 在git上发现了相同问题 https://github.com/zhangyuanw ...
- oracle重置dba用户密码
1.进入sqlplus里面: [oracle@master ~]$ sqlplus / as sysdba SQL*Plus: Release 12.1.0.2.0 Production on Tue ...
- jquery 知识整理
大纲一.jQuery简介 二.jQuery 和Dom关系及jQuery版本 1.jQuery版本 2.jQuery和Dom转换 三.jQuery 选择器 1.1.基本 1.2.层级 2.基本筛选器 3 ...
- wiki部署
一.准备环节 1.上传软件 [root@web01 tools]# tar xf jdk-8u60-linux-x64.tar.gz -C /application/ [root@web01 ...
- Linux和Windows双系统下Windows系统插入耳机没有声音
我的笔记本装了Windows7和Debian双系统后,在Windows7下,插入耳机竟然没有声音. 按常规思路分析:首先考虑是耳机问题还是笔记本电脑问题.确定耳机没问题后问题就在笔记本身上了.而问题在 ...
- PXE自动化部署
PXE 预启动执行环境,基于tftp条件下完成基于网络的自动化部署软件 原理: 网卡利用自身的tftp 请求dhcp 服务器获取ip和一个pxelinux.0的地址 在给定的tftp目录下存有ks的配 ...
- Nginx实用整理
1. nginx 简述 1.1Nginx是轻量级高并发HTTP服务器和反向代理服务器:同时也是一个IMAP.POP3.SMTP代理服务器:Nginx可以作为一个HTTP服务器进行网站的发布处理,另外N ...
- 标准C语言(5)
无法预知的数字叫随机数,rand标准函数可以用来获得随机数,为了使用这个标准函数需要包含stdlib.h头文件 srand标准函数用来设置随机数种子,这个函数把一个整数作为种子使用不同的种子可以得到不 ...
- 【TJOI 2019】唱、跳、rap和篮球
题意 有 $a$ 个 $0$,$b$ 个 $1$,$c$ 个 $2$,$d$ 个 $3$,求有多少种长度为 $n$ 且不包含 $0123$ 这个子串的字符串个数. $n\le 1000,\space ...
- 页面内置函数${fn:}
引入头文件<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions " %&g ...