seed.go raw
1 package connmgr
2
3 import (
4 "fmt"
5 "github.com/p9c/p9/pkg/chaincfg"
6 mrand "math/rand"
7 "net"
8 "strconv"
9 "time"
10
11 "github.com/p9c/p9/pkg/wire"
12 )
13
14 const (
15 // These constants are used by the DNS seed code to pick a random last seen time.
16 secondsIn3Days int32 = 24 * 60 * 60 * 3
17 secondsIn4Days int32 = 24 * 60 * 60 * 4
18 )
19
20 // OnSeed is the signature of the callback function which is invoked when DNS seeding is succesful
21 type OnSeed func(addrs []*wire.NetAddress)
22
23 // LookupFunc is the signature of the DNS lookup function.
24 type LookupFunc func(string) ([]net.IP, error)
25
26 // SeedFromDNS uses DNS seeding to populate the address manager with peers.
27 func SeedFromDNS(
28 chainParams *chaincfg.Params, reqServices wire.ServiceFlag,
29 lookupFn LookupFunc, seedFn OnSeed,
30 ) {
31 for _, dnsseed := range chainParams.DNSSeeds {
32 var host string
33 if !dnsseed.HasFiltering || reqServices == wire.SFNodeNetwork {
34 host = dnsseed.Host
35 } else {
36 host = fmt.Sprintf("x%x.%s", uint64(reqServices), dnsseed.Host)
37 }
38 go func(host string) {
39 randSource := mrand.New(mrand.NewSource(time.Now().UnixNano()))
40 seedpeers, e := lookupFn(host)
41 if e != nil {
42 E.F("DNS routeable failed on seed %s: %v", host, e)
43 return
44 }
45 numPeers := len(seedpeers)
46 D.F("%d addresses found from DNS seed %s", numPeers, host)
47 if numPeers == 0 {
48 return
49 }
50 addresses := make([]*wire.NetAddress, len(seedpeers))
51 // if this errors then we have *real* problems
52 intPort, _ := strconv.Atoi(chainParams.DefaultPort)
53 for i, peer := range seedpeers {
54 addresses[i] = wire.NewNetAddressTimestamp(
55 // bitcoind seeds with addresses from a time randomly
56 // selected between 3 and 7 days ago.
57 time.Now().Add(
58 -1*time.Second*time.Duration(
59 secondsIn3Days+
60 randSource.Int31n(secondsIn4Days),
61 ),
62 ),
63 0, peer, uint16(intPort),
64 )
65 }
66 seedFn(addresses)
67 }(host)
68 }
69 }
70