mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-07-17 13:21:06 +03:00
230 lines
4.1 KiB
Go
230 lines
4.1 KiB
Go
package httpmask
|
|
|
|
import (
|
|
"io"
|
|
"net"
|
|
"os"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
type pipeDeadline struct {
|
|
mu sync.Mutex
|
|
timer *time.Timer
|
|
cancel chan struct{}
|
|
}
|
|
|
|
func makePipeDeadline() pipeDeadline {
|
|
return pipeDeadline{cancel: make(chan struct{})}
|
|
}
|
|
|
|
func (d *pipeDeadline) set(t time.Time) {
|
|
d.mu.Lock()
|
|
defer d.mu.Unlock()
|
|
|
|
if d.timer != nil && !d.timer.Stop() {
|
|
<-d.cancel
|
|
}
|
|
d.timer = nil
|
|
|
|
closed := isClosedPipeChan(d.cancel)
|
|
if t.IsZero() {
|
|
if closed {
|
|
d.cancel = make(chan struct{})
|
|
}
|
|
return
|
|
}
|
|
|
|
if dur := time.Until(t); dur > 0 {
|
|
if closed {
|
|
d.cancel = make(chan struct{})
|
|
}
|
|
d.timer = time.AfterFunc(dur, func() {
|
|
close(d.cancel)
|
|
})
|
|
return
|
|
}
|
|
|
|
if !closed {
|
|
close(d.cancel)
|
|
}
|
|
}
|
|
|
|
func (d *pipeDeadline) wait() <-chan struct{} {
|
|
d.mu.Lock()
|
|
ch := d.cancel
|
|
d.mu.Unlock()
|
|
return ch
|
|
}
|
|
|
|
func isClosedPipeChan(ch <-chan struct{}) bool {
|
|
select {
|
|
case <-ch:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
type halfPipeAddr struct{}
|
|
|
|
func (halfPipeAddr) Network() string { return "pipe" }
|
|
func (halfPipeAddr) String() string { return "pipe" }
|
|
|
|
type halfPipeConn struct {
|
|
wrMu sync.Mutex
|
|
|
|
rdRx <-chan []byte
|
|
rdTx chan<- int
|
|
|
|
wrTx chan<- []byte
|
|
wrRx <-chan int
|
|
|
|
readOnce sync.Once
|
|
writeOnce sync.Once
|
|
|
|
localReadDone chan struct{}
|
|
localWriteDone chan struct{}
|
|
|
|
remoteReadDone <-chan struct{}
|
|
remoteWriteDone <-chan struct{}
|
|
|
|
readDeadline pipeDeadline
|
|
writeDeadline pipeDeadline
|
|
}
|
|
|
|
func newHalfPipe() (net.Conn, net.Conn) {
|
|
cb1 := make(chan []byte)
|
|
cb2 := make(chan []byte)
|
|
cn1 := make(chan int)
|
|
cn2 := make(chan int)
|
|
|
|
r1 := make(chan struct{})
|
|
w1 := make(chan struct{})
|
|
r2 := make(chan struct{})
|
|
w2 := make(chan struct{})
|
|
|
|
c1 := &halfPipeConn{
|
|
rdRx: cb1,
|
|
rdTx: cn1,
|
|
wrTx: cb2,
|
|
wrRx: cn2,
|
|
|
|
localReadDone: r1,
|
|
localWriteDone: w1,
|
|
remoteReadDone: r2,
|
|
remoteWriteDone: w2,
|
|
|
|
readDeadline: makePipeDeadline(),
|
|
writeDeadline: makePipeDeadline(),
|
|
}
|
|
c2 := &halfPipeConn{
|
|
rdRx: cb2,
|
|
rdTx: cn2,
|
|
wrTx: cb1,
|
|
wrRx: cn1,
|
|
|
|
localReadDone: r2,
|
|
localWriteDone: w2,
|
|
remoteReadDone: r1,
|
|
remoteWriteDone: w1,
|
|
|
|
readDeadline: makePipeDeadline(),
|
|
writeDeadline: makePipeDeadline(),
|
|
}
|
|
return c1, c2
|
|
}
|
|
|
|
func (*halfPipeConn) LocalAddr() net.Addr { return halfPipeAddr{} }
|
|
func (*halfPipeConn) RemoteAddr() net.Addr { return halfPipeAddr{} }
|
|
|
|
func (c *halfPipeConn) Read(p []byte) (int, error) {
|
|
switch {
|
|
case isClosedPipeChan(c.localReadDone):
|
|
return 0, io.ErrClosedPipe
|
|
case isClosedPipeChan(c.remoteWriteDone):
|
|
return 0, io.EOF
|
|
case isClosedPipeChan(c.readDeadline.wait()):
|
|
return 0, os.ErrDeadlineExceeded
|
|
}
|
|
|
|
select {
|
|
case b := <-c.rdRx:
|
|
n := copy(p, b)
|
|
c.rdTx <- n
|
|
return n, nil
|
|
case <-c.localReadDone:
|
|
return 0, io.ErrClosedPipe
|
|
case <-c.remoteWriteDone:
|
|
return 0, io.EOF
|
|
case <-c.readDeadline.wait():
|
|
return 0, os.ErrDeadlineExceeded
|
|
}
|
|
}
|
|
|
|
func (c *halfPipeConn) Write(p []byte) (int, error) {
|
|
switch {
|
|
case isClosedPipeChan(c.localWriteDone):
|
|
return 0, io.ErrClosedPipe
|
|
case isClosedPipeChan(c.remoteReadDone):
|
|
return 0, io.ErrClosedPipe
|
|
case isClosedPipeChan(c.writeDeadline.wait()):
|
|
return 0, os.ErrDeadlineExceeded
|
|
}
|
|
|
|
c.wrMu.Lock()
|
|
defer c.wrMu.Unlock()
|
|
|
|
var (
|
|
total int
|
|
rest = p
|
|
)
|
|
for once := true; once || len(rest) > 0; once = false {
|
|
select {
|
|
case c.wrTx <- rest:
|
|
n := <-c.wrRx
|
|
rest = rest[n:]
|
|
total += n
|
|
case <-c.localWriteDone:
|
|
return total, io.ErrClosedPipe
|
|
case <-c.remoteReadDone:
|
|
return total, io.ErrClosedPipe
|
|
case <-c.writeDeadline.wait():
|
|
return total, os.ErrDeadlineExceeded
|
|
}
|
|
}
|
|
return total, nil
|
|
}
|
|
|
|
func (c *halfPipeConn) CloseWrite() error {
|
|
c.writeOnce.Do(func() { close(c.localWriteDone) })
|
|
return nil
|
|
}
|
|
|
|
func (c *halfPipeConn) CloseRead() error {
|
|
c.readOnce.Do(func() { close(c.localReadDone) })
|
|
return nil
|
|
}
|
|
|
|
func (c *halfPipeConn) Close() error {
|
|
_ = c.CloseRead()
|
|
_ = c.CloseWrite()
|
|
return nil
|
|
}
|
|
|
|
func (c *halfPipeConn) SetDeadline(t time.Time) error {
|
|
c.readDeadline.set(t)
|
|
c.writeDeadline.set(t)
|
|
return nil
|
|
}
|
|
|
|
func (c *halfPipeConn) SetReadDeadline(t time.Time) error {
|
|
c.readDeadline.set(t)
|
|
return nil
|
|
}
|
|
|
|
func (c *halfPipeConn) SetWriteDeadline(t time.Time) error {
|
|
c.writeDeadline.set(t)
|
|
return nil
|
|
}
|