Skip to content

Commit 301d832

Browse files
committed
Trim client MTU probing overhead and remove unused MTU result state
1 parent f53bc6f commit 301d832

File tree

4 files changed

+79
-81
lines changed

4 files changed

+79
-81
lines changed

TODO

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
Check Clean for server and client.
22
Client Reconnect.
3-
Client to server: Notify End of Session.
3+
loop for reconnect/test mtu, and notify end of session.

internal/client/client.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ type Client struct {
6363
stream0Runtime *stream0Runtime
6464
streamsMu sync.RWMutex
6565
streams map[uint16]*clientStream
66+
mtuTestRetries int
67+
mtuTestTimeout time.Duration
6668
streamTXWindow int
6769
streamTXQueueLimit int
6870
streamTXMaxRetries int
@@ -161,6 +163,8 @@ func New(cfg config.ClientConfig, log *logger.Logger, codec *security.Codec) *Cl
161163
),
162164
localDNSFragTTL: time.Duration(cfg.LocalDNSFragmentTimeoutSec * float64(time.Second)),
163165
streams: make(map[uint16]*clientStream, 16),
166+
mtuTestRetries: cfg.MTUTestRetries,
167+
mtuTestTimeout: time.Duration(cfg.MTUTestTimeout * float64(time.Second)),
164168
streamTXWindow: cfg.StreamTXWindow,
165169
streamTXQueueLimit: cfg.StreamTXQueueLimit,
166170
streamTXMaxRetries: cfg.StreamTXMaxRetries,
@@ -169,12 +173,23 @@ func New(cfg config.ClientConfig, log *logger.Logger, codec *security.Codec) *Cl
169173
resolverRecheck: make(map[string]resolverRecheckState, len(cfg.Domains)*len(cfg.Resolvers)),
170174
runtimeDisabled: make(map[string]resolverDisabledState, len(cfg.Domains)*len(cfg.Resolvers)),
171175
}
176+
172177
if c.localDNSCacheFlushTick <= 0 {
173178
c.localDNSCacheFlushTick = time.Minute
174179
}
180+
175181
if c.localDNSFragTTL <= 0 {
176182
c.localDNSFragTTL = 5 * time.Minute
177183
}
184+
185+
if c.mtuTestRetries < 1 {
186+
c.mtuTestRetries = 1
187+
}
188+
189+
if c.mtuTestTimeout <= 0 {
190+
c.mtuTestTimeout = time.Second
191+
}
192+
178193
c.ResetRuntimeState(true)
179194
c.uploadCompression = uint8(cfg.UploadCompressionType)
180195
c.downloadCompression = uint8(cfg.DownloadCompressionType)

internal/client/mtu.go

Lines changed: 62 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import (
1313
"encoding/binary"
1414
"errors"
1515
"sync"
16-
"time"
1716

1817
DnsParser "masterdnsvpn-go/internal/dnsparser"
1918
Enums "masterdnsvpn-go/internal/enums"
@@ -31,10 +30,7 @@ const (
3130
defaultUploadMaxCap = 512
3231
)
3332

34-
type MTUResult struct {
35-
UploadBytes int
36-
DownloadBytes int
37-
}
33+
const mtuProbeFillPattern = "MasterDnsVPN-MTU-Probe-Fill-Pattern-2026"
3834

3935
func (c *Client) RunInitialMTUTests() error {
4036
if len(c.connections) == 0 {
@@ -51,14 +47,12 @@ func (c *Client) RunInitialMTUTests() error {
5147
jobs := make(chan int, len(c.connections))
5248
var wg sync.WaitGroup
5349
for range workerCount {
54-
wg.Add(1)
55-
go func() {
56-
defer wg.Done()
50+
wg.Go(func() {
5751
for idx := range jobs {
5852
conn := &c.connections[idx]
5953
c.safeRunConnectionMTUTest(conn, uploadCaps[conn.Domain])
6054
}
61-
}()
55+
})
6256
}
6357
for idx := range c.connections {
6458
jobs <- idx
@@ -67,22 +61,16 @@ func (c *Client) RunInitialMTUTests() error {
6761
wg.Wait()
6862
}
6963

70-
validCount := 0
71-
for _, conn := range c.connections {
72-
if conn.IsValid {
73-
validCount++
74-
}
75-
}
76-
7764
c.balancer.RefreshValidConnections()
65+
validCount, minUpload, minDownload, minUploadChars := summarizeConnectionMTUStats(c.connections, c)
7866
if validCount == 0 {
7967
return ErrNoValidConnections
8068
}
8169

8270
c.successMTUChecks = true
83-
c.syncedUploadMTU = minConnectionMTU(c.connections, true)
84-
c.syncedDownloadMTU = minConnectionMTU(c.connections, false)
85-
c.syncedUploadChars = minConnectionUploadChars(c.connections, c)
71+
c.syncedUploadMTU = minUpload
72+
c.syncedDownloadMTU = minDownload
73+
c.syncedUploadChars = minUploadChars
8674
c.initResolverRecheckMeta()
8775
c.updateMaxPackedBlocks()
8876
return nil
@@ -194,21 +182,15 @@ func (c *Client) binarySearchMTU(minValue, maxValue int, testFn func(int) (bool,
194182
return 0
195183
}
196184

197-
cache := make(map[int]bool, 8)
198185
check := func(value int) bool {
199-
if cached, ok := cache[value]; ok {
200-
return cached
201-
}
202-
203186
ok := false
204-
for attempt := 0; attempt < max(1, c.cfg.MTUTestRetries); attempt++ {
187+
for attempt := 0; attempt < c.mtuTestRetries; attempt++ {
205188
passed, err := testFn(value)
206189
if err == nil && passed {
207190
ok = true
208191
break
209192
}
210193
}
211-
cache[value] = ok
212194
return ok
213195
}
214196

@@ -242,33 +224,22 @@ func (c *Client) sendUploadMTUProbe(conn *Connection, probeTransport *udpQueryTr
242224
return false, nil
243225
}
244226

245-
payload := make([]byte, mtuSize)
246-
payload[0] = mtuProbeRawResponse
247-
if c.cfg.BaseEncodeData {
248-
payload[0] = mtuProbeBase64Reply
249-
}
250-
code, err := randomBytes(mtuProbeCodeLength)
227+
payload, code, useBase64, err := c.buildMTUProbePayload(mtuSize, 0)
251228
if err != nil {
252229
return false, err
253230
}
254-
copy(payload[1:1+mtuProbeCodeLength], code)
255-
if len(payload) > 1+mtuProbeCodeLength {
256-
if _, err := rand.Read(payload[1+mtuProbeCodeLength:]); err != nil {
257-
return false, err
258-
}
259-
}
260231

261232
query, err := c.buildMTUProbeQuery(conn.Domain, Enums.PACKET_MTU_UP_REQ, payload)
262233
if err != nil {
263234
return false, nil
264235
}
265236

266-
response, err := exchangeUDPQuery(probeTransport, query, time.Duration(c.cfg.MTUTestTimeout*float64(time.Second)))
237+
response, err := exchangeUDPQuery(probeTransport, query, c.mtuTestTimeout)
267238
if err != nil {
268239
return false, nil
269240
}
270241

271-
packet, err := DnsParser.ExtractVPNResponse(response, payload[0] == mtuProbeBase64Reply)
242+
packet, err := DnsParser.ExtractVPNResponse(response, useBase64)
272243
if err != nil {
273244
return false, nil
274245
}
@@ -293,34 +264,23 @@ func (c *Client) sendDownloadMTUProbe(conn *Connection, probeTransport *udpQuery
293264
}
294265

295266
requestLen := max(1+mtuProbeCodeLength+2, uploadMTU)
296-
payload := make([]byte, requestLen)
297-
payload[0] = mtuProbeRawResponse
298-
if c.cfg.BaseEncodeData {
299-
payload[0] = mtuProbeBase64Reply
300-
}
301-
code, err := randomBytes(mtuProbeCodeLength)
267+
payload, code, useBase64, err := c.buildMTUProbePayload(requestLen, 2)
302268
if err != nil {
303269
return false, err
304270
}
305-
copy(payload[1:1+mtuProbeCodeLength], code)
306271
binary.BigEndian.PutUint16(payload[1+mtuProbeCodeLength:1+mtuProbeCodeLength+2], uint16(mtuSize))
307-
if len(payload) > 1+mtuProbeCodeLength+2 {
308-
if _, err := rand.Read(payload[1+mtuProbeCodeLength+2:]); err != nil {
309-
return false, err
310-
}
311-
}
312272

313273
query, err := c.buildMTUProbeQuery(conn.Domain, Enums.PACKET_MTU_DOWN_REQ, payload)
314274
if err != nil {
315275
return false, nil
316276
}
317277

318-
response, err := exchangeUDPQuery(probeTransport, query, time.Duration(c.cfg.MTUTestTimeout*float64(time.Second)))
278+
response, err := exchangeUDPQuery(probeTransport, query, c.mtuTestTimeout)
319279
if err != nil {
320280
return false, nil
321281
}
322282

323-
packet, err := DnsParser.ExtractVPNResponse(response, payload[0] == mtuProbeBase64Reply)
283+
packet, err := DnsParser.ExtractVPNResponse(response, useBase64)
324284
if err != nil {
325285
return false, nil
326286
}
@@ -400,6 +360,43 @@ func (c *Client) canBuildUploadPayload(domain string, payloadLen int) bool {
400360
return err == nil
401361
}
402362

363+
func (c *Client) buildMTUProbePayload(length int, reservedTailPrefix int) ([]byte, []byte, bool, error) {
364+
if length <= 0 {
365+
return nil, nil, false, nil
366+
}
367+
368+
payload := make([]byte, length)
369+
useBase64 := c != nil && c.cfg.BaseEncodeData
370+
payload[0] = mtuProbeRawResponse
371+
if useBase64 {
372+
payload[0] = mtuProbeBase64Reply
373+
}
374+
375+
code, err := randomBytes(mtuProbeCodeLength)
376+
if err != nil {
377+
return nil, nil, false, err
378+
}
379+
copy(payload[1:1+mtuProbeCodeLength], code)
380+
381+
fillOffset := 1 + mtuProbeCodeLength + reservedTailPrefix
382+
if fillOffset < len(payload) {
383+
fillMTUProbeBytes(payload[fillOffset:])
384+
}
385+
386+
return payload, code, useBase64, nil
387+
}
388+
389+
func fillMTUProbeBytes(dst []byte) {
390+
if len(dst) == 0 {
391+
return
392+
}
393+
pattern := mtuProbeFillPattern
394+
offset := 0
395+
for offset < len(dst) {
396+
offset += copy(dst[offset:], pattern)
397+
}
398+
}
399+
403400
func randomBytes(length int) ([]byte, error) {
404401
if length <= 0 {
405402
return []byte{}, nil
@@ -411,41 +408,28 @@ func randomBytes(length int) ([]byte, error) {
411408
return buf, nil
412409
}
413410

414-
func minConnectionMTU(connections []Connection, upload bool) int {
415-
best := 0
411+
func summarizeConnectionMTUStats(connections []Connection, c *Client) (validCount int, minUpload int, minDownload int, minUploadChars int) {
416412
for _, conn := range connections {
417413
if !conn.IsValid {
418414
continue
419415
}
420-
value := conn.DownloadMTUBytes
421-
if upload {
422-
value = conn.UploadMTUBytes
423-
}
424-
if value <= 0 {
425-
continue
416+
validCount++
417+
418+
if conn.UploadMTUBytes > 0 && (minUpload == 0 || conn.UploadMTUBytes < minUpload) {
419+
minUpload = conn.UploadMTUBytes
426420
}
427-
if best == 0 || value < best {
428-
best = value
421+
if conn.DownloadMTUBytes > 0 && (minDownload == 0 || conn.DownloadMTUBytes < minDownload) {
422+
minDownload = conn.DownloadMTUBytes
429423
}
430-
}
431-
return best
432-
}
433-
434-
func minConnectionUploadChars(connections []Connection, c *Client) int {
435-
best := 0
436-
for _, conn := range connections {
437-
if !conn.IsValid || conn.UploadMTUBytes <= 0 {
424+
if conn.UploadMTUBytes <= 0 || c == nil {
438425
continue
439426
}
440427
value := c.encodedCharsForPayload(conn.UploadMTUBytes)
441-
if value <= 0 {
442-
continue
443-
}
444-
if best == 0 || value < best {
445-
best = value
428+
if value > 0 && (minUploadChars == 0 || value < minUploadChars) {
429+
minUploadChars = value
446430
}
447431
}
448-
return best
432+
return validCount, minUpload, minDownload, minUploadChars
449433
}
450434

451435
func (c *Client) encodedCharsForPayload(payloadLen int) int {

internal/client/session.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import (
1111
"bytes"
1212
"encoding/binary"
1313
"errors"
14-
"time"
1514

1615
"masterdnsvpn-go/internal/compression"
1716
DnsParser "masterdnsvpn-go/internal/dnsparser"
@@ -58,7 +57,7 @@ func (c *Client) InitializeSession(maxAttempts int) error {
5857
continue
5958
}
6059

61-
response, err := exchangeUDPQuery(transport, query, time.Duration(c.cfg.MTUTestTimeout*float64(time.Second)))
60+
response, err := exchangeUDPQuery(transport, query, c.mtuTestTimeout)
6261
_ = transport.conn.Close()
6362
if err != nil {
6463
c.SetConnectionValidity(conn.Key, false)

0 commit comments

Comments
 (0)