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