Move address manager to its own package.
This commit does just enough to move the address manager into its own package. Since it was not originally written as a package, it will require a bit of refactoring and cleanup to turn it into a robust package with a friendly API.
This commit is contained in:
parent
ebc5db2710
commit
62f21d3600
5 changed files with 227 additions and 203 deletions
|
@ -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()
|
||||
|
||||
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
|
||||
// NetAddress returns the underlying btcwire.NetAddress associated with the
|
||||
// known address.
|
||||
func (ka *knownAddress) NetAddress() *btcwire.NetAddress {
|
||||
return ka.na
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
|
@ -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
|
3
log.go
3
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
|
||||
|
|
15
peer.go
15
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)
|
||||
|
|
41
server.go
41
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue