sock_sendmsg的代码很简单

  1. int sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
  2. {
  3. struct kiocb iocb;
  4. struct sock_iocb siocb;
  5. int ret;
  6. init_sync_kiocb(&iocb, NULL);
  7. iocb.private = &siocb;
  8. ret = __sock_sendmsg(&iocb, sock, msg, size);
  9. if (-EIOCBQUEUED == ret)
  10. ret = wait_on_sync_kiocb(&iocb);
  11. return ret;
  12. }
首先定义了一个struct kiocb类型的iocb——linux内核中所有I/O操作都要依赖于合格结构,然后初始化它。然后调用__sock_sendmsg,而__sock_sendmsg又调用UDP的sendmsg去做真正的发送。
也就是说,对于UDP的socket来说,sendto调用,真正去做工作的是udp_sendmsg这个函数。
  1. int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
  2. size_t len)
  3. {
  4. struct inet_sock *inet = inet_sk(sk);
  5. struct udp_sock *up = udp_sk(sk);
  6. int ulen = len;
  7. struct ipcm_cookie ipc;
  8. struct rtable *rt = NULL;
  9. int free = 0;
  10. int connected = 0;
  11. __be32 daddr, faddr, saddr;
  12. __be16 dport;
  13. u8 tos;
  14. int err, is_udplite = IS_UDPLITE(sk);
  15. int corkreq = up->corkflag || msg->msg_flags&MSG_MORE;
  16. int (*getfrag)(void *, char *, int, int, int, struct sk_buff *);
将sk转为udp内部使用的类型指针,在TCP/IP中充斥了这样的转换。主要原因是因为对于上层来说,需要一个统一的类型,而到了底层的具体实现时,都会将上层抽象的数据类型,转为自己所需的类型。
并判断该UDP是否是udplite——udplite的定义见http://en.wikipedia.org/wiki/UDP_Lite
  1. if (len > 0xFFFF)
  2. return -EMSGSIZE;
  3. /*
  4. * Check the flags.
  5. */
  6. if (msg->msg_flags & MSG_OOB) /* Mirror BSD error message compatibility */
  7. return -EOPNOTSUPP;
进行一些错误检测。
  1. ipc.opt = NULL;
  2. ipc.shtx.flags = 0;
  3. if (up->pending) {
  4. /*
  5. * There are pending frames.
  6. * The socket lock must be held while it's corked.
  7. */
  8. lock_sock(sk);
  9. if (likely(up->pending)) {
  10. if (unlikely(up->pending != AF_INET)) {
  11. release_sock(sk);
  12. return -EINVAL;
  13. }
  14. goto do_append_data;
  15. }
  16. release_sock(sk);
  17. }
  18. ulen += sizeof(struct udphdr);
如果该socket有pending的frame,那么直接将数据追加。如果没有就ulen加上udp首部的长度。
  1. /*
  2. * Get and verify the address.
  3. */
  4. if (msg->msg_name) {
  5. struct sockaddr_in * usin = (struct sockaddr_in *)msg->msg_name;
  6. if (msg->msg_namelen < sizeof(*usin))
  7. return -EINVAL;
  8. if (usin->sin_family != AF_INET) {
  9. if (usin->sin_family != AF_UNSPEC)
  10. return -EAFNOSUPPORT;
  11. }
  12. daddr = usin->sin_addr.s_addr;
  13. dport = usin->sin_port;
  14. if (dport == 0)
  15. return -EINVAL;
  16. } else {
  17. if (sk->sk_state != TCP_ESTABLISHED)
  18. return -EDESTADDRREQ;
  19. daddr = inet->inet_daddr;
  20. dport = inet->inet_dport;
  21. /* Open fast path for connected socket.
  22. Route will not be used, if at least one option is set.
  23. */
  24. connected = 1;
  25. }
  26. ipc.addr = inet->inet_saddr;
如果msg->msg_name不为空,就说明指定了目的地址,对其进行检验。如果为空,就就需要对sock的状态进行检验,查看其是否是连接状态——UDP的socket同样是可以调用connect,这样就不需要每次都指定发送地址了。

内核中的UDP socket流程(7)——udp_sendmsg相关推荐

  1. 内核中的UDP socket流程(2)——API “sys_socket”

    内核中的UDP socket流程(2)--API "sys_socket" 作者:gfree.wind@gmail.com 原文:http://blog.chinaunix.net ...

  2. 内核中的UDP socket流程(1)

    内核中的UDP socket流程(1)  相对于TCP,UDP协议要简单的多.所以我决定由简入繁,先从UDP协议入手. 前一遍文章已经确定了struct sk_buff被用于socket的接受和发送缓 ...

  3. 内核中的UDP socket流程(5)——inet_create

    进入函数inet_create static int inet_create(struct net *net, struct socket *sock, int protocol,           ...

  4. 内核中的UDP socket流程(3)(4)——sock_create

    好了,闲话少说.上次看到了sys_socket调用sock_create的地方了.下面开始研究sock_create了. sys_socket将自己的参数family, type, protocol传 ...

  5. 内核中的UDP socket流程(6)——sendto

    现在开始新的API sendto,那么就重新回到了socket.c文件. SYSCALL_DEFINE6(sendto, int, fd, void __user *, buff, size_t, l ...

  6. 内核中的UDP socket流程(11)——ip_append_data

    作者:gfree.wind@gmail.com 博客:linuxfocus.blog.chinaunix.net 继续ip_append_data, if (copy > length) cop ...

  7. 一文讲解Linux内核中根文件系统挂载流程

    根文件系统的概念 根文件系统是控制权从linux内核转移到用户空间的一个桥梁.linux内核就类似于一个黑匣子,只向用户提供各种功能的接口,但是功能的具体实现不可见,用户程序通过对这些功能接口的不同整 ...

  8. linux程序获取透传参数,Linux内核中TCP SACK处理流程分析

    frankzfz2014-07-27 17:32 demo121:frankzfz您好: 我想请教一个问题,就是将写好的GenericApp项目(没有配置工具),我加入zigbee协议栈的配置工具后还 ...

  9. Linux内核网络协议栈8—socket监听

    几个问题  了解以下几个问题的同学可以直接忽略下文: 1.listen 库函数主要做了什么?  2. 什么是最大并发连接请求数?  3.什么是等待连接队列? socket 监听相对还是比较简单的,先看 ...

最新文章

  1. Understanding JVM Internals---不得不转载呀
  2. SSH框架整合的流程
  3. 容器化的 DevOps 工作流
  4. 1099: 角谷猜想(多实例测试)
  5. 安卓学习笔记45:初探开源框架OrmLite
  6. 保存Drawable资源为Bitmap文件
  7. JS精粹知识点和我的解释
  8. CAPL编程语言简介
  9. 简单案例之人人网登录界面
  10. 用python编写加减乘除计算器_python实现加减乘除计算器
  11. /etc/profile文件详解
  12. 科研过程中Linux相关问题
  13. 【转发】RS485总线拓扑结构
  14. GROUP BY 条件查询最新时间记录
  15. 历年医院招计算机考题,2020医院招聘考试历年试题——医学影像学(64)
  16. java文字类小游戏2.0版本
  17. Linux上显示sh-4.2$,笔记四、Linux基础入门
  18. win7安装centOS双系统超详细(转)
  19. el 表达式 判断字符串是否相等
  20. 计算机专业的学生简历范文,计算机专业学生的简历范文精选

热门文章

  1. 2021赣一中高考成绩查询,赣州中学2021年高一招生问答
  2. 主板19针接口_装机新人手册:一分钟学会主板跳线
  3. pytorch Embedding模块,自动为文本加载预训练的embedding
  4. scrapy中使用css选择器罗列下一级的所有标签
  5. Python生成(x,y,z)三维坐标序列
  6. 树莓派连接wifi_「树莓派已入侵工控领域」树莓派工控机助力雷诺汽车连接智能电网...
  7. vuejs简单介绍特点
  8. 目录与文件的权限意义
  9. systemctl自定义service
  10. NAS 百科 —— http://baike.baidu.com/item/NAS%E7%BD%91%E7%BB%9C%E5%AD%98%E5%82%A8