github.com/NebulousLabs/Sia@v1.3.7/modules/gateway/ip.go (about) 1 package gateway 2 3 import ( 4 "net" 5 "time" 6 7 "github.com/NebulousLabs/Sia/encoding" 8 "github.com/NebulousLabs/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 peers := g.Peers() 41 // Check if there are enough peers. Otherwise wait. 42 if len(peers) < minPeersForIPDiscovery { 43 g.managedSleep(peerDiscoveryRetryInterval) 44 continue 45 } 46 // Ask all the peers about our ip in parallel 47 returnChan := make(chan string) 48 for _, peer := range peers { 49 go g.RPC(peer.NetAddress, "DiscoverIP", func(conn modules.PeerConn) error { 50 var address string 51 err := encoding.ReadObject(conn, &address, 100) 52 if err != nil { 53 returnChan <- "" 54 g.log.Debugf("DEBUG: failed to receive ip address: %v", err) 55 return err 56 } 57 addr := net.ParseIP(address) 58 if addr == nil { 59 returnChan <- "" 60 g.log.Debug("DEBUG: failed to parse ip address") 61 return errors.New("failed to parse ip address") 62 } 63 returnChan <- addr.String() 64 return err 65 }) 66 } 67 // Wait for their responses 68 addresses := make(map[string]int) 69 successfulResponses := 0 70 for i := 0; i < len(peers); i++ { 71 addr := <-returnChan 72 if addr != "" { 73 addresses[addr]++ 74 successfulResponses++ 75 } 76 } 77 // If there haven't been enough successful responses we wait some time. 78 if successfulResponses < minPeersForIPDiscovery { 79 g.managedSleep(peerDiscoveryRetryInterval) 80 continue 81 } 82 // If an address was returned by more than half the peers we consider 83 // it valid. 84 for addr, count := range addresses { 85 if count > successfulResponses/2 { 86 g.log.Println("ip successfully discovered using peers:", addr) 87 return addr, nil 88 } 89 } 90 // Otherwise we wait before trying again. 91 g.managedSleep(peerDiscoveryRetryInterval) 92 } 93 }