core "github.com/bytom/protocol"
"github.com/bytom/protocol/bc"
"github.com/bytom/version"
+ "net"
+ "time"
)
//SyncManager Sync Manager is responsible for the business layer information synchronization
fetcher *Fetcher
blockKeeper *blockKeeper
peers *peerSet
+ mapResult bool
newBlockCh chan *bc.Hash
newPeerCh chan struct{}
manager.sw.AddReactor("PROTOCOL", protocolReactor)
// Create & add listener
+ var mapResult bool
+ var l p2p.Listener
if !config.VaultMode {
p, address := protocolAndAddress(manager.config.P2P.ListenAddress)
- l := p2p.NewDefaultListener(p, address, manager.config.P2P.SkipUPNP, nil)
+ l, mapResult = p2p.NewDefaultListener(p, address, manager.config.P2P.SkipUPNP, nil)
manager.sw.AddListener(l)
}
- manager.sw.SetNodeInfo(manager.makeNodeInfo())
+ manager.sw.SetNodeInfo(manager.makeNodeInfo(mapResult))
manager.sw.SetNodePrivKey(manager.privKey)
-
+ manager.mapResult = mapResult
// Optionally, start the pex reactor
//var addrBook *p2p.AddrBook
if config.P2P.PexReactor {
return p, address
}
-func (sm *SyncManager) makeNodeInfo() *p2p.NodeInfo {
+func (sm *SyncManager) makeNodeInfo(listenOpen bool) *p2p.NodeInfo {
nodeInfo := &p2p.NodeInfo{
PubKey: sm.privKey.PubKey().Unwrap().(crypto.PubKeyEd25519),
Moniker: sm.config.Moniker,
}
p2pListener := sm.sw.Listeners()[0]
- p2pHost := p2pListener.ExternalAddress().IP.String()
- p2pPort := p2pListener.ExternalAddress().Port
// We assume that the rpcListener has the same ExternalAddress.
// This is probably true because both P2P and RPC listeners use UPnP,
// except of course if the rpc is only bound to localhost
- nodeInfo.ListenAddr = cmn.Fmt("%v:%v", p2pHost, p2pPort)
+ if listenOpen {
+ nodeInfo.ListenAddr = cmn.Fmt("%v:%v", p2pListener.ExternalAddress().IP.String(), p2pListener.ExternalAddress().Port)
+ } else {
+ nodeInfo.ListenAddr = cmn.Fmt("%v:%v", p2pListener.InternalAddress().IP.String(), p2pListener.InternalAddress().Port)
+ }
return nodeInfo
}
return err
}
+ if !sm.mapResult {
+ conn, err := net.DialTimeout("tcp", sm.NodeInfo().ListenAddr, 3*time.Second)
+
+ if err != nil && conn == nil {
+ log.Info("Could not open listen port")
+ }
+
+ if err == nil && conn != nil {
+ log.Info("Success open listen port")
+ conn.Close()
+ sm.sw.SetNodeInfo(sm.makeNodeInfo(true))
+ }
+ }
+
// If seeds exist, add them to the address book and dial out
if sm.config.P2P.Seeds != "" {
// dial out
}
// skipUPNP: If true, does not try getUPNPExternalAddress()
-func NewDefaultListener(protocol string, lAddr string, skipUPNP bool, logger tlog.Logger) Listener {
+func NewDefaultListener(protocol string, lAddr string, skipUPNP bool, logger tlog.Logger) (Listener, bool) {
// Local listen IP & port
lAddrIP, lAddrPort := splitHostPort(lAddr)
// Create listener
var listener net.Listener
var err error
+ var mapResult bool
for i := 0; i < tryListenSeconds; i++ {
listener, err = net.Listen(protocol, lAddr)
if err == nil {
// If the lAddrIP is INADDR_ANY, try UPnP
if lAddrIP == "" || lAddrIP == "0.0.0.0" {
extAddr = getUPNPExternalAddress(lAddrPort, listenerPort)
+ if extAddr!=nil {
+ mapResult = true
+ }
+ }
+ }
+ if extAddr == nil {
+ if address := GetIP([]string{}, time.Duration(0)); address.Success == true {
+ extAddr = NewNetAddressIPPort(net.ParseIP(address.Ip), uint16(lAddrPort))
}
}
// Otherwise just use the local address...
}
dl.BaseService = *cmn.NewBaseService(logger, "DefaultListener", dl)
dl.Start() // Started upon construction
- return dl
+ return dl, mapResult
}
func (l *DefaultListener) OnStart() error {
--- /dev/null
+package p2p
+
+import (
+ "errors"
+ "fmt"
+ "io/ioutil"
+ "net/http"
+ "strings"
+ "time"
+ "regexp"
+)
+
+var defaultServices = []string{
+ "http://icanhazip.com/",
+ "http://ifconfig.io/ip",
+ "http://ident.me/",
+ "http://whatismyip.akamai.com/",
+ "http://myip.dnsomatic.com/",
+ "http://diagnostic.opendns.com/myip",
+}
+
+type IpResult struct {
+ Success bool
+ Ip string
+ Error error
+}
+
+var timeout time.Duration
+
+func GetIP(services []string, to time.Duration) *IpResult {
+
+ if services == nil || len(services) == 0 {
+ services = defaultServices
+ }
+ if to == 0 {
+ to = time.Duration(10)
+ }
+ timeout = to
+
+ count := len(services)
+ done := make(chan *IpResult)
+ for k := range services {
+ go ipAddress(services[k], done)
+ }
+ for ;; {
+ select{
+ case result := <-done:
+ if result.Success {
+ return result
+ } else {
+ count--
+ if count == 0 {
+ result.Error = errors.New("All services doesn't available.")
+ return result
+ }
+ }
+ continue
+ case <-time.After(time.Second * timeout):
+ return &IpResult{false, "", errors.New("Timed out")}
+ }
+ }
+}
+
+func ipAddress(service string, done chan<- *IpResult) {
+
+ timeout := time.Duration(time.Second * timeout)
+ client := http.Client{Timeout: timeout}
+ resp, err := client.Get(service)
+
+ if err != nil {
+ sendResult(&IpResult{false, "", errors.New("Time out")}, done)
+ return
+ }
+
+ if err == nil {
+
+ defer resp.Body.Close()
+
+ address, err := ioutil.ReadAll(resp.Body)
+ ip := fmt.Sprintf("%s", strings.TrimSpace(string(address)))
+ if err== nil && checkIp(ip) {
+ sendResult(&IpResult{true, ip, nil}, done)
+ return
+ }
+ }
+ sendResult(&IpResult{false, "", errors.New("Unable to talk with a service")}, done)
+}
+
+func sendResult(result *IpResult, done chan<- *IpResult) {
+ select {
+ case done <- result:
+ return
+ default:
+ return
+ }
+}
+
+func checkIp(ip string) bool {
+ match, _ := regexp.MatchString(`^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$`, ip)
+ if match {
+ return true
+ }
+ return false
+}
}
//permute the list, dial them in random order.
perm := rand.Perm(len(netAddrs))
- for i := 0; i < len(perm)/2; i++ {
+ for i := 0; i < len(perm); i++ {
j := perm[i]
sw.dialSeed(netAddrs[j])
}