Skip to content

Commit 64da665

Browse files
committed
kademlia/iterator: allow for the configuration of a lookup request timeout
kademlia/protocol: allow for the configuration of a ping request timeout node: resolve public address if passed in as an option, and pass its parameters towards NewID on Listen noise: bump to v1.1.2
1 parent 8a67549 commit 64da665

File tree

6 files changed

+76
-11
lines changed

6 files changed

+76
-11
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,9 +151,9 @@ Releases are marked with a version number formatted as MAJOR.MINOR.PATCH. Major
151151

152152
Therefore, **noise** _mostly_ respects semantic versioning.
153153

154-
The rationale behind this is due to improper tagging of prior releases (v0.1.0, v1.0.0, and v1.1.0), which has caused for the improper caching of module information on _proxy.golang.org_ and _sum.golang.org_.
154+
The rationale behind this is due to improper tagging of prior releases (v0.1.0, v1.0.0, v1.1.0, and v1.1.1), which has caused for the improper caching of module information on _proxy.golang.org_ and _sum.golang.org_.
155155

156-
As a result, _noise's initial development phase starts from v1.1.1_. Until Noise's API is stable, subsequent releases will only comprise of bumps in MINOR and PATCH.
156+
As a result, _noise's initial development phase starts from v1.1.2_. Until Noise's API is stable, subsequent releases will only comprise of bumps in MINOR and PATCH.
157157

158158
## License
159159

kademlia/iterator.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ type Iterator struct {
2424
maxNumResults int
2525
numParallelLookups int
2626
numParallelRequestsPerLookup int
27+
28+
lookupTimeout time.Duration
2729
}
2830

2931
// NewIterator instantiates a new overlay network iterator bounded to a node and routing table that may be
@@ -37,6 +39,8 @@ func NewIterator(node *noise.Node, table *Table, opts ...IteratorOption) *Iterat
3739
maxNumResults: BucketSize,
3840
numParallelLookups: 3,
3941
numParallelRequestsPerLookup: 8,
42+
43+
lookupTimeout: 3 * time.Second,
4044
}
4145

4246
for _, opt := range opts {
@@ -155,7 +159,7 @@ func (it *Iterator) processLookupRequests(in <-chan noise.ID, out chan<- []noise
155159
}
156160

157161
func (it *Iterator) lookupRequest(id noise.ID, out chan<- []noise.ID) {
158-
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
162+
ctx, cancel := context.WithTimeout(context.Background(), it.lookupTimeout)
159163
defer cancel()
160164

161165
obj, err := it.node.RequestMessage(ctx, id.Address, FindNodeRequest{Target: id.ID})

kademlia/iterator_options.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package kademlia
22

3-
import "go.uber.org/zap"
3+
import (
4+
"go.uber.org/zap"
5+
"time"
6+
)
47

58
// IteratorOption represents a functional option which may be passed to NewIterator, or to (*Protocol).Find or
69
// (*Protocol).Discover to configure Iterator.
@@ -37,3 +40,11 @@ func WithIteratorNumParallelRequestsPerLookup(numParallelRequestsPerLookup int)
3740
it.numParallelRequestsPerLookup = numParallelRequestsPerLookup
3841
}
3942
}
43+
44+
// WithIteratorLookupTimeout sets the max duration to wait until we declare a lookup request sent in amidst
45+
// a single disjoint lookup to have timed out. By default, it is set to 3 seconds.
46+
func WithIteratorLookupTimeout(lookupTimeout time.Duration) IteratorOption {
47+
return func(it *Iterator) {
48+
it.lookupTimeout = lookupTimeout
49+
}
50+
}

kademlia/protocol.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,15 @@ type Protocol struct {
2626
table *Table
2727

2828
events Events
29+
30+
pingTimeout time.Duration
2931
}
3032

3133
// New returns a new instance of the Kademlia protocol.
3234
func New(opts ...ProtocolOption) *Protocol {
33-
p := &Protocol{}
35+
p := &Protocol{
36+
pingTimeout: 3 * time.Second,
37+
}
3438

3539
for _, opt := range opts {
3640
opt(p)
@@ -102,7 +106,7 @@ func (p *Protocol) Ack(id noise.ID) {
102106
bucket := p.table.Bucket(id.ID)
103107
last := bucket[len(bucket)-1]
104108

105-
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
109+
ctx, cancel := context.WithTimeout(context.Background(), p.pingTimeout)
106110
pong, err := p.node.RequestMessage(ctx, last.Address, Ping{})
107111
cancel()
108112

kademlia/protocol_options.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package kademlia
22

3-
import "go.uber.org/zap"
3+
import (
4+
"go.uber.org/zap"
5+
"time"
6+
)
47

58
// ProtocolOption represents a functional option which may be passed to New to configure a Protocol.
69
type ProtocolOption func(p *Protocol)
@@ -19,3 +22,12 @@ func WithProtocolLogger(logger *zap.Logger) ProtocolOption {
1922
p.logger = logger
2023
}
2124
}
25+
26+
// WithProtocolPingTimeout configures the amount of time to wait for until we declare a ping to have failed. Peers
27+
// typically either are pinged through a call of (*Protocol).Ping, or in amidst the execution of Kademlia's peer
28+
// eviction policy. By default, it is set to 3 seconds.
29+
func WithProtocolPingTimeout(pingTimeout time.Duration) ProtocolOption {
30+
return func(p *Protocol) {
31+
p.pingTimeout = pingTimeout
32+
}
33+
}

node.go

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -127,25 +127,51 @@ func (n *Node) Listen() error {
127127

128128
addr, ok := n.listener.Addr().(*net.TCPAddr)
129129
if !ok {
130-
err = fmt.Errorf("did not listen for tcp: %w", n.listener.Close())
131-
return err
130+
n.listener.Close()
131+
return errors.New("did not bind to a tcp addr")
132132
}
133133

134134
n.host = addr.IP
135135
n.port = uint16(addr.Port)
136136

137137
if n.addr == "" {
138138
n.addr = net.JoinHostPort(normalizeIP(n.host), strconv.FormatUint(uint64(n.port), 10))
139-
}
139+
n.id = NewID(n.publicKey, n.host, n.port)
140+
} else {
141+
resolved, err := ResolveAddress(n.addr)
142+
if err != nil {
143+
n.listener.Close()
144+
return err
145+
}
146+
147+
hostStr, portStr, err := net.SplitHostPort(resolved)
148+
if err != nil {
149+
n.listener.Close()
150+
return err
151+
}
140152

141-
n.id = NewID(n.publicKey, n.host, n.port)
153+
host := net.ParseIP(hostStr)
154+
if host == nil {
155+
n.listener.Close()
156+
return errors.New("host in provided public address is invalid (must be IPv4/IPv6)")
157+
}
158+
159+
port, err := strconv.ParseUint(portStr, 10, 16)
160+
if err != nil {
161+
n.listener.Close()
162+
return err
163+
}
164+
165+
n.id = NewID(n.publicKey, host, uint16(port))
166+
}
142167

143168
for _, protocol := range n.protocols {
144169
if protocol.Bind == nil {
145170
continue
146171
}
147172

148173
if err = protocol.Bind(n); err != nil {
174+
n.listener.Close()
149175
return err
150176
}
151177
}
@@ -383,6 +409,14 @@ func (n *Node) dialIfNotExists(ctx context.Context, addr string) (*Client, error
383409
client.waitUntilClosed()
384410

385411
if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
412+
for _, protocol := range n.protocols {
413+
if protocol.OnPingFailed == nil {
414+
continue
415+
}
416+
417+
protocol.OnPingFailed(addr, err)
418+
}
419+
386420
return nil, err
387421
}
388422
}

0 commit comments

Comments
 (0)