1
0
mirror of https://github.com/MetaCubeX/mihomo.git synced 2026-10-10 12:13:10 +08:00

chore: change the brutal negotiation in shadowquic to be asynchronous

This commit is contained in:
wwqgtxx
2026-07-16 00:02:50 +08:00
parent c079b0cc12
commit e9119858b2
5 changed files with 24 additions and 45 deletions
+4 -4
View File
@@ -1508,8 +1508,8 @@ proxies: # socks5
# zero-rtt: false # 官方 server 的 0-RTT 路径可能在 JLS 认证完成前读取用户状态(已确认影响 v0.3.11);使用官方 server 时必须在服务端关闭 zero-rtt
# keep-alive-interval: 10000
# congestion-controller: bbr # Available: "cubic", "new_reno", "bbr". Default: "cubic"
# up: 100 Mbps # enables brutal; client upload speed; requires mihomo ShadowQuic on both ends
# down: 100 Mbps # enables brutal; requested client download speed, capped by listener up; requires mihomo ShadowQuic on both ends
# up: 100 Mbps # enables brutal negotiation via a mihomo private extension; client upload speed; falls back to congestion-controller when unsupported
# down: 100 Mbps # enables brutal negotiation via a mihomo private extension; requested client download speed, capped by listener up; falls back to congestion-controller when unsupported
# cwnd: 10 # default: 32
# bbr-profile: "" # Available: "standard", "conservative", "aggressive". Default: "standard"
# max-datagram-frame-size: 1400
@@ -2271,8 +2271,8 @@ listeners:
# quic-versions: [v1] # 本机手动配置及探测失败时的版本;支持 v1/v2
# zero-rtt: true
# congestion-controller: bbr # Available: "cubic", "new_reno", "bbr". Default: "cubic"
# up: 100 Mbps # enables brutal; server upload/client download speed cap; requires mihomo ShadowQuic on both ends
# down: 100 Mbps # enables brutal; requested server download/client upload speed; requires mihomo ShadowQuic on both ends
# up: 100 Mbps # enables brutal negotiation via a mihomo private extension; server upload/client download speed cap; falls back to congestion-controller when unsupported
# down: 100 Mbps # enables brutal negotiation via a mihomo private extension; requested server download/client upload speed; falls back to congestion-controller when unsupported
# ignore-client-bandwidth: false # for brutal; ignore outbound down and use listener down/auto instead
# cwnd: 10 # default: 32
# bbr-profile: "" # Available: "standard", "conservative", "aggressive". Default: "standard"
+16 -17
View File
@@ -5,6 +5,7 @@ import (
"errors"
"net"
"sync"
"time"
C "github.com/metacubex/mihomo/constant"
@@ -52,43 +53,41 @@ func (c *Client) getConn(ctx context.Context) (*connState, error) {
if err != nil {
return nil, err
}
if err = c.configureCongestion(ctx, quicConn); err != nil {
_ = quicConn.CloseWithError(0, err.Error())
return nil, err
}
SetCongestionController(quicConn, c.option.CongestionController, c.option.CWND, c.option.BBRProfile)
c.conn = newConnState(quicConn)
if c.brutalEnabled() {
// Brutal is an optional upgrade; keep the connection usable while it is negotiated.
go c.negotiateBrutal(c.conn)
}
return c.conn, nil
}
func (c *Client) configureCongestion(ctx context.Context, quicConn *quic.Conn) error {
if !c.brutalEnabled() {
SetCongestionController(quicConn, c.option.CongestionController, c.option.CWND, c.option.BBRProfile)
return nil
}
stream, err := quicConn.OpenStreamSync(ctx)
func (c *Client) negotiateBrutal(state *connState) {
ctx, cancel := context.WithTimeout(state.ctx, brutalNegotiationTimeout)
defer cancel()
stream, err := state.quicConn.OpenStreamSync(ctx)
if err != nil {
return err
return
}
defer stream.Close()
_ = stream.SetDeadline(time.Now().Add(brutalNegotiationTimeout))
if err = WriteBrutalNegotiationRequest(stream, c.option.ReceiveBPS); err != nil {
return err
return
}
rx, rxAuto, err := ReadBrutalNegotiationResponse(stream)
if err != nil {
return err
return
}
actualTx := rx
if actualTx == 0 || actualTx > c.option.SendBPS {
actualTx = c.option.SendBPS
}
if !rxAuto && actualTx > 0 {
setBrutalCongestionController(quicConn, actualTx)
setBrutalCongestionController(state.quicConn, actualTx)
} else {
SetCongestionController(quicConn, "bbr", c.option.CWND, c.option.BBRProfile)
SetCongestionController(state.quicConn, "bbr", c.option.CWND, c.option.BBRProfile)
}
return nil
}
func (c *Client) brutalEnabled() bool {
+2
View File
@@ -4,6 +4,7 @@ import (
"encoding/binary"
"errors"
"io"
"time"
)
const (
@@ -16,6 +17,7 @@ const (
brutalNegotiationMaxPayloadLen = 64
brutalNegotiationFlagRxAuto byte = 1 << 0
brutalNegotiationTimeout = 10 * time.Second
)
var (
+2 -13
View File
@@ -49,9 +49,8 @@ func (s *Server) Serve() error {
if err != nil {
return err
}
if !s.brutalRequired() {
SetCongestionController(conn, s.option.CongestionController, s.option.CWND, s.option.BBRProfile)
}
// Application streams may arrive before Brutal negotiation completes.
SetCongestionController(conn, s.option.CongestionController, s.option.CWND, s.option.BBRProfile)
state := newConnState(conn)
go s.handleConnection(state)
}
@@ -79,11 +78,6 @@ func (s *Server) handleStream(state *connState, stream *quic.Stream) {
_ = conn.Close()
return
}
if command != CommandExtension && s.brutalRequired() && !state.isBrutalNegotiated() {
_ = conn.Close()
return
}
switch command {
case CommandConnect:
target, err := ReadRequestAddr(conn)
@@ -122,10 +116,6 @@ func (s *Server) handleStream(state *connState, stream *quic.Stream) {
}
}
func (s *Server) brutalRequired() bool {
return s.option.SendBPS > 0 || s.option.ReceiveBPS > 0
}
func (s *Server) handleBrutalNegotiation(state *connState, conn net.Conn) {
rx, err := ReadBrutalNegotiationRequest(conn)
if err != nil {
@@ -135,7 +125,6 @@ func (s *Server) handleBrutalNegotiation(state *connState, conn net.Conn) {
if err != nil {
return
}
state.markBrutalNegotiated()
if err = WriteBrutalNegotiationResponse(conn, s.option.ReceiveBPS, rxAuto); err != nil {
return
}
-11
View File
@@ -5,7 +5,6 @@ import (
"io"
"net"
"sync"
"sync/atomic"
"github.com/metacubex/mihomo/transport/socks5"
@@ -36,8 +35,6 @@ type connState struct {
nextID uint16
activeSend map[uint16]struct{}
recv map[uint16]*recvSlot
brutalNegotiated atomic.Bool
}
type recvSlot struct {
@@ -84,14 +81,6 @@ func (s *connState) closeWithError(code quic.ApplicationErrorCode, message strin
return s.quicConn.CloseWithError(code, message)
}
func (s *connState) markBrutalNegotiated() {
s.brutalNegotiated.Store(true)
}
func (s *connState) isBrutalNegotiated() bool {
return s.brutalNegotiated.Load()
}
func (s *connState) handleDatagrams() {
for {
message, err := s.quicConn.ReceiveDatagram(s.ctx)