mirror of
https://github.com/tailscale/tailscale.git
synced 2024-12-01 14:05:39 +00:00
derp: remove a client round-trip waiting on serverInfo
It just has a version number in it and it's not really needed. Instead just return it as a normal Recv message type for those that care (currently only tests). Updates #150 (in that it shares the same goal: initial DERP latency) Updates #199 (in that it removes some DERP versioning)
This commit is contained in:
parent
f6dc47efe4
commit
6b80bcf112
@ -209,13 +209,6 @@ func writeFrame(bw *bufio.Writer, t frameType, b []byte) error {
|
|||||||
return bw.Flush()
|
return bw.Flush()
|
||||||
}
|
}
|
||||||
|
|
||||||
func minInt(a, b int) int {
|
|
||||||
if a < b {
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
func minUint32(a, b uint32) uint32 {
|
func minUint32(a, b uint32) uint32 {
|
||||||
if a < b {
|
if a < b {
|
||||||
return a
|
return a
|
||||||
|
@ -21,14 +21,13 @@
|
|||||||
|
|
||||||
// Client is a DERP client.
|
// Client is a DERP client.
|
||||||
type Client struct {
|
type Client struct {
|
||||||
serverKey key.Public // of the DERP server; not a machine or node key
|
serverKey key.Public // of the DERP server; not a machine or node key
|
||||||
privateKey key.Private
|
privateKey key.Private
|
||||||
publicKey key.Public // of privateKey
|
publicKey key.Public // of privateKey
|
||||||
protoVersion int // min of server+client
|
logf logger.Logf
|
||||||
logf logger.Logf
|
nc Conn
|
||||||
nc Conn
|
br *bufio.Reader
|
||||||
br *bufio.Reader
|
meshKey string
|
||||||
meshKey string
|
|
||||||
|
|
||||||
wmu sync.Mutex // hold while writing to bw
|
wmu sync.Mutex // hold while writing to bw
|
||||||
bw *bufio.Writer
|
bw *bufio.Writer
|
||||||
@ -85,11 +84,6 @@ func newClient(privateKey key.Private, nc Conn, brw *bufio.ReadWriter, logf logg
|
|||||||
if err := c.sendClientKey(); err != nil {
|
if err := c.sendClientKey(); err != nil {
|
||||||
return nil, fmt.Errorf("derp.Client: failed to send client key: %v", err)
|
return nil, fmt.Errorf("derp.Client: failed to send client key: %v", err)
|
||||||
}
|
}
|
||||||
info, err := c.recvServerInfo()
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("derp.Client: failed to receive server info: %v", err)
|
|
||||||
}
|
|
||||||
c.protoVersion = minInt(protocolVersion, info.Version)
|
|
||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,12 +104,9 @@ func (c *Client) recvServerKey() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) recvServerInfo() (*serverInfo, error) {
|
func (c *Client) parseServerInfo(b []byte) (*serverInfo, error) {
|
||||||
fl, err := readFrameTypeHeader(c.br, frameServerInfo)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
const maxLength = nonceLen + maxInfoLen
|
const maxLength = nonceLen + maxInfoLen
|
||||||
|
fl := len(b)
|
||||||
if fl < nonceLen {
|
if fl < nonceLen {
|
||||||
return nil, fmt.Errorf("short serverInfo frame")
|
return nil, fmt.Errorf("short serverInfo frame")
|
||||||
}
|
}
|
||||||
@ -124,21 +115,15 @@ func (c *Client) recvServerInfo() (*serverInfo, error) {
|
|||||||
}
|
}
|
||||||
// TODO: add a read-nonce-and-box helper
|
// TODO: add a read-nonce-and-box helper
|
||||||
var nonce [nonceLen]byte
|
var nonce [nonceLen]byte
|
||||||
if _, err := io.ReadFull(c.br, nonce[:]); err != nil {
|
copy(nonce[:], b)
|
||||||
return nil, fmt.Errorf("nonce: %v", err)
|
msgbox := b[nonceLen:]
|
||||||
}
|
|
||||||
msgLen := fl - nonceLen
|
|
||||||
msgbox := make([]byte, msgLen)
|
|
||||||
if _, err := io.ReadFull(c.br, msgbox); err != nil {
|
|
||||||
return nil, fmt.Errorf("msgbox: %v", err)
|
|
||||||
}
|
|
||||||
msg, ok := box.Open(nil, msgbox, &nonce, c.serverKey.B32(), c.privateKey.B32())
|
msg, ok := box.Open(nil, msgbox, &nonce, c.serverKey.B32(), c.privateKey.B32())
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("msgbox: cannot open len=%d with server key %x", msgLen, c.serverKey[:])
|
return nil, fmt.Errorf("failed to open naclbox from server key %x", c.serverKey[:])
|
||||||
}
|
}
|
||||||
info := new(serverInfo)
|
info := new(serverInfo)
|
||||||
if err := json.Unmarshal(msg, info); err != nil {
|
if err := json.Unmarshal(msg, info); err != nil {
|
||||||
return nil, fmt.Errorf("msg: %v", err)
|
return nil, fmt.Errorf("invalid JSON: %v", err)
|
||||||
}
|
}
|
||||||
return info, nil
|
return info, nil
|
||||||
}
|
}
|
||||||
@ -318,6 +303,11 @@ func (PeerGoneMessage) msg() {}
|
|||||||
|
|
||||||
func (PeerPresentMessage) msg() {}
|
func (PeerPresentMessage) msg() {}
|
||||||
|
|
||||||
|
// ServerInfoMessage is sent by the server upon first connect.
|
||||||
|
type ServerInfoMessage struct{}
|
||||||
|
|
||||||
|
func (ServerInfoMessage) msg() {}
|
||||||
|
|
||||||
// Recv reads a message from the DERP server.
|
// Recv reads a message from the DERP server.
|
||||||
//
|
//
|
||||||
// The returned message may alias memory owned by the Client; it
|
// The returned message may alias memory owned by the Client; it
|
||||||
@ -364,7 +354,7 @@ func (c *Client) recvTimeout(timeout time.Duration) (m ReceivedMessage, err erro
|
|||||||
// If the frame fits in our bufio.Reader buffer, just use it.
|
// If the frame fits in our bufio.Reader buffer, just use it.
|
||||||
// In practice it's 4KB (from derphttp.Client's bufio.NewReader(httpConn)) and
|
// In practice it's 4KB (from derphttp.Client's bufio.NewReader(httpConn)) and
|
||||||
// in practive, WireGuard packets (and thus DERP frames) are under 1.5KB.
|
// in practive, WireGuard packets (and thus DERP frames) are under 1.5KB.
|
||||||
// So This is the common path.
|
// So this is the common path.
|
||||||
if int(n) <= c.br.Size() {
|
if int(n) <= c.br.Size() {
|
||||||
b, err = c.br.Peek(int(n))
|
b, err = c.br.Peek(int(n))
|
||||||
c.peeked = int(n)
|
c.peeked = int(n)
|
||||||
@ -382,6 +372,19 @@ func (c *Client) recvTimeout(timeout time.Duration) (m ReceivedMessage, err erro
|
|||||||
switch t {
|
switch t {
|
||||||
default:
|
default:
|
||||||
continue
|
continue
|
||||||
|
case frameServerInfo:
|
||||||
|
// Server sends this at start-up. Currently unused.
|
||||||
|
// Just has a JSON message saying "version: 2",
|
||||||
|
// but the protocol seems extensible enough as-is without
|
||||||
|
// needing to wait an RTT to discover the version at startup.
|
||||||
|
// We'd prefer to give the connection to the client (magicsock)
|
||||||
|
// to start writing as soon as possible.
|
||||||
|
_, err := c.parseServerInfo(b)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid server info frame: %v", err)
|
||||||
|
}
|
||||||
|
// TODO: add the results of parseServerInfo to ServerInfoMessage if we ever need it.
|
||||||
|
return ServerInfoMessage{}, nil
|
||||||
case frameKeepAlive:
|
case frameKeepAlive:
|
||||||
// TODO: eventually we'll have server->client pings that
|
// TODO: eventually we'll have server->client pings that
|
||||||
// require ack pongs.
|
// require ack pongs.
|
||||||
@ -406,16 +409,12 @@ func (c *Client) recvTimeout(timeout time.Duration) (m ReceivedMessage, err erro
|
|||||||
|
|
||||||
case frameRecvPacket:
|
case frameRecvPacket:
|
||||||
var rp ReceivedPacket
|
var rp ReceivedPacket
|
||||||
if c.protoVersion < protocolSrcAddrs {
|
if n < keyLen {
|
||||||
rp.Data = b[:n]
|
c.logf("[unexpected] dropping short packet from DERP server")
|
||||||
} else {
|
continue
|
||||||
if n < keyLen {
|
|
||||||
c.logf("[unexpected] dropping short packet from DERP server")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
copy(rp.Source[:], b[:keyLen])
|
|
||||||
rp.Data = b[keyLen:n]
|
|
||||||
}
|
}
|
||||||
|
copy(rp.Source[:], b[:keyLen])
|
||||||
|
rp.Data = b[keyLen:n]
|
||||||
return rp, nil
|
return rp, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,6 +80,8 @@ func TestSendRecv(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("client %d: %v", i, err)
|
t.Fatalf("client %d: %v", i, err)
|
||||||
}
|
}
|
||||||
|
waitConnect(t, c)
|
||||||
|
|
||||||
clients = append(clients, c)
|
clients = append(clients, c)
|
||||||
recvChs = append(recvChs, make(chan []byte))
|
recvChs = append(recvChs, make(chan []byte))
|
||||||
t.Logf("Connected client %d.", i)
|
t.Logf("Connected client %d.", i)
|
||||||
@ -119,7 +121,7 @@ func TestSendRecv(t *testing.T) {
|
|||||||
if got := string(b); got != want {
|
if got := string(b); got != want {
|
||||||
t.Errorf("client1.Recv=%q, want %q", got, want)
|
t.Errorf("client1.Recv=%q, want %q", got, want)
|
||||||
}
|
}
|
||||||
case <-time.After(1 * time.Second):
|
case <-time.After(5 * time.Second):
|
||||||
t.Errorf("client%d.Recv, got nothing, want %q", i, want)
|
t.Errorf("client%d.Recv, got nothing, want %q", i, want)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -225,6 +227,7 @@ func TestSendFreeze(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
waitConnect(t, c)
|
||||||
return c, c2
|
return c, c2
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -503,7 +506,13 @@ func newTestClient(t *testing.T, ts *testServer, name string, newClient func(net
|
|||||||
func newRegularClient(t *testing.T, ts *testServer, name string) *testClient {
|
func newRegularClient(t *testing.T, ts *testServer, name string) *testClient {
|
||||||
return newTestClient(t, ts, name, func(nc net.Conn, priv key.Private, logf logger.Logf) (*Client, error) {
|
return newTestClient(t, ts, name, func(nc net.Conn, priv key.Private, logf logger.Logf) (*Client, error) {
|
||||||
brw := bufio.NewReadWriter(bufio.NewReader(nc), bufio.NewWriter(nc))
|
brw := bufio.NewReadWriter(bufio.NewReader(nc), bufio.NewWriter(nc))
|
||||||
return NewClient(priv, nc, brw, logf)
|
c, err := NewClient(priv, nc, brw, logf)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
waitConnect(t, c)
|
||||||
|
return c, nil
|
||||||
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -514,6 +523,7 @@ func newTestWatcher(t *testing.T, ts *testServer, name string) *testClient {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
waitConnect(t, c)
|
||||||
if err := c.WatchConnectionChanges(); err != nil {
|
if err := c.WatchConnectionChanges(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -834,3 +844,12 @@ func BenchmarkReadUint32(b *testing.B) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func waitConnect(t testing.TB, c *Client) {
|
||||||
|
t.Helper()
|
||||||
|
if m, err := c.Recv(); err != nil {
|
||||||
|
t.Fatalf("client first Recv: %v", err)
|
||||||
|
} else if v, ok := m.(ServerInfoMessage); !ok {
|
||||||
|
t.Fatalf("client first Recv was unexpected type %T", v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
crand "crypto/rand"
|
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -19,22 +18,15 @@
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestSendRecv(t *testing.T) {
|
func TestSendRecv(t *testing.T) {
|
||||||
|
serverPrivateKey := key.NewPrivate()
|
||||||
|
|
||||||
const numClients = 3
|
const numClients = 3
|
||||||
var serverPrivateKey key.Private
|
|
||||||
if _, err := crand.Read(serverPrivateKey[:]); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
var clientPrivateKeys []key.Private
|
var clientPrivateKeys []key.Private
|
||||||
for i := 0; i < numClients; i++ {
|
|
||||||
var key key.Private
|
|
||||||
if _, err := crand.Read(key[:]); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
clientPrivateKeys = append(clientPrivateKeys, key)
|
|
||||||
}
|
|
||||||
var clientKeys []key.Public
|
var clientKeys []key.Public
|
||||||
for _, privKey := range clientPrivateKeys {
|
for i := 0; i < numClients; i++ {
|
||||||
clientKeys = append(clientKeys, privKey.Public())
|
priv := key.NewPrivate()
|
||||||
|
clientPrivateKeys = append(clientPrivateKeys, priv)
|
||||||
|
clientKeys = append(clientKeys, priv.Public())
|
||||||
}
|
}
|
||||||
|
|
||||||
s := derp.NewServer(serverPrivateKey, t.Logf)
|
s := derp.NewServer(serverPrivateKey, t.Logf)
|
||||||
@ -81,6 +73,7 @@ func TestSendRecv(t *testing.T) {
|
|||||||
if err := c.Connect(context.Background()); err != nil {
|
if err := c.Connect(context.Background()); err != nil {
|
||||||
t.Fatalf("client %d Connect: %v", i, err)
|
t.Fatalf("client %d Connect: %v", i, err)
|
||||||
}
|
}
|
||||||
|
waitConnect(t, c)
|
||||||
clients = append(clients, c)
|
clients = append(clients, c)
|
||||||
recvChs = append(recvChs, make(chan []byte))
|
recvChs = append(recvChs, make(chan []byte))
|
||||||
|
|
||||||
@ -95,6 +88,11 @@ func TestSendRecv(t *testing.T) {
|
|||||||
}
|
}
|
||||||
m, err := c.Recv()
|
m, err := c.Recv()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
}
|
||||||
t.Logf("client%d: %v", i, err)
|
t.Logf("client%d: %v", i, err)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -118,7 +116,7 @@ func TestSendRecv(t *testing.T) {
|
|||||||
if got := string(b); got != want {
|
if got := string(b); got != want {
|
||||||
t.Errorf("client1.Recv=%q, want %q", got, want)
|
t.Errorf("client1.Recv=%q, want %q", got, want)
|
||||||
}
|
}
|
||||||
case <-time.After(1 * time.Second):
|
case <-time.After(5 * time.Second):
|
||||||
t.Errorf("client%d.Recv, got nothing, want %q", i, want)
|
t.Errorf("client%d.Recv, got nothing, want %q", i, want)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -146,5 +144,13 @@ func TestSendRecv(t *testing.T) {
|
|||||||
recv(2, string(msg2))
|
recv(2, string(msg2))
|
||||||
recvNothing(0)
|
recvNothing(0)
|
||||||
recvNothing(1)
|
recvNothing(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func waitConnect(t testing.TB, c *Client) {
|
||||||
|
t.Helper()
|
||||||
|
if m, err := c.Recv(); err != nil {
|
||||||
|
t.Fatalf("client first Recv: %v", err)
|
||||||
|
} else if v, ok := m.(derp.ServerInfoMessage); !ok {
|
||||||
|
t.Fatalf("client first Recv was unexpected type %T", v)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user