mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-09-18 08:07:14 +00:00
fix(tuic): evict the oldest relay flow instead of refusing new clients
udpRelay.flowFor returned "max relay flows reached" once the table held maxRelayFlows entries, and only the idle sweep (every minute, two-minute cutoff) freed slots. One host sending a single datagram from each of 4096 source ports therefore locked every new TUIC client out of the inbound for up to two minutes, repeatably. A full table now evicts the flow last seen longest ago, which under such a flood is one of the junk flows, and the newcomer is admitted. TestUDPRelayFullTableAdmitsNewClient fails on the refusing code with a read timeout for the third client.
This commit is contained in:
@@ -125,3 +125,26 @@ func TestUDPRelayRefusesFlowsAfterClose(t *testing.T) {
|
||||
t.Fatalf("%d flow(s) registered after Close", n)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUDPRelayFullTableAdmitsNewClient(t *testing.T) {
|
||||
relay, err := startUDPRelay("127.0.0.1:0", doublingEcho(t), relayFlowIdle)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(relay.Close)
|
||||
relay.mu.Lock()
|
||||
relay.maxFlows = 2
|
||||
relay.mu.Unlock()
|
||||
|
||||
roundTrip(t, relay, []byte("a"))
|
||||
roundTrip(t, relay, []byte("b"))
|
||||
if got := roundTrip(t, relay, []byte("c")); got != 2 {
|
||||
t.Fatalf("third client reply = %d bytes, want 2: a full table must evict, not refuse", got)
|
||||
}
|
||||
relay.mu.Lock()
|
||||
n := len(relay.flows)
|
||||
relay.mu.Unlock()
|
||||
if n != 2 {
|
||||
t.Fatalf("flow table holds %d flows after admitting a third client, want the cap of 2", n)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user