github.com/puellanivis/breton@v0.2.16/lib/files/socketfiles/dgram.go (about) 1 package socketfiles 2 3 import ( 4 "context" 5 "io" 6 "os" 7 "sync" 8 "time" 9 10 "github.com/puellanivis/breton/lib/files/wrapper" 11 ) 12 13 type datagramWriter struct { 14 *wrapper.Info 15 16 mu sync.Mutex 17 closed chan struct{} 18 19 noerrs bool 20 21 buf []byte 22 off int 23 24 sock *socket 25 } 26 27 func (w *datagramWriter) IgnoreErrors(state bool) bool { 28 w.mu.Lock() 29 defer w.mu.Unlock() 30 31 prev := w.noerrs 32 33 w.noerrs = state 34 35 return prev 36 } 37 38 func (w *datagramWriter) err(err error) error { 39 if w.noerrs && err != io.ErrShortWrite { 40 return nil 41 } 42 43 return err 44 } 45 46 func (w *datagramWriter) SetPacketSize(size int) int { 47 w.mu.Lock() 48 defer w.mu.Unlock() 49 50 prev := len(w.buf) 51 52 switch { 53 case size <= 0: 54 w.buf = nil 55 56 case size <= len(w.buf): 57 w.buf = w.buf[:size] 58 59 default: 60 w.buf = append(w.buf, make([]byte, size-len(w.buf))...) 61 } 62 63 if w.off > len(w.buf) { 64 w.off = len(w.buf) 65 } 66 67 w.sock.packetSize = len(w.buf) 68 w.sock.updateDelay(len(w.buf)) 69 70 // Update filename. 71 w.Info.SetNameFromURL(w.sock.uri()) 72 73 return prev 74 } 75 76 func (w *datagramWriter) SetBitrate(bitrate int) int { 77 w.mu.Lock() 78 defer w.mu.Unlock() 79 80 prev := w.sock.setBitrate(bitrate, len(w.buf)) 81 82 // Update filename. 83 w.Info.SetNameFromURL(w.sock.uri()) 84 85 return prev 86 } 87 88 func (w *datagramWriter) Sync() error { 89 w.mu.Lock() 90 defer w.mu.Unlock() 91 92 _, err := w.sync() 93 return w.err(err) 94 } 95 96 func (w *datagramWriter) sync() (n int, err error) { 97 if w.off < 1 { 98 return 0, nil 99 } 100 101 // zero out the end of the buffer. 102 b := w.buf[w.off:] 103 for i := range b { 104 b[i] = 0 105 } 106 107 w.off = 0 108 return w.write(w.buf) 109 } 110 111 func (w *datagramWriter) write(b []byte) (n int, err error) { 112 // We should have already prescaled the delay, so scale=1 here. 113 w.sock.throttle(1) 114 115 n, err = w.sock.conn.Write(b) 116 if n != len(b) { 117 if (w.noerrs && n > 0) || err == nil { 118 err = io.ErrShortWrite 119 } 120 } 121 122 return n, err 123 } 124 125 func (w *datagramWriter) Close() error { 126 w.mu.Lock() 127 defer w.mu.Unlock() 128 129 select { 130 case <-w.closed: 131 default: 132 close(w.closed) 133 } 134 135 _, err := w.sync() 136 137 if err2 := w.sock.conn.Close(); err == nil { 138 err = err2 139 } 140 141 return err 142 } 143 144 func (w *datagramWriter) Write(b []byte) (n int, err error) { 145 w.mu.Lock() 146 defer w.mu.Unlock() 147 148 if len(w.buf) < 1 { 149 w.sock.throttle(len(b)) 150 151 n, err = w.sock.conn.Write(b) 152 return n, w.err(err) 153 } 154 155 if w.off > 0 { 156 n = copy(w.buf[w.off:], b) 157 w.off += n 158 159 if w.off < len(w.buf) { 160 // The full length of b was copied into buffer, 161 // and we haven’t filled the buffer. 162 // So, we’re done. 163 return n, nil 164 } 165 166 _, err2 := w.sync() 167 if err = w.err(err2); err != nil { 168 return n, err 169 } 170 171 b = b[n:] 172 } 173 174 sz := len(w.buf) 175 for len(b) >= sz { 176 n2, err2 := w.write(b[:sz]) 177 n += n2 178 179 if err = w.err(err2); err != nil { 180 return n, err 181 } 182 183 // skip the whole packet size, even if n2 < sz 184 b = b[sz:] 185 } 186 187 if len(b) > 0 { 188 w.off = copy(w.buf, b) 189 n += w.off 190 } 191 192 return n, nil 193 } 194 195 func newDatagramWriter(ctx context.Context, sock *socket) *datagramWriter { 196 w := &datagramWriter{ 197 Info: wrapper.NewInfo(sock.uri(), 0, time.Now()), 198 sock: sock, 199 200 closed: make(chan struct{}), 201 } 202 203 w.SetPacketSize(sock.packetSize) 204 205 go func() { 206 select { 207 case <-w.closed: 208 case <-ctx.Done(): 209 w.Close() 210 } 211 }() 212 213 return w 214 } 215 216 type datagramReader struct { 217 *wrapper.Info 218 sock *socket 219 220 mu sync.Mutex 221 222 buf []byte 223 cnt int 224 read int 225 } 226 227 // defaultMaxPacketSize is the maximum size of an IPv4 payload, and non-Jumbogram IPv6 payload. 228 // This is an overly safe default. 229 const defaultMaxPacketSize = 64 * 1024 230 231 func (r *datagramReader) SetPacketSize(size int) int { 232 r.mu.Lock() 233 defer r.mu.Unlock() 234 235 prev := len(r.buf) 236 237 if size <= 0 { 238 size = defaultMaxPacketSize 239 } 240 241 switch { 242 case size <= len(r.buf): 243 r.buf = r.buf[:size] 244 245 default: 246 r.buf = append(r.buf, make([]byte, size-len(r.buf))...) 247 } 248 249 if r.read > len(r.buf) { 250 r.read = len(r.buf) 251 } 252 if r.cnt > len(r.buf) { 253 r.cnt = len(r.buf) 254 } 255 256 r.sock.maxPacketSize = len(r.buf) 257 258 // Update filename. 259 r.Info.SetNameFromURL(r.sock.uri()) 260 261 return prev 262 } 263 264 func (r *datagramReader) Seek(offset int64, whence int) (int64, error) { 265 return 0, os.ErrInvalid 266 } 267 268 func (r *datagramReader) Close() error { 269 // Do not attempt to acquire the Mutex. 270 // Doing so will deadlock with a concurrent blocking Read(), 271 // and prevent read cancellation. 272 return r.sock.conn.Close() 273 } 274 275 // ReadPacket reads a single packet from a data source. 276 // It is up to the caller to ensure that the given buffer is sufficient to read a full packet. 277 func (r *datagramReader) ReadPacket(b []byte) (n int, err error) { 278 return r.sock.conn.Read(b) 279 } 280 281 // Read performs reads from a datagram source into a continuous stream. 282 // 283 // It does this by ensuring that each read on the datagram socket is to a sufficiently sized buffer. 284 // If the given buffer is too small, it will read to an internal buffer with length set from max_pkt_size, 285 // and following reads will read from that buffer until it is empty. 286 // 287 // Properly, a datagram source should know it is reading packets, 288 // and ensure each given buffer is large enough to read the maximum packet size expected. 289 // Unfortunately, some APIs in Go can expect Read()s to operate as a continuous stream instead of packets, 290 // and that a short read buffer, will just leave the rest of the unread data ready to read, not dropped on the floor. 291 func (r *datagramReader) Read(b []byte) (n int, err error) { 292 r.mu.Lock() 293 defer r.mu.Unlock() 294 295 if r.read >= r.cnt { 296 // Nothing is buffered. 297 298 if len(b) >= len(r.buf) { 299 // The read can be done directly. 300 return r.ReadPacket(b) 301 } 302 303 // Given buffer is too small, use internal buffer. 304 r.read = 0 // reset read start buffer. 305 r.cnt, err = r.ReadPacket(r.buf) 306 } 307 308 n = copy(b, r.buf[r.read:r.cnt]) 309 r.read += n 310 return n, err 311 } 312 313 func newDatagramReader(ctx context.Context, sock *socket) *datagramReader { 314 r := &datagramReader{ 315 Info: wrapper.NewInfo(sock.uri(), 0, time.Now()), 316 sock: sock, 317 } 318 319 r.SetPacketSize(sock.maxPacketSize) 320 321 return r 322 }