github.com/sagernet/gvisor@v0.0.0-20240428053021-e691de28565f/pkg/buffer/buffer.go (about)

     1  // Copyright 2022 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package buffer provides the implementation of a non-contiguous buffer that
    16  // is reference counted, pooled, and copy-on-write. It allows O(1) append,
    17  // and prepend operations.
    18  package buffer
    19  
    20  import (
    21  	"fmt"
    22  	"github.com/sagernet/sing/common"
    23  	"io"
    24  
    25  	"github.com/sagernet/gvisor/pkg/tcpip/checksum"
    26  )
    27  
    28  // Buffer is a non-linear buffer.
    29  //
    30  // +stateify savable
    31  type Buffer struct {
    32  	data ViewList `state:".([]byte)"`
    33  	size int64
    34  }
    35  
    36  func (b *Buffer) removeView(v *View) {
    37  	b.data.Remove(v)
    38  	v.Release()
    39  }
    40  
    41  // MakeWithData creates a new Buffer initialized with given data. This function
    42  // should be used with caution to avoid unnecessary []byte allocations. When in
    43  // doubt use NewWithView to maximize chunk reuse.
    44  func MakeWithData(b []byte) Buffer {
    45  	buf := Buffer{}
    46  	if len(b) == 0 {
    47  		return buf
    48  	}
    49  	v := NewViewWithData(b)
    50  	buf.Append(v)
    51  	return buf
    52  }
    53  
    54  // MakeWithView creates a new Buffer initialized with given view. This function
    55  // takes ownership of v.
    56  func MakeWithView(v *View) Buffer {
    57  	if v == nil {
    58  		return Buffer{}
    59  	}
    60  	b := Buffer{
    61  		size: int64(v.Size()),
    62  	}
    63  	if b.size == 0 {
    64  		v.Release()
    65  		return b
    66  	}
    67  	b.data.PushBack(v)
    68  	return b
    69  }
    70  
    71  // Release frees all resources held by b.
    72  func (b *Buffer) Release() {
    73  	for v := b.data.Front(); v != nil; v = b.data.Front() {
    74  		b.removeView(v)
    75  	}
    76  	b.size = 0
    77  }
    78  
    79  // TrimFront removes the first count bytes from the buffer.
    80  func (b *Buffer) TrimFront(count int64) {
    81  	if count >= b.size {
    82  		b.advanceRead(b.size)
    83  	} else {
    84  		b.advanceRead(count)
    85  	}
    86  }
    87  
    88  // ReadAt implements io.ReaderAt.ReadAt.
    89  func (b *Buffer) ReadAt(p []byte, offset int64) (int, error) {
    90  	var (
    91  		skipped int64
    92  		done    int64
    93  	)
    94  	for v := b.data.Front(); v != nil && done < int64(len(p)); v = v.Next() {
    95  		needToSkip := int(offset - skipped)
    96  		if sz := v.Size(); sz <= needToSkip {
    97  			skipped += int64(sz)
    98  			continue
    99  		}
   100  
   101  		// Actually read data.
   102  		n := copy(p[done:], v.AsSlice()[needToSkip:])
   103  		skipped += int64(needToSkip)
   104  		done += int64(n)
   105  	}
   106  	if int(done) < len(p) || offset+done == b.size {
   107  		return int(done), io.EOF
   108  	}
   109  	return int(done), nil
   110  }
   111  
   112  // advanceRead advances the Buffer's read index.
   113  //
   114  // Precondition: there must be sufficient bytes in the buffer.
   115  func (b *Buffer) advanceRead(count int64) {
   116  	for v := b.data.Front(); v != nil && count > 0; {
   117  		sz := int64(v.Size())
   118  		if sz > count {
   119  			// There is still data for reading.
   120  			v.TrimFront(int(count))
   121  			b.size -= count
   122  			count = 0
   123  			return
   124  		}
   125  
   126  		// Consume the whole view.
   127  		oldView := v
   128  		v = v.Next() // Iterate.
   129  		b.removeView(oldView)
   130  
   131  		// Update counts.
   132  		count -= sz
   133  		b.size -= sz
   134  	}
   135  	if count > 0 {
   136  		panic(fmt.Sprintf("advanceRead still has %d bytes remaining", count))
   137  	}
   138  }
   139  
   140  // Truncate truncates the Buffer to the given length.
   141  //
   142  // This will not grow the Buffer, only shrink it. If a length is passed that is
   143  // greater than the current size of the Buffer, then nothing will happen.
   144  //
   145  // Precondition: length must be >= 0.
   146  func (b *Buffer) Truncate(length int64) {
   147  	if length < 0 {
   148  		panic("negative length provided")
   149  	}
   150  	if length >= b.size {
   151  		return // Nothing to do.
   152  	}
   153  	for v := b.data.Back(); v != nil && b.size > length; v = b.data.Back() {
   154  		sz := int64(v.Size())
   155  		if after := b.size - sz; after < length {
   156  			// Truncate the buffer locally.
   157  			left := (length - after)
   158  			v.write = v.read + int(left)
   159  			b.size = length
   160  			break
   161  		}
   162  
   163  		// Drop the buffer completely; see above.
   164  		b.removeView(v)
   165  		b.size -= sz
   166  	}
   167  }
   168  
   169  // GrowTo grows the given Buffer to the number of bytes, which will be appended.
   170  // If zero is true, all these bytes will be zero. If zero is false, then this is
   171  // the caller's responsibility.
   172  //
   173  // Precondition: length must be >= 0.
   174  func (b *Buffer) GrowTo(length int64, zero bool) {
   175  	if length < 0 {
   176  		panic("negative length provided")
   177  	}
   178  	for b.size < length {
   179  		v := b.data.Back()
   180  
   181  		// Is there some space in the last buffer?
   182  		if v.Full() {
   183  			v = NewView(int(length - b.size))
   184  			b.data.PushBack(v)
   185  		}
   186  
   187  		// Write up to length bytes.
   188  		sz := v.AvailableSize()
   189  		if int64(sz) > length-b.size {
   190  			sz = int(length - b.size)
   191  		}
   192  
   193  		// Zero the written section.
   194  		if zero {
   195  			common.ClearArray(v.chunk.data[v.write : v.write+sz])
   196  		}
   197  
   198  		// Advance the index.
   199  		v.Grow(sz)
   200  		b.size += int64(sz)
   201  	}
   202  }
   203  
   204  // Prepend prepends the given data. Prepend takes ownership of src.
   205  func (b *Buffer) Prepend(src *View) error {
   206  	if src == nil {
   207  		return nil
   208  	}
   209  	if src.Size() == 0 {
   210  		src.Release()
   211  		return nil
   212  	}
   213  	// If the first buffer does not have room just prepend the view.
   214  	v := b.data.Front()
   215  	if v == nil || v.read == 0 {
   216  		b.prependOwned(src)
   217  		return nil
   218  	}
   219  
   220  	// If there's room at the front and we won't incur a copy by writing to this
   221  	// view, fill in the extra room first.
   222  	if !v.sharesChunk() {
   223  		avail := v.read
   224  		vStart := 0
   225  		srcStart := src.Size() - avail
   226  		if avail > src.Size() {
   227  			vStart = avail - src.Size()
   228  			srcStart = 0
   229  		}
   230  		// Save the write index and restore it after.
   231  		old := v.write
   232  		v.read = vStart
   233  		n, err := v.WriteAt(src.AsSlice()[srcStart:], 0)
   234  		if err != nil {
   235  			return fmt.Errorf("could not write to view during append: %w", err)
   236  		}
   237  		b.size += int64(n)
   238  		v.write = old
   239  		src.write = srcStart
   240  
   241  		// If there's no more to be written, then we're done.
   242  		if src.Size() == 0 {
   243  			src.Release()
   244  			return nil
   245  		}
   246  	}
   247  
   248  	// Otherwise, just prepend the view.
   249  	b.prependOwned(src)
   250  	return nil
   251  }
   252  
   253  // Append appends the given data. Append takes ownership of src.
   254  func (b *Buffer) Append(src *View) error {
   255  	if src == nil {
   256  		return nil
   257  	}
   258  	if src.Size() == 0 {
   259  		src.Release()
   260  		return nil
   261  	}
   262  	// If the last buffer is full, just append the view.
   263  	v := b.data.Back()
   264  	if v.Full() {
   265  		b.appendOwned(src)
   266  		return nil
   267  	}
   268  
   269  	// If a write won't incur a copy, then fill the back of the existing last
   270  	// chunk.
   271  	if !v.sharesChunk() {
   272  		writeSz := src.Size()
   273  		if src.Size() > v.AvailableSize() {
   274  			writeSz = v.AvailableSize()
   275  		}
   276  		done, err := v.Write(src.AsSlice()[:writeSz])
   277  		if err != nil {
   278  			return fmt.Errorf("could not write to view during append: %w", err)
   279  		}
   280  		src.TrimFront(done)
   281  		b.size += int64(done)
   282  		if src.Size() == 0 {
   283  			src.Release()
   284  			return nil
   285  		}
   286  	}
   287  
   288  	// If there is still data left just append the src.
   289  	b.appendOwned(src)
   290  	return nil
   291  }
   292  
   293  func (b *Buffer) appendOwned(v *View) {
   294  	b.data.PushBack(v)
   295  	b.size += int64(v.Size())
   296  }
   297  
   298  func (b *Buffer) prependOwned(v *View) {
   299  	b.data.PushFront(v)
   300  	b.size += int64(v.Size())
   301  }
   302  
   303  // PullUp makes the specified range contiguous and returns the backing memory.
   304  func (b *Buffer) PullUp(offset, length int) (View, bool) {
   305  	if length == 0 {
   306  		return View{}, true
   307  	}
   308  	tgt := Range{begin: offset, end: offset + length}
   309  	if tgt.Intersect(Range{end: int(b.size)}).Len() != length {
   310  		return View{}, false
   311  	}
   312  
   313  	curr := Range{}
   314  	v := b.data.Front()
   315  	for ; v != nil; v = v.Next() {
   316  		origLen := v.Size()
   317  		curr.end = curr.begin + origLen
   318  
   319  		if x := curr.Intersect(tgt); x.Len() == tgt.Len() {
   320  			// buf covers the whole requested target range.
   321  			sub := x.Offset(-curr.begin)
   322  			// Don't increment the reference count of the underlying chunk. Views
   323  			// returned by PullUp are explicitly unowned and read only
   324  			new := View{
   325  				read:  v.read + sub.begin,
   326  				write: v.read + sub.end,
   327  				chunk: v.chunk,
   328  			}
   329  			return new, true
   330  		} else if x.Len() > 0 {
   331  			// buf is pointing at the starting buffer we want to merge.
   332  			break
   333  		}
   334  
   335  		curr.begin += origLen
   336  	}
   337  
   338  	// Calculate the total merged length.
   339  	totLen := 0
   340  	for n := v; n != nil; n = n.Next() {
   341  		totLen += n.Size()
   342  		if curr.begin+totLen >= tgt.end {
   343  			break
   344  		}
   345  	}
   346  
   347  	// Merge the buffers.
   348  	merged := NewViewSize(totLen)
   349  	off := 0
   350  	for n := v; n != nil && off < totLen; {
   351  		merged.WriteAt(n.AsSlice(), off)
   352  		off += n.Size()
   353  
   354  		// Remove buffers except for the first one, which will be reused.
   355  		if n == v {
   356  			n = n.Next()
   357  		} else {
   358  			old := n
   359  			n = n.Next()
   360  			b.removeView(old)
   361  		}
   362  	}
   363  	// Make data the first buffer.
   364  	b.data.InsertBefore(v, merged)
   365  	b.removeView(v)
   366  
   367  	r := tgt.Offset(-curr.begin)
   368  	pulled := View{
   369  		read:  r.begin,
   370  		write: r.end,
   371  		chunk: merged.chunk,
   372  	}
   373  	return pulled, true
   374  }
   375  
   376  // Flatten returns a flattened copy of this data.
   377  //
   378  // This method should not be used in any performance-sensitive paths. It may
   379  // allocate a fresh byte slice sufficiently large to contain all the data in
   380  // the buffer. This is principally for debugging.
   381  //
   382  // N.B. Tee data still belongs to this Buffer, as if there is a single buffer
   383  // present, then it will be returned directly. This should be used for
   384  // temporary use only, and a reference to the given slice should not be held.
   385  func (b *Buffer) Flatten() []byte {
   386  	if v := b.data.Front(); v == nil {
   387  		return nil // No data at all.
   388  	}
   389  	data := make([]byte, 0, b.size) // Need to flatten.
   390  	for v := b.data.Front(); v != nil; v = v.Next() {
   391  		// Copy to the allocated slice.
   392  		data = append(data, v.AsSlice()...)
   393  	}
   394  	return data
   395  }
   396  
   397  // Size indicates the total amount of data available in this Buffer.
   398  func (b *Buffer) Size() int64 {
   399  	return b.size
   400  }
   401  
   402  // AsViewList returns the ViewList backing b. Users may not save or modify the
   403  // ViewList returned.
   404  func (b *Buffer) AsViewList() ViewList {
   405  	return b.data
   406  }
   407  
   408  // Clone creates a copy-on-write clone of b. The underlying chunks are shared
   409  // until they are written to.
   410  func (b *Buffer) Clone() Buffer {
   411  	other := Buffer{
   412  		size: b.size,
   413  	}
   414  	for v := b.data.Front(); v != nil; v = v.Next() {
   415  		newView := v.Clone()
   416  		other.data.PushBack(newView)
   417  	}
   418  	return other
   419  }
   420  
   421  // DeepClone creates a deep clone of b, copying data such that no bytes are
   422  // shared with any other Buffers.
   423  func (b *Buffer) DeepClone() Buffer {
   424  	newBuf := Buffer{}
   425  	buf := b.Clone()
   426  	reader := buf.AsBufferReader()
   427  	newBuf.WriteFromReader(&reader, b.size)
   428  	return newBuf
   429  }
   430  
   431  // Apply applies the given function across all valid data.
   432  func (b *Buffer) Apply(fn func(*View)) {
   433  	for v := b.data.Front(); v != nil; v = v.Next() {
   434  		d := v.Clone()
   435  		fn(d)
   436  		d.Release()
   437  	}
   438  }
   439  
   440  // SubApply applies fn to a given range of data in b. Any part of the range
   441  // outside of b is ignored.
   442  func (b *Buffer) SubApply(offset, length int, fn func(*View)) {
   443  	for v := b.data.Front(); length > 0 && v != nil; v = v.Next() {
   444  		if offset >= v.Size() {
   445  			offset -= v.Size()
   446  			continue
   447  		}
   448  		d := v.Clone()
   449  		if offset > 0 {
   450  			d.TrimFront(offset)
   451  			offset = 0
   452  		}
   453  		if length < d.Size() {
   454  			d.write = d.read + length
   455  		}
   456  		fn(d)
   457  		length -= d.Size()
   458  		d.Release()
   459  	}
   460  }
   461  
   462  // Checksum calculates a checksum over the buffer's payload starting at offset.
   463  func (b *Buffer) Checksum(offset int) uint16 {
   464  	if offset >= int(b.size) {
   465  		return 0
   466  	}
   467  	var v *View
   468  	for v = b.data.Front(); v != nil && offset >= v.Size(); v = v.Next() {
   469  		offset -= v.Size()
   470  	}
   471  
   472  	var cs checksum.Checksumer
   473  	cs.Add(v.AsSlice()[offset:])
   474  	for v = v.Next(); v != nil; v = v.Next() {
   475  		cs.Add(v.AsSlice())
   476  	}
   477  	return cs.Checksum()
   478  }
   479  
   480  // Merge merges the provided Buffer with this one.
   481  //
   482  // The other Buffer will be appended to v, and other will be empty after this
   483  // operation completes.
   484  func (b *Buffer) Merge(other *Buffer) {
   485  	b.data.PushBackList(&other.data)
   486  	other.data = ViewList{}
   487  
   488  	// Adjust sizes.
   489  	b.size += other.size
   490  	other.size = 0
   491  }
   492  
   493  // WriteFromReader writes to the buffer from an io.Reader. A maximum read size
   494  // of MaxChunkSize is enforced to prevent allocating views from the heap.
   495  func (b *Buffer) WriteFromReader(r io.Reader, count int64) (int64, error) {
   496  	return b.WriteFromReaderAndLimitedReader(r, count, nil)
   497  }
   498  
   499  // WriteFromReaderAndLimitedReader is the same as WriteFromReader, but
   500  // optimized to avoid allocations if a LimitedReader is passed in.
   501  //
   502  // This function clobbers the values of lr.
   503  func (b *Buffer) WriteFromReaderAndLimitedReader(r io.Reader, count int64, lr *io.LimitedReader) (int64, error) {
   504  	if lr == nil {
   505  		lr = &io.LimitedReader{}
   506  	}
   507  
   508  	var done int64
   509  	for done < count {
   510  		vsize := count - done
   511  		if vsize > MaxChunkSize {
   512  			vsize = MaxChunkSize
   513  		}
   514  		v := NewView(int(vsize))
   515  		lr.R = r
   516  		lr.N = vsize
   517  		n, err := io.Copy(v, lr)
   518  		b.Append(v)
   519  		done += n
   520  		if err == io.EOF {
   521  			break
   522  		}
   523  		if err != nil {
   524  			return done, err
   525  		}
   526  	}
   527  	return done, nil
   528  }
   529  
   530  // ReadToWriter reads from the buffer into an io.Writer.
   531  //
   532  // N.B. This does not consume the bytes read. TrimFront should
   533  // be called appropriately after this call in order to do so.
   534  func (b *Buffer) ReadToWriter(w io.Writer, count int64) (int64, error) {
   535  	bytesLeft := int(count)
   536  	for v := b.data.Front(); v != nil && bytesLeft > 0; v = v.Next() {
   537  		view := v.Clone()
   538  		if view.Size() > bytesLeft {
   539  			view.CapLength(bytesLeft)
   540  		}
   541  		n, err := io.Copy(w, view)
   542  		bytesLeft -= int(n)
   543  		view.Release()
   544  		if err != nil {
   545  			return count - int64(bytesLeft), err
   546  		}
   547  	}
   548  	return count - int64(bytesLeft), nil
   549  }
   550  
   551  // read implements the io.Reader interface. This method is used by BufferReader
   552  // to consume its underlying buffer. To perform io operations on buffers
   553  // directly, use ReadToWriter or WriteToReader.
   554  func (b *Buffer) read(p []byte) (int, error) {
   555  	if len(p) == 0 {
   556  		return 0, nil
   557  	}
   558  	if b.Size() == 0 {
   559  		return 0, io.EOF
   560  	}
   561  	done := 0
   562  	v := b.data.Front()
   563  	for v != nil && done < len(p) {
   564  		n, err := v.Read(p[done:])
   565  		done += n
   566  		next := v.Next()
   567  		if v.Size() == 0 {
   568  			b.removeView(v)
   569  		}
   570  		b.size -= int64(n)
   571  		if err != nil && err != io.EOF {
   572  			return done, err
   573  		}
   574  		v = next
   575  	}
   576  	return done, nil
   577  }
   578  
   579  // readByte implements the io.ByteReader interface. This method is used by
   580  // BufferReader to consume its underlying buffer. To perform io operations on
   581  // buffers directly, use ReadToWriter or WriteToReader.
   582  func (b *Buffer) readByte() (byte, error) {
   583  	if b.Size() == 0 {
   584  		return 0, io.EOF
   585  	}
   586  	v := b.data.Front()
   587  	bt := v.AsSlice()[0]
   588  	b.TrimFront(1)
   589  	return bt, nil
   590  }
   591  
   592  // AsBufferReader returns the Buffer as a BufferReader capable of io methods.
   593  // The new BufferReader takes ownership of b.
   594  func (b *Buffer) AsBufferReader() BufferReader {
   595  	return BufferReader{b}
   596  }
   597  
   598  // BufferReader implements io methods on Buffer. Users must call Close()
   599  // when finished with the buffer to free the underlying memory.
   600  type BufferReader struct {
   601  	b *Buffer
   602  }
   603  
   604  // Read implements the io.Reader interface.
   605  func (br *BufferReader) Read(p []byte) (int, error) {
   606  	return br.b.read(p)
   607  }
   608  
   609  // ReadByte implements the io.ByteReader interface.
   610  func (br *BufferReader) ReadByte() (byte, error) {
   611  	return br.b.readByte()
   612  }
   613  
   614  // Close implements the io.Closer interface.
   615  func (br *BufferReader) Close() {
   616  	br.b.Release()
   617  }
   618  
   619  // Len returns the number of bytes in the unread portion of the buffer.
   620  func (br *BufferReader) Len() int {
   621  	return int(br.b.Size())
   622  }
   623  
   624  // Range specifies a range of buffer.
   625  type Range struct {
   626  	begin int
   627  	end   int
   628  }
   629  
   630  // Intersect returns the intersection of x and y.
   631  func (x Range) Intersect(y Range) Range {
   632  	if x.begin < y.begin {
   633  		x.begin = y.begin
   634  	}
   635  	if x.end > y.end {
   636  		x.end = y.end
   637  	}
   638  	if x.begin >= x.end {
   639  		return Range{}
   640  	}
   641  	return x
   642  }
   643  
   644  // Offset returns x offset by off.
   645  func (x Range) Offset(off int) Range {
   646  	x.begin += off
   647  	x.end += off
   648  	return x
   649  }
   650  
   651  // Len returns the length of x.
   652  func (x Range) Len() int {
   653  	l := x.end - x.begin
   654  	if l < 0 {
   655  		l = 0
   656  	}
   657  	return l
   658  }