Cloak/internal/multiplex/datagramBufferedPipe.go

168 lines
3.5 KiB
Go
Raw Normal View History

2019-08-14 09:04:27 +00:00
// This is base on https://github.com/golang/go/blob/0436b162397018c45068b47ca1b5924a3eafdee0/src/net/net_fake.go#L173
package multiplex
import (
2020-04-12 10:18:41 +00:00
"bytes"
2019-08-14 09:04:27 +00:00
"io"
"sync"
2020-04-09 17:56:17 +00:00
"time"
2019-08-14 09:04:27 +00:00
)
// datagramBufferedPipe is the same as streamBufferedPipe with the exception that it's message-oriented,
2019-08-20 21:43:04 +00:00
// instead of byte-oriented. The integrity of datagrams written into this buffer is preserved.
// it won't get chopped up into individual bytes
type datagramBufferedPipe struct {
2020-12-26 16:34:25 +00:00
pLens []int
2020-04-12 10:18:41 +00:00
buf *bytes.Buffer
closed bool
2020-04-09 17:56:17 +00:00
rwCond *sync.Cond
wtTimeout time.Duration
2020-04-09 17:56:17 +00:00
rDeadline time.Time
2020-12-05 23:47:52 +00:00
timeoutTimer *time.Timer
2019-08-14 09:04:27 +00:00
}
func NewDatagramBufferedPipe() *datagramBufferedPipe {
d := &datagramBufferedPipe{
2019-08-14 09:04:27 +00:00
rwCond: sync.NewCond(&sync.Mutex{}),
2020-12-26 16:34:25 +00:00
buf: new(bytes.Buffer),
2019-08-14 09:04:27 +00:00
}
return d
}
func (d *datagramBufferedPipe) Read(target []byte) (int, error) {
2019-08-14 09:04:27 +00:00
d.rwCond.L.Lock()
defer d.rwCond.L.Unlock()
for {
if d.closed && len(d.pLens) == 0 {
2019-08-14 09:04:27 +00:00
return 0, io.EOF
}
hasRDeadline := !d.rDeadline.IsZero()
if hasRDeadline {
if time.Until(d.rDeadline) <= 0 {
2020-04-09 17:56:17 +00:00
return 0, ErrTimeout
}
}
2020-04-12 10:18:41 +00:00
if len(d.pLens) > 0 {
2019-08-14 09:04:27 +00:00
break
}
if hasRDeadline {
d.broadcastAfter(time.Until(d.rDeadline))
}
2019-08-14 09:04:27 +00:00
d.rwCond.Wait()
}
2020-04-12 10:18:41 +00:00
dataLen := d.pLens[0]
if len(target) < dataLen {
2020-04-08 13:59:09 +00:00
return 0, io.ErrShortBuffer
}
2020-04-12 10:18:41 +00:00
d.pLens = d.pLens[1:]
d.buf.Read(target[:dataLen])
2019-08-14 09:04:27 +00:00
// err will always be nil because we have already verified that buf.Len() != 0
d.rwCond.Broadcast()
2020-04-12 10:18:41 +00:00
return dataLen, nil
2019-08-14 09:04:27 +00:00
}
func (d *datagramBufferedPipe) WriteTo(w io.Writer) (n int64, err error) {
2020-04-12 10:33:11 +00:00
d.rwCond.L.Lock()
defer d.rwCond.L.Unlock()
for {
if d.closed && len(d.pLens) == 0 {
2020-04-12 10:33:11 +00:00
return 0, io.EOF
}
hasRDeadline := !d.rDeadline.IsZero()
if hasRDeadline {
if time.Until(d.rDeadline) <= 0 {
2020-04-12 10:33:11 +00:00
return 0, ErrTimeout
}
}
2020-04-12 10:33:11 +00:00
if len(d.pLens) > 0 {
var dataLen int
dataLen, d.pLens = d.pLens[0], d.pLens[1:]
written, er := w.Write(d.buf.Next(dataLen))
n += int64(written)
if er != nil {
d.rwCond.Broadcast()
return n, er
}
d.rwCond.Broadcast()
} else {
if d.wtTimeout == 0 {
if hasRDeadline {
d.broadcastAfter(time.Until(d.rDeadline))
}
} else {
2020-12-05 23:47:52 +00:00
d.rDeadline = time.Now().Add(d.wtTimeout)
d.broadcastAfter(d.wtTimeout)
}
d.rwCond.Wait()
2020-04-12 10:33:11 +00:00
}
}
}
func (d *datagramBufferedPipe) Write(f *Frame) (toBeClosed bool, err error) {
2019-08-14 09:04:27 +00:00
d.rwCond.L.Lock()
defer d.rwCond.L.Unlock()
for {
if d.closed {
return true, io.ErrClosedPipe
2019-08-14 09:04:27 +00:00
}
if d.buf.Len() <= recvBufferSizeLimit {
2019-08-14 09:04:27 +00:00
// if d.buf gets too large, write() will panic. We don't want this to happen
break
}
d.rwCond.Wait()
}
2020-10-21 15:42:24 +00:00
if f.Closing != closingNothing {
d.closed = true
d.rwCond.Broadcast()
return true, nil
}
2020-04-12 10:18:41 +00:00
dataLen := len(f.Payload)
d.pLens = append(d.pLens, dataLen)
d.buf.Write(f.Payload)
2019-08-14 09:04:27 +00:00
// err will always be nil
d.rwCond.Broadcast()
return false, nil
2019-08-14 09:04:27 +00:00
}
func (d *datagramBufferedPipe) Close() error {
d.rwCond.L.Lock()
defer d.rwCond.L.Unlock()
d.closed = true
2019-08-14 09:04:27 +00:00
d.rwCond.Broadcast()
return nil
}
2020-04-09 17:56:17 +00:00
func (d *datagramBufferedPipe) SetReadDeadline(t time.Time) {
2020-04-09 17:56:17 +00:00
d.rwCond.L.Lock()
defer d.rwCond.L.Unlock()
d.rDeadline = t
d.rwCond.Broadcast()
}
func (d *datagramBufferedPipe) SetWriteToTimeout(t time.Duration) {
d.rwCond.L.Lock()
defer d.rwCond.L.Unlock()
d.wtTimeout = t
d.rwCond.Broadcast()
}
2020-12-05 23:47:52 +00:00
func (d *datagramBufferedPipe) broadcastAfter(t time.Duration) {
if d.timeoutTimer != nil {
d.timeoutTimer.Stop()
}
d.timeoutTimer = time.AfterFunc(t, d.rwCond.Broadcast)
}