diff --git a/go.mod b/go.mod index 2e5653500f..df1765bf6b 100644 --- a/go.mod +++ b/go.mod @@ -40,7 +40,7 @@ require ( github.com/pterm/pterm v0.12.83 github.com/robert-nix/ansihtml v1.0.1 github.com/sirupsen/logrus v1.9.4 - github.com/skycoin/dmsg v1.3.29-0.20260407140521-d58307854c12 + github.com/skycoin/dmsg v1.3.29-0.20260407222909-e26b29822520 github.com/skycoin/skycoin v0.28.6-0.20260401142608-a27afbb0b33b github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8 github.com/spf13/cobra v1.10.2 diff --git a/go.sum b/go.sum index b6b255973c..2168059b54 100644 --- a/go.sum +++ b/go.sum @@ -755,8 +755,8 @@ github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrf github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w= github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g= -github.com/skycoin/dmsg v1.3.29-0.20260407140521-d58307854c12 h1:yy2w8GJ0UtXmB5rn2zWEt6QK2ECJZl7E8mGUFF4hhSY= -github.com/skycoin/dmsg v1.3.29-0.20260407140521-d58307854c12/go.mod h1:uh8Nr+E8B3yVt7ciKUk4GdsZax7VoL/L3i1EagXbzjk= +github.com/skycoin/dmsg v1.3.29-0.20260407222909-e26b29822520 h1:FyjIBUteO/w4d4AHOtBfhCacSoW1j5PIkWcJs6II2F4= +github.com/skycoin/dmsg v1.3.29-0.20260407222909-e26b29822520/go.mod h1:uh8Nr+E8B3yVt7ciKUk4GdsZax7VoL/L3i1EagXbzjk= github.com/skycoin/encodertest v0.0.0-20190217072920-14c2e31898b9 h1:DElGw1Fhj4amuW1KM5q8Xowosb3RiOQce0lDJw0Qv0Y= github.com/skycoin/encodertest v0.0.0-20190217072920-14c2e31898b9/go.mod h1:OQz8NXVJUWEw7PWYASZ/1BIw5GXgVMTGvrCGDlZa9+k= github.com/skycoin/noise v0.0.0-20180327030543-2492fe189ae6 h1:1Nc5EBY6pjfw1kwW0duwyG+7WliWz5u9kgk1h5MnLuA= diff --git a/pkg/visor/api_dmsg.go b/pkg/visor/api_dmsg.go index 57a82c16c2..e59d6235b4 100644 --- a/pkg/visor/api_dmsg.go +++ b/pkg/visor/api_dmsg.go @@ -83,7 +83,7 @@ func (v *Visor) DialDmsgPingViaServer(pk cipher.PubKey, serverPK cipher.PubKey) return fmt.Errorf("no session with dmsg server %s", serverPK) } - stream, err := session.DialStream(dmsg.Addr{PK: pk, Port: skyenv.DmsgPingPort}) + stream, err := session.DialStream(context.Background(), dmsg.Addr{PK: pk, Port: skyenv.DmsgPingPort}) if err != nil { return fmt.Errorf("failed to dial dmsg ping via server %s: %w", serverPK, err) } diff --git a/static/skywire-manager-src/package-lock.json b/static/skywire-manager-src/package-lock.json index 7938e33527..38a33882c1 100644 --- a/static/skywire-manager-src/package-lock.json +++ b/static/skywire-manager-src/package-lock.json @@ -3468,6 +3468,43 @@ "node": ">=14.17.0" } }, + "node_modules/@emnapi/core": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.2.tgz", + "integrity": "sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.2.tgz", + "integrity": "sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@es-joy/jsdoccomment": { "version": "0.84.0", "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.84.0.tgz", @@ -6359,6 +6396,18 @@ "node": ">=20.0.0" } }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "dev": true, + "license": "MIT", + "peer": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, "node_modules/@rolldown/binding-android-arm64": { "version": "1.0.0-rc.4", "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.4.tgz", diff --git a/vendor/github.com/skycoin/dmsg/pkg/dmsg/client_dial.go b/vendor/github.com/skycoin/dmsg/pkg/dmsg/client_dial.go index 88c437b366..5d54c57b21 100644 --- a/vendor/github.com/skycoin/dmsg/pkg/dmsg/client_dial.go +++ b/vendor/github.com/skycoin/dmsg/pkg/dmsg/client_dial.go @@ -40,7 +40,7 @@ func (ce *Client) DialStream(ctx context.Context, addr Addr) (*Stream, error) { // Phase 0: Try cached route first (server that last successfully reached this destination). if cachedSrvPK, ok := ce.getCachedRoute(addr.PK); ok { if dSes, ok := ce.clientSession(ce.porter, cachedSrvPK); ok { - stream, err := dSes.DialStream(addr) + stream, err := dSes.DialStream(ctx, addr) if err != nil { ce.log.WithError(err).WithField("server", cachedSrvPK). Debug("DialStream failed via cached route, evicting") @@ -58,7 +58,7 @@ func (ce *Client) DialStream(ctx context.Context, addr Addr) (*Stream, error) { // Sort by latency so the lowest-latency server is tried first. delegatedSessions := ce.sortedDelegatedSessions(entry.Client.DelegatedServers) for _, dSes := range delegatedSessions { - stream, err := dSes.DialStream(addr) + stream, err := dSes.DialStream(ctx, addr) if err != nil { ce.log.WithError(err).WithField("server", dSes.RemotePK()). Debug("DialStream failed via existing session, trying next server") @@ -73,7 +73,7 @@ func (ce *Client) DialStream(ctx context.Context, addr Addr) (*Stream, error) { // Sorted by latency. meshSessions := ce.sortedMeshSessions(entry.Client.DelegatedServers) for _, ses := range meshSessions { - stream, err := ses.DialStream(addr) + stream, err := ses.DialStream(ctx, addr) if err != nil { ce.log.WithError(err).WithField("server", ses.RemotePK()). Debug("DialStream failed via mesh, trying next server") @@ -89,7 +89,7 @@ func (ce *Client) DialStream(ctx context.Context, addr Addr) (*Stream, error) { if err != nil { continue } - stream, err := dSes.DialStream(addr) + stream, err := dSes.DialStream(ctx, addr) if err != nil { ce.log.WithError(err).WithField("server", srvPK). Debug("DialStream failed via new session, trying next server") diff --git a/vendor/github.com/skycoin/dmsg/pkg/dmsg/client_session.go b/vendor/github.com/skycoin/dmsg/pkg/dmsg/client_session.go index bfe8f24d91..7e961f75df 100644 --- a/vendor/github.com/skycoin/dmsg/pkg/dmsg/client_session.go +++ b/vendor/github.com/skycoin/dmsg/pkg/dmsg/client_session.go @@ -2,6 +2,7 @@ package dmsg import ( + "context" "errors" "net" "time" @@ -28,7 +29,9 @@ func makeClientSession(entity *EntityCommon, porter *netutil.Porter, conn net.Co } // DialStream attempts to dial a stream to a remote client via the dmsg server that this session is connected to. -func (cs *ClientSession) DialStream(dst Addr) (dStr *Stream, err error) { +// The context is used to cancel the dial if the caller's deadline expires — this prevents ephemeral port +// leaks when many dials are attempted and the caller gives up before the handshake completes. +func (cs *ClientSession) DialStream(ctx context.Context, dst Addr) (dStr *Stream, err error) { log := cs.log. WithField("func", "ClientSession.DialStream"). WithField("dst_addr", dst) @@ -37,7 +40,7 @@ func (cs *ClientSession) DialStream(dst Addr) (dStr *Stream, err error) { return nil, err } - // Close stream on failure. + // Close stream on failure — this frees the reserved ephemeral port. defer func() { if err != nil { log.WithError(err). @@ -46,6 +49,23 @@ func (cs *ClientSession) DialStream(dst Addr) (dStr *Stream, err error) { } }() + // If the caller's context is canceled, close the stream to interrupt + // any blocked read/write and free the ephemeral port immediately. + ctxDone := make(chan struct{}) + go func() { + select { + case <-ctx.Done(): + dStr.Close() //nolint:errcheck,gosec + case <-ctxDone: + } + }() + defer close(ctxDone) + + // Check context before starting. + if ctx.Err() != nil { + return nil, ctx.Err() + } + // Prepare deadline. if err = dStr.SetDeadline(time.Now().Add(HandshakeTimeout)); err != nil { return nil, err diff --git a/vendor/modules.txt b/vendor/modules.txt index 8a289cf9be..f910067ea0 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -772,7 +772,7 @@ github.com/shopspring/decimal ## explicit; go 1.17 github.com/sirupsen/logrus github.com/sirupsen/logrus/hooks/syslog -# github.com/skycoin/dmsg v1.3.29-0.20260407140521-d58307854c12 +# github.com/skycoin/dmsg v1.3.29-0.20260407222909-e26b29822520 ## explicit; go 1.26.1 github.com/skycoin/dmsg/cmd/conf/commands github.com/skycoin/dmsg/cmd/dial/commands