diff --git a/addrmanager.go b/addrmgr/addrmanager.go similarity index 92% rename from addrmanager.go rename to addrmgr/addrmanager.go index 577175ba0..ec2835bd0 100644 --- a/addrmanager.go +++ b/addrmgr/addrmanager.go @@ -2,7 +2,7 @@ // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package main +package addrmgr import ( "container/list" @@ -94,84 +94,27 @@ const ( serialisationVersion = 1 ) -// updateAddress is a helper function to either update an address already known -// to the address manager, or to add the address if not already known. -func (a *AddrManager) updateAddress(netAddr, srcAddr *btcwire.NetAddress) { - // Filter out non-routable addresses. Note that non-routable - // also includes invalid and local addresses. - if !Routable(netAddr) { - return - } +// knownAddress tracks information about a known network address that is used +// to determine how viable an address is. +type knownAddress struct { + na *btcwire.NetAddress + srcAddr *btcwire.NetAddress + attempts int + lastattempt time.Time + lastsuccess time.Time + tried bool + refs int // reference count of new buckets +} - // Protect concurrent access. - a.mtx.Lock() - defer a.mtx.Unlock() +// NetAddress returns the underlying btcwire.NetAddress associated with the +// known address. +func (ka *knownAddress) NetAddress() *btcwire.NetAddress { + return ka.na +} - addr := NetAddressKey(netAddr) - ka := a.find(netAddr) - if ka != nil { - // TODO(oga) only update adresses periodically. - // Update the last seen time and services. - // note that to prevent causing excess garbage on getaddr - // messages the netaddresses in addrmaanger are *immutable*, - // if we need to change them then we replace the pointer with a - // new copy so that we don't have to copy every na for getaddr. - if netAddr.Timestamp.After(ka.na.Timestamp) || - (ka.na.Services&netAddr.Services) != - netAddr.Services { - - naCopy := *ka.na - naCopy.Timestamp = netAddr.Timestamp - naCopy.AddService(netAddr.Services) - ka.na = &naCopy - } - - // If already in tried, we have nothing to do here. - if ka.tried { - return - } - - // Already at our max? - if ka.refs == newBucketsPerAddress { - return - } - - // The more entries we have, the less likely we are to add more. - // likelyhood is 2N. - factor := int32(2 * ka.refs) - if a.rand.Int31n(factor) != 0 { - return - } - } else { - // Make a copy of the net address to avoid races since it is - // updated elsewhere in the addrmanager code and would otherwise - // change the actual netaddress on the peer. - netAddrCopy := *netAddr - ka = &knownAddress{na: &netAddrCopy, srcAddr: srcAddr} - a.addrIndex[addr] = ka - a.nNew++ - // XXX time penalty? - } - - bucket := a.getNewBucket(netAddr, srcAddr) - - // Already exists? - if _, ok := a.addrNew[bucket][addr]; ok { - return - } - - // Enforce max addresses. - if len(a.addrNew[bucket]) > newBucketSize { - amgrLog.Tracef("new bucket is full, expiring old ") - a.expireNew(bucket) - } - - // Add to new bucket. - ka.refs++ - a.addrNew[bucket][addr] = ka - - amgrLog.Tracef("Added new address %s for a total of %d addresses", - addr, a.nTried+a.nNew) +// LastAttempt returns the last time the known address was attempted. +func (ka *knownAddress) LastAttempt() time.Time { + return ka.lastattempt } // bad returns true if the address in question has not been tried in the last @@ -257,6 +200,107 @@ func chance(ka *knownAddress) float64 { return c } +// AddrManager provides a concurrency safe address manager for caching potential +// peers on the bitcoin network. +type AddrManager struct { + mtx sync.Mutex + dataDir string + lookupFunc func(string) ([]net.IP, error) + rand *rand.Rand + key [32]byte + addrIndex map[string]*knownAddress // address key to ka for all addrs. + addrNew [newBucketCount]map[string]*knownAddress + addrTried [triedBucketCount]*list.List + started int32 + shutdown int32 + wg sync.WaitGroup + quit chan struct{} + nTried int + nNew int + lamtx sync.Mutex + localAddresses map[string]*localAddress +} + +// updateAddress is a helper function to either update an address already known +// to the address manager, or to add the address if not already known. +func (a *AddrManager) updateAddress(netAddr, srcAddr *btcwire.NetAddress) { + // Filter out non-routable addresses. Note that non-routable + // also includes invalid and local addresses. + if !Routable(netAddr) { + return + } + + // Protect concurrent access. + a.mtx.Lock() + defer a.mtx.Unlock() + + addr := NetAddressKey(netAddr) + ka := a.find(netAddr) + if ka != nil { + // TODO(oga) only update adresses periodically. + // Update the last seen time and services. + // note that to prevent causing excess garbage on getaddr + // messages the netaddresses in addrmaanger are *immutable*, + // if we need to change them then we replace the pointer with a + // new copy so that we don't have to copy every na for getaddr. + if netAddr.Timestamp.After(ka.na.Timestamp) || + (ka.na.Services&netAddr.Services) != + netAddr.Services { + + naCopy := *ka.na + naCopy.Timestamp = netAddr.Timestamp + naCopy.AddService(netAddr.Services) + ka.na = &naCopy + } + + // If already in tried, we have nothing to do here. + if ka.tried { + return + } + + // Already at our max? + if ka.refs == newBucketsPerAddress { + return + } + + // The more entries we have, the less likely we are to add more. + // likelyhood is 2N. + factor := int32(2 * ka.refs) + if a.rand.Int31n(factor) != 0 { + return + } + } else { + // Make a copy of the net address to avoid races since it is + // updated elsewhere in the addrmanager code and would otherwise + // change the actual netaddress on the peer. + netAddrCopy := *netAddr + ka = &knownAddress{na: &netAddrCopy, srcAddr: srcAddr} + a.addrIndex[addr] = ka + a.nNew++ + // XXX time penalty? + } + + bucket := a.getNewBucket(netAddr, srcAddr) + + // Already exists? + if _, ok := a.addrNew[bucket][addr]; ok { + return + } + + // Enforce max addresses. + if len(a.addrNew[bucket]) > newBucketSize { + log.Tracef("new bucket is full, expiring old ") + a.expireNew(bucket) + } + + // Add to new bucket. + ka.refs++ + a.addrNew[bucket][addr] = ka + + log.Tracef("Added new address %s for a total of %d addresses", addr, + a.nTried+a.nNew) +} + // expireNew makes space in the new buckets by expiring the really bad entries. // If no bad entries are available we look at a few and remove the oldest. func (a *AddrManager) expireNew(bucket int) { @@ -268,7 +312,7 @@ func (a *AddrManager) expireNew(bucket int) { var oldest *knownAddress for k, v := range a.addrNew[bucket] { if bad(v) { - amgrLog.Tracef("expiring bad address %v", k) + log.Tracef("expiring bad address %v", k) delete(a.addrNew[bucket], k) v.refs-- if v.refs == 0 { @@ -286,7 +330,7 @@ func (a *AddrManager) expireNew(bucket int) { if oldest != nil { key := NetAddressKey(oldest.na) - amgrLog.Tracef("expiring oldest address %v", key) + log.Tracef("expiring oldest address %v", key) delete(a.addrNew[bucket], key) oldest.refs-- @@ -314,37 +358,6 @@ func (a *AddrManager) pickTried(bucket int) *list.Element { return oldestElem } -// knownAddress tracks information about a known network address that is used -// to determine how viable an address is. -type knownAddress struct { - na *btcwire.NetAddress - srcAddr *btcwire.NetAddress - attempts int - lastattempt time.Time - lastsuccess time.Time - tried bool - refs int // reference count of new buckets -} - -// AddrManager provides a concurrency safe address manager for caching potential -// peers on the bitcoin network. -type AddrManager struct { - mtx sync.Mutex - rand *rand.Rand - key [32]byte - addrIndex map[string]*knownAddress // address key to ka for all addrs. - addrNew [newBucketCount]map[string]*knownAddress - addrTried [triedBucketCount]*list.List - started int32 - shutdown int32 - wg sync.WaitGroup - quit chan struct{} - nTried int - nNew int - lamtx sync.Mutex - localAddresses map[string]*localAddress -} - func (a *AddrManager) getNewBucket(netAddr, srcAddr *btcwire.NetAddress) int { // bitcoind: // doublesha256(key + sourcegroup + int64(doublesha256(key + group + sourcegroup))%bucket_per_source_group) % num_new_buckes @@ -404,7 +417,7 @@ out: dumpAddressTicker.Stop() a.savePeers() a.wg.Done() - amgrLog.Trace("Address handler done") + log.Trace("Address handler done") } type serialisedKnownAddress struct { @@ -472,17 +485,17 @@ func (a *AddrManager) savePeers() { // May give some way to specify this later. filename := "peers.json" - filePath := filepath.Join(cfg.DataDir, filename) + filePath := filepath.Join(a.dataDir, filename) w, err := os.Create(filePath) if err != nil { - amgrLog.Error("Error opening file: ", filePath, err) + log.Error("Error opening file: ", filePath, err) return } enc := json.NewEncoder(w) defer w.Close() if err := enc.Encode(&sam); err != nil { - amgrLog.Errorf("Failed to encode %s: %v", filePath, err) + log.Errorf("Failed to encode %s: %v", filePath, err) return } } @@ -495,21 +508,20 @@ func (a *AddrManager) loadPeers() { // May give some way to specify this later. filename := "peers.json" - filePath := filepath.Join(cfg.DataDir, filename) + filePath := filepath.Join(a.dataDir, filename) err := a.deserialisePeers(filePath) if err != nil { - amgrLog.Errorf("Failed to parse %s: %v", filePath, err) + log.Errorf("Failed to parse %s: %v", filePath, err) // if it is invalid we nuke the old one unconditionally. err = os.Remove(filePath) if err != nil { - amgrLog.Warn("Failed to remove corrupt peers "+ - "file: ", err) + log.Warn("Failed to remove corrupt peers file: ", err) } a.reset() return } - amgrLog.Infof("Loaded %d addresses from '%s'", a.nNew+a.nTried, filePath) + log.Infof("Loaded %d addresses from '%s'", a.nNew+a.nTried, filePath) } func (a *AddrManager) deserialisePeers(filePath string) error { @@ -539,12 +551,12 @@ func (a *AddrManager) deserialisePeers(filePath string) error { for _, v := range sam.Addresses { ka := new(knownAddress) - ka.na, err = deserialiseNetAddress(v.Addr) + ka.na, err = a.DeserialiseNetAddress(v.Addr) if err != nil { return fmt.Errorf("failed to deserialise netaddress "+ "%s: %v", v.Addr, err) } - ka.srcAddr, err = deserialiseNetAddress(v.Src) + ka.srcAddr, err = a.DeserialiseNetAddress(v.Src) if err != nil { return fmt.Errorf("failed to deserialise netaddress "+ "%s: %v", v.Src, err) @@ -600,7 +612,7 @@ func (a *AddrManager) deserialisePeers(filePath string) error { return nil } -func deserialiseNetAddress(addr string) (*btcwire.NetAddress, error) { +func (a *AddrManager) DeserialiseNetAddress(addr string) (*btcwire.NetAddress, error) { host, portStr, err := net.SplitHostPort(addr) if err != nil { return nil, err @@ -610,7 +622,7 @@ func deserialiseNetAddress(addr string) (*btcwire.NetAddress, error) { return nil, err } - return hostToNetAddress(host, uint16(port), btcwire.SFNodeNetwork) + return a.HostToNetAddress(host, uint16(port), btcwire.SFNodeNetwork) } // Start begins the core address handler which manages a pool of known @@ -621,7 +633,7 @@ func (a *AddrManager) Start() { return } - amgrLog.Trace("Starting address manager") + log.Trace("Starting address manager") a.wg.Add(1) @@ -635,12 +647,12 @@ func (a *AddrManager) Start() { // Stop gracefully shuts down the address manager by stopping the main handler. func (a *AddrManager) Stop() error { if atomic.AddInt32(&a.shutdown, 1) != 1 { - amgrLog.Warnf("Address manager is already in the process of " + + log.Warnf("Address manager is already in the process of " + "shutting down") return nil } - amgrLog.Infof("Address manager shutting down") + log.Infof("Address manager shutting down") close(a.quit) a.wg.Wait() return nil @@ -649,8 +661,7 @@ func (a *AddrManager) Stop() error { // AddAddresses adds new addresses to the address manager. It enforces a max // number of addresses and silently ignores duplicate addresses. It is // safe for concurrent access. -func (a *AddrManager) AddAddresses(addrs []*btcwire.NetAddress, - srcAddr *btcwire.NetAddress) { +func (a *AddrManager) AddAddresses(addrs []*btcwire.NetAddress, srcAddr *btcwire.NetAddress) { for _, na := range addrs { a.updateAddress(na, srcAddr) } @@ -670,8 +681,8 @@ func (a *AddrManager) AddAddressByIP(addrIP string) { // Split IP and port addr, portStr, err := net.SplitHostPort(addrIP) if err != nil { - amgrLog.Warnf("AddADddressByIP given bullshit adddress"+ - "(%s): %v", err) + log.Warnf("AddADddressByIP given bullshit adddress (%s): %v", + err) return } // Put it in btcwire.Netaddress @@ -679,12 +690,12 @@ func (a *AddrManager) AddAddressByIP(addrIP string) { na.Timestamp = time.Now() na.IP = net.ParseIP(addr) if na.IP == nil { - amgrLog.Error("Invalid ip address:", addr) + log.Error("Invalid ip address:", addr) return } port, err := strconv.ParseUint(portStr, 10, 0) if err != nil { - amgrLog.Error("Invalid port: ", portStr, err) + log.Error("Invalid port: ", portStr, err) return } na.Port = uint16(port) @@ -757,22 +768,10 @@ func (a *AddrManager) reset() { } } -// NewAddrManager returns a new bitcoin address manager. -// Use Start to begin processing asynchronous address updates. -func NewAddrManager() *AddrManager { - am := AddrManager{ - rand: rand.New(rand.NewSource(time.Now().UnixNano())), - quit: make(chan struct{}), - localAddresses: make(map[string]*localAddress), - } - am.reset() - return &am -} - -// hostToNetAddress returns a netaddress given a host address. If the address is +// HostToNetAddress returns a netaddress given a host address. If the address is // a tor .onion address this will be taken care of. else if the host is not an // IP address it will be resolved (via tor if required). -func hostToNetAddress(host string, port uint16, services btcwire.ServiceFlag) (*btcwire.NetAddress, error) { +func (a *AddrManager) HostToNetAddress(host string, port uint16, services btcwire.ServiceFlag) (*btcwire.NetAddress, error) { // tor address is 16 char base32 + ".onion" var ip net.IP if len(host) == 22 && host[16:] == ".onion" { @@ -787,7 +786,7 @@ func hostToNetAddress(host string, port uint16, services btcwire.ServiceFlag) (* prefix := []byte{0xfd, 0x87, 0xd8, 0x7e, 0xeb, 0x43} ip = net.IP(append(prefix, data...)) } else if ip = net.ParseIP(host); ip == nil { - ips, err := btcdLookup(host) + ips, err := a.lookupFunc(host) if err != nil { return nil, err } @@ -866,7 +865,7 @@ func (a *AddrManager) GetAddress(class string, newBias int) *knownAddress { ka := e.Value.(*knownAddress) randval := a.rand.Intn(large) if float64(randval) < (factor * chance(ka) * float64(large)) { - amgrLog.Tracef("Selected %v from tried bucket", + log.Tracef("Selected %v from tried bucket", NetAddressKey(ka.na)) return ka } @@ -894,7 +893,7 @@ func (a *AddrManager) GetAddress(class string, newBias int) *knownAddress { } randval := a.rand.Intn(large) if float64(randval) < (factor * chance(ka) * float64(large)) { - amgrLog.Tracef("Selected %v from new bucket", + log.Tracef("Selected %v from new bucket", NetAddressKey(ka.na)) return ka } @@ -1034,7 +1033,7 @@ func (a *AddrManager) Good(addr *btcwire.NetAddress) { a.nNew++ rmkey := NetAddressKey(rmka.na) - amgrLog.Tracef("Replacing %s with %s in tried", rmkey, addrKey) + log.Tracef("Replacing %s with %s in tried", rmkey, addrKey) // We made sure there is space here just above. a.addrNew[newBucket][rmkey] = rmka @@ -1240,18 +1239,17 @@ type localAddress struct { score addressPrio } -// addLocalAddress adds na to the list of known local addresses to advertise +// AddLocalAddress adds na to the list of known local addresses to advertise // with the given priority. -func (a *AddrManager) addLocalAddress(na *btcwire.NetAddress, +func (a *AddrManager) AddLocalAddress(na *btcwire.NetAddress, priority addressPrio) { // sanity check. if !Routable(na) { - amgrLog.Debugf("rejecting address %s:%d due to routability", + log.Debugf("rejecting address %s:%d due to routability", na.IP, na.Port) return } - amgrLog.Debugf("adding address %s:%d", - na.IP, na.Port) + log.Debugf("adding address %s:%d", na.IP, na.Port) a.lamtx.Lock() defer a.lamtx.Unlock() @@ -1349,8 +1347,8 @@ func getReachabilityFrom(na, fromna *btcwire.NetAddress) int { } // getBestLocalAddress returns the most appropriate local address that we know -// of to be contacted by rna -func (a *AddrManager) getBestLocalAddress(rna *btcwire.NetAddress) *btcwire.NetAddress { +// of to be contacted by rna. +func (a *AddrManager) GetBestLocalAddress(rna *btcwire.NetAddress) *btcwire.NetAddress { a.lamtx.Lock() defer a.lamtx.Unlock() @@ -1367,11 +1365,10 @@ func (a *AddrManager) getBestLocalAddress(rna *btcwire.NetAddress) *btcwire.NetA } } if bestna != nil { - amgrLog.Debugf("Suggesting address %s:%d for %s:%d", - bestna.IP, bestna.Port, rna.IP, rna.Port) + log.Debugf("Suggesting address %s:%d for %s:%d", bestna.IP, + bestna.Port, rna.IP, rna.Port) } else { - amgrLog.Debugf("No worthy address for %s:%d", - rna.IP, rna.Port) + log.Debugf("No worthy address for %s:%d", rna.IP, rna.Port) // Send something unroutable if nothing suitable. bestna = &btcwire.NetAddress{ Timestamp: time.Now(), @@ -1383,3 +1380,17 @@ func (a *AddrManager) getBestLocalAddress(rna *btcwire.NetAddress) *btcwire.NetA return bestna } + +// New returns a new bitcoin address manager. +// Use Start to begin processing asynchronous address updates. +func New(dataDir string, lookupFunc func(string) ([]net.IP, error)) *AddrManager { + am := AddrManager{ + dataDir: dataDir, + lookupFunc: lookupFunc, + rand: rand.New(rand.NewSource(time.Now().UnixNano())), + quit: make(chan struct{}), + localAddresses: make(map[string]*localAddress), + } + am.reset() + return &am +} diff --git a/addrmanager_test.go b/addrmgr/addrmanager_test.go similarity index 92% rename from addrmanager_test.go rename to addrmgr/addrmanager_test.go index d510ffbb1..814c5021f 100644 --- a/addrmanager_test.go +++ b/addrmgr/addrmanager_test.go @@ -2,13 +2,15 @@ // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package main +package addrmgr_test import ( + "errors" "net" "testing" "time" + "github.com/conformal/btcd/addrmgr" "github.com/conformal/btcwire" ) @@ -163,8 +165,12 @@ func addNaTests() { addNaTest("fef3::4:4", 8336, "[fef3::4:4]:8336") } +func lookupFunc(host string) ([]net.IP, error) { + return nil, errors.New("not implemented") +} + func TestGetAddress(t *testing.T) { - n := NewAddrManager() + n := addrmgr.New("testdir", lookupFunc) if rv := n.GetAddress("any", 10); rv != nil { t.Errorf("GetAddress failed: got: %v want: %v\n", rv, nil) } @@ -175,91 +181,91 @@ func TestIPTypes(t *testing.T) { t.Logf("Running %d tests", len(ipTests)) for _, test := range ipTests { - rv := RFC1918(&test.in) + rv := addrmgr.RFC1918(&test.in) if rv != test.rfc1918 { t.Errorf("RFC1918 %s\n got: %v want: %v", test.in.IP, rv, test.rfc1918) continue } } for _, test := range ipTests { - rv := RFC3849(&test.in) + rv := addrmgr.RFC3849(&test.in) if rv != test.rfc3849 { t.Errorf("RFC3849 %s\n got: %v want: %v", test.in.IP, rv, test.rfc3849) continue } } for _, test := range ipTests { - rv := RFC3927(&test.in) + rv := addrmgr.RFC3927(&test.in) if rv != test.rfc3927 { t.Errorf("RFC3927 %s\n got: %v want: %v", test.in.IP, rv, test.rfc3927) continue } } for _, test := range ipTests { - rv := RFC3964(&test.in) + rv := addrmgr.RFC3964(&test.in) if rv != test.rfc3964 { t.Errorf("RFC3964 %s\n got: %v want: %v", test.in.IP, rv, test.rfc3964) continue } } for _, test := range ipTests { - rv := RFC4193(&test.in) + rv := addrmgr.RFC4193(&test.in) if rv != test.rfc4193 { t.Errorf("RFC4193 %s\n got: %v want: %v", test.in.IP, rv, test.rfc4193) continue } } for _, test := range ipTests { - rv := RFC4380(&test.in) + rv := addrmgr.RFC4380(&test.in) if rv != test.rfc4380 { t.Errorf("RFC4380 %s\n got: %v want: %v", test.in.IP, rv, test.rfc4380) continue } } for _, test := range ipTests { - rv := RFC4843(&test.in) + rv := addrmgr.RFC4843(&test.in) if rv != test.rfc4843 { t.Errorf("RFC4843 %s\n got: %v want: %v", test.in.IP, rv, test.rfc4843) continue } } for _, test := range ipTests { - rv := RFC4862(&test.in) + rv := addrmgr.RFC4862(&test.in) if rv != test.rfc4862 { t.Errorf("RFC4862 %s\n got: %v want: %v", test.in.IP, rv, test.rfc4862) continue } } for _, test := range ipTests { - rv := RFC6052(&test.in) + rv := addrmgr.RFC6052(&test.in) if rv != test.rfc6052 { t.Errorf("RFC6052 %s\n got: %v want: %v", test.in.IP, rv, test.rfc6052) continue } } for _, test := range ipTests { - rv := RFC6145(&test.in) + rv := addrmgr.RFC6145(&test.in) if rv != test.rfc6145 { t.Errorf("RFC1918 %s\n got: %v want: %v", test.in.IP, rv, test.rfc6145) continue } } for _, test := range ipTests { - rv := Local(&test.in) + rv := addrmgr.Local(&test.in) if rv != test.local { t.Errorf("Local %s\n got: %v want: %v", test.in.IP, rv, test.local) continue } } for _, test := range ipTests { - rv := Valid(&test.in) + rv := addrmgr.Valid(&test.in) if rv != test.valid { t.Errorf("Valid %s\n got: %v want: %v", test.in.IP, rv, test.valid) continue } } for _, test := range ipTests { - rv := Routable(&test.in) + rv := addrmgr.Routable(&test.in) if rv != test.routable { t.Errorf("Routable %s\n got: %v want: %v", test.in.IP, rv, test.routable) continue @@ -272,7 +278,7 @@ func TestNetAddressKey(t *testing.T) { t.Logf("Running %d tests", len(naTests)) for i, test := range naTests { - key := NetAddressKey(&test.in) + key := addrmgr.NetAddressKey(&test.in) if key != test.want { t.Errorf("NetAddressKey #%d\n got: %s want: %s", i, key, test.want) continue diff --git a/log.go b/log.go index b92ad78e4..44d6a4c25 100644 --- a/log.go +++ b/log.go @@ -9,6 +9,8 @@ import ( "os" "time" + "github.com/conformal/btcd/addrmgr" + "github.com/conformal/btcchain" "github.com/conformal/btcdb" "github.com/conformal/btclog" @@ -89,6 +91,7 @@ func useLogger(subsystemID string, logger btclog.Logger) { switch subsystemID { case "AMGR": amgrLog = logger + addrmgr.UseLogger(logger) case "BCDB": bcdbLog = logger diff --git a/peer.go b/peer.go index 3251f68c1..ee782123e 100644 --- a/peer.go +++ b/peer.go @@ -15,6 +15,7 @@ import ( "time" "github.com/conformal/btcchain" + "github.com/conformal/btcd/addrmgr" "github.com/conformal/btcdb" "github.com/conformal/btcutil" "github.com/conformal/btcwire" @@ -253,7 +254,7 @@ func (p *peer) pushVersionMsg() error { // Version message. msg := btcwire.NewMsgVersion( - p.server.addrManager.getBestLocalAddress(p.na), theirNa, + p.server.addrManager.GetBestLocalAddress(p.na), theirNa, p.server.nonce, int32(blockNum)) msg.AddUserAgent(userAgentName, userAgentVersion) @@ -296,8 +297,8 @@ func (p *peer) updateAddresses(msg *btcwire.MsgVersion) { // download and the local address is routable. if !cfg.DisableListen /* && isCurrent? */ { // Get address that best matches. - lna := p.server.addrManager.getBestLocalAddress(p.na) - if Routable(lna) { + lna := p.server.addrManager.GetBestLocalAddress(p.na) + if addrmgr.Routable(lna) { addresses := []*btcwire.NetAddress{lna} p.pushAddrMsg(addresses) } @@ -319,7 +320,7 @@ func (p *peer) updateAddresses(msg *btcwire.MsgVersion) { // actually connected from. One example of why this can happen // is with NAT. Only add the address to the address manager if // the addresses agree. - if NetAddressKey(&msg.AddrMe) == NetAddressKey(p.na) { + if addrmgr.NetAddressKey(&msg.AddrMe) == addrmgr.NetAddressKey(p.na) { p.server.addrManager.AddAddress(p.na, p.na) p.server.addrManager.Good(p.na) } @@ -925,7 +926,7 @@ func (p *peer) pushAddrMsg(addresses []*btcwire.NetAddress) error { msg := btcwire.NewMsgAddr() for _, na := range addresses { // Filter addresses the peer already knows about. - if _, ok := p.knownAddresses[NetAddressKey(na)]; ok { + if _, ok := p.knownAddresses[addrmgr.NetAddressKey(na)]; ok { continue } @@ -993,7 +994,7 @@ func (p *peer) handleAddrMsg(msg *btcwire.MsgAddr) { } // Add address to known addresses for this peer. - p.knownAddresses[NetAddressKey(na)] = struct{}{} + p.knownAddresses[addrmgr.NetAddressKey(na)] = struct{}{} } // Add addresses to server address manager. The address manager handles @@ -1687,7 +1688,7 @@ func newOutboundPeer(s *server, addr string, persistent bool) *peer { return nil } - p.na, err = hostToNetAddress(host, uint16(port), 0) + p.na, err = s.addrManager.HostToNetAddress(host, uint16(port), 0) if err != nil { p.logError("Can not turn host %s into netaddress: %v", host, err) diff --git a/server.go b/server.go index 9abf16109..c6e51d87a 100644 --- a/server.go +++ b/server.go @@ -11,6 +11,7 @@ import ( "errors" "fmt" "math" + mrand "math/rand" "net" "runtime" "strconv" @@ -18,6 +19,7 @@ import ( "sync/atomic" "time" + "github.com/conformal/btcd/addrmgr" "github.com/conformal/btcdb" "github.com/conformal/btcjson" "github.com/conformal/btcnet" @@ -71,7 +73,7 @@ type server struct { bytesMutex sync.Mutex // For the following two fields. bytesReceived uint64 // Total bytes received from all peers since start. bytesSent uint64 // Total bytes sent by all peers since start. - addrManager *AddrManager + addrManager *addrmgr.AddrManager rpcServer *rpcServer blockManager *blockManager txMemPool *txMemPool @@ -224,7 +226,7 @@ func (s *server) handleAddPeerMsg(state *peerState, p *peer) bool { state.peers.PushBack(p) p.Start() } else { - state.outboundGroups[GroupKey(p.na)]++ + state.outboundGroups[addrmgr.GroupKey(p.na)]++ if p.persistent { state.persistentPeers.PushBack(p) } else { @@ -256,7 +258,7 @@ func (s *server) handleDonePeerMsg(state *peerState, p *peer) { return } if !p.inbound { - state.outboundGroups[GroupKey(p.na)]-- + state.outboundGroups[addrmgr.GroupKey(p.na)]-- } list.Remove(e) srvrLog.Debugf("Removed peer %s", p) @@ -418,7 +420,7 @@ func (s *server) handleQuery(querymsg interface{}, state *peerState) { if peer.addr == msg.addr { // Keep group counts ok since we remove from // the list now. - state.outboundGroups[GroupKey(peer.na)]-- + state.outboundGroups[addrmgr.GroupKey(peer.na)]-- // This is ok because we are not continuing // to iterate so won't corrupt the loop. state.persistentPeers.Remove(e) @@ -473,6 +475,7 @@ func (s *server) seedFromDNS() { return } + randSource := mrand.New(mrand.NewSource(time.Now().UnixNano())) for _, seeder := range activeNetParams.dnsSeeds { go func(seeder string) { seedpeers, err := dnsDiscover(seeder) @@ -498,7 +501,7 @@ func (s *server) seedFromDNS() { // and 7 days ago. addresses[i].Timestamp = time.Now().Add(-1 * time.Second * time.Duration(secondsIn3Days+ - s.addrManager.rand.Int31n(secondsIn4Days))) + randSource.Int31n(secondsIn4Days))) } // Bitcoind uses a lookup of the dns seeder here. This @@ -619,7 +622,7 @@ out: if addr == nil { break } - key := GroupKey(addr.na) + key := addrmgr.GroupKey(addr.NetAddress()) // Address will not be invalid, local or unroutable // because addrmanager rejects those on addition. // Just check that we don't already have an address @@ -641,18 +644,18 @@ out: // only allow recent nodes (10mins) after we failed 30 // times - if time.Now().After(addr.lastattempt.Add(10*time.Minute)) && + if time.Now().After(addr.LastAttempt().Add(10*time.Minute)) && tries < 30 { continue } // allow nondefault ports after 50 failed tries. - if fmt.Sprintf("%d", addr.na.Port) != + if fmt.Sprintf("%d", addr.NetAddress().Port) != activeNetParams.DefaultPort && tries < 50 { continue } - addrStr := NetAddressKey(addr.na) + addrStr := addrmgr.NetAddressKey(addr.NetAddress()) tries = 0 // any failure will be due to banned peers etc. we have @@ -1027,8 +1030,8 @@ out: } na := btcwire.NewNetAddressIPPort(externalip, uint16(listenPort), btcwire.SFNodeNetwork) - s.addrManager.addLocalAddress(na, UpnpPrio) - srvrLog.Warnf("Successfully bound via UPnP to %s", NetAddressKey(na)) + s.addrManager.AddLocalAddress(na, addrmgr.UpnpPrio) + srvrLog.Warnf("Successfully bound via UPnP to %s", addrmgr.NetAddressKey(na)) first = false } timer.Reset(time.Minute * 15) @@ -1057,7 +1060,7 @@ func newServer(listenAddrs []string, db btcdb.Db, netParams *btcnet.Params) (*se return nil, err } - amgr := NewAddrManager() + amgr := addrmgr.New(cfg.DataDir, btcdLookup) var listeners []net.Listener var nat NAT @@ -1093,7 +1096,7 @@ func newServer(listenAddrs []string, db btcdb.Db, netParams *btcnet.Params) (*se } eport = uint16(port) } - na, err := hostToNetAddress(host, eport, + na, err := amgr.HostToNetAddress(host, eport, btcwire.SFNodeNetwork) if err != nil { srvrLog.Warnf("Not adding %s as "+ @@ -1101,7 +1104,7 @@ func newServer(listenAddrs []string, db btcdb.Db, netParams *btcnet.Params) (*se continue } - amgr.addLocalAddress(na, ManualPrio) + amgr.AddLocalAddress(na, addrmgr.ManualPrio) } } else if discover && cfg.Upnp { nat, err = Discover() @@ -1129,7 +1132,7 @@ func newServer(listenAddrs []string, db btcdb.Db, netParams *btcnet.Params) (*se na := btcwire.NewNetAddressIPPort(ip, uint16(port), btcwire.SFNodeNetwork) if discover { - amgr.addLocalAddress(na, InterfacePrio) + amgr.AddLocalAddress(na, addrmgr.InterfacePrio) } } } @@ -1145,8 +1148,8 @@ func newServer(listenAddrs []string, db btcdb.Db, netParams *btcnet.Params) (*se listeners = append(listeners, listener) if discover { - if na, err := deserialiseNetAddress(addr); err == nil { - amgr.addLocalAddress(na, BoundPrio) + if na, err := amgr.DeserialiseNetAddress(addr); err == nil { + amgr.AddLocalAddress(na, addrmgr.BoundPrio) } } } @@ -1160,8 +1163,8 @@ func newServer(listenAddrs []string, db btcdb.Db, netParams *btcnet.Params) (*se } listeners = append(listeners, listener) if discover { - if na, err := deserialiseNetAddress(addr); err == nil { - amgr.addLocalAddress(na, BoundPrio) + if na, err := amgr.DeserialiseNetAddress(addr); err == nil { + amgr.AddLocalAddress(na, addrmgr.BoundPrio) } } }