Chinaunix首页 | 论坛 | 博客
  • 博客访问: 148153
  • 博文数量: 24
  • 博客积分: 791
  • 博客等级: 军士长
  • 技术积分: 350
  • 用 户 组: 普通用户
  • 注册时间: 2010-02-22 11:00
文章存档

2011年(18)

2010年(6)

分类: LINUX

2011-05-03 12:53:26

一、用户空间

获取套接口选项:

1.  int getsockopt ( int sockfd, int level, int optname, void * optval, socklen_t *opteln ) 设置套接口选项:

2.  int setsockopt ( int sockfd, int level, int optname, const void * optval, socklen_t *opteln )

 

二、内核空间

系统调用setsockopt是通过内核sys_setsockopt函数实现的

  1. asmlinkage long sys_setsockopt(int fd, int level, int optname, char __user *optval, int optlen)
  2. {
  3. ……
  4.     if ((sock = sockfd_lookup_light(fd, &err, &fput_needed)) != NULL)
  5.     {
  6. ……
  7.         if (level == SOL_SOCKET)//基本套接口
  8. 套接口类型(linux/socket.h):
  9. /* Setsockoptions(2) level. Thanks to BSD these must match IPPROTO_xxx */
  10. #define SOL_IP           0
  11. /* #define SOL_ICMP        1       No-no-no! Due to Linux :-) we cannot use SOL_ICMP=1 */
  12. #define SOL_TCP                6
  13. #define SOL_UDP               17
  14. ……

  15.             err=sock_setsockopt(sock,level,optname,optval,optlen);
  16.         else
  17.             err=sock->ops->setsockopt(sock, level, optname, optval, optlen);
  18.     ……
  19.     }
  20.     return err;
  21. }
假如我们定义的套接口是IPPROTO_IP=0,所以我们将调用SOL_IP套接口,err=sock->ops->setsockopt(sock, level, optname, optval, optlen),该钩子为proto_ops类型,所以它指向了我们注册的inet_stream_ops钩子,所以setsockopt指向了sock_common_setsockopt函数(net/core/sock.c
net/ipv4/af_inet.c文件中,函数inet_init注册了inetsw_array数组
  1. for (q = inetsw_array; q < &inetsw_array[INETSW_ARRAY_LEN]; ++q)
  2.         inet_register_protosw(q);
  1. static struct inet_protosw inetsw_array[] =
  2. {
  3.         {
  4.                 .type = SOCK_STREAM,
  5.                 .protocol = IPPROTO_TCP,
  6.                 .prot = &tcp_prot,
  7.                 .ops = &inet_stream_ops,
  8.                 .capability = -1,
  9.                 .no_check = 0,
  10.                 .flags = INET_PROTOSW_PERMANENT |
  11.              INET_PROTOSW_ICSK,
  12.         },
  13.         ……
  14. };

譬如它注册了inet_stream_ops针对tcp协议

  1. const struct proto_ops inet_stream_ops = {
  2.     .family         = PF_INET,
  3.     .owner         = THIS_MODULE,
  4.     ……
  5.     .setsockopt     = sock_common_setsockopt,
  6.     .getsockopt     = sock_common_getsockopt,
  7. ……
  8. };

现在我们看接口函数sock_common_setsockopt

  1. int sock_common_setsockopt(struct socket *sock, int level, int optname,
  2.              char __user *optval, int optlen)
  3. {
  4.     struct sock *sk = sock->sk;
  5.     return sk->sk_prot->setsockopt(sk, level, optname, optval, optlen);
  6. }

由于sk->sk_prot是指向协议的钩子,如果它指向了tcp协议钩子,setsockopt指向了tcp_setsockopt函数(net/ipv4/tcp.c

  1. struct proto tcp_prot = {
  2.     .name            = "TCP",
  3.     .owner            = THIS_MODULE,
  4.     ……
  5.     .setsockopt        = tcp_setsockopt,
  6.     .getsockopt        = tcp_getsockopt,
  7.     ……
  8. }

 

  1. int tcp_setsockopt(struct sock *sk, int level, int optname, char __user *optval,
  2.          int optlen)
  3. {
  4.     struct inet_connection_sock *icsk = inet_csk(sk);

  5.     if (level != SOL_TCP)//显然我们注册的是SOL_IP所以执行下面语句
  6.         return icsk->icsk_af_ops->setsockopt(sk, level, optname,
  7.                          optval, optlen);
  8.     return do_tcp_setsockopt(sk, level, optname, optval, optlen);//如果注册时SOL_TCP就执行
  9. }

如果注册时SOL_IP则由于isck->isck_af_opsinet_connection_sock_af_ops类型的钩子,此钩子的注册为

  1. struct inet_connection_sock_af_ops ipv4_specific = {
  2. ……
  3.     .setsockopt     = ip_setsockopt,
  4.     .getsockopt     = ip_getsockopt,
  5. ……
  6. };

注册ip_setsockoptnet/ipv4/tcp_ipv4.c)接口

  1. int ip_setsockopt(struct sock *sk, int level,
  2.         int optname, char __user *optval, int optlen)
  3. {
  4.     int err;
  5.     if (level != SOL_IP)
  6.         return -ENOPROTOOPT;
  7.     err = do_ip_setsockopt(sk, level, optname, optval, optlen);//注册是IPPROTO_IP执行
  8. #ifdef CONFIG_NETFILTER
  9.     /* we need to exclude all possible ENOPROTOOPTs except default case */
  10.     if (err == -ENOPROTOOPT && optname != IP_HDRINCL &&
  11.         optname != IP_IPSEC_POLICY && optname != IP_XFRM_POLICY
  12. #ifdef CONFIG_IP_MROUTE
  13.         && (optname < MRT_BASE || optname > (MRT_BASE + 10))
  14. #endif
  15.      ) {
  16.         lock_sock(sk);
  17.         err = nf_setsockopt(sk, PF_INET, optname, optval, optlen);//如果编译选项中设置了CONFIG_NETFILTER,就调用nf_setsockopt函数
  18.         release_sock(sk);
  19.     }
  20. #endif
  21.     return err;
  22. }

到此我们知道了如果注册时IPPROTO_IP最终会调用do_ip_setsockopt和nf_setsockopt函数

如果注册了IPPROTO_TCP最终会调用do_tcp_setsockopt函数

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