注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

gmd20的个人空间

// 编程和生活

 
 
 

日志

 
 

linux raw socket 相关源码  

2014-09-19 14:07:36|  分类: linux相关 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
用到的产品代码,购买的源码之后,是在raw socket上面实现了的 sctp协议。
发现很奇怪的用法,select之后,先使用ioctl获取socket可读内容长度,然后才recvfrom 收数据。
网上看到有人说可能 ioctl FIONREAD 返回0 ,然后 recvfrom 用 0 长度缓存收包会导致数据丢失。
http://stackoverflow.com/questions/784748/raw-socket-receive-buffer
看可一下内核代码,我觉得这个情况应该不会,  ioctl返回的是保护ip 头的长度。   如果前面有0长度,丢掉也是0长度的skb吧。 没看到skb会合并的。
 
http://lxr.free-electrons.com/source/net/ipv4/af_inet.c

960 static const struct proto_ops inet_sockraw_ops = {
961         .family            = PF_INET,
962         .owner             = THIS_MODULE,
963         .release           = inet_release,
964         .bind              = inet_bind,
965         .connect           = inet_dgram_connect,
966         .socketpair        = sock_no_socketpair,
967         .accept            = sock_no_accept,
968         .getname           = inet_getname,
969         .poll              = datagram_poll,    // poll 函数 
970         .ioctl             = inet_ioctl,
971         .listen            = sock_no_listen,
972         .shutdown          = inet_shutdown,
973         .setsockopt        = sock_common_setsockopt,
974         .getsockopt        = sock_common_getsockopt,
975         .sendmsg           = inet_sendmsg,
976         .recvmsg           = inet_recvmsg,      //调用raw_recvmsg

977         .mmap              = sock_no_mmap,
978         .sendpage          = inet_sendpage,
979 #ifdef CONFIG_COMPAT
980         .compat_setsockopt = compat_sock_common_setsockopt,
981         .compat_getsockopt = compat_sock_common_getsockopt,
982         .compat_ioctl      = inet_compat_ioctl,
983 #endif
984 };
http://lxr.free-electrons.com/source/net/ipv4/raw.c
883 struct proto raw_prot = {
884         .name              = "RAW",
885         .owner             = THIS_MODULE,
886         .close             = raw_close,
887         .destroy           = raw_destroy,
888         .connect           = ip4_datagram_connect,
889         .disconnect        = udp_disconnect,
890         .ioctl             = raw_ioctl,     /// ioctl 
891         .init              = raw_init,
892         .setsockopt        = raw_setsockopt,
893         .getsockopt        = raw_getsockopt,
894         .sendmsg           = raw_sendmsg,
895         .recvmsg           = raw_recvmsg,   // 接收
896         .bind              = raw_bind,
897         .backlog_rcv       = raw_rcv_skb,   // 把包传上来
898         .release_cb        = ip4_datagram_release_cb,
899         .hash              = raw_hash_sk,
900         .unhash            = raw_unhash_sk,
901         .obj_size          = sizeof(struct raw_sock),
902         .h.raw_hash        = &raw_v4_hashinfo,
903 #ifdef CONFIG_COMPAT
904         .compat_setsockopt = compat_raw_setsockopt,
905         .compat_getsockopt = compat_raw_getsockopt,
906         .compat_ioctl      = compat_raw_ioctl,
907 #endif
908 };

http://lxr.free-electrons.com/source/net/core/datagram.c
http://lxr.free-electrons.com/source/net/socket.c

1.
recvfrom/recvmsg -> sys_recvmsg   ->  inet_recvmsg -》raw_recvmsg 从 sock 的skb队列取出skb返回给用户程序
如果recvmsg传过来用的缓存长度不足以装下整个skb的内容话,那么这个skb剩余的内容也不会被丢弃。
如过recvmsg使用0长度缓存的话,整个skb会被丢弃。  有丢弃发生的时候,函数返回给用户空间的是整个skb的长度。 

如果是recvmsg的,用户空间可以通过msg的MSG_TRUNC 标志得到通知。如果使用是recvfrom 函数那么只能通过判断返回的值是不是之前的缓存长度了,如果大的话,有内容被丢弃了
MSG_TRUNC (since Linux 2.2)
For raw (AF_PACKET), Internet datagram (since Linux 2.4.27/2.6.8), netlink (since Linux 2.6.22) and UNIX datagram (since Linux 3.4) sockets: return the real length of the packet or datagram, even when it was longer than the passed buffer. Not implemented for UNIX domain (unix(7)) sockets.



MSG_TRUNC
indicates that the trailing portion of a datagram was discarded because the datagram was larger than the buffer supplied.

2.  raw socket网络包上来的路径
ip_rcv  ->  ip_local_deliver_finish ->  raw_local_deliver ->  raw_rcv_skb 把收到的skb包放到sock的skb队列

3. poll 操作
datagram_poll   等待/检查sock 的skb队列不为空.

4.  获取socket的可读数据的长度
ioctl(fd, FIONREAD, dataLen)  ->  raw_ioctl  返回sock 的skb队列第一个skb的数据长度或者0。 如果有很多个skb应该也是是返回第一个的长度吧。
  评论这张
 
阅读(519)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017