• 套接字之sendmsg系统调用


    sendmsg系统调用允许在用户空间构造消息头和控制信息,用此函数可以发送多个数据缓冲区的数据,并支持控制信息;当调用进入内核后,会将用户端的user_msghdr对应拷贝到内核的msghdr中,然后进行数据发送;

    1 SYSCALL_DEFINE3(sendmsg, int, fd, struct user_msghdr __user *, msg, unsigned int, flags)
    2 {
    3     /* 不支持64位采用32位兼容标记 */
    4     if (flags & MSG_CMSG_COMPAT)
    5         return -EINVAL;
    6 
    7     /* 调用__sys_sendmsg */
    8     return __sys_sendmsg(fd, msg, flags);
    9 }
     1 /*
     2  *    BSD sendmsg interface
     3  */
     4 
     5 long __sys_sendmsg(int fd, struct user_msghdr __user *msg, unsigned flags)
     6 {
     7     int fput_needed, err;
     8     struct msghdr msg_sys;
     9     struct socket *sock;
    10 
    11     /* 查找socket */
    12     sock = sockfd_lookup_light(fd, &err, &fput_needed);
    13     if (!sock)
    14         goto out;
    15 
    16     /* 发送数据 */
    17     err = ___sys_sendmsg(sock, msg, &msg_sys, flags, NULL, 0);
    18 
    19     fput_light(sock->file, fput_needed);
    20 out:
    21     return err;
    22 }
      1 static int ___sys_sendmsg(struct socket *sock, struct user_msghdr __user *msg,
      2              struct msghdr *msg_sys, unsigned int flags,
      3              struct used_address *used_address,
      4              unsigned int allowed_msghdr_flags)
      5 {
      6     struct compat_msghdr __user *msg_compat =
      7         (struct compat_msghdr __user *)msg;
      8     struct sockaddr_storage address;
      9     struct iovec iovstack[UIO_FASTIOV], *iov = iovstack;
     10     unsigned char ctl[sizeof(struct cmsghdr) + 20]
     11                 __aligned(sizeof(__kernel_size_t));
     12     /* 20 is size of ipv6_pktinfo */
     13     unsigned char *ctl_buf = ctl;
     14     int ctl_len;
     15     ssize_t err;
     16 
     17     msg_sys->msg_name = &address;
     18 
     19     /* 需要做64位采用32位兼容 */
     20     if (MSG_CMSG_COMPAT & flags)
     21         /* 从64位消息头拷贝数据到32位消息头 */
     22         err = get_compat_msghdr(msg_sys, msg_compat, NULL, &iov);
     23     else
     24         /* 从用户空间拷贝消息数据到消息头 */
     25         err = copy_msghdr_from_user(msg_sys, msg, NULL, &iov);
     26     if (err < 0)
     27         return err;
     28 
     29     err = -ENOBUFS;
     30 
     31     /* 控制信息长度错误 */
     32     if (msg_sys->msg_controllen > INT_MAX)
     33         goto out_freeiov;
     34 
     35     /* 拷贝控制信息 */
     36     flags |= (msg_sys->msg_flags & allowed_msghdr_flags);
     37     ctl_len = msg_sys->msg_controllen;
     38     if ((MSG_CMSG_COMPAT & flags) && ctl_len) {
     39         err =
     40             cmsghdr_from_user_compat_to_kern(msg_sys, sock->sk, ctl,
     41                              sizeof(ctl));
     42         if (err)
     43             goto out_freeiov;
     44         ctl_buf = msg_sys->msg_control;
     45         ctl_len = msg_sys->msg_controllen;
     46     } else if (ctl_len) {
     47         BUILD_BUG_ON(sizeof(struct cmsghdr) !=
     48                  CMSG_ALIGN(sizeof(struct cmsghdr)));
     49         if (ctl_len > sizeof(ctl)) {
     50             ctl_buf = sock_kmalloc(sock->sk, ctl_len, GFP_KERNEL);
     51             if (ctl_buf == NULL)
     52                 goto out_freeiov;
     53         }
     54         err = -EFAULT;
     55         /*
     56          * Careful! Before this, msg_sys->msg_control contains a user pointer.
     57          * Afterwards, it will be a kernel pointer. Thus the compiler-assisted
     58          * checking falls down on this.
     59          */
     60         if (copy_from_user(ctl_buf,
     61                    (void __user __force *)msg_sys->msg_control,
     62                    ctl_len))
     63             goto out_freectl;
     64         msg_sys->msg_control = ctl_buf;
     65     }
     66 
     67     /* 设置发送标记 */
     68     msg_sys->msg_flags = flags;
     69 
     70     /* 设置非阻塞标记 */
     71     if (sock->file->f_flags & O_NONBLOCK)
     72         msg_sys->msg_flags |= MSG_DONTWAIT;
     73     /*
     74      * If this is sendmmsg() and current destination address is same as
     75      * previously succeeded address, omit asking LSM's decision.
     76      * used_address->name_len is initialized to UINT_MAX so that the first
     77      * destination address never matches.
     78      */
     79     /* 如果这次发送的地址跟上次成功发送的一致 */
     80     if (used_address && msg_sys->msg_name &&
     81         used_address->name_len == msg_sys->msg_namelen &&
     82         !memcmp(&used_address->name, msg_sys->msg_name,
     83             used_address->name_len)) {
     84         /* 无需进行检查,直接发送 */
     85         err = sock_sendmsg_nosec(sock, msg_sys);
     86         goto out_freectl;
     87     }
     88 
     89     /* 进行安全模块检查后发送 */
     90     err = sock_sendmsg(sock, msg_sys);
     91     /*
     92      * If this is sendmmsg() and sending to current destination address was
     93      * successful, remember it.
     94      */
     95 
     96     /* 发送成功需要更新成功地址记录 */
     97     if (used_address && err >= 0) {
     98         used_address->name_len = msg_sys->msg_namelen;
     99         if (msg_sys->msg_name)
    100             memcpy(&used_address->name, msg_sys->msg_name,
    101                    used_address->name_len);
    102     }
    103 
    104 out_freectl:
    105     if (ctl_buf != ctl)
    106         sock_kfree_s(sock->sk, ctl_buf, ctl_len);
    107 out_freeiov:
    108     kfree(iov);
    109     return err;
    110 }

    TCP层的sendmsg实现为tcp_sendmsg,详情请移步<TCP层sendmsg系统调用的实现分析>;

  • 相关阅读:
    异常
    JAVA Math类
    Spring Cloud微服务Sentinel+Apollo限流、熔断实战总结
    JAVA之JDBC数据库连接池总结篇
    利用Python-docx 读写 Word 文档中的正文、表格、段落、字体等
    python3 最基本且简单的实现组合设计模式
    原生工程接入Flutter实现混编
    a[i][j] 和 a[j][i] 有什么区别?
    iconv函数报错 Detected an illegal character in input string
    用Python把20年的GDP、人口以及房价数据进行了可视化
  • 原文地址:https://www.cnblogs.com/wanpengcoder/p/11749313.html
Copyright © 2020-2023  润新知