XTLS Vision: Defer Splice handoff until write completes (#5737)

Fixes https://github.com/XTLS/Xray-core/issues/4878
This commit is contained in:
HeXis-YS
2026-03-22 10:48:33 -07:00
committed by GitHub
parent 67a71adad1
commit f926ee4aa0

View File

@@ -322,6 +322,7 @@ func NewVisionWriter(writer buf.Writer, trafficState *TrafficState, isUplink boo
func (w *VisionWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
var isPadding *bool
var switchToDirectCopy *bool
var spliceReadyInbound *session.Inbound
if w.isUplink {
isPadding = &w.trafficState.Outbound.IsPadding
switchToDirectCopy = &w.trafficState.Outbound.UplinkWriterDirectCopy
@@ -333,7 +334,7 @@ func (w *VisionWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
if *switchToDirectCopy {
if inbound := session.InboundFromContext(w.ctx); inbound != nil {
if !w.isUplink && inbound.CanSpliceCopy == 2 {
inbound.CanSpliceCopy = 1
spliceReadyInbound = inbound
}
// if w.isUplink && w.ob != nil && w.ob.CanSpliceCopy == 2 { // TODO: enable uplink splice
// w.ob.CanSpliceCopy = 1
@@ -355,8 +356,7 @@ func (w *VisionWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
if *isPadding {
if len(mb) == 1 && mb[0] == nil {
mb[0] = XtlsPadding(nil, CommandPaddingContinue, &w.writeOnceUserUUID, true, w.ctx, w.testseed) // we do a long padding to hide vless header
return w.Writer.WriteMultiBuffer(mb)
}
} else {
isComplete := IsCompleteRecord(mb)
mb = ReshapeMultiBuffer(w.ctx, mb)
longPadding := w.trafficState.IsTLS
@@ -391,7 +391,16 @@ func (w *VisionWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
mb[i] = XtlsPadding(b, command, &w.writeOnceUserUUID, longPadding, w.ctx, w.testseed)
}
}
return w.Writer.WriteMultiBuffer(mb)
}
if err := w.Writer.WriteMultiBuffer(mb); err != nil {
return err
}
if spliceReadyInbound != nil && spliceReadyInbound.CanSpliceCopy == 2 {
// Enable splice only after this write has completed to avoid racing
// concurrent direct writes to the same TCP connection.
spliceReadyInbound.CanSpliceCopy = 1
}
return nil
}
// IsCompleteRecord Is complete tls data record
@@ -744,7 +753,6 @@ func CopyRawConnIfExist(ctx context.Context, readerConn net.Conn, writerConn net
errors.LogDebug(ctx, "CopyRawConn splice")
statWriter, _ := writer.(*dispatcher.SizeStatWriter)
//runtime.Gosched() // necessary
time.Sleep(time.Millisecond) // without this, there will be a rare ssl error for freedom splice
timer.SetTimeout(24 * time.Hour) // prevent leak, just in case
if inTimer != nil {
inTimer.SetTimeout(24 * time.Hour)