github.com/sagernet/sing@v0.2.6/common/network/thread.go (about)

     1  package network
     2  
     3  import (
     4  	"github.com/sagernet/sing/common"
     5  	"github.com/sagernet/sing/common/buf"
     6  	M "github.com/sagernet/sing/common/metadata"
     7  )
     8  
     9  type ThreadUnsafeWriter interface {
    10  	WriteIsThreadUnsafe()
    11  }
    12  
    13  type ThreadSafeReader interface {
    14  	ReadBufferThreadSafe() (buffer *buf.Buffer, err error)
    15  }
    16  
    17  type ThreadSafePacketReader interface {
    18  	ReadPacketThreadSafe() (buffer *buf.Buffer, addr M.Socksaddr, err error)
    19  }
    20  
    21  func IsUnsafeWriter(writer any) bool {
    22  	_, isUnsafe := common.Cast[ThreadUnsafeWriter](writer)
    23  	return isUnsafe
    24  }
    25  
    26  func IsSafeReader(reader any) ThreadSafeReader {
    27  	if safeReader, isSafe := reader.(ThreadSafeReader); isSafe {
    28  		return safeReader
    29  	}
    30  	if upstream, hasUpstream := reader.(ReaderWithUpstream); !hasUpstream || !upstream.ReaderReplaceable() {
    31  		return nil
    32  	}
    33  	if upstream, hasUpstream := reader.(common.WithUpstream); hasUpstream {
    34  		return IsSafeReader(upstream.Upstream())
    35  	}
    36  	if upstream, hasUpstream := reader.(WithUpstreamReader); hasUpstream {
    37  		return IsSafeReader(upstream.UpstreamReader())
    38  	}
    39  	return nil
    40  }
    41  
    42  func IsSafePacketReader(reader any) ThreadSafePacketReader {
    43  	if safeReader, isSafe := reader.(ThreadSafePacketReader); isSafe {
    44  		return safeReader
    45  	}
    46  	if upstream, hasUpstream := reader.(ReaderWithUpstream); !hasUpstream || !upstream.ReaderReplaceable() {
    47  		return nil
    48  	}
    49  	if upstream, hasUpstream := reader.(common.WithUpstream); hasUpstream {
    50  		return IsSafePacketReader(upstream.Upstream())
    51  	}
    52  	if upstream, hasUpstream := reader.(WithUpstreamReader); hasUpstream {
    53  		return IsSafePacketReader(upstream.UpstreamReader())
    54  	}
    55  	return nil
    56  }
    57  
    58  const DefaultHeadroom = 1024
    59  
    60  type FrontHeadroom interface {
    61  	FrontHeadroom() int
    62  }
    63  
    64  type RearHeadroom interface {
    65  	RearHeadroom() int
    66  }
    67  
    68  type LazyHeadroom interface {
    69  	LazyHeadroom() bool
    70  }
    71  
    72  func CalculateFrontHeadroom(writer any) int {
    73  	var headroom int
    74  	for {
    75  		if writer == nil {
    76  			break
    77  		}
    78  		if lazyRoom, isLazy := writer.(LazyHeadroom); isLazy && lazyRoom.LazyHeadroom() {
    79  			return DefaultHeadroom
    80  		}
    81  		if headroomWriter, needHeadroom := writer.(FrontHeadroom); needHeadroom {
    82  			headroom += headroomWriter.FrontHeadroom()
    83  		}
    84  		if upstreamWriter, hasUpstreamWriter := writer.(WithUpstreamWriter); hasUpstreamWriter {
    85  			writer = upstreamWriter.UpstreamWriter()
    86  		} else if upstream, hasUpstream := writer.(common.WithUpstream); hasUpstream {
    87  			writer = upstream.Upstream()
    88  		} else {
    89  			break
    90  		}
    91  	}
    92  	return headroom
    93  }
    94  
    95  func CalculateRearHeadroom(writer any) int {
    96  	var headroom int
    97  	for {
    98  		if writer == nil {
    99  			break
   100  		}
   101  		if lazyRoom, isLazy := writer.(LazyHeadroom); isLazy && lazyRoom.LazyHeadroom() {
   102  			return DefaultHeadroom
   103  		}
   104  		if headroomWriter, needHeadroom := writer.(RearHeadroom); needHeadroom {
   105  			headroom += headroomWriter.RearHeadroom()
   106  		}
   107  		if upstreamWriter, hasUpstreamWriter := writer.(WithUpstreamWriter); hasUpstreamWriter {
   108  			writer = upstreamWriter.UpstreamWriter()
   109  		} else if upstream, hasUpstream := writer.(common.WithUpstream); hasUpstream {
   110  			writer = upstream.Upstream()
   111  		} else {
   112  			break
   113  		}
   114  	}
   115  	return headroom
   116  }
   117  
   118  type ReaderWithMTU interface {
   119  	ReaderMTU() int
   120  }
   121  
   122  type WriterWithMTU interface {
   123  	WriterMTU() int
   124  }
   125  
   126  func CalculateMTU(reader any, writer any) int {
   127  	readerMTU := calculateReaderMTU(reader)
   128  	writerMTU := calculateWriterMTU(writer)
   129  	if readerMTU > writerMTU {
   130  		return readerMTU
   131  	}
   132  	if writerMTU > buf.BufferSize {
   133  		return 0
   134  	}
   135  	return writerMTU
   136  }
   137  
   138  func calculateReaderMTU(reader any) int {
   139  	var mtu int
   140  	for {
   141  		if reader == nil {
   142  			break
   143  		}
   144  		if lazyRoom, isLazy := reader.(LazyHeadroom); isLazy && lazyRoom.LazyHeadroom() {
   145  			return 0
   146  		}
   147  		if withMTU, haveMTU := reader.(ReaderWithMTU); haveMTU {
   148  			upstreamMTU := withMTU.ReaderMTU()
   149  			if upstreamMTU > mtu {
   150  				mtu = upstreamMTU
   151  			}
   152  		}
   153  		if upstreamReader, hasUpstreamReader := reader.(WithUpstreamReader); hasUpstreamReader {
   154  			reader = upstreamReader.UpstreamReader()
   155  		} else if upstream, hasUpstream := reader.(common.WithUpstream); hasUpstream {
   156  			reader = upstream.Upstream()
   157  		} else {
   158  			break
   159  		}
   160  	}
   161  	return mtu
   162  }
   163  
   164  func calculateWriterMTU(writer any) int {
   165  	var mtu int
   166  	for {
   167  		if writer == nil {
   168  			break
   169  		}
   170  		if lazyRoom, isLazy := writer.(LazyHeadroom); isLazy && lazyRoom.LazyHeadroom() {
   171  			return 0
   172  		}
   173  		if withMTU, haveMTU := writer.(WriterWithMTU); haveMTU {
   174  			upstreamMTU := withMTU.WriterMTU()
   175  			if mtu == 0 || upstreamMTU > 0 && upstreamMTU < mtu {
   176  				mtu = upstreamMTU
   177  			}
   178  		}
   179  		if upstreamWriter, hasUpstreamWriter := writer.(WithUpstreamWriter); hasUpstreamWriter {
   180  			writer = upstreamWriter.UpstreamWriter()
   181  		} else if upstream, hasUpstream := writer.(common.WithUpstream); hasUpstream {
   182  			writer = upstream.Upstream()
   183  		} else {
   184  			break
   185  		}
   186  	}
   187  	return mtu
   188  }