diff --git a/advLayer/grpcSimple/client.go b/advLayer/grpcSimple/client.go index 206c90e..14c651f 100644 --- a/advLayer/grpcSimple/client.go +++ b/advLayer/grpcSimple/client.go @@ -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 diff --git a/advLayer/ws/client.go b/advLayer/ws/client.go index 60a1317..23c9b95 100644 --- a/advLayer/ws/client.go +++ b/advLayer/ws/client.go @@ -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), } diff --git a/advLayer/ws/conn.go b/advLayer/ws/conn.go index b697b53..56ce671 100644 --- a/advLayer/ws/conn.go +++ b/advLayer/ws/conn.go @@ -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") } } diff --git a/advLayer/ws/server.go b/advLayer/ws/server.go index ea62422..10602c4 100644 --- a/advLayer/ws/server.go +++ b/advLayer/ws/server.go @@ -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 diff --git a/netLayer/netlayer.go b/netLayer/netlayer.go index ff33a35..07d0849 100644 --- a/netLayer/netlayer.go +++ b/netLayer/netlayer.go @@ -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 { diff --git a/netLayer/relay.go b/netLayer/relay.go index f002472..b8cc87d 100644 --- a/netLayer/relay.go +++ b/netLayer/relay.go @@ -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 { diff --git a/netLayer/splice.go b/netLayer/splice.go index e015832..f9ee58a 100644 --- a/netLayer/splice.go +++ b/netLayer/splice.go @@ -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") } } diff --git a/proxy/simplesocks/tcpconn.go b/proxy/simplesocks/tcpconn.go index 5b7c8a7..76d58d8 100644 --- a/proxy/simplesocks/tcpconn.go +++ b/proxy/simplesocks/tcpconn.go @@ -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() diff --git a/proxy/trojan/tcpconn.go b/proxy/trojan/tcpconn.go index 42661f8..f17f6bc 100644 --- a/proxy/trojan/tcpconn.go +++ b/proxy/trojan/tcpconn.go @@ -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() diff --git a/proxy/vless/tcpconn.go b/proxy/vless/tcpconn.go index 32fa52f..880cc5a 100644 --- a/proxy/vless/tcpconn.go +++ b/proxy/vless/tcpconn.go @@ -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()