e791ba47e2
Breaking Change: moves Connector, ConnectorPool, parseTunnelID from tunnel.go into dedicated connector.go and id.go. Bug Fixes: - dialer.go: clear stale retry err so SD fallback is not masked (nil err from pool.Get() left previous iteration's error live) - connect.go: check WriteTo errors in both mux and non-mux paths - eprelay.go: use fresh relay.Response for features sent over mux (previously reused same resp struct after resp.WriteTo(muxConn)) Refactor: - entrypoint.go: split ~790 lines into 6 files (ephttp, eptls, eprelay, epwebsocket, eplistener, entrypointsvc), moved to dedicated package - handler.go: moved initEntrypoints/createEntrypointService to entrypointsvc.go - tunnel.go: moved Connector/ConnectorPool/parseTunnelID to connector.go and id.go - connect.go: moved entrypoint-originated handleConnect to eprelay.go (handler-side handleConnect kept in connect.go) Tests (48 new, 88 total): - id_test.go: parseTunnelID variants (empty, UUID, private '$', invalid) - tunnel_test.go: Tunnel lifecycle (AddConnector, GetConnector weighted/closed filtering, CloseOnIdle, clean), Connector (NewConnector nil-opts, GetConn nil/closed session, Close, IsClosed), ConnectorPool (Add/Get/Close, idle cleanup, concurrency) - dialer_test.go: SD error paths (sd.Get error, empty address) - handler_test.go: observeStats (nil observer, cancelled context loop), initEntrypoints (no entrypoints configured) - helpers_test.go: testLogger, fakeConn for handler tests - eprelay_test.go: handleConnect ingress/dial/SD round-trip
80 lines
1.3 KiB
Go
80 lines
1.3 KiB
Go
package tunnel
|
|
|
|
import (
|
|
"context"
|
|
"net"
|
|
"time"
|
|
|
|
"github.com/go-gost/core/logger"
|
|
"github.com/go-gost/core/sd"
|
|
)
|
|
|
|
type Dialer struct {
|
|
node string
|
|
pool *ConnectorPool
|
|
sd sd.SD
|
|
retry int
|
|
timeout time.Duration
|
|
log logger.Logger
|
|
}
|
|
|
|
func (d *Dialer) Dial(ctx context.Context, network string, tid string) (conn net.Conn, node string, cid string, err error) {
|
|
retry := d.retry
|
|
if retry <= 0 {
|
|
retry = 1
|
|
}
|
|
|
|
for i := 0; i < retry; i++ {
|
|
c := d.pool.Get(network, tid)
|
|
if c == nil {
|
|
err = nil // clear stale err so SD fallback is not masked
|
|
break
|
|
}
|
|
|
|
conn, err = c.GetConn()
|
|
if err != nil {
|
|
d.log.Error(err)
|
|
continue
|
|
}
|
|
node = d.node
|
|
cid = c.id.String()
|
|
|
|
break
|
|
}
|
|
if conn != nil || err != nil {
|
|
return
|
|
}
|
|
|
|
if d.sd == nil {
|
|
err = ErrTunnelNotAvailable
|
|
return
|
|
}
|
|
|
|
ss, err := d.sd.Get(ctx, tid)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
var service *sd.Service
|
|
for _, s := range ss {
|
|
d.log.Debugf("%+v", s)
|
|
if s.Node != d.node && s.Network == network {
|
|
service = s
|
|
break
|
|
}
|
|
}
|
|
if service == nil || service.Address == "" {
|
|
err = ErrTunnelNotAvailable
|
|
return
|
|
}
|
|
|
|
node = service.Node
|
|
cid = service.ID
|
|
|
|
dialer := net.Dialer{
|
|
Timeout: d.timeout,
|
|
}
|
|
conn, err = dialer.DialContext(ctx, "tcp", service.Address)
|
|
return
|
|
}
|