|
@@ -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)
|