Skip to content

Commit 3a77d47

Browse files
authored
Merge pull request #825 from apernet/wip-hsinfo
feat: client handshake info
2 parents ee3a23f + faeef50 commit 3a77d47

File tree

8 files changed

+148
-34
lines changed

8 files changed

+148
-34
lines changed

app/cmd/client.go

+7-4
Original file line numberDiff line numberDiff line change
@@ -402,8 +402,8 @@ func runClient(cmd *cobra.Command, args []string) {
402402
logger.Fatal("failed to load client config", zap.Error(err))
403403
}
404404

405-
c, err := client.NewReconnectableClient(hyConfig, func(c client.Client, count int) {
406-
connectLog(count)
405+
c, err := client.NewReconnectableClient(hyConfig, func(c client.Client, info *client.HandshakeInfo, count int) {
406+
connectLog(info, count)
407407
// On the client side, we start checking for updates after we successfully connect
408408
// to the server, which, depending on whether lazy mode is enabled, may or may not
409409
// be immediately after the client starts. We don't want the update check request
@@ -699,8 +699,11 @@ func (f *adaptiveConnFactory) New(addr net.Addr) (net.PacketConn, error) {
699699
}
700700
}
701701

702-
func connectLog(count int) {
703-
logger.Info("connected to server", zap.Int("count", count))
702+
func connectLog(info *client.HandshakeInfo, count int) {
703+
logger.Info("connected to server",
704+
zap.Bool("udpEnabled", info.UDPEnabled),
705+
zap.Uint64("tx", info.Tx),
706+
zap.Int("count", count))
704707
}
705708

706709
type socks5Logger struct{}

app/cmd/ping.go

+5-2
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,16 @@ func runPing(cmd *cobra.Command, args []string) {
4242
logger.Fatal("failed to load client config", zap.Error(err))
4343
}
4444

45-
c, err := client.NewClient(hyConfig)
45+
c, info, err := client.NewClient(hyConfig)
4646
if err != nil {
4747
logger.Fatal("failed to initialize client", zap.Error(err))
4848
}
4949
defer c.Close()
50+
logger.Info("connected to server",
51+
zap.Bool("udpEnabled", info.UDPEnabled),
52+
zap.Uint64("tx", info.Tx))
5053

51-
logger.Info("connecting", zap.String("address", addr))
54+
logger.Info("connecting", zap.String("addr", addr))
5255
start := time.Now()
5356
conn, err := c.TCP(addr)
5457
if err != nil {

core/client/client.go

+21-11
Original file line numberDiff line numberDiff line change
@@ -34,17 +34,23 @@ type HyUDPConn interface {
3434
Close() error
3535
}
3636

37-
func NewClient(config *Config) (Client, error) {
37+
type HandshakeInfo struct {
38+
UDPEnabled bool
39+
Tx uint64 // 0 if using BBR
40+
}
41+
42+
func NewClient(config *Config) (Client, *HandshakeInfo, error) {
3843
if err := config.verifyAndFill(); err != nil {
39-
return nil, err
44+
return nil, nil, err
4045
}
4146
c := &clientImpl{
4247
config: config,
4348
}
44-
if err := c.connect(); err != nil {
45-
return nil, err
49+
info, err := c.connect()
50+
if err != nil {
51+
return nil, nil, err
4652
}
47-
return c, nil
53+
return c, info, nil
4854
}
4955

5056
type clientImpl struct {
@@ -56,10 +62,10 @@ type clientImpl struct {
5662
udpSM *udpSessionManager
5763
}
5864

59-
func (c *clientImpl) connect() error {
65+
func (c *clientImpl) connect() (*HandshakeInfo, error) {
6066
pktConn, err := c.config.ConnFactory.New(c.config.ServerAddr)
6167
if err != nil {
62-
return err
68+
return nil, err
6369
}
6470
// Convert config to TLS config & QUIC config
6571
tlsConfig := &tls.Config{
@@ -113,22 +119,23 @@ func (c *clientImpl) connect() error {
113119
_ = conn.CloseWithError(closeErrCodeProtocolError, "")
114120
}
115121
_ = pktConn.Close()
116-
return coreErrs.ConnectError{Err: err}
122+
return nil, coreErrs.ConnectError{Err: err}
117123
}
118124
if resp.StatusCode != protocol.StatusAuthOK {
119125
_ = conn.CloseWithError(closeErrCodeProtocolError, "")
120126
_ = pktConn.Close()
121-
return coreErrs.AuthError{StatusCode: resp.StatusCode}
127+
return nil, coreErrs.AuthError{StatusCode: resp.StatusCode}
122128
}
123129
// Auth OK
124130
authResp := protocol.AuthResponseFromHeader(resp.Header)
131+
var actualTx uint64
125132
if authResp.RxAuto {
126133
// Server asks client to use bandwidth detection,
127134
// ignore local bandwidth config and use BBR
128135
congestion.UseBBR(conn)
129136
} else {
130137
// actualTx = min(serverRx, clientTx)
131-
actualTx := authResp.Rx
138+
actualTx = authResp.Rx
132139
if actualTx == 0 || actualTx > c.config.BandwidthConfig.MaxTx {
133140
// Server doesn't have a limit, or our clientTx is smaller than serverRx
134141
actualTx = c.config.BandwidthConfig.MaxTx
@@ -147,7 +154,10 @@ func (c *clientImpl) connect() error {
147154
if authResp.UDPEnabled {
148155
c.udpSM = newUDPSessionManager(&udpIOImpl{Conn: conn})
149156
}
150-
return nil
157+
return &HandshakeInfo{
158+
UDPEnabled: authResp.UDPEnabled,
159+
Tx: actualTx,
160+
}, nil
151161
}
152162

153163
// openStream wraps the stream with QStream, which handles Close() properly

core/client/reconnect.go

+5-4
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,12 @@ type reconnectableClientImpl struct {
1313
config *Config
1414
client Client
1515
count int
16-
connectedFunc func(Client, int) // called when successfully connected
16+
connectedFunc func(Client, *HandshakeInfo, int) // called when successfully connected
1717
m sync.Mutex
1818
closed bool // permanent close
1919
}
2020

21-
func NewReconnectableClient(config *Config, connectedFunc func(Client, int), lazy bool) (Client, error) {
21+
func NewReconnectableClient(config *Config, connectedFunc func(Client, *HandshakeInfo, int), lazy bool) (Client, error) {
2222
// Make sure we capture any error in config and return it here,
2323
// so that the caller doesn't have to wait until the first call
2424
// to TCP() or UDP() to get the error (when lazy is true).
@@ -42,13 +42,14 @@ func (rc *reconnectableClientImpl) reconnect() error {
4242
_ = rc.client.Close()
4343
}
4444
var err error
45-
rc.client, err = NewClient(rc.config)
45+
var info *HandshakeInfo
46+
rc.client, info, err = NewClient(rc.config)
4647
if err != nil {
4748
return err
4849
} else {
4950
rc.count++
5051
if rc.connectedFunc != nil {
51-
rc.connectedFunc(rc, rc.count)
52+
rc.connectedFunc(rc, info, rc.count)
5253
}
5354
return nil
5455
}

core/internal/integration_tests/close_test.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ func TestClientServerTCPClose(t *testing.T) {
3434
go s.Serve()
3535

3636
// Create client
37-
c, err := client.NewClient(&client.Config{
37+
c, _, err := client.NewClient(&client.Config{
3838
ServerAddr: udpAddr,
3939
TLSConfig: client.TLSConfig{InsecureSkipVerify: true},
4040
})
@@ -116,7 +116,7 @@ func TestClientServerUDPIdleTimeout(t *testing.T) {
116116
go s.Serve()
117117

118118
// Create client
119-
c, err := client.NewClient(&client.Config{
119+
c, _, err := client.NewClient(&client.Config{
120120
ServerAddr: udpAddr,
121121
TLSConfig: client.TLSConfig{InsecureSkipVerify: true},
122122
})
@@ -194,7 +194,7 @@ func TestClientServerClientShutdown(t *testing.T) {
194194
go s.Serve()
195195

196196
// Create client
197-
c, err := client.NewClient(&client.Config{
197+
c, _, err := client.NewClient(&client.Config{
198198
ServerAddr: udpAddr,
199199
TLSConfig: client.TLSConfig{InsecureSkipVerify: true},
200200
})
@@ -223,7 +223,7 @@ func TestClientServerServerShutdown(t *testing.T) {
223223
go s.Serve()
224224

225225
// Create client
226-
c, err := client.NewClient(&client.Config{
226+
c, _, err := client.NewClient(&client.Config{
227227
ServerAddr: udpAddr,
228228
TLSConfig: client.TLSConfig{InsecureSkipVerify: true},
229229
QUICConfig: client.QUICConfig{

core/internal/integration_tests/smoke_test.go

+102-5
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import (
1919
// TestClientNoServer tests how the client handles a server address it cannot connect to.
2020
// NewClient should return a ConnectError.
2121
func TestClientNoServer(t *testing.T) {
22-
c, err := client.NewClient(&client.Config{
22+
c, _, err := client.NewClient(&client.Config{
2323
ServerAddr: &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 55666},
2424
})
2525
assert.Nil(t, c)
@@ -46,7 +46,7 @@ func TestClientServerBadAuth(t *testing.T) {
4646
go s.Serve()
4747

4848
// Create client
49-
c, err := client.NewClient(&client.Config{
49+
c, _, err := client.NewClient(&client.Config{
5050
ServerAddr: udpAddr,
5151
Auth: "badpassword",
5252
TLSConfig: client.TLSConfig{InsecureSkipVerify: true},
@@ -75,7 +75,7 @@ func TestClientServerUDPDisabled(t *testing.T) {
7575
go s.Serve()
7676

7777
// Create client
78-
c, err := client.NewClient(&client.Config{
78+
c, _, err := client.NewClient(&client.Config{
7979
ServerAddr: udpAddr,
8080
TLSConfig: client.TLSConfig{InsecureSkipVerify: true},
8181
})
@@ -113,7 +113,7 @@ func TestClientServerTCPEcho(t *testing.T) {
113113
go echoServer.Serve()
114114

115115
// Create client
116-
c, err := client.NewClient(&client.Config{
116+
c, _, err := client.NewClient(&client.Config{
117117
ServerAddr: udpAddr,
118118
TLSConfig: client.TLSConfig{InsecureSkipVerify: true},
119119
})
@@ -160,7 +160,7 @@ func TestClientServerUDPEcho(t *testing.T) {
160160
go echoServer.Serve()
161161

162162
// Create client
163-
c, err := client.NewClient(&client.Config{
163+
c, _, err := client.NewClient(&client.Config{
164164
ServerAddr: udpAddr,
165165
TLSConfig: client.TLSConfig{InsecureSkipVerify: true},
166166
})
@@ -181,3 +181,100 @@ func TestClientServerUDPEcho(t *testing.T) {
181181
assert.Equal(t, sData, rData)
182182
assert.Equal(t, echoAddr, rAddr)
183183
}
184+
185+
// TestClientServerHandshakeInfo tests that the client returns the correct handshake info.
186+
func TestClientServerHandshakeInfo(t *testing.T) {
187+
// Create server 1, UDP enabled, unlimited bandwidth
188+
udpConn, udpAddr, err := serverConn()
189+
assert.NoError(t, err)
190+
auth := mocks.NewMockAuthenticator(t)
191+
auth.EXPECT().Authenticate(mock.Anything, mock.Anything, mock.Anything).Return(true, "nobody")
192+
s, err := server.NewServer(&server.Config{
193+
TLSConfig: serverTLSConfig(),
194+
Conn: udpConn,
195+
Authenticator: auth,
196+
})
197+
assert.NoError(t, err)
198+
go s.Serve()
199+
200+
// Create client 1, with specified tx bandwidth
201+
c, info, err := client.NewClient(&client.Config{
202+
ServerAddr: udpAddr,
203+
TLSConfig: client.TLSConfig{InsecureSkipVerify: true},
204+
BandwidthConfig: client.BandwidthConfig{
205+
MaxTx: 123456,
206+
},
207+
})
208+
assert.NoError(t, err)
209+
assert.Equal(t, &client.HandshakeInfo{
210+
UDPEnabled: true,
211+
Tx: 123456,
212+
}, info)
213+
214+
// Close server 1 and client 1
215+
_ = s.Close()
216+
_ = c.Close()
217+
218+
// Create server 2, UDP disabled, limited rx bandwidth
219+
udpConn, udpAddr, err = serverConn()
220+
assert.NoError(t, err)
221+
s, err = server.NewServer(&server.Config{
222+
TLSConfig: serverTLSConfig(),
223+
Conn: udpConn,
224+
BandwidthConfig: server.BandwidthConfig{
225+
MaxRx: 100000,
226+
},
227+
DisableUDP: true,
228+
Authenticator: auth,
229+
})
230+
assert.NoError(t, err)
231+
go s.Serve()
232+
233+
// Create client 2, with specified tx bandwidth
234+
c, info, err = client.NewClient(&client.Config{
235+
ServerAddr: udpAddr,
236+
TLSConfig: client.TLSConfig{InsecureSkipVerify: true},
237+
BandwidthConfig: client.BandwidthConfig{
238+
MaxTx: 123456,
239+
},
240+
})
241+
assert.NoError(t, err)
242+
assert.Equal(t, &client.HandshakeInfo{
243+
UDPEnabled: false,
244+
Tx: 100000,
245+
}, info)
246+
247+
// Close server 2 and client 2
248+
_ = s.Close()
249+
_ = c.Close()
250+
251+
// Create server 3, UDP enabled, ignore client bandwidth
252+
udpConn, udpAddr, err = serverConn()
253+
assert.NoError(t, err)
254+
s, err = server.NewServer(&server.Config{
255+
TLSConfig: serverTLSConfig(),
256+
Conn: udpConn,
257+
IgnoreClientBandwidth: true,
258+
Authenticator: auth,
259+
})
260+
assert.NoError(t, err)
261+
go s.Serve()
262+
263+
// Create client 3, with specified tx bandwidth
264+
c, info, err = client.NewClient(&client.Config{
265+
ServerAddr: udpAddr,
266+
TLSConfig: client.TLSConfig{InsecureSkipVerify: true},
267+
BandwidthConfig: client.BandwidthConfig{
268+
MaxTx: 123456,
269+
},
270+
})
271+
assert.NoError(t, err)
272+
assert.Equal(t, &client.HandshakeInfo{
273+
UDPEnabled: true,
274+
Tx: 0,
275+
}, info)
276+
277+
// Close server 3 and client 3
278+
_ = s.Close()
279+
_ = c.Close()
280+
}

core/internal/integration_tests/stress_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ func TestClientServerTCPStress(t *testing.T) {
148148
go echoServer.Serve()
149149

150150
// Create client
151-
c, err := client.NewClient(&client.Config{
151+
c, _, err := client.NewClient(&client.Config{
152152
ServerAddr: udpAddr,
153153
TLSConfig: client.TLSConfig{InsecureSkipVerify: true},
154154
})
@@ -192,7 +192,7 @@ func TestClientServerUDPStress(t *testing.T) {
192192
go echoServer.Serve()
193193

194194
// Create client
195-
c, err := client.NewClient(&client.Config{
195+
c, _, err := client.NewClient(&client.Config{
196196
ServerAddr: udpAddr,
197197
TLSConfig: client.TLSConfig{InsecureSkipVerify: true},
198198
})

core/internal/integration_tests/trafficlogger_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ func TestClientServerTrafficLoggerTCP(t *testing.T) {
3535
go s.Serve()
3636

3737
// Create client
38-
c, err := client.NewClient(&client.Config{
38+
c, _, err := client.NewClient(&client.Config{
3939
ServerAddr: udpAddr,
4040
TLSConfig: client.TLSConfig{InsecureSkipVerify: true},
4141
})
@@ -114,7 +114,7 @@ func TestClientServerTrafficLoggerUDP(t *testing.T) {
114114
go s.Serve()
115115

116116
// Create client
117-
c, err := client.NewClient(&client.Config{
117+
c, _, err := client.NewClient(&client.Config{
118118
ServerAddr: udpAddr,
119119
TLSConfig: client.TLSConfig{InsecureSkipVerify: true},
120120
})

0 commit comments

Comments
 (0)