github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/p2p/netutil/iptrack.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 19:16:41</date>
    10  //</624450105306517504>
    11  
    12  
    13  package netutil
    14  
    15  import (
    16  	"time"
    17  
    18  	"github.com/ethereum/go-ethereum/common/mclock"
    19  )
    20  
    21  //IPtracker预测本地主机的外部端点,即IP地址和端口
    22  //基于其他主机的语句。
    23  type IPTracker struct {
    24  	window          time.Duration
    25  	contactWindow   time.Duration
    26  	minStatements   int
    27  	clock           mclock.Clock
    28  	statements      map[string]ipStatement
    29  	contact         map[string]mclock.AbsTime
    30  	lastStatementGC mclock.AbsTime
    31  	lastContactGC   mclock.AbsTime
    32  }
    33  
    34  type ipStatement struct {
    35  	endpoint string
    36  	time     mclock.AbsTime
    37  }
    38  
    39  //newiptracker创建一个IP跟踪器。
    40  //
    41  //窗口参数配置保留的过去网络事件的数量。这个
    42  //minStatements参数强制执行必须记录的最小语句数
    43  //在做出任何预测之前。这些参数的值越高,则“拍打”越小。
    44  //网络条件变化时的预测。窗口持续时间值通常应在
    45  //分钟的范围。
    46  func NewIPTracker(window, contactWindow time.Duration, minStatements int) *IPTracker {
    47  	return &IPTracker{
    48  		window:        window,
    49  		contactWindow: contactWindow,
    50  		statements:    make(map[string]ipStatement),
    51  		minStatements: minStatements,
    52  		contact:       make(map[string]mclock.AbsTime),
    53  		clock:         mclock.System{},
    54  	}
    55  }
    56  
    57  //PredictTfullconenat检查本地主机是否位于全锥NAT之后。它预测
    58  //正在检查是否已从以前未联系的节点接收到任何语句
    59  //声明已作出。
    60  func (it *IPTracker) PredictFullConeNAT() bool {
    61  	now := it.clock.Now()
    62  	it.gcContact(now)
    63  	it.gcStatements(now)
    64  	for host, st := range it.statements {
    65  		if c, ok := it.contact[host]; !ok || c > st.time {
    66  			return true
    67  		}
    68  	}
    69  	return false
    70  }
    71  
    72  //PredictEndPoint返回外部终结点的当前预测。
    73  func (it *IPTracker) PredictEndpoint() string {
    74  	it.gcStatements(it.clock.Now())
    75  
    76  //当前的策略很简单:使用大多数语句查找端点。
    77  	counts := make(map[string]int)
    78  	maxcount, max := 0, ""
    79  	for _, s := range it.statements {
    80  		c := counts[s.endpoint] + 1
    81  		counts[s.endpoint] = c
    82  		if c > maxcount && c >= it.minStatements {
    83  			maxcount, max = c, s.endpoint
    84  		}
    85  	}
    86  	return max
    87  }
    88  
    89  //addStatement记录某个主机认为我们的外部端点是给定的端点。
    90  func (it *IPTracker) AddStatement(host, endpoint string) {
    91  	now := it.clock.Now()
    92  	it.statements[host] = ipStatement{endpoint, now}
    93  	if time.Duration(now-it.lastStatementGC) >= it.window {
    94  		it.gcStatements(now)
    95  	}
    96  }
    97  
    98  //addcontact记录包含端点信息的数据包已发送到
    99  //某些宿主。
   100  func (it *IPTracker) AddContact(host string) {
   101  	now := it.clock.Now()
   102  	it.contact[host] = now
   103  	if time.Duration(now-it.lastContactGC) >= it.contactWindow {
   104  		it.gcContact(now)
   105  	}
   106  }
   107  
   108  func (it *IPTracker) gcStatements(now mclock.AbsTime) {
   109  	it.lastStatementGC = now
   110  	cutoff := now.Add(-it.window)
   111  	for host, s := range it.statements {
   112  		if s.time < cutoff {
   113  			delete(it.statements, host)
   114  		}
   115  	}
   116  }
   117  
   118  func (it *IPTracker) gcContact(now mclock.AbsTime) {
   119  	it.lastContactGC = now
   120  	cutoff := now.Add(-it.contactWindow)
   121  	for host, ct := range it.contact {
   122  		if ct < cutoff {
   123  			delete(it.contact, host)
   124  		}
   125  	}
   126  }
   127