github.com/Synthesix/Sia@v1.3.3-0.20180413141344-f863baeed3ca/modules/gateway/ip.go (about) 1 package gateway 2 3 import ( 4 "net" 5 "time" 6 7 "github.com/Synthesix/Sia/encoding" 8 "github.com/Synthesix/Sia/modules" 9 "github.com/NebulousLabs/errors" 10 ) 11 12 // discoverPeerIP is the handler for the discoverPeer RPC. It returns the 13 // public ip of the caller back to the caller. This allows for peer-to-peer ip 14 // discovery without centralized services. 15 func (g *Gateway) discoverPeerIP(conn modules.PeerConn) error { 16 conn.SetDeadline(time.Now().Add(connStdDeadline)) 17 host, _, err := net.SplitHostPort(conn.RemoteAddr().String()) 18 if err != nil { 19 return errors.AddContext(err, "failed to split host from port") 20 } 21 return encoding.WriteObject(conn, host) 22 } 23 24 // managedIPFromPeers asks the peers the node is connected to for the node's 25 // public ip address. If not enough peers are available we wait a bit and try 26 // again. In the worst case managedIPFromPeers will fail after a few minutes. 27 func (g *Gateway) managedIPFromPeers() (string, error) { 28 // Stop after timeoutIPDiscovery time. 29 timeout := time.After(timeoutIPDiscovery) 30 for { 31 // Check for shutdown signal or timeout. 32 select { 33 case <-g.peerTG.StopChan(): 34 return "", errors.New("interrupted by shutdown") 35 case <-timeout: 36 return "", errors.New("failed to discover ip in time") 37 default: 38 } 39 // Get peers 40 g.mu.RLock() 41 peers := g.Peers() 42 g.mu.RUnlock() 43 // Check if there are enough peers. Otherwise wait. 44 if len(peers) < minPeersForIPDiscovery { 45 g.managedSleep(peerDiscoveryRetryInterval) 46 continue 47 } 48 // Ask all the peers about our ip in parallel 49 returnChan := make(chan string) 50 for _, peer := range peers { 51 go g.RPC(peer.NetAddress, "DiscoverIP", func(conn modules.PeerConn) error { 52 var address string 53 err := encoding.ReadObject(conn, &address, 100) 54 if err != nil { 55 returnChan <- "" 56 g.log.Debugf("DEBUG: failed to receive ip address: %v", err) 57 return err 58 } 59 addr := net.ParseIP(address) 60 if addr == nil { 61 returnChan <- "" 62 g.log.Debug("DEBUG: failed to parse ip address") 63 return errors.New("failed to parse ip address") 64 } 65 returnChan <- addr.String() 66 return err 67 }) 68 } 69 // Wait for their responses 70 addresses := make(map[string]int) 71 successfulResponses := 0 72 for i := 0; i < len(peers); i++ { 73 addr := <-returnChan 74 if addr != "" { 75 addresses[addr]++ 76 successfulResponses++ 77 } 78 } 79 // If there haven't been enough successful responses we wait some time. 80 if successfulResponses < minPeersForIPDiscovery { 81 g.managedSleep(peerDiscoveryRetryInterval) 82 continue 83 } 84 // If an address was returned by more than half the peers we consider 85 // it valid. 86 for addr, count := range addresses { 87 if count > successfulResponses/2 { 88 g.log.Println("ip successfully discovered using peers:", addr) 89 return addr, nil 90 } 91 } 92 // Otherwise we wait before trying again. 93 g.managedSleep(peerDiscoveryRetryInterval) 94 } 95 }