recvmsg系统调用允许用户指定msghdr结构来接收数据,可以将数据接收到多个缓冲区中,并且可以接收控制信息;接收信息过程与其他接收系统调用核心一致,都是调用传输层的接收函数进行数据接收;

 SYSCALL_DEFINE3(recvmsg, int, fd, struct user_msghdr __user *, msg,
unsigned int, flags)
{
/* 不支持64位采用32位兼容标记 */
if (flags & MSG_CMSG_COMPAT)
return -EINVAL; /* 接收消息 */
return __sys_recvmsg(fd, msg, flags);
}
 /*
* BSD recvmsg interface
*/ long __sys_recvmsg(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_recvmsg(sock, msg, &msg_sys, flags, ); fput_light(sock->file, fput_needed);
out:
return err;
}
 static int ___sys_recvmsg(struct socket *sock, struct user_msghdr __user *msg,
struct msghdr *msg_sys, unsigned int flags, int nosec)
{
struct compat_msghdr __user *msg_compat =
(struct compat_msghdr __user *)msg;
struct iovec iovstack[UIO_FASTIOV];
struct iovec *iov = iovstack;
unsigned long cmsg_ptr;
int len;
ssize_t err; /* kernel mode address */
struct sockaddr_storage addr; /* user mode address pointers */
struct sockaddr __user *uaddr;
int __user *uaddr_len = COMPAT_NAMELEN(msg); msg_sys->msg_name = &addr; /* 需要做64位采用32位兼容 */
if (MSG_CMSG_COMPAT & flags)
/* 从64位消息头拷贝到32位消息头 */
err = get_compat_msghdr(msg_sys, msg_compat, &uaddr, &iov);
else
/* 拷贝消息头 */
err = copy_msghdr_from_user(msg_sys, msg, &uaddr, &iov);
if (err < )
return err; /* 控制信息 */
cmsg_ptr = (unsigned long)msg_sys->msg_control;
msg_sys->msg_flags = flags & (MSG_CMSG_CLOEXEC|MSG_CMSG_COMPAT); /* We assume all kernel code knows the size of sockaddr_storage */
msg_sys->msg_namelen = ; /* 设置非阻塞标记 */
if (sock->file->f_flags & O_NONBLOCK)
flags |= MSG_DONTWAIT; /* 调用读取函数 */
err = (nosec ? sock_recvmsg_nosec : sock_recvmsg)(sock, msg_sys, flags);
if (err < )
goto out_freeiov;
len = err; /* 拷贝地址到用户空间 */
if (uaddr != NULL) {
err = move_addr_to_user(&addr,
msg_sys->msg_namelen, uaddr,
uaddr_len);
if (err < )
goto out_freeiov;
} /* 拷贝标志到用户空间 */
err = __put_user((msg_sys->msg_flags & ~MSG_CMSG_COMPAT),
COMPAT_FLAGS(msg));
if (err)
goto out_freeiov; /* 拷贝控制信息长度到用户空间 */
if (MSG_CMSG_COMPAT & flags)
err = __put_user((unsigned long)msg_sys->msg_control - cmsg_ptr,
&msg_compat->msg_controllen);
else
err = __put_user((unsigned long)msg_sys->msg_control - cmsg_ptr,
&msg->msg_controllen);
if (err)
goto out_freeiov;
err = len; out_freeiov:
kfree(iov);
return err;
}

TCP层的recvmsg系统调用的实现函数为tcp_recvmsg,具体分析请移步<TCP层recvmsg系统调用的实现分析>;

最新文章

  1. HotApp小程序服务范围资质查询器
  2. 泛函编程(29)-泛函实用结构:Trampoline-不再怕StackOverflow
  3. nodejs随记03
  4. sprint1的个人总结及《构建之法》8、9、10章读后感
  5. 关于ubuntu中的软件安装
  6. 15个nosql
  7. veridata实验例(3)验证veridata发现insert操作不会导致同步
  8. 《DSP using MATLAB》示例Example6.4
  9. OO第二单元多线程电梯总结分析
  10. js 实现二级联动
  11. nginx的启动、停止、重载配置、验证配置
  12. Centos7.4安装配置haproxy和Keepalived
  13. Java中的集合迭代器
  14. 【占位符替换】替换String中的占位符标志位{placeholder}
  15. 用Python开始机器学习(2:决策树分类算法)
  16. ISE中的Force Process Up-to-Date功能:ISE中如何在未综合实现的前提下打开ChipScope ?
  17. Nodepad++ 资料整理
  18. BZOJ2121: 字符串游戏(DP)(字符串删单词,求最多可以删去多少)
  19. git从历史上的某一次提交处建立分支
  20. .net 获取客户端Ip地址

热门文章

  1. vscode 格式化vue代码单引号变双引号
  2. Linux小知识:sudo su和su的区别
  3. 简析P和NP问题的概念
  4. 三剑客-awk(简写)
  5. Get MySQL这5个优化技巧
  6. git取消操作命令
  7. 第八篇 CSS定位
  8. 记一次生产环境presto删表失败的问题
  9. postgres外部表
  10. CDH中Oozie无法卸载