mirror of
https://github.com/e1732a364fed/v2ray_simple.git
synced 2025-12-24 13:27:56 +08:00
try解决splice的问题, 关联#160 里面第二个发现的问题
这是一个古老的bug;过去一直认为unix可以用于splice, 这次重新查看资料才知道,只有tcp可以splice写入
This commit is contained in:
@@ -35,7 +35,7 @@ type Config struct {
|
||||
//implements net.Conn
|
||||
type ClientConn struct {
|
||||
commonPart
|
||||
//timeouter
|
||||
|
||||
netLayer.EasyDeadline
|
||||
|
||||
client *Client
|
||||
@@ -218,13 +218,6 @@ func (c *Client) DialSubConn(underlay any) (net.Conn, error) {
|
||||
client: c,
|
||||
}
|
||||
|
||||
/*
|
||||
conn.timeouter = timeouter{
|
||||
closeFunc: func() {
|
||||
conn.Close()
|
||||
},
|
||||
}*/
|
||||
|
||||
go conn.handshakeOnce.Do(conn.handshake) //necessary。 因为 handshake不会立刻退出,所以必须要用 goroutine, 否则会卡住
|
||||
|
||||
return conn, nil
|
||||
|
||||
@@ -101,6 +101,7 @@ func (c *Client) Handshake(underlay net.Conn, firstPayloadLen int) (net.Conn, er
|
||||
theConn := &Conn{
|
||||
Conn: underlay,
|
||||
state: ws.StateClientSide,
|
||||
underlayIsTCP: netLayer.IsTCP(underlay) != nil,
|
||||
underlayIsBasic: netLayer.IsBasicConn(underlay),
|
||||
}
|
||||
|
||||
@@ -170,6 +171,7 @@ func (edc *EarlyDataConn) Write(p []byte) (int, error) {
|
||||
theConn := &Conn{
|
||||
Conn: edc.Conn,
|
||||
state: ws.StateClientSide,
|
||||
underlayIsTCP: netLayer.IsTCP(edc.Conn) != nil,
|
||||
underlayIsBasic: netLayer.IsBasicConn(edc.Conn),
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ type Conn struct {
|
||||
|
||||
serverEndGotEarlyData []byte
|
||||
|
||||
underlayIsTCP bool
|
||||
underlayIsBasic bool
|
||||
|
||||
bigHeaderEverUsed bool
|
||||
@@ -112,7 +113,7 @@ func (c *Conn) Read(p []byte) (int, error) {
|
||||
}
|
||||
|
||||
func (c *Conn) EverPossibleToSplice() bool {
|
||||
return c.underlayIsBasic && c.state == ws.StateServerSide
|
||||
return c.underlayIsTCP && c.state == ws.StateServerSide
|
||||
}
|
||||
|
||||
//采用 “超长包” 的办法 试图进行splice
|
||||
@@ -133,7 +134,7 @@ func (c *Conn) tryWriteBigHeader() (e error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (c *Conn) CanSplice() (r bool, conn net.Conn) {
|
||||
func (c *Conn) CanSplice() (r bool, conn *net.TCPConn) {
|
||||
if !c.EverPossibleToSplice() {
|
||||
return
|
||||
}
|
||||
@@ -141,7 +142,14 @@ func (c *Conn) CanSplice() (r bool, conn net.Conn) {
|
||||
if c.tryWriteBigHeader() != nil {
|
||||
return
|
||||
}
|
||||
return true, c.Conn
|
||||
|
||||
if tc := netLayer.IsTCP(c.Conn); tc != nil {
|
||||
r = true
|
||||
conn = tc
|
||||
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
@@ -156,11 +164,11 @@ func (c *Conn) ReadFrom(r io.Reader) (written int64, err error) {
|
||||
if e != nil {
|
||||
return 0, e
|
||||
}
|
||||
if c.underlayIsBasic {
|
||||
if c.underlayIsTCP {
|
||||
if rt, ok := c.Conn.(io.ReaderFrom); ok {
|
||||
return rt.ReadFrom(r)
|
||||
} else {
|
||||
panic("ws.Conn underlayIsBasic, but can't cast to ReadFrom")
|
||||
panic("ws.Conn underlayIsTCP, but can't cast to ReadFrom")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -283,11 +283,11 @@ func (s *Server) Handshake(underlay net.Conn) (net.Conn, error) {
|
||||
}
|
||||
|
||||
theConn := &Conn{
|
||||
Conn: underlay,
|
||||
underlayIsBasic: netLayer.IsBasicConn(underlay),
|
||||
state: ws.StateServerSide,
|
||||
r: wsutil.NewServerSideReader(underlay),
|
||||
realRaddr: realAddr,
|
||||
Conn: underlay,
|
||||
underlayIsTCP: netLayer.IsTCP(underlay) != nil,
|
||||
state: ws.StateServerSide,
|
||||
r: wsutil.NewServerSideReader(underlay),
|
||||
realRaddr: realAddr,
|
||||
}
|
||||
//不想客户端;服务端是不怕客户端在握手阶段传来任何多余数据的
|
||||
// 因为我们还没实现 0-rtt
|
||||
|
||||
@@ -46,6 +46,14 @@ func PersistConn(c net.Conn) {
|
||||
c.SetDeadline(time.Time{})
|
||||
}
|
||||
|
||||
func IsTCP(r any) *net.TCPConn {
|
||||
if tc, ok := r.(*net.TCPConn); ok {
|
||||
return tc
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
//net.IPConn, net.TCPConn, net.UDPConn, net.UnixConn
|
||||
func IsBasicConn(r interface{}) bool {
|
||||
if _, ok := r.(syscall.Conn); ok {
|
||||
|
||||
@@ -35,11 +35,11 @@ func TryCopy(writeConn io.Writer, readConn io.Reader, identity uint32) (allnum i
|
||||
|
||||
if SystemCanSplice {
|
||||
|
||||
rCanSplice := CanSpliceDirectly(readConn)
|
||||
rCanSplice := CanRSplice(readConn)
|
||||
|
||||
if rCanSplice {
|
||||
var wCanSplice bool
|
||||
wCanSpliceDirectly := CanSpliceDirectly(writeConn)
|
||||
wCanSpliceDirectly := CanWSplice(writeConn)
|
||||
if wCanSpliceDirectly {
|
||||
wCanSplice = true
|
||||
} else {
|
||||
|
||||
@@ -13,24 +13,43 @@ var ErrInvalidWrite = errors.New("readfrom, invalid write result")
|
||||
|
||||
const SystemCanSplice = runtime.GOARCH != "wasm" && runtime.GOOS != "windows"
|
||||
|
||||
//Splicer 是一个 可以进行Write时使用splice的接口。
|
||||
type Splicer interface {
|
||||
EverPossibleToSplice() bool //是否有机会splice, 如果这个返回false,则永远无法splice; 主要审视自己能否向裸连接写入数据; 读不用splicer担心。
|
||||
CanSplice() (bool, net.Conn) //当前状态是否可以splice
|
||||
EverPossibleToSplice() bool //是否有机会splice, 如果这个返回false,则永远无法splice; 主要审视自己能否向裸连接写入数据; 读不用splicer担心。
|
||||
CanSplice() (bool, *net.TCPConn) //当前状态是否可以splice,返回的 net.Conn必须是tcp
|
||||
}
|
||||
|
||||
//这里认为能 splice 或 sendfile的 都算,具体可参考go标准代码的实现, 总之就是tcp和 unix domain socket 可以.
|
||||
func CanSpliceDirectly(r any) bool {
|
||||
|
||||
//tcp, unix
|
||||
func CanRSplice(r io.Reader) bool {
|
||||
switch r.(type) {
|
||||
case *net.TCPConn:
|
||||
return true
|
||||
case *net.UnixConn:
|
||||
case *net.TCPConn, *net.UnixConn:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
//tcp
|
||||
func CanWSplice(w io.Writer) bool {
|
||||
switch w.(type) {
|
||||
case *net.TCPConn:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
//这里认为能 splice 或 sendfile的 都算,具体可参考go标准代码的实现, 之前以为tcp和 unix domain socket 可以,仔细观察才发现,只有tcp可以。unix只是可以接受tcp的splice,但是不能主动进行splice。
|
||||
//就是说,tcp可以从tcp或者 stream oriented unix 来读取数据,用 splice 来写入tcp。但是unix不能被splice写入。
|
||||
func CanSpliceDirectly(w io.Writer, r io.Reader) bool {
|
||||
|
||||
if CanWSplice(w) {
|
||||
if CanRSplice(r) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func CanSpliceEventually(r any) bool {
|
||||
if s, ok := r.(Splicer); ok {
|
||||
return s.EverPossibleToSplice()
|
||||
@@ -39,26 +58,27 @@ func CanSpliceEventually(r any) bool {
|
||||
}
|
||||
|
||||
//从r读取数据,写入 maySpliceConn / classicWriter, 在条件合适时会使用splice进行加速。
|
||||
//
|
||||
// 若maySpliceConn不是基本Conn,则会试图转换为Splicer并获取底层Conn.
|
||||
// 本函数主要应用于裸奔时,一端是socks5/直连,另一端是vless/vless+ws的情况, 因为vless等协议就算裸奔也是要处理一下数据头等情况的, 所以需要进行处理才可裸奔.
|
||||
//
|
||||
// 注意,splice只有在 maySpliceConn【本身是】/【变成】 basicConn, 且 r 也是 basicConn时,才会发生。
|
||||
// 如果r本身就不是 basicConn,则调用本函数没有意义, 因为既然拿不到basicConn那就不是裸奔,也就不可能splice。
|
||||
//
|
||||
func TryReadFrom_withSplice(classicWriter io.Writer, maySpliceConn net.Conn, r io.Reader, canDirectFunc func() bool) (written int64, err error) {
|
||||
func TryReadFrom_withSplice(classicWriter io.Writer, maySpliceW io.Writer, r io.Reader, canDirectFunc func() bool) (written int64, err error) {
|
||||
|
||||
underlay_canSpliceDirectly := CanSpliceDirectly(maySpliceConn)
|
||||
underlay_canSpliceDirectly := CanSpliceDirectly(maySpliceW, r)
|
||||
|
||||
var underlay_canSpliceEventually bool
|
||||
|
||||
if !underlay_canSpliceDirectly {
|
||||
underlay_canSpliceEventually = CanSpliceEventually(maySpliceConn)
|
||||
underlay_canSpliceEventually = CanRSplice(r) && CanSpliceEventually(maySpliceW)
|
||||
}
|
||||
|
||||
var splicer Splicer
|
||||
var splicerW Splicer
|
||||
|
||||
if underlay_canSpliceEventually {
|
||||
splicer = maySpliceConn.(Splicer)
|
||||
splicerW = maySpliceW.(Splicer)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -71,7 +91,7 @@ func TryReadFrom_withSplice(classicWriter io.Writer, maySpliceConn net.Conn, r i
|
||||
|
||||
if underlay_canSpliceDirectly || underlay_canSpliceEventually {
|
||||
if underlay_canSpliceDirectly && canDirectFunc() {
|
||||
if rt, ok := maySpliceConn.(io.ReaderFrom); ok {
|
||||
if rt, ok := maySpliceW.(io.ReaderFrom); ok {
|
||||
return rt.ReadFrom(r)
|
||||
} else {
|
||||
panic("uc.underlayIsBasic, but can't cast to ReadFrom")
|
||||
@@ -107,7 +127,7 @@ func TryReadFrom_withSplice(classicWriter io.Writer, maySpliceConn net.Conn, r i
|
||||
}
|
||||
|
||||
if underlay_canSpliceDirectly {
|
||||
if rt, ok := maySpliceConn.(io.ReaderFrom); ok {
|
||||
if rt, ok := maySpliceW.(io.ReaderFrom); ok {
|
||||
var readfromN int64
|
||||
readfromN, err = rt.ReadFrom(r)
|
||||
written += readfromN
|
||||
@@ -117,14 +137,14 @@ func TryReadFrom_withSplice(classicWriter io.Writer, maySpliceConn net.Conn, r i
|
||||
}
|
||||
} else {
|
||||
|
||||
if canStartSplice, rawConn := splicer.CanSplice(); canStartSplice {
|
||||
if rt, ok := rawConn.(io.ReaderFrom); ok {
|
||||
if canStartSplice, rawConn := splicerW.CanSplice(); canStartSplice {
|
||||
if rawConn != nil {
|
||||
var readfromN int64
|
||||
readfromN, err = rt.ReadFrom(r)
|
||||
readfromN, err = rawConn.ReadFrom(r)
|
||||
written += readfromN
|
||||
return
|
||||
} else {
|
||||
panic("uc.underlayIsBasic, but can't cast to ReadFrom")
|
||||
panic("uc.underlayIsBasic, but tcp conn is nil")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ func (c *TCPConn) Write(p []byte) (int, error) {
|
||||
|
||||
func (c *TCPConn) EverPossibleToSplice() bool {
|
||||
|
||||
if netLayer.IsBasicConn(c.Conn) {
|
||||
if netLayer.IsTCP(c.Conn) != nil {
|
||||
return true
|
||||
}
|
||||
if s, ok := c.Conn.(netLayer.Splicer); ok {
|
||||
@@ -45,14 +45,14 @@ func (c *TCPConn) EverPossibleToSplice() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *TCPConn) CanSplice() (r bool, conn net.Conn) {
|
||||
func (c *TCPConn) CanSplice() (r bool, conn *net.TCPConn) {
|
||||
if !c.isServerEnd && c.remainFirstBufLen > 0 {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if netLayer.IsBasicConn(c.Conn) {
|
||||
if tc := netLayer.IsTCP(c.Conn); tc != nil {
|
||||
r = true
|
||||
conn = c.Conn
|
||||
conn = tc
|
||||
|
||||
} else if s, ok := c.Conn.(netLayer.Splicer); ok {
|
||||
r, conn = s.CanSplice()
|
||||
|
||||
@@ -43,7 +43,7 @@ func (c *UserTCPConn) Write(p []byte) (int, error) {
|
||||
|
||||
func (c *UserTCPConn) EverPossibleToSplice() bool {
|
||||
|
||||
if netLayer.IsBasicConn(c.Conn) {
|
||||
if netLayer.IsTCP(c.Conn) != nil {
|
||||
return true
|
||||
}
|
||||
if s, ok := c.Conn.(netLayer.Splicer); ok {
|
||||
@@ -52,14 +52,14 @@ func (c *UserTCPConn) EverPossibleToSplice() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *UserTCPConn) CanSplice() (r bool, conn net.Conn) {
|
||||
func (c *UserTCPConn) CanSplice() (r bool, conn *net.TCPConn) {
|
||||
if !c.isServerEnd && c.remainFirstBufLen > 0 {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if netLayer.IsBasicConn(c.Conn) {
|
||||
if tc := netLayer.IsTCP(c.Conn); tc != nil {
|
||||
r = true
|
||||
conn = c.Conn
|
||||
conn = tc
|
||||
|
||||
} else if s, ok := c.Conn.(netLayer.Splicer); ok {
|
||||
r, conn = s.CanSplice()
|
||||
|
||||
@@ -47,7 +47,7 @@ func (c *UserTCPConn) canDirectWrite() bool {
|
||||
|
||||
func (c *UserTCPConn) EverPossibleToSplice() bool {
|
||||
|
||||
if netLayer.IsBasicConn(c.Conn) {
|
||||
if netLayer.IsTCP(c.Conn) != nil {
|
||||
return true
|
||||
}
|
||||
if s, ok := c.Conn.(netLayer.Splicer); ok {
|
||||
@@ -56,15 +56,15 @@ func (c *UserTCPConn) EverPossibleToSplice() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *UserTCPConn) CanSplice() (r bool, conn net.Conn) {
|
||||
func (c *UserTCPConn) CanSplice() (r bool, conn *net.TCPConn) {
|
||||
|
||||
if !c.canDirectWrite() {
|
||||
return
|
||||
}
|
||||
|
||||
if netLayer.IsBasicConn(c.Conn) {
|
||||
if tc := netLayer.IsTCP(c.Conn); tc != nil {
|
||||
r = true
|
||||
conn = c.Conn
|
||||
conn = tc
|
||||
|
||||
} else if s, ok := c.Conn.(netLayer.Splicer); ok {
|
||||
r, conn = s.CanSplice()
|
||||
|
||||
Reference in New Issue
Block a user