Skip to content

Commit be4974c

Browse files
authored
Merge pull request #184 from SiaFoundation/christopher/fix-timeout-v1-scan
Prevent scanning functions from hanging on some v1 hosts
2 parents 403fc57 + 2fd2cb0 commit be4974c

File tree

3 files changed

+63
-28
lines changed

3 files changed

+63
-28
lines changed

cmd/explored/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ var cfg = config.Config{
4646
},
4747
Scanner: config.Scanner{
4848
Threads: 10,
49-
Timeout: 30 * time.Second,
49+
Timeout: 1 * time.Minute,
5050
MaxLastScan: 1 * time.Hour,
5151
MinLastAnnouncement: 365 * 24 * time.Hour,
5252
},

explorer/scan.go

Lines changed: 61 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"time"
99

1010
crhpv2 "go.sia.tech/core/rhp/v2"
11+
crhpv3 "go.sia.tech/core/rhp/v3"
1112
"go.sia.tech/core/types"
1213
crhpv4 "go.sia.tech/coreutils/rhp/v4"
1314
"go.sia.tech/coreutils/rhp/v4/siamux"
@@ -53,53 +54,91 @@ func (e *Explorer) waitForSync() error {
5354
return nil
5455
}
5556

56-
func (e *Explorer) scanV1Host(locator geoip.Locator, host UnscannedHost) (HostScan, error) {
57-
ctx, cancel := context.WithTimeout(e.ctx, e.scanCfg.Timeout)
58-
defer cancel()
57+
func rhpv2Settings(ctx context.Context, publicKey types.PublicKey, netAddress string) (crhpv2.HostSettings, error) {
58+
conn, err := (&net.Dialer{}).DialContext(ctx, "tcp", netAddress)
59+
if err != nil {
60+
return crhpv2.HostSettings{}, fmt.Errorf("failed to connect to host: %w", err)
61+
}
62+
defer conn.Close()
63+
64+
// default timeout if context doesn't have one
65+
deadline := time.Now().Add(30 * time.Second)
66+
if dl, ok := ctx.Deadline(); ok && !dl.IsZero() {
67+
deadline = dl
68+
}
69+
if err := conn.SetDeadline(deadline); err != nil {
70+
return crhpv2.HostSettings{}, fmt.Errorf("failed to set deadline: %w", err)
71+
}
5972

60-
dialer := (&net.Dialer{})
73+
t, err := crhpv2.NewRenterTransport(conn, publicKey)
74+
if err != nil {
75+
return crhpv2.HostSettings{}, fmt.Errorf("failed to establish rhpv2 transport: %w", err)
76+
}
77+
defer t.Close()
6178

62-
conn, err := dialer.DialContext(ctx, "tcp", host.NetAddress)
79+
settings, err := rhpv2.RPCSettings(ctx, t)
6380
if err != nil {
64-
return HostScan{}, fmt.Errorf("scanHost: failed to connect to host: %w", err)
81+
return crhpv2.HostSettings{}, fmt.Errorf("failed to call settings RPC: %w", err)
82+
}
83+
return settings, nil
84+
}
85+
86+
func rhpv3PriceTable(ctx context.Context, publicKey types.PublicKey, netAddress string) (priceTable crhpv3.HostPriceTable, err error) {
87+
conn, err := (&net.Dialer{}).DialContext(ctx, "tcp", netAddress)
88+
if err != nil {
89+
return crhpv3.HostPriceTable{}, fmt.Errorf("failed to connect to siamux port: %w", err)
6590
}
6691
defer conn.Close()
6792

68-
transport, err := crhpv2.NewRenterTransport(conn, host.PublicKey)
93+
// default timeout if context doesn't have one
94+
deadline := time.Now().Add(30 * time.Second)
95+
if dl, ok := ctx.Deadline(); ok && !dl.IsZero() {
96+
deadline = dl
97+
}
98+
if err := conn.SetDeadline(deadline); err != nil {
99+
return crhpv3.HostPriceTable{}, fmt.Errorf("failed to set deadline: %w", err)
100+
}
101+
102+
v3Session, err := rhpv3.NewSession(ctx, conn, publicKey, nil, nil)
69103
if err != nil {
70-
return HostScan{}, fmt.Errorf("scanHost: failed to establish v2 transport: %w", err)
104+
return crhpv3.HostPriceTable{}, fmt.Errorf("failed to establish rhpv3 transport: %w", err)
71105
}
72-
defer transport.Close()
106+
defer v3Session.Close()
73107

74-
settings, err := rhpv2.RPCSettings(ctx, transport)
108+
table, err := v3Session.ScanPriceTable()
75109
if err != nil {
76-
return HostScan{}, fmt.Errorf("scanHost: failed to get host settings: %w", err)
110+
return crhpv3.HostPriceTable{}, fmt.Errorf("failed to scan price table: %w", err)
77111
}
112+
return table, nil
113+
}
78114

79-
hostIP, _, err := net.SplitHostPort(settings.NetAddress)
115+
func (e *Explorer) scanV1Host(locator geoip.Locator, host UnscannedHost) (HostScan, error) {
116+
ctx, cancel := context.WithTimeout(e.ctx, e.scanCfg.Timeout)
117+
defer cancel()
118+
119+
settings, err := rhpv2Settings(ctx, host.PublicKey, host.NetAddress)
80120
if err != nil {
81-
return HostScan{}, fmt.Errorf("scanHost: failed to parse net address: %w", err)
121+
return HostScan{}, fmt.Errorf("scanV1Host: failed to get host settings: %w", err)
82122
}
83123

84-
resolved, err := net.ResolveIPAddr("ip", hostIP)
124+
hostIP, _, err := net.SplitHostPort(settings.NetAddress)
85125
if err != nil {
86-
return HostScan{}, fmt.Errorf("scanHost: failed to resolve host address: %w", err)
126+
return HostScan{}, fmt.Errorf("scanV1Host: failed to parse net address: %w", err)
87127
}
88128

89-
location, err := locator.Locate(resolved)
129+
table, err := rhpv3PriceTable(ctx, host.PublicKey, net.JoinHostPort(hostIP, settings.SiaMuxPort))
90130
if err != nil {
91-
e.log.Debug("Failed to resolve IP geolocation, not setting country code", zap.String("addr", host.NetAddress))
131+
return HostScan{}, fmt.Errorf("scanV1Host: failed to get price table: %w", err)
92132
}
93133

94-
v3Addr := net.JoinHostPort(hostIP, settings.SiaMuxPort)
95-
v3Session, err := rhpv3.NewSession(ctx, host.PublicKey, v3Addr, e.cm, nil)
134+
resolved, err := net.ResolveIPAddr("ip", hostIP)
96135
if err != nil {
97-
return HostScan{}, fmt.Errorf("scanHost: failed to establish v3 transport: %w", err)
136+
return HostScan{}, fmt.Errorf("scanV1Host: failed to resolve host address: %w", err)
98137
}
99138

100-
table, err := v3Session.ScanPriceTable()
139+
location, err := locator.Locate(resolved)
101140
if err != nil {
102-
return HostScan{}, fmt.Errorf("scanHost: failed to scan price table: %w", err)
141+
e.log.Debug("Failed to resolve IP geolocation, not setting country code", zap.String("addr", host.NetAddress))
103142
}
104143

105144
return HostScan{

internal/rhp/v3/rhp.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -799,11 +799,7 @@ func AccountPayment(account rhp3.Account, privateKey types.PrivateKey) PaymentMe
799799
}
800800

801801
// NewSession creates a new session with a host
802-
func NewSession(ctx context.Context, hostKey types.PublicKey, hostAddr string, cm ChainManager, w Wallet) (*Session, error) {
803-
conn, err := (&net.Dialer{}).DialContext(ctx, "tcp", hostAddr)
804-
if err != nil {
805-
return nil, fmt.Errorf("failed to dial host: %w", err)
806-
}
802+
func NewSession(ctx context.Context, conn net.Conn, hostKey types.PublicKey, cm ChainManager, w Wallet) (*Session, error) {
807803
t, err := rhp3.NewRenterTransport(conn, hostKey)
808804
if err != nil {
809805
conn.Close()

0 commit comments

Comments
 (0)