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 }