mirror of
https://github.com/XTLS/Xray-core.git
synced 2025-04-30 09:18:34 +00:00
Add session context outbounds as slice (#3356)
* Add session context outbounds as slice slice is needed for dialer proxy where two outbounds work on top of each other There are two sets of target addr for example It also enable Xtls to correctly do splice copy by checking both outbounds are ready to do direct copy * Fill outbound tag info * Splice now checks capalibility from all outbounds * Fix unit tests
This commit is contained in:
parent
0735053348
commit
017f53b5fc
42 changed files with 303 additions and 236 deletions
102
proxy/proxy.go
102
proxy/proxy.go
|
@ -474,45 +474,73 @@ func CopyRawConnIfExist(ctx context.Context, readerConn net.Conn, writerConn net
|
|||
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))
|
||||
statWriter, _ := writer.(*dispatcher.SizeStatWriter)
|
||||
//runtime.Gosched() // necessary
|
||||
time.Sleep(time.Millisecond) // without this, there will be a rare ssl error for freedom splice
|
||||
w, err := tc.ReadFrom(readerConn)
|
||||
if readCounter != nil {
|
||||
readCounter.Add(w) // outbound stats
|
||||
}
|
||||
if writeCounter != nil {
|
||||
writeCounter.Add(w) // inbound stats
|
||||
}
|
||||
if statWriter != nil {
|
||||
statWriter.Counter.Add(w) // user stats
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
if runtime.GOOS != "linux" && runtime.GOOS != "android" {
|
||||
return readV(ctx, reader, writer, timer, readCounter)
|
||||
}
|
||||
tc, ok := writerConn.(*net.TCPConn)
|
||||
if !ok || readerConn == nil || writerConn == nil {
|
||||
return readV(ctx, reader, writer, timer, readCounter)
|
||||
}
|
||||
inbound := session.InboundFromContext(ctx)
|
||||
if inbound == nil || inbound.CanSpliceCopy == 3 {
|
||||
return readV(ctx, reader, writer, timer, readCounter)
|
||||
}
|
||||
outbounds := session.OutboundsFromContext(ctx)
|
||||
if len(outbounds) == 0 {
|
||||
return readV(ctx, reader, writer, timer, readCounter)
|
||||
}
|
||||
for _, ob := range outbounds {
|
||||
if ob.CanSpliceCopy == 3 {
|
||||
return readV(ctx, reader, writer, timer, readCounter)
|
||||
}
|
||||
}
|
||||
|
||||
for {
|
||||
inbound := session.InboundFromContext(ctx)
|
||||
outbounds := session.OutboundsFromContext(ctx)
|
||||
var splice = inbound.CanSpliceCopy == 1
|
||||
for _, ob := range outbounds {
|
||||
if ob.CanSpliceCopy != 1 {
|
||||
splice = false
|
||||
}
|
||||
}
|
||||
if splice {
|
||||
newError("CopyRawConn splice").WriteToLog(session.ExportIDToError(ctx))
|
||||
statWriter, _ := writer.(*dispatcher.SizeStatWriter)
|
||||
//runtime.Gosched() // necessary
|
||||
time.Sleep(time.Millisecond) // without this, there will be a rare ssl error for freedom splice
|
||||
w, err := tc.ReadFrom(readerConn)
|
||||
if readCounter != nil {
|
||||
readCounter.Add(w) // outbound stats
|
||||
}
|
||||
if writeCounter != nil {
|
||||
writeCounter.Add(w) // inbound stats
|
||||
}
|
||||
if statWriter != nil {
|
||||
statWriter.Counter.Add(w) // user stats
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func readV(ctx context.Context, reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater, readCounter stats.Counter) error {
|
||||
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)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue