This commit is contained in:
2026-08-16 19:02:48 -03:00
parent 96fe00eb2b
commit c8e3011f21
31 changed files with 3457 additions and 351 deletions
+55 -6
View File
@@ -19,6 +19,7 @@ import (
"sync/atomic"
"time"
"dragontcp/internal/cover"
"dragontcp/internal/protocol"
)
@@ -57,6 +58,24 @@ type Options struct {
pollDelay time.Duration
txnTimeout time.Duration
tcpBuffer int
headerMask byte
coverProfile cover.Profile
}
// WithHeaderMask returns a copy using one fixed frame-magic profile. The mask
// is selected during startup discovery and remains unchanged for normal data.
func (o Options) WithHeaderMask(mask byte) Options {
o.headerMask = mask
o.coverProfile = cover.Profile{}
return o
}
// WithCoverProfile returns a copy using a fixed startup-selected preface,
// padding length, and frame mask.
func (o Options) WithCoverProfile(profile cover.Profile) Options {
o.coverProfile = profile
o.headerMask = profile.HeaderMask
return o
}
func wireToken(token string) string {
@@ -219,17 +238,21 @@ type txnLane struct {
tcpBuffer int
reconnectEvery int
timeout time.Duration
headerMask byte
coverProfile cover.Profile
conn net.Conn
count int
closed bool
}
func newTxnLane(serverAddr string, tcpBuffer, reconnectEvery int, timeout time.Duration) *txnLane {
func newTxnLane(serverAddr string, tcpBuffer, reconnectEvery int, timeout time.Duration, headerMask byte, coverProfile cover.Profile) *txnLane {
return &txnLane{
serverAddr: serverAddr,
tcpBuffer: tcpBuffer,
reconnectEvery: reconnectEvery,
timeout: timeout,
headerMask: headerMask,
coverProfile: coverProfile,
}
}
@@ -262,6 +285,10 @@ func (l *txnLane) ensureConn() error {
if err != nil {
return err
}
if err := cover.WritePreface(conn, l.coverProfile); err != nil {
_ = conn.Close()
return err
}
protocol.TuneTCP(conn)
protocol.TuneTCPBuffer(conn, l.tcpBuffer)
l.conn = conn
@@ -285,12 +312,12 @@ func (l *txnLane) Do(payload []byte) ([]byte, error) {
_ = l.conn.SetDeadline(time.Now().Add(timeout))
requestID := requestCounter.Add(1)
if err := protocol.WriteRequestFrame(l.conn, requestID, payload); err != nil {
if err := protocol.WriteRequestFrameProfile(l.conn, requestID, payload, l.headerMask); err != nil {
l.closeLocked()
return nil, err
}
responseID, response, err := protocol.ReadResponseFrame(l.conn)
responseID, response, err := protocol.ReadResponseFrameProfile(l.conn, l.headerMask)
if err != nil {
l.closeLocked()
return nil, err
@@ -324,6 +351,28 @@ func doControl(lane *txnLane, payload []byte) ([]byte, error) {
return nil, lastErr
}
// ProbeProfile performs one small authenticated transaction using the selected
// frame-magic mask. It does not create a target session.
func ProbeProfile(serverAddr, token string, opts Options) bool {
timeout := opts.txnTimeout
if timeout <= 0 || timeout > 2*time.Second {
timeout = 2 * time.Second
}
lane := newTxnLane(serverAddr, opts.tcpBuffer, 1, timeout, opts.headerMask, opts.coverProfile)
defer lane.Close()
resp, err := lane.Do([]byte("CPROBE " + wireToken(token)))
if err != nil {
return false
}
if string(resp) == "PROBEOK" {
return true
}
// Servers predating profile discovery do not know CPROBE, but receiving a
// correctly framed error still proves that the legacy mask-zero header
// survived. The subsequent end-to-end probe remains authoritative.
return opts.headerMask == 0 && strings.HasPrefix(string(resp), "ERR expected TUNNEL")
}
type chunkResult struct {
seq uint64
data []byte
@@ -425,7 +474,7 @@ func Open(serverAddr, token, targetHost string, targetPort int, opts Options) (n
c.upSizer = newAdaptiveSizer("upload", opts)
c.downSizer = newAdaptiveSizer("download", opts)
c.pushLane = newTxnLane(serverAddr, opts.tcpBuffer, opts.reconnectEvery, opts.txnTimeout)
c.pushLane = newTxnLane(serverAddr, opts.tcpBuffer, opts.reconnectEvery, opts.txnTimeout, opts.headerMask, opts.coverProfile)
openPayload := []byte(fmt.Sprintf(
"COPEN %s %s %s %d",
@@ -464,7 +513,7 @@ func Open(serverAddr, token, targetHost string, targetPort int, opts Options) (n
c.pullLanes = make([]*txnLane, opts.pollers)
for i := 0; i < opts.pollers; i++ {
lane := newTxnLane(serverAddr, opts.tcpBuffer, opts.reconnectEvery, opts.txnTimeout)
lane := newTxnLane(serverAddr, opts.tcpBuffer, opts.reconnectEvery, opts.txnTimeout, opts.headerMask, opts.coverProfile)
c.pullLanes[i] = lane
c.workers.Add(1)
go c.pullWorker(lane)
@@ -762,7 +811,7 @@ func (c *chunkConn) Close() error {
c.once.Do(func() {
c.cancel()
lane := newTxnLane(c.serverAddr, c.opts.tcpBuffer, 1, c.opts.txnTimeout)
lane := newTxnLane(c.serverAddr, c.opts.tcpBuffer, 1, c.opts.txnTimeout, c.opts.headerMask, c.opts.coverProfile)
_, _ = doControl(lane, []byte(fmt.Sprintf("CCLOSE %s %s", wireToken(c.token), c.sid)))
lane.Close()