github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/p2p/nat/nat.go (about)

     1  
     2  //此源码被清华学神尹成大魔王专业翻译分析并修改
     3  //尹成QQ77025077
     4  //尹成微信18510341407
     5  //尹成所在QQ群721929980
     6  //尹成邮箱 yinc13@mails.tsinghua.edu.cn
     7  //尹成毕业于清华大学,微软区块链领域全球最有价值专家
     8  //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620
     9  //版权所有2015 Go Ethereum作者
    10  //此文件是Go以太坊库的一部分。
    11  //
    12  //Go-Ethereum库是免费软件:您可以重新分发它和/或修改
    13  //根据GNU发布的较低通用公共许可证的条款
    14  //自由软件基金会,或者许可证的第3版,或者
    15  //(由您选择)任何更高版本。
    16  //
    17  //Go以太坊图书馆的发行目的是希望它会有用,
    18  //但没有任何保证;甚至没有
    19  //适销性或特定用途的适用性。见
    20  //GNU较低的通用公共许可证,了解更多详细信息。
    21  //
    22  //你应该收到一份GNU较低级别的公共许可证副本
    23  //以及Go以太坊图书馆。如果没有,请参见<http://www.gnu.org/licenses/>。
    24  
    25  //包NAT提供对公共网络端口映射协议的访问。
    26  package nat
    27  
    28  import (
    29  	"errors"
    30  	"fmt"
    31  	"net"
    32  	"strings"
    33  	"sync"
    34  	"time"
    35  
    36  	"github.com/ethereum/go-ethereum/log"
    37  	"github.com/jackpal/go-nat-pmp"
    38  )
    39  
    40  //一个nat.interface的实现可以将本地端口映射到端口
    41  //可从Internet访问。
    42  type Interface interface {
    43  //这些方法管理本地端口之间的映射
    44  //机器到可以从Internet连接到的端口。
    45  //
    46  //协议是“udp”或“tcp”。某些实现允许设置
    47  //映射的显示名称。映射可以通过
    48  //网关的生命周期结束时。
    49  	AddMapping(protocol string, extport, intport int, name string, lifetime time.Duration) error
    50  	DeleteMapping(protocol string, extport, intport int) error
    51  
    52  //此方法应返回外部(面向Internet)
    53  //网关设备的地址。
    54  	ExternalIP() (net.IP, error)
    55  
    56  //应返回方法的名称。这用于日志记录。
    57  	String() string
    58  }
    59  
    60  //解析解析一个NAT接口描述。
    61  //当前接受以下格式。
    62  //请注意,机制名称不区分大小写。
    63  //
    64  //“”或“无”返回零
    65  //“extip:77.12.33.4”将假定在给定的IP上可以访问本地计算机。
    66  //“任意”使用第一个自动检测机制
    67  //“UPNP”使用通用即插即用协议
    68  //“pmp”使用具有自动检测到的网关地址的nat-pmp
    69  //“pmp:192.168.0.1”使用具有给定网关地址的nat-pmp
    70  func Parse(spec string) (Interface, error) {
    71  	var (
    72  		parts = strings.SplitN(spec, ":", 2)
    73  		mech  = strings.ToLower(parts[0])
    74  		ip    net.IP
    75  	)
    76  	if len(parts) > 1 {
    77  		ip = net.ParseIP(parts[1])
    78  		if ip == nil {
    79  			return nil, errors.New("invalid IP address")
    80  		}
    81  	}
    82  	switch mech {
    83  	case "", "none", "off":
    84  		return nil, nil
    85  	case "any", "auto", "on":
    86  		return Any(), nil
    87  	case "extip", "ip":
    88  		if ip == nil {
    89  			return nil, errors.New("missing IP address")
    90  		}
    91  		return ExtIP(ip), nil
    92  	case "upnp":
    93  		return UPnP(), nil
    94  	case "pmp", "natpmp", "nat-pmp":
    95  		return PMP(ip), nil
    96  	default:
    97  		return nil, fmt.Errorf("unknown mechanism %q", parts[0])
    98  	}
    99  }
   100  
   101  const (
   102  	mapTimeout        = 20 * time.Minute
   103  	mapUpdateInterval = 15 * time.Minute
   104  )
   105  
   106  //map在m上添加了一个端口映射,并在c关闭之前保持它的活动状态。
   107  //此函数通常在自己的goroutine中调用。
   108  func Map(m Interface, c chan struct{}, protocol string, extport, intport int, name string) {
   109  	log := log.New("proto", protocol, "extport", extport, "intport", intport, "interface", m)
   110  	refresh := time.NewTimer(mapUpdateInterval)
   111  	defer func() {
   112  		refresh.Stop()
   113  		log.Debug("Deleting port mapping")
   114  		m.DeleteMapping(protocol, extport, intport)
   115  	}()
   116  	if err := m.AddMapping(protocol, extport, intport, name, mapTimeout); err != nil {
   117  		log.Debug("Couldn't add port mapping", "err", err)
   118  	} else {
   119  		log.Info("Mapped network port")
   120  	}
   121  	for {
   122  		select {
   123  		case _, ok := <-c:
   124  			if !ok {
   125  				return
   126  			}
   127  		case <-refresh.C:
   128  			log.Trace("Refreshing port mapping")
   129  			if err := m.AddMapping(protocol, extport, intport, name, mapTimeout); err != nil {
   130  				log.Debug("Couldn't add port mapping", "err", err)
   131  			}
   132  			refresh.Reset(mapUpdateInterval)
   133  		}
   134  	}
   135  }
   136  
   137  //extip假定在给定的
   138  //外部IP地址,以及手动映射所需的任何端口。
   139  //映射操作不会返回错误,但实际上不会执行任何操作。
   140  func ExtIP(ip net.IP) Interface {
   141  	if ip == nil {
   142  		panic("IP must not be nil")
   143  	}
   144  	return extIP(ip)
   145  }
   146  
   147  type extIP net.IP
   148  
   149  func (n extIP) ExternalIP() (net.IP, error) { return net.IP(n), nil }
   150  func (n extIP) String() string              { return fmt.Sprintf("ExtIP(%v)", net.IP(n)) }
   151  
   152  //这些什么都不做。
   153  func (extIP) AddMapping(string, int, int, string, time.Duration) error { return nil }
   154  func (extIP) DeleteMapping(string, int, int) error                     { return nil }
   155  
   156  //any返回一个端口映射器,该映射器尝试发现任何支持的
   157  //本地网络上的机制。
   158  func Any() Interface {
   159  //TODO:尝试发现本地计算机是否具有
   160  //Internet类地址。在这种情况下返回extip。
   161  	return startautodisc("UPnP or NAT-PMP", func() Interface {
   162  		found := make(chan Interface, 2)
   163  		go func() { found <- discoverUPnP() }()
   164  		go func() { found <- discoverPMP() }()
   165  		for i := 0; i < cap(found); i++ {
   166  			if c := <-found; c != nil {
   167  				return c
   168  			}
   169  		}
   170  		return nil
   171  	})
   172  }
   173  
   174  //UPNP返回使用UPNP的端口映射器。它将试图
   175  //使用UDP广播发现路由器的地址。
   176  func UPnP() Interface {
   177  	return startautodisc("UPnP", discoverUPnP)
   178  }
   179  
   180  //pmp返回使用nat-pmp的端口映射器。提供的网关
   181  //地址应该是路由器的IP。如果给定的网关
   182  //地址为零,PMP将尝试自动发现路由器。
   183  func PMP(gateway net.IP) Interface {
   184  	if gateway != nil {
   185  		return &pmp{gw: gateway, c: natpmp.NewClient(gateway)}
   186  	}
   187  	return startautodisc("NAT-PMP", discoverPMP)
   188  }
   189  
   190  //自动发现表示仍在
   191  //自动发现。调用此类型上的接口方法将
   192  //等待发现完成,然后在
   193  //发现了机制。
   194  //
   195  //这种类型很有用,因为发现可能需要一段时间,但是我们
   196  //要立即从upnp、pmp和auto返回接口值。
   197  type autodisc struct {
   198  what string //正在自动发现的接口类型
   199  	once sync.Once
   200  	doit func() Interface
   201  
   202  	mu    sync.Mutex
   203  	found Interface
   204  }
   205  
   206  func startautodisc(what string, doit func() Interface) Interface {
   207  //TODO:监视网络配置,并在其更改时重新运行DOIT。
   208  	return &autodisc{what: what, doit: doit}
   209  }
   210  
   211  func (n *autodisc) AddMapping(protocol string, extport, intport int, name string, lifetime time.Duration) error {
   212  	if err := n.wait(); err != nil {
   213  		return err
   214  	}
   215  	return n.found.AddMapping(protocol, extport, intport, name, lifetime)
   216  }
   217  
   218  func (n *autodisc) DeleteMapping(protocol string, extport, intport int) error {
   219  	if err := n.wait(); err != nil {
   220  		return err
   221  	}
   222  	return n.found.DeleteMapping(protocol, extport, intport)
   223  }
   224  
   225  func (n *autodisc) ExternalIP() (net.IP, error) {
   226  	if err := n.wait(); err != nil {
   227  		return nil, err
   228  	}
   229  	return n.found.ExternalIP()
   230  }
   231  
   232  func (n *autodisc) String() string {
   233  	n.mu.Lock()
   234  	defer n.mu.Unlock()
   235  	if n.found == nil {
   236  		return n.what
   237  	} else {
   238  		return n.found.String()
   239  	}
   240  }
   241  
   242  //等待块,直到执行自动发现。
   243  func (n *autodisc) wait() error {
   244  	n.once.Do(func() {
   245  		n.mu.Lock()
   246  		n.found = n.doit()
   247  		n.mu.Unlock()
   248  	})
   249  	if n.found == nil {
   250  		return fmt.Errorf("no %s router discovered", n.what)
   251  	}
   252  	return nil
   253  }