diff --git a/Bootstrap.go b/Bootstrap.go index 4aff1c5..89b4654 100644 --- a/Bootstrap.go +++ b/Bootstrap.go @@ -43,12 +43,12 @@ loopSeedList: // parse the Public Key publicKeyB, err := hex.DecodeString(seed.PublicKey) if err != nil { - Filters.LogError("initSeedList", "public key '%s': %v", seed.PublicKey, err.Error()) + Filters.LogError("initSeedList", "public key '%s': %v\n", seed.PublicKey, err.Error()) continue } if peer.publicKey, err = btcec.ParsePubKey(publicKeyB, btcec.S256()); err != nil { - Filters.LogError("initSeedList", "public key '%s': %v", seed.PublicKey, err.Error()) + Filters.LogError("initSeedList", "public key '%s': %v\n", seed.PublicKey, err.Error()) continue } @@ -60,7 +60,7 @@ loopSeedList: for _, addressA := range seed.Address { address, err := parseAddress(addressA) if err != nil { - Filters.LogError("initSeedList", "public key '%s' address '%s': %v", seed.PublicKey, addressA, err.Error()) + Filters.LogError("initSeedList", "public key '%s' address '%s': %v\n", seed.PublicKey, addressA, err.Error()) continue loopSeedList } @@ -162,13 +162,13 @@ func autoMulticastBroadcast() { for _, network := range networks6 { if err := network.MulticastIPv6Send(); err != nil { - Filters.LogError("autoMulticastBroadcast", "multicast from network address '%s': %v", network.address.IP.String(), err.Error()) + Filters.LogError("autoMulticastBroadcast", "multicast from network address '%s': %v\n", network.address.IP.String(), err.Error()) } } for _, network := range networks4 { if err := network.BroadcastIPv4Send(); err != nil { - Filters.LogError("autoMulticastBroadcast", "broadcast from network address '%s': %v", network.address.IP.String(), err.Error()) + Filters.LogError("autoMulticastBroadcast", "broadcast from network address '%s': %v\n", network.address.IP.String(), err.Error()) } } } diff --git a/Connection.go b/Connection.go index d655bd2..687660e 100644 --- a/Connection.go +++ b/Connection.go @@ -69,6 +69,11 @@ func (c *Connection) IsPortForward() bool { return c.PortExternal > 0 } +// IsVirtual returns true if the peer has not been connected yet. This is the case if another peer responds with peer details, and that peer shall be contacted. +func (peer *PeerInfo) IsVirtual() bool { + return peer.isVirtual +} + // GetConnections returns the list of connections func (peer *PeerInfo) GetConnections(active bool) (connections []*Connection) { peer.RLock() diff --git a/Filter.go b/Filter.go index 39aefa0..dd49d84 100644 --- a/Filter.go +++ b/Filter.go @@ -8,7 +8,11 @@ Filters allow the caller to intercept events to log, modify, or prevent. package core -import "log" +import ( + "log" + + "github.com/PeernetOfficial/core/dht" +) // Filters contains all functions to install the hook. Use nil for unused. // The functions are called sequentially and block execution; if the filter takes a long time it should start a Go routine. @@ -23,14 +27,25 @@ var Filters struct { // LogError is called for any error. If this function is overwritten by the caller, the caller must write errors into the log file if desired, or call DefaultLogError. LogError func(function, format string, v ...interface{}) + + // DHTSearchStatus is called with updates of searches in the DHT. It allows to see the live progress of searches. + DHTSearchStatus func(client *dht.SearchClient, function, format string, v ...interface{}) } func initFilters() { // Set default filters to blank functions so they can be safely called without constant nil checks. - Filters.NewPeer = func(peer *PeerInfo, connection *Connection) {} - Filters.NewPeerConnection = func(peer *PeerInfo, connection *Connection) {} + // Only if not already set before init. + + if Filters.NewPeer == nil { + Filters.NewPeer = func(peer *PeerInfo, connection *Connection) {} + } + if Filters.NewPeerConnection == nil { + Filters.NewPeerConnection = func(peer *PeerInfo, connection *Connection) {} + } + if Filters.DHTSearchStatus == nil { + Filters.DHTSearchStatus = func(client *dht.SearchClient, function, format string, v ...interface{}) {} + } - // Only set the error function if not already set before init. if Filters.LogError == nil { Filters.LogError = DefaultLogError } diff --git a/Kademlia.go b/Kademlia.go index c92a4e7..db7e553 100644 --- a/Kademlia.go +++ b/Kademlia.go @@ -56,6 +56,8 @@ func initKademlia() { node.Info.(*PeerInfo).sendAnnouncementFindValue(request) } } + + nodesDHT.FilterSearchStatus = Filters.DHTSearchStatus } // autoBucketRefresh refreshes buckets every 5 minutes to meet the alpha nodes per bucket target. Force full refresh every hour. @@ -175,3 +177,21 @@ func IsNodeContact(nodeID []byte) (node *dht.Node, peer *PeerInfo) { return node, node.Info.(*PeerInfo) } + +// FindNode finds a node via the DHT +func FindNode(nodeID []byte, Timeout time.Duration) (node *dht.Node, peer *PeerInfo, err error) { + node, err = nodesDHT.FindNode(nodeID) + if node == nil { + return nil, nil, err + } + + return node, node.Info.(*PeerInfo), err +} + +// ---- Asynchronous Search ---- + +// AsyncSearch creates an async search for the given key in the DHT. +// Timeout is the total time the search may take, covering all information requests. TimeoutIR is the time an information request may take. +func AsyncSearch(Action int, Key []byte, Timeout, TimeoutIR time.Duration) (client *dht.SearchClient) { + return nodesDHT.NewSearch(Action, Key, Timeout, TimeoutIR) +} diff --git a/Network UPnP.go b/Network UPnP.go index 3abe41a..41b48d1 100644 --- a/Network UPnP.go +++ b/Network UPnP.go @@ -147,7 +147,7 @@ monitorLoop: } // invalid :( - Filters.LogError("upnpMonitorPortForward", "port forwarding invalidated for local IP %s (adapter %s) external IP %s port %d", network.address.String(), network.iface.Name, network.ipExternal.String(), network.portExternal) + Filters.LogError("upnpMonitorPortForward", "port forwarding invalidated for local IP %s (adapter %s) external IP %s port %d\n", network.address.String(), network.iface.Name, network.ipExternal.String(), network.portExternal) network.portExternal = 0 network.ipExternal = net.IP{}