github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/socket/unix/transport/queue.go (about)

     1  // Copyright 2018 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 transport
    16  
    17  import (
    18  	"github.com/SagerNet/gvisor/pkg/context"
    19  	"github.com/SagerNet/gvisor/pkg/sync"
    20  	"github.com/SagerNet/gvisor/pkg/syserr"
    21  	"github.com/SagerNet/gvisor/pkg/tcpip"
    22  	"github.com/SagerNet/gvisor/pkg/tcpip/buffer"
    23  	"github.com/SagerNet/gvisor/pkg/waiter"
    24  )
    25  
    26  // queue is a buffer queue.
    27  //
    28  // +stateify savable
    29  type queue struct {
    30  	queueRefs
    31  
    32  	ReaderQueue *waiter.Queue
    33  	WriterQueue *waiter.Queue
    34  
    35  	mu       sync.Mutex `state:"nosave"`
    36  	closed   bool
    37  	unread   bool
    38  	used     int64
    39  	limit    int64
    40  	dataList messageList
    41  }
    42  
    43  // Close closes q for reading and writing. It is immediately not writable and
    44  // will become unreadable when no more data is pending.
    45  //
    46  // Both the read and write queues must be notified after closing:
    47  // q.ReaderQueue.Notify(waiter.ReadableEvents)
    48  // q.WriterQueue.Notify(waiter.WritableEvents)
    49  func (q *queue) Close() {
    50  	q.mu.Lock()
    51  	q.closed = true
    52  	q.mu.Unlock()
    53  }
    54  
    55  // Reset empties the queue and Releases all of the Entries.
    56  //
    57  // Both the read and write queues must be notified after resetting:
    58  // q.ReaderQueue.Notify(waiter.ReadableEvents)
    59  // q.WriterQueue.Notify(waiter.WritableEvents)
    60  func (q *queue) Reset(ctx context.Context) {
    61  	q.mu.Lock()
    62  	for cur := q.dataList.Front(); cur != nil; cur = cur.Next() {
    63  		cur.Release(ctx)
    64  	}
    65  	q.dataList.Reset()
    66  	q.used = 0
    67  	q.mu.Unlock()
    68  }
    69  
    70  // DecRef implements RefCounter.DecRef.
    71  func (q *queue) DecRef(ctx context.Context) {
    72  	q.queueRefs.DecRef(func() {
    73  		// We don't need to notify after resetting because no one cares about
    74  		// this queue after all references have been dropped.
    75  		q.Reset(ctx)
    76  	})
    77  }
    78  
    79  // IsReadable determines if q is currently readable.
    80  func (q *queue) IsReadable() bool {
    81  	q.mu.Lock()
    82  	defer q.mu.Unlock()
    83  
    84  	return q.closed || q.dataList.Front() != nil
    85  }
    86  
    87  // bufWritable returns true if there is space for writing.
    88  //
    89  // N.B. Linux only considers a unix socket "writable" if >75% of the buffer is
    90  // free.
    91  //
    92  // See net/unix/af_unix.c:unix_writeable.
    93  func (q *queue) bufWritable() bool {
    94  	return 4*q.used < q.limit
    95  }
    96  
    97  // IsWritable determines if q is currently writable.
    98  func (q *queue) IsWritable() bool {
    99  	q.mu.Lock()
   100  	defer q.mu.Unlock()
   101  
   102  	return q.closed || q.bufWritable()
   103  }
   104  
   105  // Enqueue adds an entry to the data queue if room is available.
   106  //
   107  // If discardEmpty is true and there are zero bytes of data, the packet is
   108  // dropped.
   109  //
   110  // If truncate is true, Enqueue may truncate the message before enqueuing it.
   111  // Otherwise, the entire message must fit. If l is less than the size of data,
   112  // err indicates why.
   113  //
   114  // If notify is true, ReaderQueue.Notify must be called:
   115  // q.ReaderQueue.Notify(waiter.ReadableEvents)
   116  func (q *queue) Enqueue(ctx context.Context, data [][]byte, c ControlMessages, from tcpip.FullAddress, discardEmpty bool, truncate bool) (l int64, notify bool, err *syserr.Error) {
   117  	q.mu.Lock()
   118  
   119  	if q.closed {
   120  		q.mu.Unlock()
   121  		return 0, false, syserr.ErrClosedForSend
   122  	}
   123  
   124  	for _, d := range data {
   125  		l += int64(len(d))
   126  	}
   127  	if discardEmpty && l == 0 {
   128  		q.mu.Unlock()
   129  		c.Release(ctx)
   130  		return 0, false, nil
   131  	}
   132  
   133  	free := q.limit - q.used
   134  
   135  	if l > free && truncate {
   136  		if free == 0 {
   137  			// Message can't fit right now.
   138  			q.mu.Unlock()
   139  			return 0, false, syserr.ErrWouldBlock
   140  		}
   141  
   142  		l = free
   143  		err = syserr.ErrWouldBlock
   144  	}
   145  
   146  	if l > q.limit {
   147  		// Message is too big to ever fit.
   148  		q.mu.Unlock()
   149  		return 0, false, syserr.ErrMessageTooLong
   150  	}
   151  
   152  	if l > free {
   153  		// Message can't fit right now, and could not be truncated.
   154  		q.mu.Unlock()
   155  		return 0, false, syserr.ErrWouldBlock
   156  	}
   157  
   158  	// Aggregate l bytes of data. This will truncate the data if l is less than
   159  	// the total bytes held in data.
   160  	v := make([]byte, l)
   161  	for i, b := 0, v; i < len(data) && len(b) > 0; i++ {
   162  		n := copy(b, data[i])
   163  		b = b[n:]
   164  	}
   165  
   166  	notify = q.dataList.Front() == nil
   167  	q.used += l
   168  	q.dataList.PushBack(&message{
   169  		Data:    buffer.View(v),
   170  		Control: c,
   171  		Address: from,
   172  	})
   173  
   174  	q.mu.Unlock()
   175  
   176  	return l, notify, err
   177  }
   178  
   179  // Dequeue removes the first entry in the data queue, if one exists.
   180  //
   181  // If notify is true, WriterQueue.Notify must be called:
   182  // q.WriterQueue.Notify(waiter.WritableEvents)
   183  func (q *queue) Dequeue() (e *message, notify bool, err *syserr.Error) {
   184  	q.mu.Lock()
   185  
   186  	if q.dataList.Front() == nil {
   187  		err := syserr.ErrWouldBlock
   188  		if q.closed {
   189  			err = syserr.ErrClosedForReceive
   190  			if q.unread {
   191  				err = syserr.ErrConnectionReset
   192  			}
   193  		}
   194  		q.mu.Unlock()
   195  
   196  		return nil, false, err
   197  	}
   198  
   199  	notify = !q.bufWritable()
   200  
   201  	e = q.dataList.Front()
   202  	q.dataList.Remove(e)
   203  	q.used -= e.Length()
   204  
   205  	notify = notify && q.bufWritable()
   206  
   207  	q.mu.Unlock()
   208  
   209  	return e, notify, nil
   210  }
   211  
   212  // Peek returns the first entry in the data queue, if one exists.
   213  func (q *queue) Peek() (*message, *syserr.Error) {
   214  	q.mu.Lock()
   215  	defer q.mu.Unlock()
   216  
   217  	if q.dataList.Front() == nil {
   218  		err := syserr.ErrWouldBlock
   219  		if q.closed {
   220  			if err = syserr.ErrClosedForReceive; q.unread {
   221  				err = syserr.ErrConnectionReset
   222  			}
   223  		}
   224  		return nil, err
   225  	}
   226  
   227  	return q.dataList.Front().Peek(), nil
   228  }
   229  
   230  // QueuedSize returns the number of bytes currently in the queue, that is, the
   231  // number of readable bytes.
   232  func (q *queue) QueuedSize() int64 {
   233  	q.mu.Lock()
   234  	defer q.mu.Unlock()
   235  	return q.used
   236  }
   237  
   238  // MaxQueueSize returns the maximum number of bytes storable in the queue.
   239  func (q *queue) MaxQueueSize() int64 {
   240  	q.mu.Lock()
   241  	defer q.mu.Unlock()
   242  	return q.limit
   243  }
   244  
   245  // SetMaxQueueSize sets the maximum number of bytes storable in the queue.
   246  func (q *queue) SetMaxQueueSize(v int64) {
   247  	q.mu.Lock()
   248  	defer q.mu.Unlock()
   249  	q.limit = v
   250  }
   251  
   252  // CloseUnread sets flag to indicate that the peer is closed (not shutdown)
   253  // with unread data. So if read on this queue shall return ECONNRESET error.
   254  func (q *queue) CloseUnread() {
   255  	q.mu.Lock()
   256  	defer q.mu.Unlock()
   257  	q.unread = true
   258  }