diff --git a/transport/vless/vision/conn.go b/transport/vless/vision/conn.go index fd9f787b..fd6df56c 100644 --- a/transport/vless/vision/conn.go +++ b/transport/vless/vision/conn.go @@ -36,6 +36,7 @@ type Conn struct { enableXTLS bool cipher uint16 remainingServerHello uint16 + readRemainingBuffer *buf.Buffer readRemainingContent int readRemainingPadding int readProcess bool @@ -56,23 +57,46 @@ func (vc *Conn) Read(b []byte) (int, error) { } func (vc *Conn) ReadBuffer(buffer *buf.Buffer) error { - if vc.readRemainingContent > 0 { - toRead := buffer.FreeBytes() - if vc.readRemainingContent < buffer.FreeLen() { - toRead = toRead[:vc.readRemainingContent] + if vc.readRemainingBuffer != nil { + _, err := buffer.ReadOnceFrom(vc.readRemainingBuffer) + if vc.readRemainingBuffer.IsEmpty() { + vc.readRemainingBuffer.Release() + vc.readRemainingBuffer = nil } - n, err := vc.ExtendedReader.Read(toRead) - buffer.Truncate(n) + return err + } + if vc.readRemainingContent > 0 { + readSize := xrayBufSize // at least read xrayBufSize + if buffer.FreeLen() > readSize { // input buffer larger than xrayBufSize, read as much as possible + readSize = buffer.FreeLen() + } + if readSize > vc.readRemainingContent { // don't read out of bounds + readSize = vc.readRemainingContent + } + + readBuffer := buffer + if buffer.FreeLen() < readSize { + readBuffer = buf.NewSize(readSize) + vc.readRemainingBuffer = readBuffer + } + n, err := vc.ExtendedReader.Read(readBuffer.FreeBytes()[:readSize]) + readBuffer.Truncate(n) vc.readRemainingContent -= n - vc.FilterTLS(toRead) + vc.FilterTLS(readBuffer.Bytes()) + if vc.readRemainingBuffer != nil { + innerErr := vc.ReadBuffer(buffer) // back to top but not losing err + if err != nil { + err = innerErr + } + } return err } if vc.readRemainingPadding > 0 { - _, err := io.CopyN(io.Discard, vc.ExtendedReader, int64(vc.readRemainingPadding)) + n, err := io.CopyN(io.Discard, vc.ExtendedReader, int64(vc.readRemainingPadding)) if err != nil { return err } - vc.readRemainingPadding = 0 + vc.readRemainingPadding -= int(n) } if vc.readProcess { switch vc.readLastCommand { @@ -228,6 +252,10 @@ func (vc *Conn) NeedHandshake() bool { return vc.writeOnceUserUUID != nil } +func (vc *Conn) NeedAdditionalReadDeadline() bool { + return true +} + func (vc *Conn) Upstream() any { if vc.writeDirect || vc.readLastCommand == commandPaddingDirect { diff --git a/transport/vless/vision/padding.go b/transport/vless/vision/padding.go index 38609552..157dfee8 100644 --- a/transport/vless/vision/padding.go +++ b/transport/vless/vision/padding.go @@ -44,8 +44,9 @@ func ApplyPadding(buffer *buf.Buffer, command byte, userUUID *[]byte, paddingTLS log.Debugln("XTLS Vision write padding: command=%d, payloadLen=%d, paddingLen=%d", command, contentLen, paddingLen) } +const xrayBufSize = 8192 + func (vc *Conn) ReshapeBuffer(buffer *buf.Buffer) []*buf.Buffer { - const xrayBufSize = 8192 if buffer.Len() <= xrayBufSize-PaddingHeaderLen { return []*buf.Buffer{buffer} }