mirror of
https://github.com/refraction-networking/uquic.git
synced 2025-04-04 20:57:36 +03:00
implement a listener that returns early sessions
This commit is contained in:
parent
cc76441539
commit
5cbb8d6597
5 changed files with 551 additions and 308 deletions
694
server_test.go
694
server_test.go
|
@ -39,6 +39,12 @@ var _ = Describe("Server", func() {
|
|||
}
|
||||
}
|
||||
|
||||
parseHeader := func(data []byte) *wire.Header {
|
||||
hdr, _, _, err := wire.ParsePacket(data, 0)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
return hdr
|
||||
}
|
||||
|
||||
BeforeEach(func() {
|
||||
conn = newMockPacketConn()
|
||||
conn.addr = &net.UDPAddr{}
|
||||
|
@ -61,7 +67,7 @@ var _ = Describe("Server", func() {
|
|||
It("fills in default values if options are not set in the Config", func() {
|
||||
ln, err := Listen(conn, tlsConf, &Config{})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
server := ln.(*server)
|
||||
server := ln.(*baseServer)
|
||||
Expect(server.config.Versions).To(Equal(protocol.SupportedVersions))
|
||||
Expect(server.config.HandshakeTimeout).To(Equal(protocol.DefaultHandshakeTimeout))
|
||||
Expect(server.config.IdleTimeout).To(Equal(protocol.DefaultIdleTimeout))
|
||||
|
@ -86,7 +92,7 @@ var _ = Describe("Server", func() {
|
|||
}
|
||||
ln, err := Listen(conn, tlsConf, &config)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
server := ln.(*server)
|
||||
server := ln.(*baseServer)
|
||||
Expect(server.sessionHandler).ToNot(BeNil())
|
||||
Expect(server.config.Versions).To(Equal(supportedVersions))
|
||||
Expect(server.config.HandshakeTimeout).To(Equal(1337 * time.Hour))
|
||||
|
@ -103,8 +109,7 @@ var _ = Describe("Server", func() {
|
|||
addr := "127.0.0.1:13579"
|
||||
ln, err := ListenAddr(addr, tlsConf, &Config{})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
serv := ln.(*server)
|
||||
Expect(serv.Addr().String()).To(Equal(addr))
|
||||
Expect(ln.Addr().String()).To(Equal(addr))
|
||||
// stop the listener
|
||||
Expect(ln.Close()).To(Succeed())
|
||||
})
|
||||
|
@ -121,173 +126,427 @@ var _ = Describe("Server", func() {
|
|||
Expect(err).To(BeAssignableToTypeOf(&net.OpError{}))
|
||||
})
|
||||
|
||||
Context("handling packets", func() {
|
||||
var serv *server
|
||||
Context("server accepting sessions that completed the handshake", func() {
|
||||
var serv *baseServer
|
||||
|
||||
BeforeEach(func() {
|
||||
ln, err := Listen(conn, tlsConf, nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
serv = ln.(*server)
|
||||
serv = ln.(*baseServer)
|
||||
})
|
||||
|
||||
parseHeader := func(data []byte) *wire.Header {
|
||||
hdr, _, _, err := wire.ParsePacket(data, 0)
|
||||
Context("handling packets", func() {
|
||||
It("drops Initial packets with a too short connection ID", func() {
|
||||
serv.handlePacket(getPacket(&wire.Header{
|
||||
IsLongHeader: true,
|
||||
Type: protocol.PacketTypeInitial,
|
||||
DestConnectionID: protocol.ConnectionID{1, 2, 3, 4},
|
||||
Version: serv.config.Versions[0],
|
||||
}, nil))
|
||||
Consistently(conn.dataWritten).ShouldNot(Receive())
|
||||
})
|
||||
|
||||
It("drops too small Initial", func() {
|
||||
serv.handlePacket(getPacket(&wire.Header{
|
||||
IsLongHeader: true,
|
||||
Type: protocol.PacketTypeInitial,
|
||||
DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8},
|
||||
Version: serv.config.Versions[0],
|
||||
}, make([]byte, protocol.MinInitialPacketSize-100),
|
||||
))
|
||||
Consistently(conn.dataWritten).ShouldNot(Receive())
|
||||
})
|
||||
|
||||
It("drops packets with a too short connection ID", func() {
|
||||
serv.handlePacket(getPacket(&wire.Header{
|
||||
IsLongHeader: true,
|
||||
Type: protocol.PacketTypeInitial,
|
||||
SrcConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8},
|
||||
DestConnectionID: protocol.ConnectionID{1, 2, 3, 4},
|
||||
Version: serv.config.Versions[0],
|
||||
}, make([]byte, protocol.MinInitialPacketSize)))
|
||||
Consistently(conn.dataWritten).ShouldNot(Receive())
|
||||
})
|
||||
|
||||
It("drops non-Initial packets", func() {
|
||||
serv.handlePacket(getPacket(
|
||||
&wire.Header{
|
||||
Type: protocol.PacketTypeHandshake,
|
||||
Version: serv.config.Versions[0],
|
||||
},
|
||||
[]byte("invalid"),
|
||||
))
|
||||
})
|
||||
|
||||
It("decodes the token from the Token field", func() {
|
||||
raddr := &net.UDPAddr{
|
||||
IP: net.IPv4(192, 168, 13, 37),
|
||||
Port: 1337,
|
||||
}
|
||||
done := make(chan struct{})
|
||||
serv.config.AcceptToken = func(addr net.Addr, token *Token) bool {
|
||||
Expect(addr).To(Equal(raddr))
|
||||
Expect(token).ToNot(BeNil())
|
||||
close(done)
|
||||
return false
|
||||
}
|
||||
token, err := serv.tokenGenerator.NewRetryToken(raddr, nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
packet := getPacket(&wire.Header{
|
||||
IsLongHeader: true,
|
||||
Type: protocol.PacketTypeInitial,
|
||||
Token: token,
|
||||
Version: serv.config.Versions[0],
|
||||
}, make([]byte, protocol.MinInitialPacketSize))
|
||||
packet.remoteAddr = raddr
|
||||
serv.handlePacket(packet)
|
||||
Eventually(done).Should(BeClosed())
|
||||
})
|
||||
|
||||
It("passes an empty token to the callback, if decoding fails", func() {
|
||||
raddr := &net.UDPAddr{
|
||||
IP: net.IPv4(192, 168, 13, 37),
|
||||
Port: 1337,
|
||||
}
|
||||
done := make(chan struct{})
|
||||
serv.config.AcceptToken = func(addr net.Addr, token *Token) bool {
|
||||
Expect(addr).To(Equal(raddr))
|
||||
Expect(token).To(BeNil())
|
||||
close(done)
|
||||
return false
|
||||
}
|
||||
packet := getPacket(&wire.Header{
|
||||
IsLongHeader: true,
|
||||
Type: protocol.PacketTypeInitial,
|
||||
Token: []byte("foobar"),
|
||||
Version: serv.config.Versions[0],
|
||||
}, make([]byte, protocol.MinInitialPacketSize))
|
||||
packet.remoteAddr = raddr
|
||||
serv.handlePacket(packet)
|
||||
Eventually(done).Should(BeClosed())
|
||||
})
|
||||
|
||||
It("sends a Version Negotiation Packet for unsupported versions", func() {
|
||||
srcConnID := protocol.ConnectionID{1, 2, 3, 4, 5}
|
||||
destConnID := protocol.ConnectionID{1, 2, 3, 4, 5, 6}
|
||||
packet := getPacket(&wire.Header{
|
||||
IsLongHeader: true,
|
||||
Type: protocol.PacketTypeInitial,
|
||||
SrcConnectionID: srcConnID,
|
||||
DestConnectionID: destConnID,
|
||||
Version: 0x42,
|
||||
}, make([]byte, protocol.MinInitialPacketSize))
|
||||
packet.remoteAddr = &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 1337}
|
||||
serv.handlePacket(packet)
|
||||
var write mockPacketConnWrite
|
||||
Eventually(conn.dataWritten).Should(Receive(&write))
|
||||
Expect(write.to.String()).To(Equal("127.0.0.1:1337"))
|
||||
Expect(wire.IsVersionNegotiationPacket(write.data)).To(BeTrue())
|
||||
hdr := parseHeader(write.data)
|
||||
Expect(hdr.DestConnectionID).To(Equal(srcConnID))
|
||||
Expect(hdr.SrcConnectionID).To(Equal(destConnID))
|
||||
Expect(hdr.SupportedVersions).ToNot(ContainElement(protocol.VersionNumber(0x42)))
|
||||
})
|
||||
|
||||
It("replies with a Retry packet, if a Token is required", func() {
|
||||
serv.config.AcceptToken = func(_ net.Addr, _ *Token) bool { return false }
|
||||
hdr := &wire.Header{
|
||||
IsLongHeader: true,
|
||||
Type: protocol.PacketTypeInitial,
|
||||
SrcConnectionID: protocol.ConnectionID{5, 4, 3, 2, 1},
|
||||
DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
|
||||
Version: protocol.VersionTLS,
|
||||
}
|
||||
packet := getPacket(hdr, make([]byte, protocol.MinInitialPacketSize))
|
||||
packet.remoteAddr = &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 1337}
|
||||
serv.handlePacket(packet)
|
||||
var write mockPacketConnWrite
|
||||
Eventually(conn.dataWritten).Should(Receive(&write))
|
||||
Expect(write.to.String()).To(Equal("127.0.0.1:1337"))
|
||||
replyHdr := parseHeader(write.data)
|
||||
Expect(replyHdr.Type).To(Equal(protocol.PacketTypeRetry))
|
||||
Expect(replyHdr.SrcConnectionID).ToNot(Equal(hdr.DestConnectionID))
|
||||
Expect(replyHdr.DestConnectionID).To(Equal(hdr.SrcConnectionID))
|
||||
Expect(replyHdr.OrigDestConnectionID).To(Equal(hdr.DestConnectionID))
|
||||
Expect(replyHdr.Token).ToNot(BeEmpty())
|
||||
})
|
||||
|
||||
It("creates a session, if no Token is required", func() {
|
||||
serv.config.AcceptToken = func(_ net.Addr, _ *Token) bool { return true }
|
||||
hdr := &wire.Header{
|
||||
IsLongHeader: true,
|
||||
Type: protocol.PacketTypeInitial,
|
||||
SrcConnectionID: protocol.ConnectionID{5, 4, 3, 2, 1},
|
||||
DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
|
||||
Version: protocol.VersionTLS,
|
||||
}
|
||||
p := getPacket(hdr, make([]byte, protocol.MinInitialPacketSize))
|
||||
run := make(chan struct{})
|
||||
serv.newSession = func(
|
||||
_ connection,
|
||||
_ sessionRunner,
|
||||
origConnID protocol.ConnectionID,
|
||||
destConnID protocol.ConnectionID,
|
||||
srcConnID protocol.ConnectionID,
|
||||
_ *Config,
|
||||
_ *tls.Config,
|
||||
_ *handshake.TransportParameters,
|
||||
_ *handshake.TokenGenerator,
|
||||
_ utils.Logger,
|
||||
_ protocol.VersionNumber,
|
||||
) (quicSession, error) {
|
||||
Expect(origConnID).To(Equal(hdr.DestConnectionID))
|
||||
Expect(destConnID).To(Equal(hdr.SrcConnectionID))
|
||||
// make sure we're using a server-generated connection ID
|
||||
Expect(srcConnID).ToNot(Equal(hdr.DestConnectionID))
|
||||
Expect(srcConnID).ToNot(Equal(hdr.SrcConnectionID))
|
||||
sess := NewMockQuicSession(mockCtrl)
|
||||
sess.EXPECT().handlePacket(p)
|
||||
sess.EXPECT().run().Do(func() { close(run) })
|
||||
sess.EXPECT().Context().Return(context.Background())
|
||||
sess.EXPECT().HandshakeComplete().Return(context.Background())
|
||||
return sess, nil
|
||||
}
|
||||
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
defer GinkgoRecover()
|
||||
serv.handlePacket(p)
|
||||
// the Handshake packet is written by the session
|
||||
Consistently(conn.dataWritten).ShouldNot(Receive())
|
||||
close(done)
|
||||
}()
|
||||
// make sure we're using a server-generated connection ID
|
||||
Eventually(run).Should(BeClosed())
|
||||
Eventually(done).Should(BeClosed())
|
||||
})
|
||||
|
||||
It("rejects new connection attempts if the accept queue is full", func() {
|
||||
serv.config.AcceptToken = func(_ net.Addr, _ *Token) bool { return true }
|
||||
senderAddr := &net.UDPAddr{IP: net.IPv4(1, 2, 3, 4), Port: 42}
|
||||
|
||||
hdr := &wire.Header{
|
||||
IsLongHeader: true,
|
||||
Type: protocol.PacketTypeInitial,
|
||||
SrcConnectionID: protocol.ConnectionID{5, 4, 3, 2, 1},
|
||||
DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
|
||||
Version: protocol.VersionTLS,
|
||||
}
|
||||
p := getPacket(hdr, make([]byte, protocol.MinInitialPacketSize))
|
||||
p.remoteAddr = senderAddr
|
||||
serv.newSession = func(
|
||||
_ connection,
|
||||
runner sessionRunner,
|
||||
_ protocol.ConnectionID,
|
||||
_ protocol.ConnectionID,
|
||||
_ protocol.ConnectionID,
|
||||
_ *Config,
|
||||
_ *tls.Config,
|
||||
_ *handshake.TransportParameters,
|
||||
_ *handshake.TokenGenerator,
|
||||
_ utils.Logger,
|
||||
_ protocol.VersionNumber,
|
||||
) (quicSession, error) {
|
||||
sess := NewMockQuicSession(mockCtrl)
|
||||
sess.EXPECT().handlePacket(p)
|
||||
sess.EXPECT().run()
|
||||
sess.EXPECT().Context().Return(context.Background())
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
cancel()
|
||||
sess.EXPECT().HandshakeComplete().Return(ctx)
|
||||
return sess, nil
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(protocol.MaxAcceptQueueSize)
|
||||
for i := 0; i < protocol.MaxAcceptQueueSize; i++ {
|
||||
go func() {
|
||||
defer GinkgoRecover()
|
||||
defer wg.Done()
|
||||
serv.handlePacket(p)
|
||||
Consistently(conn.dataWritten).ShouldNot(Receive())
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
serv.handlePacket(p)
|
||||
var reject mockPacketConnWrite
|
||||
Eventually(conn.dataWritten).Should(Receive(&reject))
|
||||
Expect(reject.to).To(Equal(senderAddr))
|
||||
rejectHdr := parseHeader(reject.data)
|
||||
Expect(rejectHdr.Type).To(Equal(protocol.PacketTypeInitial))
|
||||
Expect(rejectHdr.Version).To(Equal(hdr.Version))
|
||||
Expect(rejectHdr.DestConnectionID).To(Equal(hdr.SrcConnectionID))
|
||||
Expect(rejectHdr.SrcConnectionID).To(Equal(hdr.DestConnectionID))
|
||||
})
|
||||
|
||||
It("doesn't accept new sessions if they were closed in the mean time", func() {
|
||||
serv.config.AcceptToken = func(_ net.Addr, _ *Token) bool { return true }
|
||||
senderAddr := &net.UDPAddr{IP: net.IPv4(1, 2, 3, 4), Port: 42}
|
||||
|
||||
hdr := &wire.Header{
|
||||
IsLongHeader: true,
|
||||
Type: protocol.PacketTypeInitial,
|
||||
SrcConnectionID: protocol.ConnectionID{5, 4, 3, 2, 1},
|
||||
DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
|
||||
Version: protocol.VersionTLS,
|
||||
}
|
||||
p := getPacket(hdr, make([]byte, protocol.MinInitialPacketSize))
|
||||
p.remoteAddr = senderAddr
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
sessionCreated := make(chan struct{})
|
||||
sess := NewMockQuicSession(mockCtrl)
|
||||
serv.newSession = func(
|
||||
_ connection,
|
||||
runner sessionRunner,
|
||||
_ protocol.ConnectionID,
|
||||
_ protocol.ConnectionID,
|
||||
_ protocol.ConnectionID,
|
||||
_ *Config,
|
||||
_ *tls.Config,
|
||||
_ *handshake.TransportParameters,
|
||||
_ *handshake.TokenGenerator,
|
||||
_ utils.Logger,
|
||||
_ protocol.VersionNumber,
|
||||
) (quicSession, error) {
|
||||
sess.EXPECT().handlePacket(p)
|
||||
sess.EXPECT().run()
|
||||
sess.EXPECT().Context().Return(ctx)
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
cancel()
|
||||
sess.EXPECT().HandshakeComplete().Return(ctx)
|
||||
close(sessionCreated)
|
||||
return sess, nil
|
||||
}
|
||||
|
||||
serv.handlePacket(p)
|
||||
Consistently(conn.dataWritten).ShouldNot(Receive())
|
||||
Eventually(sessionCreated).Should(BeClosed())
|
||||
cancel()
|
||||
time.Sleep(scaleDuration(200 * time.Millisecond))
|
||||
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
defer GinkgoRecover()
|
||||
serv.Accept(context.Background())
|
||||
close(done)
|
||||
}()
|
||||
Consistently(done).ShouldNot(BeClosed())
|
||||
|
||||
// make the go routine return
|
||||
sess.EXPECT().getPerspective()
|
||||
Expect(serv.Close()).To(Succeed())
|
||||
Eventually(done).Should(BeClosed())
|
||||
})
|
||||
})
|
||||
|
||||
Context("accepting sessions", func() {
|
||||
It("returns Accept when an error occurs", func() {
|
||||
testErr := errors.New("test err")
|
||||
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
defer GinkgoRecover()
|
||||
_, err := serv.Accept(context.Background())
|
||||
Expect(err).To(MatchError(testErr))
|
||||
close(done)
|
||||
}()
|
||||
|
||||
serv.setCloseError(testErr)
|
||||
Eventually(done).Should(BeClosed())
|
||||
})
|
||||
|
||||
It("returns immediately, if an error occurred before", func() {
|
||||
testErr := errors.New("test err")
|
||||
serv.setCloseError(testErr)
|
||||
for i := 0; i < 3; i++ {
|
||||
_, err := serv.Accept(context.Background())
|
||||
Expect(err).To(MatchError(testErr))
|
||||
}
|
||||
})
|
||||
|
||||
It("returns when the context is canceled", func() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
defer GinkgoRecover()
|
||||
_, err := serv.Accept(ctx)
|
||||
Expect(err).To(MatchError("context canceled"))
|
||||
close(done)
|
||||
}()
|
||||
|
||||
Consistently(done).ShouldNot(BeClosed())
|
||||
cancel()
|
||||
Eventually(done).Should(BeClosed())
|
||||
})
|
||||
|
||||
It("accepts new sessions when the handshake completes", func() {
|
||||
sess := NewMockQuicSession(mockCtrl)
|
||||
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
defer GinkgoRecover()
|
||||
s, err := serv.Accept(context.Background())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(s).To(Equal(sess))
|
||||
close(done)
|
||||
}()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background()) // handshake context
|
||||
serv.newSession = func(
|
||||
_ connection,
|
||||
runner sessionRunner,
|
||||
_ protocol.ConnectionID,
|
||||
_ protocol.ConnectionID,
|
||||
_ protocol.ConnectionID,
|
||||
_ *Config,
|
||||
_ *tls.Config,
|
||||
_ *handshake.TransportParameters,
|
||||
_ *handshake.TokenGenerator,
|
||||
_ utils.Logger,
|
||||
_ protocol.VersionNumber,
|
||||
) (quicSession, error) {
|
||||
sess.EXPECT().HandshakeComplete().Return(ctx)
|
||||
sess.EXPECT().run().Do(func() {})
|
||||
sess.EXPECT().Context().Return(context.Background())
|
||||
return sess, nil
|
||||
}
|
||||
_, err := serv.createNewSession(&net.UDPAddr{}, nil, nil, nil, nil, protocol.VersionWhatever)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Consistently(done).ShouldNot(BeClosed())
|
||||
cancel() // complete the handshake
|
||||
Eventually(done).Should(BeClosed())
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Context("server accepting sessions that haven't completed the handshake", func() {
|
||||
var serv *earlyServer
|
||||
|
||||
BeforeEach(func() {
|
||||
ln, err := ListenEarly(conn, tlsConf, nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
return hdr
|
||||
}
|
||||
|
||||
It("drops Initial packets with a too short connection ID", func() {
|
||||
serv.handlePacket(getPacket(&wire.Header{
|
||||
IsLongHeader: true,
|
||||
Type: protocol.PacketTypeInitial,
|
||||
DestConnectionID: protocol.ConnectionID{1, 2, 3, 4},
|
||||
Version: serv.config.Versions[0],
|
||||
}, nil))
|
||||
Consistently(conn.dataWritten).ShouldNot(Receive())
|
||||
serv = ln.(*earlyServer)
|
||||
})
|
||||
|
||||
It("drops too small Initial", func() {
|
||||
serv.handlePacket(getPacket(&wire.Header{
|
||||
IsLongHeader: true,
|
||||
Type: protocol.PacketTypeInitial,
|
||||
DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8},
|
||||
Version: serv.config.Versions[0],
|
||||
}, make([]byte, protocol.MinInitialPacketSize-100),
|
||||
))
|
||||
Consistently(conn.dataWritten).ShouldNot(Receive())
|
||||
})
|
||||
It("accepts new sessions when they become ready", func() {
|
||||
sess := NewMockQuicSession(mockCtrl)
|
||||
|
||||
It("drops packets with a too short connection ID", func() {
|
||||
serv.handlePacket(getPacket(&wire.Header{
|
||||
IsLongHeader: true,
|
||||
Type: protocol.PacketTypeInitial,
|
||||
SrcConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8},
|
||||
DestConnectionID: protocol.ConnectionID{1, 2, 3, 4},
|
||||
Version: serv.config.Versions[0],
|
||||
}, make([]byte, protocol.MinInitialPacketSize)))
|
||||
Consistently(conn.dataWritten).ShouldNot(Receive())
|
||||
})
|
||||
|
||||
It("drops non-Initial packets", func() {
|
||||
serv.handlePacket(getPacket(
|
||||
&wire.Header{
|
||||
Type: protocol.PacketTypeHandshake,
|
||||
Version: serv.config.Versions[0],
|
||||
},
|
||||
[]byte("invalid"),
|
||||
))
|
||||
})
|
||||
|
||||
It("decodes the token from the Token field", func() {
|
||||
raddr := &net.UDPAddr{
|
||||
IP: net.IPv4(192, 168, 13, 37),
|
||||
Port: 1337,
|
||||
}
|
||||
done := make(chan struct{})
|
||||
serv.config.AcceptToken = func(addr net.Addr, token *Token) bool {
|
||||
Expect(addr).To(Equal(raddr))
|
||||
Expect(token).ToNot(BeNil())
|
||||
go func() {
|
||||
defer GinkgoRecover()
|
||||
s, err := serv.Accept(context.Background())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(s).To(Equal(sess))
|
||||
close(done)
|
||||
return false
|
||||
}
|
||||
token, err := serv.tokenGenerator.NewRetryToken(raddr, nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
packet := getPacket(&wire.Header{
|
||||
IsLongHeader: true,
|
||||
Type: protocol.PacketTypeInitial,
|
||||
Token: token,
|
||||
Version: serv.config.Versions[0],
|
||||
}, make([]byte, protocol.MinInitialPacketSize))
|
||||
packet.remoteAddr = raddr
|
||||
serv.handlePacket(packet)
|
||||
Eventually(done).Should(BeClosed())
|
||||
})
|
||||
}()
|
||||
|
||||
It("passes an empty token to the callback, if decoding fails", func() {
|
||||
raddr := &net.UDPAddr{
|
||||
IP: net.IPv4(192, 168, 13, 37),
|
||||
Port: 1337,
|
||||
}
|
||||
done := make(chan struct{})
|
||||
serv.config.AcceptToken = func(addr net.Addr, token *Token) bool {
|
||||
Expect(addr).To(Equal(raddr))
|
||||
Expect(token).To(BeNil())
|
||||
close(done)
|
||||
return false
|
||||
}
|
||||
packet := getPacket(&wire.Header{
|
||||
IsLongHeader: true,
|
||||
Type: protocol.PacketTypeInitial,
|
||||
Token: []byte("foobar"),
|
||||
Version: serv.config.Versions[0],
|
||||
}, make([]byte, protocol.MinInitialPacketSize))
|
||||
packet.remoteAddr = raddr
|
||||
serv.handlePacket(packet)
|
||||
Eventually(done).Should(BeClosed())
|
||||
})
|
||||
|
||||
It("sends a Version Negotiation Packet for unsupported versions", func() {
|
||||
srcConnID := protocol.ConnectionID{1, 2, 3, 4, 5}
|
||||
destConnID := protocol.ConnectionID{1, 2, 3, 4, 5, 6}
|
||||
packet := getPacket(&wire.Header{
|
||||
IsLongHeader: true,
|
||||
Type: protocol.PacketTypeInitial,
|
||||
SrcConnectionID: srcConnID,
|
||||
DestConnectionID: destConnID,
|
||||
Version: 0x42,
|
||||
}, make([]byte, protocol.MinInitialPacketSize))
|
||||
packet.remoteAddr = &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 1337}
|
||||
serv.handlePacket(packet)
|
||||
var write mockPacketConnWrite
|
||||
Eventually(conn.dataWritten).Should(Receive(&write))
|
||||
Expect(write.to.String()).To(Equal("127.0.0.1:1337"))
|
||||
Expect(wire.IsVersionNegotiationPacket(write.data)).To(BeTrue())
|
||||
hdr := parseHeader(write.data)
|
||||
Expect(hdr.DestConnectionID).To(Equal(srcConnID))
|
||||
Expect(hdr.SrcConnectionID).To(Equal(destConnID))
|
||||
Expect(hdr.SupportedVersions).ToNot(ContainElement(protocol.VersionNumber(0x42)))
|
||||
})
|
||||
|
||||
It("replies with a Retry packet, if a Token is required", func() {
|
||||
serv.config.AcceptToken = func(_ net.Addr, _ *Token) bool { return false }
|
||||
hdr := &wire.Header{
|
||||
IsLongHeader: true,
|
||||
Type: protocol.PacketTypeInitial,
|
||||
SrcConnectionID: protocol.ConnectionID{5, 4, 3, 2, 1},
|
||||
DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
|
||||
Version: protocol.VersionTLS,
|
||||
}
|
||||
packet := getPacket(hdr, make([]byte, protocol.MinInitialPacketSize))
|
||||
packet.remoteAddr = &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 1337}
|
||||
serv.handlePacket(packet)
|
||||
var write mockPacketConnWrite
|
||||
Eventually(conn.dataWritten).Should(Receive(&write))
|
||||
Expect(write.to.String()).To(Equal("127.0.0.1:1337"))
|
||||
replyHdr := parseHeader(write.data)
|
||||
Expect(replyHdr.Type).To(Equal(protocol.PacketTypeRetry))
|
||||
Expect(replyHdr.SrcConnectionID).ToNot(Equal(hdr.DestConnectionID))
|
||||
Expect(replyHdr.DestConnectionID).To(Equal(hdr.SrcConnectionID))
|
||||
Expect(replyHdr.OrigDestConnectionID).To(Equal(hdr.DestConnectionID))
|
||||
Expect(replyHdr.Token).ToNot(BeEmpty())
|
||||
})
|
||||
|
||||
It("creates a session, if no Token is required", func() {
|
||||
serv.config.AcceptToken = func(_ net.Addr, _ *Token) bool { return true }
|
||||
hdr := &wire.Header{
|
||||
IsLongHeader: true,
|
||||
Type: protocol.PacketTypeInitial,
|
||||
SrcConnectionID: protocol.ConnectionID{5, 4, 3, 2, 1},
|
||||
DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
|
||||
Version: protocol.VersionTLS,
|
||||
}
|
||||
p := getPacket(hdr, make([]byte, protocol.MinInitialPacketSize))
|
||||
run := make(chan struct{})
|
||||
ready := make(chan struct{})
|
||||
serv.newSession = func(
|
||||
_ connection,
|
||||
_ sessionRunner,
|
||||
origConnID protocol.ConnectionID,
|
||||
destConnID protocol.ConnectionID,
|
||||
srcConnID protocol.ConnectionID,
|
||||
runner sessionRunner,
|
||||
_ protocol.ConnectionID,
|
||||
_ protocol.ConnectionID,
|
||||
_ protocol.ConnectionID,
|
||||
_ *Config,
|
||||
_ *tls.Config,
|
||||
_ *handshake.TransportParameters,
|
||||
|
@ -295,29 +554,15 @@ var _ = Describe("Server", func() {
|
|||
_ utils.Logger,
|
||||
_ protocol.VersionNumber,
|
||||
) (quicSession, error) {
|
||||
Expect(origConnID).To(Equal(hdr.DestConnectionID))
|
||||
Expect(destConnID).To(Equal(hdr.SrcConnectionID))
|
||||
// make sure we're using a server-generated connection ID
|
||||
Expect(srcConnID).ToNot(Equal(hdr.DestConnectionID))
|
||||
Expect(srcConnID).ToNot(Equal(hdr.SrcConnectionID))
|
||||
sess := NewMockQuicSession(mockCtrl)
|
||||
sess.EXPECT().handlePacket(p)
|
||||
sess.EXPECT().run().Do(func() { close(run) })
|
||||
sess.EXPECT().run().Do(func() {})
|
||||
sess.EXPECT().earlySessionReady().Return(ready)
|
||||
sess.EXPECT().Context().Return(context.Background())
|
||||
sess.EXPECT().HandshakeComplete().Return(context.Background())
|
||||
return sess, nil
|
||||
}
|
||||
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
defer GinkgoRecover()
|
||||
serv.handlePacket(p)
|
||||
// the Handshake packet is written by the session
|
||||
Consistently(conn.dataWritten).ShouldNot(Receive())
|
||||
close(done)
|
||||
}()
|
||||
// make sure we're using a server-generated connection ID
|
||||
Eventually(run).Should(BeClosed())
|
||||
_, err := serv.createNewSession(&net.UDPAddr{}, nil, nil, nil, nil, protocol.VersionWhatever)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Consistently(done).ShouldNot(BeClosed())
|
||||
close(ready)
|
||||
Eventually(done).Should(BeClosed())
|
||||
})
|
||||
|
||||
|
@ -347,13 +592,13 @@ var _ = Describe("Server", func() {
|
|||
_ utils.Logger,
|
||||
_ protocol.VersionNumber,
|
||||
) (quicSession, error) {
|
||||
ready := make(chan struct{})
|
||||
close(ready)
|
||||
sess := NewMockQuicSession(mockCtrl)
|
||||
sess.EXPECT().handlePacket(p)
|
||||
sess.EXPECT().run()
|
||||
sess.EXPECT().earlySessionReady().Return(ready)
|
||||
sess.EXPECT().Context().Return(context.Background())
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
cancel()
|
||||
sess.EXPECT().HandshakeComplete().Return(ctx)
|
||||
return sess, nil
|
||||
}
|
||||
|
||||
|
@ -410,10 +655,8 @@ var _ = Describe("Server", func() {
|
|||
) (quicSession, error) {
|
||||
sess.EXPECT().handlePacket(p)
|
||||
sess.EXPECT().run()
|
||||
sess.EXPECT().earlySessionReady()
|
||||
sess.EXPECT().Context().Return(ctx)
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
cancel()
|
||||
sess.EXPECT().HandshakeComplete().Return(ctx)
|
||||
close(sessionCreated)
|
||||
return sess, nil
|
||||
}
|
||||
|
@ -438,93 +681,6 @@ var _ = Describe("Server", func() {
|
|||
Eventually(done).Should(BeClosed())
|
||||
})
|
||||
})
|
||||
|
||||
Context("accepting sessions", func() {
|
||||
var serv *server
|
||||
|
||||
BeforeEach(func() {
|
||||
ln, err := Listen(conn, tlsConf, nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
serv = ln.(*server)
|
||||
})
|
||||
|
||||
It("returns Accept when an error occurs", func() {
|
||||
testErr := errors.New("test err")
|
||||
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
defer GinkgoRecover()
|
||||
_, err := serv.Accept(context.Background())
|
||||
Expect(err).To(MatchError(testErr))
|
||||
close(done)
|
||||
}()
|
||||
|
||||
serv.setCloseError(testErr)
|
||||
Eventually(done).Should(BeClosed())
|
||||
})
|
||||
|
||||
It("returns immediately, if an error occurred before", func() {
|
||||
testErr := errors.New("test err")
|
||||
serv.setCloseError(testErr)
|
||||
for i := 0; i < 3; i++ {
|
||||
_, err := serv.Accept(context.Background())
|
||||
Expect(err).To(MatchError(testErr))
|
||||
}
|
||||
})
|
||||
|
||||
It("returns when the context is canceled", func() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
defer GinkgoRecover()
|
||||
_, err := serv.Accept(ctx)
|
||||
Expect(err).To(MatchError("context canceled"))
|
||||
close(done)
|
||||
}()
|
||||
|
||||
Consistently(done).ShouldNot(BeClosed())
|
||||
cancel()
|
||||
Eventually(done).Should(BeClosed())
|
||||
})
|
||||
|
||||
It("accepts new sessions when the handshake completes", func() {
|
||||
sess := NewMockQuicSession(mockCtrl)
|
||||
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
defer GinkgoRecover()
|
||||
s, err := serv.Accept(context.Background())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(s).To(Equal(sess))
|
||||
close(done)
|
||||
}()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background()) // handshake context
|
||||
serv.newSession = func(
|
||||
_ connection,
|
||||
runner sessionRunner,
|
||||
_ protocol.ConnectionID,
|
||||
_ protocol.ConnectionID,
|
||||
_ protocol.ConnectionID,
|
||||
_ *Config,
|
||||
_ *tls.Config,
|
||||
_ *handshake.TransportParameters,
|
||||
_ *handshake.TokenGenerator,
|
||||
_ utils.Logger,
|
||||
_ protocol.VersionNumber,
|
||||
) (quicSession, error) {
|
||||
sess.EXPECT().HandshakeComplete().Return(ctx)
|
||||
sess.EXPECT().run().Do(func() {})
|
||||
sess.EXPECT().Context().Return(context.Background())
|
||||
return sess, nil
|
||||
}
|
||||
_, err := serv.createNewSession(&net.UDPAddr{}, nil, nil, nil, nil, protocol.VersionWhatever)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Consistently(done).ShouldNot(BeClosed())
|
||||
cancel() // complete the handshake
|
||||
Eventually(done).Should(BeClosed())
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
var _ = Describe("default source address verification", func() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue