Chinaunix首页 | 论坛 | 博客
  • 博客访问: 820429
  • 博文数量: 97
  • 博客积分: 3042
  • 博客等级: 中校
  • 技术积分: 1610
  • 用 户 组: 普通用户
  • 注册时间: 2010-07-21 11:48
文章存档

2015年(1)

2014年(3)

2013年(4)

2012年(43)

2011年(44)

2010年(2)

分类: LINUX

2012-10-27 14:12:22

  系统调用sendto最终调用内核函数 asmlinkage long sys_sendto(int fd, void __user * buff, size_t len, unsigned flags, struct sockaddr __user *addr, int addr_len)

    sys_sendto构建一个结构体struct msghdr,用于接收来自应用层的数据包 ,下面是结构体struct msghdr的定义:

        struct msghdr {

            void            *msg_name;// 存数据包的目的地址,网络包指向sockaddr_in

                                                   //向内核发数据时,指向sockaddr_nl

            int             msg_namelen;// 地址长度

            struct iovec    *msg_iov;

            __kernel_size_t msg_iovlen;

            void            *msg_control;

            __kernel_size_t msg_controllen;

            unsigned        msg_flags;

        };

    这个结构体的内容可以分为四组。

    第一组是msg_name和msg_namelen,记录这个消息的名字,其实就是数据包的目的地址msg_name是指向一个结构体struct sockaddr的指针 。长度为16:

        struct sockaddr{

            sa_family_t sa_family;

            char        sa_addr[14];

        }

所以,msg_namelen的长度为16。需要注意的是,结构体struct sockaddr只在进行参数传递时使用,无论是在用户态还是在内核态,我们都把其强制转化为结构体struct sockaddr_in:

        strcut sockaddr_in{

            sa_family_t         sin_family;

            unsigned short int sin_port;

            struct in_addr      sin_addr;

            unsigned char       __pad[__SOCK_SIZE__ - sizeof(short int) -

                                sizeof(unsigned short int) - sizeof(struct in_addr)];

        };

        struct in_addr{

            __u32 s_addr;

        }

__SOCK_SIZE__的值为16,所以,struct sockaddr中真正有用的数据只有8bytes。在我们的ping例子中,传入到内核的msghdr结构中:

    msg.msg_name = { sa_family_t = MY_AF_INET, sin_port = 0, sin_addr.s_addr = 172.16.48.1 }

    msg_msg_namelen = 16。

请求回显icmp包没有目的端地址的端口号。

    第二组是msg_iov和msg_iovlen,记录这个消息的内容。msg_iov是一个指向结构体struct iovec的指针,实际上,确切地说,应该是一个结构体strcut iovec的数组 。下面是该结构体的定义:

    struct iovec{

        void __user     *iov_base;

        __kernel_size_t iov_len;

    };

    iov_base指向数据包缓冲区,即参数buff,iov_len是buff的长度。msghdr中允许一次传递多个buff,以数组的形式组织在 msg_iov中,msg_iovlen就记录数组的长度 (即有多少个buff)。在我们的ping程序的实例中:

    msg.msg_iov = { struct iovec = { iov_base = { icmp头+填充字符'E' }, iov_len = 40 } }

    msg.msg_len = 1

    第三组是msg_control和msg_controllen,它们可被用于发送任何的控制信息,在我们的例子中,没有控制信息要发送。暂时略过。

    第四组是msg_flags。其值即为传入的参数flags。raw协议不支持MSG_ OOB 向标志,即带外数据。 向内核发送msg 时使用msghdr,netlink socket使用自己的消息头nlmsghdr和自己的消息地址sockaddr_nl:

struct sockaddr_nl
{
sa_family_t    nl_family;
unsigned short nl_pad;
__u32          nl_pid;
__u32          nl_groups;
};
struct nlmsghdr
{
__u32 nlmsg_len;   /* Length of message */
__u16 nlmsg_type; /* Message type*/
__u16 nlmsg_flags; /* Additional flags */
__u32 nlmsg_seq;   /* Sequence number */
__u32 nlmsg_pid;   /* Sending process PID */
};

阅读(5519) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~