Skip to content

Commit 9c878c3

Browse files
correctly handle static relays
1 parent b4a94f7 commit 9c878c3

File tree

6 files changed

+80
-34
lines changed

6 files changed

+80
-34
lines changed

config/config.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ type Config struct {
101101

102102
EnableAutoRelay bool
103103
AutoNATConfig
104-
StaticRelayOpt autorelay.StaticRelayOption
104+
StaticRelayOpt autorelay.Option
105105

106106
EnableHolePunching bool
107107
HolePunchingOptions []holepunch.Option

options.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ func EnableRelayService(opts ...relayv2.Option) Option {
250250
//
251251
// This subsystem performs automatic address rewriting to advertise relay addresses when it
252252
// detects that the node is publicly unreachable (e.g. behind a NAT).
253-
func EnableAutoRelay(opts ...autorelay.StaticRelayOption) Option {
253+
func EnableAutoRelay(opts ...autorelay.Option) Option {
254254
return func(cfg *Config) error {
255255
if len(opts) > 0 {
256256
if len(opts) > 1 {

p2p/host/autorelay/autorelay.go

+23-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ type AutoRelay struct {
2222
ctx context.Context
2323
ctxCancel context.CancelFunc
2424

25+
conf *config
26+
2527
mx sync.Mutex
2628
status network.Reachability
2729

@@ -49,6 +51,7 @@ func NewAutoRelay(bhost *basic.BasicHost, peerChan <-chan peer.AddrInfo, opts ..
4951
return nil, err
5052
}
5153
}
54+
r.conf = &conf
5255
r.relayFinder = newRelayFinder(bhost, r.peerChanOut, &conf)
5356
bhost.AddrsFactory = r.hostAddrs
5457

@@ -68,6 +71,25 @@ func (r *AutoRelay) background() {
6871
}
6972
defer subReachability.Close()
7073

74+
var peerChan <-chan peer.AddrInfo
75+
if len(r.conf.staticRelays) == 0 {
76+
peerChan = r.peerChanIn
77+
} else {
78+
pc := make(chan peer.AddrInfo)
79+
peerChan = pc
80+
r.refCount.Add(1)
81+
go func() {
82+
defer r.refCount.Done()
83+
for _, sr := range r.conf.staticRelays {
84+
select {
85+
case pc <- sr:
86+
case <-r.ctx.Done():
87+
return
88+
}
89+
}
90+
}()
91+
}
92+
7193
for {
7294
select {
7395
case <-r.ctx.Done():
@@ -89,7 +111,7 @@ func (r *AutoRelay) background() {
89111
r.mx.Lock()
90112
r.status = evt.Reachability
91113
r.mx.Unlock()
92-
case pi := <-r.peerChanIn:
114+
case pi := <-peerChan:
93115
select {
94116
case r.peerChanOut <- pi: // if there's space in the channel, great
95117
default:

p2p/host/autorelay/autorelay_test.go

+27-4
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,6 @@ func newBrokenRelay(t *testing.T, workAfter int) host.Host {
8383
require.NoError(t, err)
8484
var n int32
8585
h.SetStreamHandler(circuitv2_proto.ProtoIDv2Hop, func(str network.Stream) {
86-
t.Log("rejecting reservation")
8786
str.Reset()
8887
num := atomic.AddInt32(&n, 1)
8988
if int(num) >= workAfter {
@@ -201,12 +200,36 @@ func TestMaxBackoffs(t *testing.T) {
201200
require.NoError(t, err)
202201
defer ar.Close()
203202

204-
r1 := newBrokenRelay(t, 4)
205-
t.Cleanup(func() { r1.Close() })
206-
peerChan <- peer.AddrInfo{ID: r1.ID(), Addrs: r1.Addrs()}
203+
r := newBrokenRelay(t, 4)
204+
t.Cleanup(func() { r.Close() })
205+
peerChan <- peer.AddrInfo{ID: r.ID(), Addrs: r.Addrs()}
207206

208207
// make sure we don't add any relays yet
209208
require.Never(t, func() bool {
210209
return len(ma.FilterAddrs(h.Addrs(), isRelayAddr)) > 0
211210
}, 300*time.Millisecond, 50*time.Millisecond)
212211
}
212+
213+
func TestStaticRelays(t *testing.T) {
214+
const numRelays = 3
215+
var staticRelays []peer.AddrInfo
216+
for i := 0; i < numRelays; i++ {
217+
r := newRelay(t)
218+
t.Cleanup(func() { r.Close() })
219+
staticRelays = append(staticRelays, peer.AddrInfo{ID: r.ID(), Addrs: r.Addrs()})
220+
}
221+
222+
h := newPrivateNode(t)
223+
ar, err := autorelay.NewAutoRelay(
224+
h,
225+
nil,
226+
autorelay.WithStaticRelays(staticRelays),
227+
autorelay.WithNumRelays(1),
228+
)
229+
require.NoError(t, err)
230+
defer ar.Close()
231+
232+
require.Eventually(t, func() bool {
233+
return len(ma.FilterAddrs(h.Addrs(), isRelayAddr)) > 0
234+
}, 500*time.Millisecond, 50*time.Millisecond)
235+
}

p2p/host/autorelay/options.go

+5-6
Original file line numberDiff line numberDiff line change
@@ -57,19 +57,18 @@ func init() {
5757
}
5858

5959
type Option func(*config) error
60-
type StaticRelayOption Option
6160

62-
func WithStaticRelays(static []peer.AddrInfo) StaticRelayOption {
63-
return func(r *config) error {
64-
if len(r.staticRelays) > 0 {
61+
func WithStaticRelays(static []peer.AddrInfo) Option {
62+
return func(c *config) error {
63+
if len(c.staticRelays) > 0 {
6564
return errors.New("can't set static relays, static relays already configured")
6665
}
67-
r.staticRelays = static
66+
c.staticRelays = static
6867
return nil
6968
}
7069
}
7170

72-
func WithDefaultStaticRelays() StaticRelayOption {
71+
func WithDefaultStaticRelays() Option {
7372
return WithStaticRelays(defaultStaticRelays)
7473
}
7574

p2p/host/autorelay/relay_finder.go

+23-21
Original file line numberDiff line numberDiff line change
@@ -95,13 +95,11 @@ func newRelayFinder(host *basic.BasicHost, peerChan <-chan peer.AddrInfo, conf *
9595
}
9696

9797
func (rf *relayFinder) background(ctx context.Context) {
98-
if len(rf.conf.staticRelays) == 0 {
99-
rf.refCount.Add(1)
100-
go func() {
101-
defer rf.refCount.Done()
102-
rf.findNodes(ctx)
103-
}()
104-
}
98+
rf.refCount.Add(1)
99+
go func() {
100+
defer rf.refCount.Done()
101+
rf.findNodes(ctx)
102+
}()
105103

106104
subConnectedness, err := rf.host.EventBus().Subscribe(new(event.EvtPeerConnectednessChanged))
107105
if err != nil {
@@ -138,10 +136,8 @@ func (rf *relayFinder) background(ctx context.Context) {
138136
}
139137
rf.relayMx.Unlock()
140138
case <-rf.candidateFound:
141-
log.Debugf("candidate found")
142139
rf.handleNewCandidate(ctx)
143140
case <-bootDelayTimer.C:
144-
log.Debugf("boot delay timer")
145141
rf.handleNewCandidate(ctx)
146142
case <-rf.relayUpdated:
147143
push = true
@@ -163,7 +159,7 @@ func (rf *relayFinder) background(ctx context.Context) {
163159
}
164160

165161
// findNodes accepts nodes from the channel and tests if they support relaying.
166-
// It is run on both public and private nodes (but not when static relays are set).
162+
// It is run on both public and private nodes.
167163
// It garbage collects old entries, so that nodes doesn't overflow.
168164
// This makes sure that as soon as we need to find relay candidates, we have them available.
169165
func (rf *relayFinder) findNodes(ctx context.Context) {
@@ -189,6 +185,13 @@ func (rf *relayFinder) findNodes(ctx context.Context) {
189185
}
190186
}
191187

188+
func (rf *relayFinder) notifyNewCandidate() {
189+
select {
190+
case rf.candidateFound <- struct{}{}:
191+
default:
192+
}
193+
}
194+
192195
// handleNewNode tests if a peer supports circuit v1 or v2.
193196
// This method is only run on private nodes.
194197
// If a peer does, it is added to the candidates map.
@@ -220,13 +223,6 @@ func (rf *relayFinder) handleNewNode(ctx context.Context, pi peer.AddrInfo) {
220223
rf.notifyNewCandidate()
221224
}
222225

223-
func (rf *relayFinder) notifyNewCandidate() {
224-
select {
225-
case rf.candidateFound <- struct{}{}:
226-
default:
227-
}
228-
}
229-
230226
// tryNode checks if a peer actually supports either circuit v1 or circuit v2.
231227
// It does not modify any internal state.
232228
func (rf *relayFinder) tryNode(ctx context.Context, pi peer.AddrInfo) (supportsRelayV1 bool, err error) {
@@ -293,10 +289,16 @@ func (rf *relayFinder) handleNewCandidate(ctx context.Context) {
293289
if len(rf.relays) == rf.conf.desiredRelays {
294290
return
295291
}
296-
// During the startup phase, we don't want to connect to the first candidate that we find.
297-
// Instead, we wait until we've found at least minCandidates, and then select the best of those.
298-
// However, if that takes too long (longer than bootDelay),
299-
if len(rf.relays) == 0 && len(rf.candidates) < rf.conf.minCandidates && time.Since(rf.bootTime) < rf.conf.bootDelay {
292+
293+
if len(rf.conf.staticRelays) != 0 {
294+
// make sure we read all static relays before continuing
295+
if len(rf.peerChan) > 0 && len(rf.candidates) < rf.conf.minCandidates && time.Since(rf.bootTime) < rf.conf.bootDelay {
296+
return
297+
}
298+
} else if len(rf.relays) == 0 && len(rf.candidates) < rf.conf.minCandidates && time.Since(rf.bootTime) < rf.conf.bootDelay {
299+
// During the startup phase, we don't want to connect to the first candidate that we find.
300+
// Instead, we wait until we've found at least minCandidates, and then select the best of those.
301+
// However, if that takes too long (longer than bootDelay), we still go ahead.
300302
return
301303
}
302304

0 commit comments

Comments
 (0)