getsockopt的TCP层实现剖析

2130阅读 0评论2015-08-24 zhanggf8220
分类:嵌入式

应用层

 

NAME

    getsockopt - get options on sockets

SYNOPSIS

    #include <sys/types.h>

    #include <sys/socket.h>

    int getsockopt (int s, int level, int optname, void *optval, socklen_t *optlen);

 

调用关系

 

 函数的调用关系图如下:

 

数据结构

 

[java] view plaincopy
  1. struct tcp_sock {  
  2.     ...  
  3.     u32 mss_cache; /* Cached effective mss, not including SACKS */  
  4.     u8 nonagle : 4/* Disable Nagle algorithm? */  
  5.           thin_lto : 1/* Use linear timeouts for thin streams */  
  6.           thin_dupack : 1/* Fast retransmit on first dupack */  
  7.           unused : 2;  
  8.     unsigned int keepalive_time; /* time before keep alive takes place */  
  9.     unsigned int keepalive_intvl; /* time interval between keep alive probes */  
  10.     u8 keepalive_probes; /* num of allowed keep alive probes */  
  11.     int linger2;  
  12.     u8 ecn_flags; /* ECN status bits. */  
  13.     u32 rcv_tstamp; /* timestamp of last received ACK (for keepalives) */  
  14.     u32 lsndtime; /* timestamp of last sent data packet (for restart window) */  
  15.   
  16.     u32 window_clamp; /* Maximal window to advertise,本端通告窗口最大值 */  
  17.     u32 rcv_ssthresh; /* Current window clamp */  
  18.    
  19.     u16 advmss; /* Advertised MSS,本端的通告MSS */  
  20.     u32 total_retrans; /* Total retransmits for entire connection */  
  21.     ...  
  22. }  
[java] view plaincopy
  1. struct tcp_options_received {  
  2.     ...  
  3.     u16 saw_tstamp : 1/* Saw TIMESTAMP on last packet */  
  4.              tstamp_ok : 1/* TIMESTAMP seen on SYN packet */  
  5.              dsack : 1/* D-SACK is scheduled */  
  6.              wscale_ok : 1/* Wscale seen on SYN packet */  
  7.              sack_ok : 4/* SACK seen on SYN packet */  
  8.              snd_wscale : 4/* Window scaling received from sender */  
  9.              rcv_wscale : 4/* Window scaling to send to receiver */  
  10.     ...  
  11. }  
[java] view plaincopy
  1. /* for TCP_INFO socket option */  
  2. #define TCPI_OPT_TIMESTAMPS 1  
  3. #define TCPI_OPT_SACK 2  
  4. #define TCPI_OPT_WSCALE 4  
  5. #define TCPI_OPT_ECN 8  
  6.   
  7. struct tcp_info {  
  8.     __u8 tcpi_state; /* TCP状态 */  
  9.     __u8 tcpi_ca_state; /* TCP拥塞状态 */  
  10.     __u8 tcpi_retransmits; /* 超时重传的次数 */  
  11.     __u8 tcpi_probes; /* 持续定时器或保活定时器发送且未确认的段数*/  
  12.     __u8 tcpi_backoff; /* 退避指数 */  
  13.     __u8 tcpi_options; /* 时间戳选项、SACK选项、窗口扩大选项、ECN选项是否启用*/  
  14.     __u8 tcpi_snd_wscale : 4, tcpi_rcv_wscale : 4/* 发送、接收的窗口扩大因子*/  
  15.   
  16.     __u32 tcpi_rto; /* 超时时间,单位为微秒*/  
  17.     __u32 tcpi_ato; /* 延时确认的估值,单位为微秒*/  
  18.     __u32 tcpi_snd_mss; /* 本端的MSS */  
  19.     __u32 tcpi_rcv_mss; /* 对端的MSS */  
  20.   
  21.     __u32 tcpi_unacked; /* 未确认的数据段数,或者current listen backlog */  
  22.     __u32 tcpi_sacked; /* SACKed的数据段数,或者listen backlog set in listen() */  
  23.     __u32 tcpi_lost; /* 丢失且未恢复的数据段数 */  
  24.     __u32 tcpi_retrans; /* 重传且未确认的数据段数 */  
  25.     __u32 tcpi_fackets; /* FACKed的数据段数 */  
  26.   
  27.     /* Times. 单位为毫秒 */  
  28.     __u32 tcpi_last_data_sent; /* 最近一次发送数据包在多久之前 */  
  29.     __u32 tcpi_last_ack_sent;  /* 不能用。Not remembered, sorry. */  
  30.     __u32 tcpi_last_data_recv; /* 最近一次接收数据包在多久之前 */  
  31.     __u32 tcpi_last_ack_recv; /* 最近一次接收ACK包在多久之前 */  
  32.   
  33.     /* Metrics. */  
  34.     __u32 tcpi_pmtu; /* 最后一次更新的路径MTU */  
  35.     __u32 tcpi_rcv_ssthresh; /* current window clamp,rcv_wnd的阈值 */  
  36.     __u32 tcpi_rtt; /* 平滑的RTT,单位为微秒 */  
  37.     __u32 tcpi_rttvar; /* 四分之一mdev,单位为微秒v */  
  38.     __u32 tcpi_snd_ssthresh; /* 慢启动阈值 */  
  39.     __u32 tcpi_snd_cwnd; /* 拥塞窗口 */  
  40.     __u32 tcpi_advmss; /* 本端能接受的MSS上限,在建立连接时用来通告对端 */  
  41.     __u32 tcpi_reordering; /* 没有丢包时,可以重新排序的数据段数 */  
  42.   
  43.     __u32 tcpi_rcv_rtt; /* 作为接收端,测出的RTT值,单位为微秒*/  
  44.     __u32 tcpi_rcv_space;  /* 当前接收缓存的大小 */  
  45.   
  46.     __u32 tcpi_total_retrans; /* 本连接的总重传个数 */  
  47. };  

 

函数实现

 

内核版本:2.6.37

[java] view plaincopy
  1. int tcp_getsockopt (struct sock *sk, int level, int optname, char __user *optval, int __user *optlen)  
  2. {  
  3.     struct inet_connection_sock *icsk = inet_csk(sk);  
  4.   
  5.     if (level != SOL_TCP)  
  6.         return icsk->icsk_af_ops->getsockopt(sk, level, optname, optval, optlen);  
  7.   
  8.     return do_tcp_getsockopt(sk, level, optname, optval, optlen);  
  9. }  
[java] view plaincopy
  1. static int do_tcp_getsockopt (struct sock *sk, int level, int optname, char __user *optval, int __user *optlen)  
  2. {  
  3.     struct inet_connection_sock *icsk = inet_csk(sk);  
  4.     struct tcp_sock *tp = tcp_sk(sk);  
  5.     int val, len;  
  6.   
  7.     if (get_user(len, optlen))  
  8.         return -EFAULT;  
  9.   
  10.     len = min_t(unsigned int, len, sizeof(int));   
  11.     if (len < 0)   
  12.         return -EINVAL;  
  13.    
  14.     switch (optname) {  
  15.         case TCP_MAXSEG:  
  16.             val = tp->mss_cache; /* 默认为1460 */  
  17.             if (!val && ((1 << sk->sk_state) & (TCPF_CLOSE) | TCPF_LISTEN))  
  18.                 val = tp->rx_opt.user_mss; /* mss requested by user in ioctl */  
  19.             break;  
  20.   
  21.         case TCP_NODELAY:  
  22.             val = !! (tp->nonagle & TCP_NAGLE_OFF); /* Nagle默认使用,故默认值为0 */  
  23.             break;  
  24.   
  25.         case TCP_CORK:  
  26.             val = !! (tp->nonagle & TCP_NAGLE_CORK); /* 默认值为0 */  
  27.             break;  
  28.   
  29.         case TCP_KEEPIDLE:  
  30.             val = keepalive_time_when(tp) / HZ; /* 默认为7200s */  
  31.             break;  
  32.   
  33.         case TCP_KEEPINTVL:  
  34.             val = keepalive_intvl_when(tp) / HZ; /* 默认为75s */  
  35.             break;  
  36.   
  37.         case TCP_KEEPCNT:  
  38.             val = keepalive_probes(tp); /* 默认为9 */  
  39.             break;  
  40.   
  41.         case TCP_SYNCNT:  
  42.             val = icsk->icsk_syn_retries ? : sysctl_tcp_syn_retries; /* 默认为5 */  
  43.             break;  
  44.   
  45.         case TCP_LINGER2:  
  46.             val = tp->linger2;  
  47.             if (val >= 0)  
  48.                 val = (val ? : sysctl_tcp_fin_timeout) / HZ; /* 默认为60s */  
  49.   
  50.         case TCP_DEFER_ACCEPT:  
  51.             ...  
  52.   
  53.         case TCP_WINDOW_CLAMP:  
  54.             val = tp->window_clamp;  
  55.             break;  
  56.   
  57.         case TCP_INFO: {  
  58.             struct tcp_info info;  
  59.   
  60.             if (get_user(len, optlen))  
  61.                 return -EFAULT;  
  62.    
  63.             tcp_get_info(sk, &info); /* 获取TCP连接的详细信息!*/  
  64.    
  65.             len = min_t(unsigned int, len, sizeof(info));  
  66.   
  67.             if (put_user(len, optlen))  
  68.                 return -EFAULT;  
  69.   
  70.             if (copy_to_user(optval, &info, len))  
  71.                  return -EFAULT;  
  72.   
  73.             return 0;  
  74.         }  
  75.   
  76.         case TCP_QUICKACK:  
  77.             val = ! icsk->icsk_ack.pingpong; /* 快速确认模式 */  
  78.             break;  
  79.   
  80.         case TCP_CONGESTION:  
  81.             if (get_user(len, optlen))  
  82.                 return -EFAULT;  
  83.   
  84.             len = min_t(unsigned int, len, TCP_CA_NAME_MAX); /* 16 Bytes */  
  85.   
  86.             if (put_user(len, optlen)  
  87.                 return -EFAULT;  
  88.   
  89.             if (copy_to_user(optval, icsk->icsk_ca_ops->name, len)) /* 默认为cubic */  
  90.                 return -EFAULT;  
  91.   
  92.             return 0;  
  93.   
  94.         case TCP_COOKIE_TRANSACTIONS :  
  95.             ...  
  96.   
  97.         case TCP_THIN_LINEAR_TIMEOUTS:  
  98.             val = tp->thin_lto; /* 默认为0 */  
  99.             break;  
  100.   
  101.         case TCP_THIN_DUPACK:  
  102.             val = tp->thin_dupack; /* 默认为0 */  
  103.             break;  
  104.   
  105.         case TCP_USER_TIMEOUT:  
  106.             val = jiffies_to_msecs(icsk->icsk_user_timeout);  
  107.             break;  
  108.   
  109.         default:  
  110.             return -ENOPROTOOPT;  
  111.     }  
  112.   
  113.     if (put_user(len, optlen))  
  114.         return -EFAULT;  
  115.   
  116.     if (copy_to_user(optval, &val, len))  
  117.         return -EFAULT;  
  118.   
  119.     return 0;  
  120. }  
[java] view plaincopy
  1. static inline int keepalive_time_when(const struct tcp_sock *tp)  
  2. {  
  3.     return tp->keepalive_time ? : sysctl_tcp_keepalive_time;   
  4. }  
  5.   
  6. static inline int keepalive_intvl_when(const struct tcp_sock *tp)  
  7. {  
  8.     return tp->keepalive_intvl ? : sysctl_tcp_keepalive_intvl;  
  9. }  
  10.   
  11. static inline int keepalive_probes(const struct tcp_sock *tp)  
  12. {  
  13.     return tp->keepalive_probes ? : sysctl_tcp_keepalive_probes;  
  14. }  

 

TCP_INFO

  

[java] view plaincopy
  1. /* Return information about state of tcp endpoint in API format. */  
  2.   
  3. void tcp_get_info(struct sock *sk, struct tcp_info *info)  
  4. {  
  5.     struct tcp_sock *tp = tcp_sk(sk);  
  6.     const struct inet_connection_sock *icsk = inet_csk(sk);  
  7.     u32 now = tcp_time_stamp;  
  8.    
  9.     memset(info, 0, sizeof(*info));  
  10.       
  11.     info->tcpi_state = sk->sk_state; /* TCP状态 */  
  12.     info->tcpi_ca_state = icsk_ca_state; /* TCP拥塞状态 */  
  13.     info->tcpi_retransmits = icsk->icsk_retransmits; /* Number of unrecovered [RTO] timeouts */  
  14.     info->tcpi_probes = icsk->icsk_probes_out; /* unanswered 0 window probes */  
  15.     info->tcpi_backoff = icsk->icsk_backoff; /* 退避指数 */  
  16.   
  17.     if (tp->rx_opt.tstamp_ok) /* TIMESTAMP seen on SYN packet */  
  18.         info->tcpi_options |= TCPI_OPT_TIMESTAMPS; /* 时间戳选项使用与否 */  
  19.     if (tcp_is_sack(tp))  
  20.         info->tcpi_options |= TCPI_OPT_SACK; /* SACK选项使用与否 */  
  21.     if (tp->rx_opt.wscale_ok) { /* Wscale seen on SYN packet */  
  22.         info->tcpi_options |= TCPI_OPT_WSCALE; /* 窗口扩大选项使用与否 */  
  23.         info->tcpi_snd_wscale = tp->rx_opt.snd_wscale; /* 发送窗口扩大因子 */  
  24.         info->tcpi_rcv_wscale = tp->rx_opt.rcv_wscale; /* 接收窗口扩大因子 */  
  25.     }  
  26.   
  27.     if (tp->ecn_flags & TCP_ECN_OK)  
  28.         info->tcpi_options |= TCPI_OPT_ECN; /* ECN选项使用与否 */  
  29.   
  30.     info->tcpi_rto = jiffies_to_usecs(icsk->icsk_rto); /* RTO,单位微秒 */  
  31.     info->tcpi_ato = jiffies_to_usecs(icsk->icsk_ack.ato); /* Predicted tick of soft clock */  
  32.     info->tcpi_snd_mss = tp->mss_cache; /* 本端MSS */  
  33.     info->tcpi_rcv_mss = icsk->icsk_ack.rcv_mss; /* 对端MSS */  
  34.   
  35.     if (sk->sk_state == TCP_LISTEN) {  
  36.         info->tcpi_unacked = sk->sk_ack_backlog; /* current listen backlog */  
  37.         info->tcpi_sacked = sk->sk_max_ack_backlog; /* listen backlog set in listen() */  
  38.   
  39.     } else {  
  40.         info->tcpi_unacked = tp->packets_out; /* 未确认的数据包数 */  
  41.         info->tcpi_sacked = tp->sacked_out; /* SACKed的数据包数 */  
  42.     }  
  43.   
  44.     info->tcpi_lost = tp->lost_out; /* 丢失的数据包数 */  
  45.     info->tcpi_retrans = tp->retrans_out; /* 重传的数据包数 */  
  46.     info->tcpi_fackets = tp->fackets_out; /* FACKed的数据包数 */  
  47.    
  48.     info->tcpi_last_data_sent = jiffies_to_msecs(now - tp->lsndtime); /* 最近一次发数据包的时间间隔 */  
  49.     info->tcpi_last_data_recv = jiffies_to_msecs(now - icsk->icsk_ack.lrcvtime); /* 最近一次收数据包的时间间隔 */  
  50.     info->tcpi_last_ack_recv = jiffies_to_msecs(now - tp->rcv_tstamp); /* 最近一次收ACK包的时间间隔 */  
  51.    
  52.     info->tcpi_pmtu = icsk->icsk_pmtu_cookie; /* Last pmtu seen by socket */  
  53.     info->tcpi_rcv_ssthresh = tp->rcv_ssthresh; /* current window clamp*/  
  54.     info->tcpi_rtt = jiffies_to_usecs(tp->srtt) >> 3/* 平滑的RTT */  
  55.     info->tcpi_rttvar = jiffies_to_usecs(tp->mdev) >> 2/* 四分之一mdev */  
  56.   
  57.     info->tcpi_snd_ssthresh = tp->snd_ssthresh;  
  58.     info->tcpi_snd_cwnd = tp->snd_cwnd;  
  59.     info->tcpi_advmss = tp->advmss; /* 本端能接受的MSS上限,在建立连接时用来通告对端 */  
  60.     info->tcpi_reordering = tp->reordering; /* 没有丢包时,可以重新排序的数据段数 */  
  61.    
  62.     info->tcpi_rcv_rtt = jiffies_to_usecs(tp->rcv_rtt_est.rtt) >> 3/* 作为接收端,测出的RTT值 */  
  63.     info->tcpi_rcv_space = tp->rcvq_space.space; /* 接收缓存的大小 */  
  64.   
  65.     info->tcpi_total_retrans = tp->total_retrans; /* 本连接的总重传个数 */  
  66. }  
上一篇:安装和使用Linux花生壳
下一篇:win 串口编程