Improve multiplexer
This commit is contained in:
@@ -15,40 +15,44 @@ import (
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
"github.com/sagernet/sing/common/x/list"
|
||||
|
||||
"github.com/hashicorp/yamux"
|
||||
)
|
||||
|
||||
var _ N.Dialer = (*Client)(nil)
|
||||
|
||||
type Client struct {
|
||||
access sync.Mutex
|
||||
connections list.List[*yamux.Session]
|
||||
connections list.List[abstractSession]
|
||||
ctx context.Context
|
||||
dialer N.Dialer
|
||||
protocol Protocol
|
||||
maxConnections int
|
||||
minStreams int
|
||||
maxStreams int
|
||||
}
|
||||
|
||||
func NewClient(ctx context.Context, dialer N.Dialer, maxConnections int, minStreams int, maxStreams int) *Client {
|
||||
func NewClient(ctx context.Context, dialer N.Dialer, protocol Protocol, maxConnections int, minStreams int, maxStreams int) *Client {
|
||||
return &Client{
|
||||
ctx: ctx,
|
||||
dialer: dialer,
|
||||
protocol: protocol,
|
||||
maxConnections: maxConnections,
|
||||
minStreams: minStreams,
|
||||
maxStreams: maxStreams,
|
||||
}
|
||||
}
|
||||
|
||||
func NewClientWithOptions(ctx context.Context, dialer N.Dialer, options option.MultiplexOptions) N.Dialer {
|
||||
func NewClientWithOptions(ctx context.Context, dialer N.Dialer, options option.MultiplexOptions) (N.Dialer, error) {
|
||||
if !options.Enabled {
|
||||
return dialer
|
||||
return dialer, nil
|
||||
}
|
||||
if options.MaxConnections == 0 && options.MaxStreams == 0 {
|
||||
options.MinStreams = 8
|
||||
}
|
||||
return NewClient(ctx, dialer, options.MaxConnections, options.MinStreams, options.MaxStreams)
|
||||
protocol, err := ParseProtocol(options.Protocol)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewClient(ctx, dialer, protocol, options.MaxConnections, options.MinStreams, options.MaxStreams), nil
|
||||
}
|
||||
|
||||
func (c *Client) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||
@@ -80,8 +84,8 @@ func (c *Client) ListenPacket(ctx context.Context, destination M.Socksaddr) (net
|
||||
|
||||
func (c *Client) openStream() (net.Conn, error) {
|
||||
var (
|
||||
session *yamux.Session
|
||||
stream *yamux.Stream
|
||||
session abstractSession
|
||||
stream net.Conn
|
||||
err error
|
||||
)
|
||||
for attempts := 0; attempts < 2; attempts++ {
|
||||
@@ -89,7 +93,7 @@ func (c *Client) openStream() (net.Conn, error) {
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
stream, err = session.OpenStream()
|
||||
stream, err = session.Open()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
@@ -101,11 +105,11 @@ func (c *Client) openStream() (net.Conn, error) {
|
||||
return &wrapStream{stream}, nil
|
||||
}
|
||||
|
||||
func (c *Client) offer() (*yamux.Session, error) {
|
||||
func (c *Client) offer() (abstractSession, error) {
|
||||
c.access.Lock()
|
||||
defer c.access.Unlock()
|
||||
|
||||
sessions := make([]*yamux.Session, 0, c.maxConnections)
|
||||
sessions := make([]abstractSession, 0, c.maxConnections)
|
||||
for element := c.connections.Front(); element != nil; {
|
||||
if element.Value.IsClosed() {
|
||||
nextElement := element.Next()
|
||||
@@ -120,10 +124,7 @@ func (c *Client) offer() (*yamux.Session, error) {
|
||||
if sLen == 0 {
|
||||
return c.offerNew()
|
||||
}
|
||||
// session := common.MinBy(sessions, yamux.Session.NumStreams)
|
||||
session := common.MinBy(sessions, func(it *yamux.Session) int {
|
||||
return it.NumStreams()
|
||||
})
|
||||
session := common.MinBy(sessions, abstractSession.NumStreams)
|
||||
numStreams := session.NumStreams()
|
||||
if numStreams == 0 {
|
||||
return session, nil
|
||||
@@ -140,12 +141,12 @@ func (c *Client) offer() (*yamux.Session, error) {
|
||||
return c.offerNew()
|
||||
}
|
||||
|
||||
func (c *Client) offerNew() (*yamux.Session, error) {
|
||||
func (c *Client) offerNew() (abstractSession, error) {
|
||||
conn, err := c.dialer.DialContext(c.ctx, N.NetworkTCP, Destination)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
session, err := yamux.Client(conn, newMuxConfig())
|
||||
session, err := c.protocol.newClient(&protocolConn{Conn: conn, protocol: c.protocol})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -170,7 +171,7 @@ type ClientConn struct {
|
||||
}
|
||||
|
||||
func (c *ClientConn) readResponse() error {
|
||||
response, err := ReadResponse(c.Conn)
|
||||
response, err := ReadStreamResponse(c.Conn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -195,7 +196,7 @@ func (c *ClientConn) Write(b []byte) (n int, err error) {
|
||||
if c.requestWrite {
|
||||
return c.Conn.Write(b)
|
||||
}
|
||||
request := Request{
|
||||
request := StreamRequest{
|
||||
Network: N.NetworkTCP,
|
||||
Destination: c.destination,
|
||||
}
|
||||
@@ -203,7 +204,7 @@ func (c *ClientConn) Write(b []byte) (n int, err error) {
|
||||
defer common.KeepAlive(_buffer)
|
||||
buffer := common.Dup(_buffer)
|
||||
defer buffer.Release()
|
||||
EncodeRequest(request, buffer)
|
||||
EncodeStreamRequest(request, buffer)
|
||||
buffer.Write(b)
|
||||
_, err = c.Conn.Write(buffer.Bytes())
|
||||
if err != nil {
|
||||
@@ -255,7 +256,7 @@ type ClientPacketConn struct {
|
||||
}
|
||||
|
||||
func (c *ClientPacketConn) readResponse() error {
|
||||
response, err := ReadResponse(c.ExtendedConn)
|
||||
response, err := ReadStreamResponse(c.ExtendedConn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -285,7 +286,7 @@ func (c *ClientPacketConn) Read(b []byte) (n int, err error) {
|
||||
}
|
||||
|
||||
func (c *ClientPacketConn) writeRequest(payload []byte) (n int, err error) {
|
||||
request := Request{
|
||||
request := StreamRequest{
|
||||
Network: N.NetworkUDP,
|
||||
Destination: c.destination,
|
||||
}
|
||||
@@ -297,7 +298,7 @@ func (c *ClientPacketConn) writeRequest(payload []byte) (n int, err error) {
|
||||
defer common.KeepAlive(_buffer)
|
||||
buffer := common.Dup(_buffer)
|
||||
defer buffer.Release()
|
||||
EncodeRequest(request, buffer)
|
||||
EncodeStreamRequest(request, buffer)
|
||||
if len(payload) > 0 {
|
||||
common.Must(
|
||||
binary.Write(buffer, binary.BigEndian, uint16(len(payload))),
|
||||
@@ -363,7 +364,7 @@ type ClientPacketAddrConn struct {
|
||||
}
|
||||
|
||||
func (c *ClientPacketAddrConn) readResponse() error {
|
||||
response, err := ReadResponse(c.ExtendedConn)
|
||||
response, err := ReadStreamResponse(c.ExtendedConn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -399,7 +400,7 @@ func (c *ClientPacketAddrConn) ReadFrom(p []byte) (n int, addr net.Addr, err err
|
||||
}
|
||||
|
||||
func (c *ClientPacketAddrConn) writeRequest(payload []byte, destination M.Socksaddr) (n int, err error) {
|
||||
request := Request{
|
||||
request := StreamRequest{
|
||||
Network: N.NetworkUDP,
|
||||
Destination: c.destination,
|
||||
PacketAddr: true,
|
||||
@@ -412,7 +413,7 @@ func (c *ClientPacketAddrConn) writeRequest(payload []byte, destination M.Socksa
|
||||
defer common.KeepAlive(_buffer)
|
||||
buffer := common.Dup(_buffer)
|
||||
defer buffer.Release()
|
||||
EncodeRequest(request, buffer)
|
||||
EncodeStreamRequest(request, buffer)
|
||||
if len(payload) > 0 {
|
||||
common.Must(
|
||||
M.SocksaddrSerializer.WriteAddrPort(buffer, destination),
|
||||
|
||||
Reference in New Issue
Block a user