2018-04-16 08:57:13 -04:00
|
|
|
package pipe
|
|
|
|
|
|
|
|
import (
|
2018-04-18 09:11:03 -04:00
|
|
|
"errors"
|
2018-04-16 08:57:13 -04:00
|
|
|
"io"
|
2018-11-11 12:58:58 -05:00
|
|
|
"runtime"
|
2018-04-16 08:57:13 -04:00
|
|
|
"sync"
|
|
|
|
"time"
|
|
|
|
|
2022-01-02 10:16:23 -05:00
|
|
|
"github.com/v2fly/v2ray-core/v5/common"
|
|
|
|
"github.com/v2fly/v2ray-core/v5/common/buf"
|
|
|
|
"github.com/v2fly/v2ray-core/v5/common/signal"
|
|
|
|
"github.com/v2fly/v2ray-core/v5/common/signal/done"
|
2018-04-16 08:57:13 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
type state byte
|
|
|
|
|
|
|
|
const (
|
|
|
|
open state = iota
|
|
|
|
closed
|
|
|
|
errord
|
|
|
|
)
|
|
|
|
|
2018-11-14 06:31:59 -05:00
|
|
|
type pipeOption struct {
|
|
|
|
limit int32 // maximum buffer size in bytes
|
|
|
|
discardOverflow bool
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o *pipeOption) isFull(curSize int32) bool {
|
|
|
|
return o.limit >= 0 && curSize > o.limit
|
|
|
|
}
|
|
|
|
|
2018-04-16 08:57:13 -04:00
|
|
|
type pipe struct {
|
|
|
|
sync.Mutex
|
2018-11-14 06:31:59 -05:00
|
|
|
data buf.MultiBuffer
|
|
|
|
readSignal *signal.Notifier
|
|
|
|
writeSignal *signal.Notifier
|
|
|
|
done *done.Instance
|
|
|
|
option pipeOption
|
|
|
|
state state
|
2018-04-16 08:57:13 -04:00
|
|
|
}
|
|
|
|
|
2021-05-19 17:28:52 -04:00
|
|
|
var (
|
|
|
|
errBufferFull = errors.New("buffer full")
|
|
|
|
errSlowDown = errors.New("slow down")
|
|
|
|
)
|
2018-04-18 09:11:03 -04:00
|
|
|
|
2018-04-16 08:57:13 -04:00
|
|
|
func (p *pipe) getState(forRead bool) error {
|
|
|
|
switch p.state {
|
|
|
|
case open:
|
2018-11-14 06:31:59 -05:00
|
|
|
if !forRead && p.option.isFull(p.data.Len()) {
|
2018-04-18 09:11:03 -04:00
|
|
|
return errBufferFull
|
|
|
|
}
|
2018-04-16 08:57:13 -04:00
|
|
|
return nil
|
|
|
|
case closed:
|
2018-04-23 10:26:29 -04:00
|
|
|
if !forRead {
|
|
|
|
return io.ErrClosedPipe
|
2018-04-16 08:57:13 -04:00
|
|
|
}
|
2018-04-23 10:26:29 -04:00
|
|
|
if !p.data.IsEmpty() {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return io.EOF
|
2018-04-16 08:57:13 -04:00
|
|
|
case errord:
|
|
|
|
return io.ErrClosedPipe
|
|
|
|
default:
|
|
|
|
panic("impossible case")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *pipe) readMultiBufferInternal() (buf.MultiBuffer, error) {
|
|
|
|
p.Lock()
|
|
|
|
defer p.Unlock()
|
|
|
|
|
|
|
|
if err := p.getState(true); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
data := p.data
|
|
|
|
p.data = nil
|
|
|
|
return data, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *pipe) ReadMultiBuffer() (buf.MultiBuffer, error) {
|
|
|
|
for {
|
|
|
|
data, err := p.readMultiBufferInternal()
|
|
|
|
if data != nil || err != nil {
|
2018-04-16 18:45:38 -04:00
|
|
|
p.writeSignal.Signal()
|
2018-04-16 08:57:13 -04:00
|
|
|
return data, err
|
|
|
|
}
|
|
|
|
|
2018-06-08 22:47:37 -04:00
|
|
|
select {
|
|
|
|
case <-p.readSignal.Wait():
|
|
|
|
case <-p.done.Wait():
|
|
|
|
}
|
2018-04-16 08:57:13 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-27 06:21:22 -04:00
|
|
|
func (p *pipe) ReadMultiBufferTimeout(d time.Duration) (buf.MultiBuffer, error) {
|
2018-08-09 06:23:27 -04:00
|
|
|
timer := time.NewTimer(d)
|
|
|
|
defer timer.Stop()
|
|
|
|
|
2018-04-16 08:57:13 -04:00
|
|
|
for {
|
|
|
|
data, err := p.readMultiBufferInternal()
|
|
|
|
if data != nil || err != nil {
|
|
|
|
p.writeSignal.Signal()
|
|
|
|
return data, err
|
|
|
|
}
|
|
|
|
|
|
|
|
select {
|
|
|
|
case <-p.readSignal.Wait():
|
2018-06-08 22:47:37 -04:00
|
|
|
case <-p.done.Wait():
|
2018-08-09 06:23:27 -04:00
|
|
|
case <-timer.C:
|
2018-04-16 18:31:10 -04:00
|
|
|
return nil, buf.ErrReadTimeout
|
2018-04-16 08:57:13 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *pipe) writeMultiBufferInternal(mb buf.MultiBuffer) error {
|
|
|
|
p.Lock()
|
|
|
|
defer p.Unlock()
|
|
|
|
|
|
|
|
if err := p.getState(false); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2018-11-17 13:47:30 -05:00
|
|
|
if p.data == nil {
|
|
|
|
p.data = mb
|
2018-11-20 04:45:02 -05:00
|
|
|
return nil
|
2018-11-17 13:47:30 -05:00
|
|
|
}
|
|
|
|
|
2018-11-20 04:45:02 -05:00
|
|
|
p.data, _ = buf.MergeMulti(p.data, mb)
|
|
|
|
return errSlowDown
|
2018-04-16 08:57:13 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
func (p *pipe) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
|
|
|
if mb.IsEmpty() {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
for {
|
2018-04-18 09:11:03 -04:00
|
|
|
err := p.writeMultiBufferInternal(mb)
|
2018-11-20 04:45:02 -05:00
|
|
|
if err == nil {
|
|
|
|
p.readSignal.Signal()
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if err == errSlowDown {
|
2018-08-31 06:35:08 -04:00
|
|
|
p.readSignal.Signal()
|
2018-11-11 12:58:58 -05:00
|
|
|
|
|
|
|
// Yield current goroutine. Hopefully the reading counterpart can pick up the payload.
|
|
|
|
runtime.Gosched()
|
2018-08-31 06:35:08 -04:00
|
|
|
return nil
|
2018-11-20 04:45:02 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if err == errBufferFull && p.option.discardOverflow {
|
2018-11-17 16:45:07 -05:00
|
|
|
buf.ReleaseMulti(mb)
|
2018-09-02 18:56:43 -04:00
|
|
|
return nil
|
2018-11-20 04:45:02 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if err != errBufferFull {
|
2018-11-17 16:45:07 -05:00
|
|
|
buf.ReleaseMulti(mb)
|
2018-04-18 09:11:03 -04:00
|
|
|
p.readSignal.Signal()
|
|
|
|
return err
|
2018-04-16 08:57:13 -04:00
|
|
|
}
|
|
|
|
|
2018-06-08 22:47:37 -04:00
|
|
|
select {
|
|
|
|
case <-p.writeSignal.Wait():
|
|
|
|
case <-p.done.Wait():
|
|
|
|
return io.ErrClosedPipe
|
|
|
|
}
|
2018-04-16 08:57:13 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *pipe) Close() error {
|
|
|
|
p.Lock()
|
|
|
|
defer p.Unlock()
|
|
|
|
|
2018-04-16 18:31:10 -04:00
|
|
|
if p.state == closed || p.state == errord {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-04-16 08:57:13 -04:00
|
|
|
p.state = closed
|
2018-08-31 06:12:40 -04:00
|
|
|
common.Must(p.done.Close())
|
2018-04-16 08:57:13 -04:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-12-31 15:25:10 -05:00
|
|
|
// Interrupt implements common.Interruptible.
|
|
|
|
func (p *pipe) Interrupt() {
|
2018-04-16 08:57:13 -04:00
|
|
|
p.Lock()
|
|
|
|
defer p.Unlock()
|
|
|
|
|
2018-04-23 10:26:29 -04:00
|
|
|
if p.state == closed || p.state == errord {
|
|
|
|
return
|
|
|
|
}
|
2018-04-16 08:57:13 -04:00
|
|
|
|
2018-04-23 10:42:37 -04:00
|
|
|
p.state = errord
|
|
|
|
|
2018-04-16 08:57:13 -04:00
|
|
|
if !p.data.IsEmpty() {
|
2018-11-17 16:45:07 -05:00
|
|
|
buf.ReleaseMulti(p.data)
|
2018-04-16 08:57:13 -04:00
|
|
|
p.data = nil
|
|
|
|
}
|
|
|
|
|
2018-08-31 06:12:40 -04:00
|
|
|
common.Must(p.done.Close())
|
2018-04-16 08:57:13 -04:00
|
|
|
}
|