mirror of
https://github.com/XTLS/Xray-core.git
synced 2025-04-30 17:38:41 +00:00
Enable splice for freedom outbound (downlink only)
- Add outbound name - Add outbound conn in ctx - Refactor splice: it can be turn on from all inbounds and outbounds - Refactor splice: Add splice copy to vless inbound - Fix http error test - Add freedom splice toggle via env var - Populate outbound obj in context - Use CanSpliceCopy to mark a connection - Turn off splice by default
This commit is contained in:
parent
ae2fa30e01
commit
efd32b0fb2
32 changed files with 282 additions and 168 deletions
|
@ -7,13 +7,24 @@ package proxy
|
|||
|
||||
import (
|
||||
"context"
|
||||
gotls "crypto/tls"
|
||||
"io"
|
||||
"runtime"
|
||||
|
||||
"github.com/pires/go-proxyproto"
|
||||
"github.com/xtls/xray-core/common/buf"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/protocol"
|
||||
"github.com/xtls/xray-core/common/session"
|
||||
"github.com/xtls/xray-core/common/signal"
|
||||
"github.com/xtls/xray-core/features/routing"
|
||||
"github.com/xtls/xray-core/features/stats"
|
||||
"github.com/xtls/xray-core/transport"
|
||||
"github.com/xtls/xray-core/transport/internet"
|
||||
"github.com/xtls/xray-core/transport/internet/reality"
|
||||
"github.com/xtls/xray-core/transport/internet/stat"
|
||||
"github.com/xtls/xray-core/transport/internet/tls"
|
||||
)
|
||||
|
||||
// An Inbound processes inbound connections.
|
||||
|
@ -47,3 +58,78 @@ type GetInbound interface {
|
|||
type GetOutbound interface {
|
||||
GetOutbound() Outbound
|
||||
}
|
||||
|
||||
// UnwrapRawConn support unwrap stats, tls, utls, reality and proxyproto conn and get raw tcp conn from it
|
||||
func UnwrapRawConn(conn net.Conn) (net.Conn, stats.Counter, stats.Counter) {
|
||||
var readCounter, writerCounter stats.Counter
|
||||
if conn != nil {
|
||||
statConn, ok := conn.(*stat.CounterConnection)
|
||||
if ok {
|
||||
conn = statConn.Connection
|
||||
readCounter = statConn.ReadCounter
|
||||
writerCounter = statConn.WriteCounter
|
||||
}
|
||||
if xc, ok := conn.(*gotls.Conn); ok {
|
||||
conn = xc.NetConn()
|
||||
} else if utlsConn, ok := conn.(*tls.UConn); ok {
|
||||
conn = utlsConn.NetConn()
|
||||
} else if realityConn, ok := conn.(*reality.Conn); ok {
|
||||
conn = realityConn.NetConn()
|
||||
} else if realityUConn, ok := conn.(*reality.UConn); ok {
|
||||
conn = realityUConn.NetConn()
|
||||
}
|
||||
if pc, ok := conn.(*proxyproto.Conn); ok {
|
||||
conn = pc.Raw()
|
||||
// 8192 > 4096, there is no need to process pc's bufReader
|
||||
}
|
||||
}
|
||||
return conn, readCounter, writerCounter
|
||||
}
|
||||
|
||||
// CopyRawConnIfExist use the most efficient copy method.
|
||||
// - If caller don't want to turn on splice, do not pass in both reader conn and writer conn
|
||||
// - writer are from *transport.Link
|
||||
func CopyRawConnIfExist(ctx context.Context, readerConn net.Conn, writerConn net.Conn, writer buf.Writer, timer signal.ActivityUpdater) error {
|
||||
readerConn, readCounter, _ := UnwrapRawConn(readerConn)
|
||||
writerConn, _, writeCounter := UnwrapRawConn(writerConn)
|
||||
reader := buf.NewReader(readerConn)
|
||||
if inbound := session.InboundFromContext(ctx); inbound != nil {
|
||||
if tc, ok := writerConn.(*net.TCPConn); ok && readerConn != nil && writerConn != nil && (runtime.GOOS == "linux" || runtime.GOOS == "android") {
|
||||
for inbound.CanSpliceCopy != 3 {
|
||||
if inbound.CanSpliceCopy == 1 {
|
||||
newError("CopyRawConn splice").WriteToLog(session.ExportIDToError(ctx))
|
||||
runtime.Gosched() // necessary
|
||||
w, err := tc.ReadFrom(readerConn)
|
||||
if readCounter != nil {
|
||||
readCounter.Add(w)
|
||||
}
|
||||
if writeCounter != nil {
|
||||
writeCounter.Add(w)
|
||||
}
|
||||
if err != nil && errors.Cause(err) != io.EOF {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
buffer, err := reader.ReadMultiBuffer()
|
||||
if !buffer.IsEmpty() {
|
||||
if readCounter != nil {
|
||||
readCounter.Add(int64(buffer.Len()))
|
||||
}
|
||||
timer.Update()
|
||||
if werr := writer.WriteMultiBuffer(buffer); werr != nil {
|
||||
return werr
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
newError("CopyRawConn readv").WriteToLog(session.ExportIDToError(ctx))
|
||||
if err := buf.Copy(reader, writer, buf.UpdateActivity(timer), buf.AddToStatCounter(readCounter)); err != nil {
|
||||
return newError("failed to process response").Base(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue