diff --git a/common/buf/multi.go b/common/buf/multi.go index 1a63418..2d74ab5 100644 --- a/common/buf/multi.go +++ b/common/buf/multi.go @@ -16,6 +16,14 @@ func ToSliceMulti(buffers []*Buffer) [][]byte { }) } +func CopyMulti(toBuffer []byte, buffers []*Buffer) int { + var n int + for _, buffer := range buffers { + n += copy(toBuffer[n:], buffer.Bytes()) + } + return n +} + func ReleaseMulti(buffers []*Buffer) { for _, buffer := range buffers { buffer.Release() diff --git a/common/bufio/chunk.go b/common/bufio/chunk.go index 81db6cc..9c60f80 100644 --- a/common/bufio/chunk.go +++ b/common/bufio/chunk.go @@ -49,11 +49,29 @@ func (c *ChunkReader) Read(p []byte) (n int, err error) { c.cache.FullReset() err = c.upstream.ReadBuffer(c.cache) if err != nil { + c.cache.Release() + c.cache = nil return } return c.cache.Read(p) } +func (c *ChunkReader) ReadChunk() (*buf.Buffer, error) { + if c.cache == nil { + c.cache = buf.NewSize(c.maxChunkSize) + } else if !c.cache.IsEmpty() { + return c.cache, nil + } + c.cache.FullReset() + err := c.upstream.ReadBuffer(c.cache) + if err != nil { + c.cache.Release() + c.cache = nil + return nil, err + } + return c.cache, nil +} + func (c *ChunkReader) MTU() int { return c.maxChunkSize } diff --git a/common/bufio/vectorised.go b/common/bufio/vectorised.go index d3979ae..47444f4 100644 --- a/common/bufio/vectorised.go +++ b/common/bufio/vectorised.go @@ -3,7 +3,6 @@ package bufio import ( "io" "net" - "sync" "syscall" "github.com/sagernet/sing/common" @@ -16,7 +15,7 @@ func NewVectorisedWriter(writer io.Writer) N.VectorisedWriter { if vectorisedWriter, ok := CreateVectorisedWriter(writer); ok { return vectorisedWriter } - return &SerialVectorisedWriter{upstream: writer} + return &BufferedVectorisedWriter{upstream: writer} } func CreateVectorisedWriter(writer any) (N.VectorisedWriter, bool) { @@ -57,26 +56,30 @@ func CreateVectorisedPacketWriter(writer any) (N.VectorisedPacketWriter, bool) { return nil, false } -var _ N.VectorisedWriter = (*SerialVectorisedWriter)(nil) +var _ N.VectorisedWriter = (*BufferedVectorisedWriter)(nil) -type SerialVectorisedWriter struct { +type BufferedVectorisedWriter struct { upstream io.Writer - access sync.Mutex } -func (w *SerialVectorisedWriter) WriteVectorised(buffers []*buf.Buffer) error { - w.access.Lock() - defer w.access.Unlock() - for _, buffer := range buffers { - _, err := w.upstream.Write(buffer.Bytes()) - if err != nil { - return err - } +func (w *BufferedVectorisedWriter) WriteVectorised(buffers []*buf.Buffer) error { + defer buf.ReleaseMulti(buffers) + bufferLen := buf.LenMulti(buffers) + var bufferBytes []byte + if bufferLen > 65535 { + bufferBytes = make([]byte, bufferLen) + } else { + _buffer := buf.StackNewSize(bufferLen) + defer common.KeepAlive(_buffer) + buffer := common.Dup(_buffer) + defer buffer.Release() + bufferBytes = buffer.FreeBytes() } - return nil + buf.CopyMulti(bufferBytes, buffers) + return common.Error(w.upstream.Write(bufferBytes)) } -func (w *SerialVectorisedWriter) Upstream() any { +func (w *BufferedVectorisedWriter) Upstream() any { return w.upstream } diff --git a/go.sum b/go.sum index c309d01..ba21016 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,2 @@ -golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18= -golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=