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  }