68 lines
1.3 KiB
Go
68 lines
1.3 KiB
Go
|
package net
|
||
|
|
||
|
import (
|
||
|
"net"
|
||
|
"sync"
|
||
|
"sync/atomic"
|
||
|
"unsafe"
|
||
|
|
||
|
"github.com/metacubex/mihomo/common/buf"
|
||
|
)
|
||
|
|
||
|
type earlyConn struct {
|
||
|
ExtendedConn // only expose standard N.ExtendedConn function to outside
|
||
|
resFunc func() error
|
||
|
resOnce sync.Once
|
||
|
resErr error
|
||
|
}
|
||
|
|
||
|
func (conn *earlyConn) Response() error {
|
||
|
conn.resOnce.Do(func() {
|
||
|
conn.resErr = conn.resFunc()
|
||
|
})
|
||
|
return conn.resErr
|
||
|
}
|
||
|
|
||
|
func (conn *earlyConn) Read(b []byte) (n int, err error) {
|
||
|
err = conn.Response()
|
||
|
if err != nil {
|
||
|
return 0, err
|
||
|
}
|
||
|
return conn.ExtendedConn.Read(b)
|
||
|
}
|
||
|
|
||
|
func (conn *earlyConn) ReadBuffer(buffer *buf.Buffer) (err error) {
|
||
|
err = conn.Response()
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
return conn.ExtendedConn.ReadBuffer(buffer)
|
||
|
}
|
||
|
|
||
|
func (conn *earlyConn) Upstream() any {
|
||
|
return conn.ExtendedConn
|
||
|
}
|
||
|
|
||
|
func (conn *earlyConn) Success() bool {
|
||
|
// atomic visit sync.Once.done
|
||
|
return atomic.LoadUint32((*uint32)(unsafe.Pointer(&conn.resOnce))) == 1 && conn.resErr == nil
|
||
|
}
|
||
|
|
||
|
func (conn *earlyConn) ReaderReplaceable() bool {
|
||
|
return conn.Success()
|
||
|
}
|
||
|
|
||
|
func (conn *earlyConn) ReaderPossiblyReplaceable() bool {
|
||
|
return !conn.Success()
|
||
|
}
|
||
|
|
||
|
func (conn *earlyConn) WriterReplaceable() bool {
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
var _ ExtendedConn = (*earlyConn)(nil)
|
||
|
|
||
|
func NewEarlyConn(c net.Conn, f func() error) net.Conn {
|
||
|
return &earlyConn{ExtendedConn: NewExtendedConn(c), resFunc: f}
|
||
|
}
|