Commit 1580169e authored by Matthew Holt's avatar Matthew Holt

vendor: Update quic-go

parent 95514da9
...@@ -8,19 +8,20 @@ import ( ...@@ -8,19 +8,20 @@ import (
var bufferPool sync.Pool var bufferPool sync.Pool
func getPacketBuffer() []byte { func getPacketBuffer() *[]byte {
return bufferPool.Get().([]byte) return bufferPool.Get().(*[]byte)
} }
func putPacketBuffer(buf []byte) { func putPacketBuffer(buf *[]byte) {
if cap(buf) != int(protocol.MaxReceivePacketSize) { if cap(*buf) != int(protocol.MaxReceivePacketSize) {
panic("putPacketBuffer called with packet of wrong size!") panic("putPacketBuffer called with packet of wrong size!")
} }
bufferPool.Put(buf[:0]) bufferPool.Put(buf)
} }
func init() { func init() {
bufferPool.New = func() interface{} { bufferPool.New = func() interface{} {
return make([]byte, 0, protocol.MaxReceivePacketSize) b := make([]byte, 0, protocol.MaxReceivePacketSize)
return &b
} }
} }
...@@ -85,6 +85,14 @@ func Dial( ...@@ -85,6 +85,14 @@ func Dial(
} }
} }
// check that all versions are actually supported
if config != nil {
for _, v := range config.Versions {
if !protocol.IsValidVersion(v) {
return nil, fmt.Errorf("%s is not a valid QUIC version", v)
}
}
}
clientConfig := populateClientConfig(config) clientConfig := populateClientConfig(config)
c := &client{ c := &client{
conn: &conn{pconn: pconn, currentAddr: remoteAddr}, conn: &conn{pconn: pconn, currentAddr: remoteAddr},
...@@ -132,6 +140,18 @@ func populateClientConfig(config *Config) *Config { ...@@ -132,6 +140,18 @@ func populateClientConfig(config *Config) *Config {
if maxReceiveConnectionFlowControlWindow == 0 { if maxReceiveConnectionFlowControlWindow == 0 {
maxReceiveConnectionFlowControlWindow = protocol.DefaultMaxReceiveConnectionFlowControlWindowClient maxReceiveConnectionFlowControlWindow = protocol.DefaultMaxReceiveConnectionFlowControlWindowClient
} }
maxIncomingStreams := config.MaxIncomingStreams
if maxIncomingStreams == 0 {
maxIncomingStreams = protocol.DefaultMaxIncomingStreams
} else if maxIncomingStreams < 0 {
maxIncomingStreams = 0
}
maxIncomingUniStreams := config.MaxIncomingUniStreams
if maxIncomingUniStreams == 0 {
maxIncomingUniStreams = protocol.DefaultMaxIncomingUniStreams
} else if maxIncomingUniStreams < 0 {
maxIncomingUniStreams = 0
}
return &Config{ return &Config{
Versions: versions, Versions: versions,
...@@ -140,7 +160,9 @@ func populateClientConfig(config *Config) *Config { ...@@ -140,7 +160,9 @@ func populateClientConfig(config *Config) *Config {
RequestConnectionIDOmission: config.RequestConnectionIDOmission, RequestConnectionIDOmission: config.RequestConnectionIDOmission,
MaxReceiveStreamFlowControlWindow: maxReceiveStreamFlowControlWindow, MaxReceiveStreamFlowControlWindow: maxReceiveStreamFlowControlWindow,
MaxReceiveConnectionFlowControlWindow: maxReceiveConnectionFlowControlWindow, MaxReceiveConnectionFlowControlWindow: maxReceiveConnectionFlowControlWindow,
KeepAlive: config.KeepAlive, MaxIncomingStreams: maxIncomingStreams,
MaxIncomingUniStreams: maxIncomingUniStreams,
KeepAlive: config.KeepAlive,
} }
} }
...@@ -171,9 +193,8 @@ func (c *client) dialTLS() error { ...@@ -171,9 +193,8 @@ func (c *client) dialTLS() error {
ConnectionFlowControlWindow: protocol.ReceiveConnectionFlowControlWindow, ConnectionFlowControlWindow: protocol.ReceiveConnectionFlowControlWindow,
IdleTimeout: c.config.IdleTimeout, IdleTimeout: c.config.IdleTimeout,
OmitConnectionID: c.config.RequestConnectionIDOmission, OmitConnectionID: c.config.RequestConnectionIDOmission,
// TODO(#523): make these values configurable MaxBidiStreams: uint16(c.config.MaxIncomingStreams),
MaxBidiStreamID: protocol.MaxBidiStreamID(protocol.MaxIncomingStreams, protocol.PerspectiveClient), MaxUniStreams: uint16(c.config.MaxIncomingUniStreams),
MaxUniStreamID: protocol.MaxUniStreamID(protocol.MaxIncomingStreams, protocol.PerspectiveClient),
} }
csc := handshake.NewCryptoStreamConn(nil) csc := handshake.NewCryptoStreamConn(nil)
extHandler := handshake.NewExtensionHandlerClient(params, c.initialVersion, c.config.Versions, c.version) extHandler := handshake.NewExtensionHandlerClient(params, c.initialVersion, c.config.Versions, c.version)
...@@ -245,7 +266,7 @@ func (c *client) listen() { ...@@ -245,7 +266,7 @@ func (c *client) listen() {
for { for {
var n int var n int
var addr net.Addr var addr net.Addr
data := getPacketBuffer() data := *getPacketBuffer()
data = data[:protocol.MaxReceivePacketSize] data = data[:protocol.MaxReceivePacketSize]
// The packet size should not exceed protocol.MaxReceivePacketSize bytes // The packet size should not exceed protocol.MaxReceivePacketSize bytes
// If it does, we only read a truncated packet, which will then end up undecryptable // If it does, we only read a truncated packet, which will then end up undecryptable
...@@ -347,6 +368,8 @@ func (c *client) handleVersionNegotiationPacket(hdr *wire.Header) error { ...@@ -347,6 +368,8 @@ func (c *client) handleVersionNegotiationPacket(hdr *wire.Header) error {
} }
} }
utils.Infof("Received a Version Negotiation Packet. Supported Versions: %s", hdr.SupportedVersions)
newVersion, ok := protocol.ChooseSupportedVersion(c.config.Versions, hdr.SupportedVersions) newVersion, ok := protocol.ChooseSupportedVersion(c.config.Versions, hdr.SupportedVersions)
if !ok { if !ok {
return qerr.InvalidVersion return qerr.InvalidVersion
......
...@@ -108,7 +108,9 @@ func (c *client) handleHeaderStream() { ...@@ -108,7 +108,9 @@ func (c *client) handleHeaderStream() {
for err == nil { for err == nil {
err = c.readResponse(h2framer, decoder) err = c.readResponse(h2framer, decoder)
} }
utils.Debugf("Error handling header stream: %s", err) if quicErr, ok := err.(*qerr.QuicError); !ok || quicErr.ErrorCode != qerr.PeerGoingAway {
utils.Debugf("Error handling header stream: %s", err)
}
c.headerErr = qerr.Error(qerr.InvalidHeadersStreamData, err.Error()) c.headerErr = qerr.Error(qerr.InvalidHeadersStreamData, err.Error())
// stop all running request // stop all running request
close(c.headerErrored) close(c.headerErrored)
...@@ -202,6 +204,7 @@ func (c *client) RoundTrip(req *http.Request) (*http.Response, error) { ...@@ -202,6 +204,7 @@ func (c *client) RoundTrip(req *http.Request) (*http.Response, error) {
bodySent = true bodySent = true
} }
ctx := req.Context()
for !(bodySent && receivedResponse) { for !(bodySent && receivedResponse) {
select { select {
case res = <-responseChan: case res = <-responseChan:
...@@ -214,8 +217,16 @@ func (c *client) RoundTrip(req *http.Request) (*http.Response, error) { ...@@ -214,8 +217,16 @@ func (c *client) RoundTrip(req *http.Request) (*http.Response, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
case <-ctx.Done():
// error code 6 signals that stream was canceled
dataStream.CancelRead(6)
dataStream.CancelWrite(6)
c.mutex.Lock()
delete(c.responses, dataStream.StreamID())
c.mutex.Unlock()
return nil, ctx.Err()
case <-c.headerErrored: case <-c.headerErrored:
// an error occured on the header stream // an error occurred on the header stream
_ = c.CloseWithError(c.headerErr) _ = c.CloseWithError(c.headerErr)
return nil, c.headerErr return nil, c.headerErr
} }
......
...@@ -76,9 +76,8 @@ func (w *requestWriter) encodeHeaders(req *http.Request, addGzipHeader bool, tra ...@@ -76,9 +76,8 @@ func (w *requestWriter) encodeHeaders(req *http.Request, addGzipHeader bool, tra
if !validPseudoPath(path) { if !validPseudoPath(path) {
if req.URL.Opaque != "" { if req.URL.Opaque != "" {
return nil, fmt.Errorf("invalid request :path %q from URL.Opaque = %q", orig, req.URL.Opaque) return nil, fmt.Errorf("invalid request :path %q from URL.Opaque = %q", orig, req.URL.Opaque)
} else {
return nil, fmt.Errorf("invalid request :path %q", orig)
} }
return nil, fmt.Errorf("invalid request :path %q", orig)
} }
} }
} }
......
...@@ -3,7 +3,6 @@ package h2quic ...@@ -3,7 +3,6 @@ package h2quic
import ( import (
"bytes" "bytes"
"errors" "errors"
"io"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"net/textproto" "net/textproto"
...@@ -16,7 +15,7 @@ import ( ...@@ -16,7 +15,7 @@ import (
// copied from net/http2/transport.go // copied from net/http2/transport.go
var errResponseHeaderListSize = errors.New("http2: response header list larger than advertised limit") var errResponseHeaderListSize = errors.New("http2: response header list larger than advertised limit")
var noBody io.ReadCloser = ioutil.NopCloser(bytes.NewReader(nil)) var noBody = ioutil.NopCloser(bytes.NewReader(nil))
// from the handleResponse function // from the handleResponse function
func responseFromHeaders(f *http2.MetaHeadersFrame) (*http.Response, error) { func responseFromHeaders(f *http2.MetaHeadersFrame) (*http.Response, error) {
...@@ -33,16 +32,7 @@ func responseFromHeaders(f *http2.MetaHeadersFrame) (*http.Response, error) { ...@@ -33,16 +32,7 @@ func responseFromHeaders(f *http2.MetaHeadersFrame) (*http.Response, error) {
return nil, errors.New("malformed non-numeric status pseudo header") return nil, errors.New("malformed non-numeric status pseudo header")
} }
if statusCode == 100 { // TODO: handle statusCode == 100
// TODO: handle this
// traceGot100Continue(cs.trace)
// if cs.on100 != nil {
// cs.on100() // forces any write delay timer to fire
// }
// cs.pastHeaders = false // do it all again
// return nil, nil
}
header := make(http.Header) header := make(http.Header)
res := &http.Response{ res := &http.Response{
...@@ -78,13 +68,7 @@ func setLength(res *http.Response, isHead, streamEnded bool) *http.Response { ...@@ -78,13 +68,7 @@ func setLength(res *http.Response, isHead, streamEnded bool) *http.Response {
if clens := res.Header["Content-Length"]; len(clens) == 1 { if clens := res.Header["Content-Length"]; len(clens) == 1 {
if clen64, err := strconv.ParseInt(clens[0], 10, 64); err == nil { if clen64, err := strconv.ParseInt(clens[0], 10, 64); err == nil {
res.ContentLength = clen64 res.ContentLength = clen64
} else {
// TODO: care? unlike http/1, it won't mess up our framing, so it's
// more safe smuggling-wise to ignore.
} }
} else if len(clens) > 1 {
// TODO: care? unlike http/1, it won't mess up our framing, so it's
// more safe smuggling-wise to ignore.
} }
} }
return res return res
......
...@@ -7,6 +7,7 @@ import ( ...@@ -7,6 +7,7 @@ import (
"time" "time"
"github.com/lucas-clemente/quic-go/internal/protocol" "github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
) )
// Connection is a UDP connection // Connection is a UDP connection
...@@ -43,6 +44,8 @@ func (d Direction) String() string { ...@@ -43,6 +44,8 @@ func (d Direction) String() string {
} }
} }
// Is says if one direction matches another direction.
// For example, incoming matches both incoming and both, but not outgoing.
func (d Direction) Is(dir Direction) bool { func (d Direction) Is(dir Direction) bool {
if d == DirectionBoth || dir == DirectionBoth { if d == DirectionBoth || dir == DirectionBoth {
return true return true
...@@ -131,12 +134,20 @@ func NewQuicProxy(local string, version protocol.VersionNumber, opts *Opts) (*Qu ...@@ -131,12 +134,20 @@ func NewQuicProxy(local string, version protocol.VersionNumber, opts *Opts) (*Qu
version: version, version: version,
} }
utils.Debugf("Starting UDP Proxy %s <-> %s", conn.LocalAddr(), raddr)
go p.runProxy() go p.runProxy()
return &p, nil return &p, nil
} }
// Close stops the UDP Proxy // Close stops the UDP Proxy
func (p *QuicProxy) Close() error { func (p *QuicProxy) Close() error {
p.mutex.Lock()
defer p.mutex.Unlock()
for _, c := range p.clientDict {
if err := c.ServerConn.Close(); err != nil {
return err
}
}
return p.conn.Close() return p.conn.Close()
} }
...@@ -189,19 +200,27 @@ func (p *QuicProxy) runProxy() error { ...@@ -189,19 +200,27 @@ func (p *QuicProxy) runProxy() error {
packetCount := atomic.AddUint64(&conn.incomingPacketCounter, 1) packetCount := atomic.AddUint64(&conn.incomingPacketCounter, 1)
if p.dropPacket(DirectionIncoming, packetCount) { if p.dropPacket(DirectionIncoming, packetCount) {
if utils.Debug() {
utils.Debugf("dropping incoming packet %d (%d bytes)", packetCount, n)
}
continue continue
} }
// Send the packet to the server // Send the packet to the server
delay := p.delayPacket(DirectionIncoming, packetCount) delay := p.delayPacket(DirectionIncoming, packetCount)
if delay != 0 { if delay != 0 {
if utils.Debug() {
utils.Debugf("delaying incoming packet %d (%d bytes) to %s by %s", packetCount, n, conn.ServerConn.RemoteAddr(), delay)
}
time.AfterFunc(delay, func() { time.AfterFunc(delay, func() {
// TODO: handle error // TODO: handle error
_, _ = conn.ServerConn.Write(raw) _, _ = conn.ServerConn.Write(raw)
}) })
} else { } else {
_, err := conn.ServerConn.Write(raw) if utils.Debug() {
if err != nil { utils.Debugf("forwarding incoming packet %d (%d bytes) to %s", packetCount, n, conn.ServerConn.RemoteAddr())
}
if _, err := conn.ServerConn.Write(raw); err != nil {
return err return err
} }
} }
...@@ -221,18 +240,26 @@ func (p *QuicProxy) runConnection(conn *connection) error { ...@@ -221,18 +240,26 @@ func (p *QuicProxy) runConnection(conn *connection) error {
packetCount := atomic.AddUint64(&conn.outgoingPacketCounter, 1) packetCount := atomic.AddUint64(&conn.outgoingPacketCounter, 1)
if p.dropPacket(DirectionOutgoing, packetCount) { if p.dropPacket(DirectionOutgoing, packetCount) {
if utils.Debug() {
utils.Debugf("dropping outgoing packet %d (%d bytes)", packetCount, n)
}
continue continue
} }
delay := p.delayPacket(DirectionOutgoing, packetCount) delay := p.delayPacket(DirectionOutgoing, packetCount)
if delay != 0 { if delay != 0 {
if utils.Debug() {
utils.Debugf("delaying outgoing packet %d (%d bytes) to %s by %s", packetCount, n, conn.ClientAddr, delay)
}
time.AfterFunc(delay, func() { time.AfterFunc(delay, func() {
// TODO: handle error // TODO: handle error
_, _ = p.conn.WriteToUDP(raw, conn.ClientAddr) _, _ = p.conn.WriteToUDP(raw, conn.ClientAddr)
}) })
} else { } else {
_, err := p.conn.WriteToUDP(raw, conn.ClientAddr) if utils.Debug() {
if err != nil { utils.Debugf("forwarding outgoing packet %d (%d bytes) to %s", packetCount, n, conn.ClientAddr)
}
if _, err := p.conn.WriteToUDP(raw, conn.ClientAddr); err != nil {
return err return err
} }
} }
......
...@@ -22,7 +22,9 @@ const ( ...@@ -22,7 +22,9 @@ const (
) )
var ( var (
PRData = GeneratePRData(dataLen) // PRData contains dataLen bytes of pseudo-random data.
PRData = GeneratePRData(dataLen)
// PRDataLong contains dataLenLong bytes of pseudo-random data.
PRDataLong = GeneratePRData(dataLenLong) PRDataLong = GeneratePRData(dataLenLong)
server *h2quic.Server server *h2quic.Server
...@@ -105,11 +107,13 @@ func StartQuicServer(versions []protocol.VersionNumber) { ...@@ -105,11 +107,13 @@ func StartQuicServer(versions []protocol.VersionNumber) {
}() }()
} }
// StopQuicServer stops the h2quic.Server.
func StopQuicServer() { func StopQuicServer() {
Expect(server.Close()).NotTo(HaveOccurred()) Expect(server.Close()).NotTo(HaveOccurred())
Eventually(stoppedServing).Should(BeClosed()) Eventually(stoppedServing).Should(BeClosed())
} }
// Port returns the UDP port of the QUIC server.
func Port() string { func Port() string {
return port return port
} }
...@@ -113,15 +113,23 @@ type StreamError interface { ...@@ -113,15 +113,23 @@ type StreamError interface {
// A Session is a QUIC connection between two peers. // A Session is a QUIC connection between two peers.
type Session interface { type Session interface {
// AcceptStream returns the next stream opened by the peer, blocking until one is available. // AcceptStream returns the next stream opened by the peer, blocking until one is available.
// Since stream 1 is reserved for the crypto stream, the first stream is either 2 (for a client) or 3 (for a server).
AcceptStream() (Stream, error) AcceptStream() (Stream, error)
// OpenStream opens a new QUIC stream, returning a special error when the peer's concurrent stream limit is reached. // AcceptUniStream returns the next unidirectional stream opened by the peer, blocking until one is available.
// New streams always have the smallest possible stream ID. AcceptUniStream() (ReceiveStream, error)
// TODO: Enable testing for the special error // OpenStream opens a new bidirectional QUIC stream.
// It returns a special error when the peer's concurrent stream limit is reached.
// TODO(#1152): Enable testing for the special error
OpenStream() (Stream, error) OpenStream() (Stream, error)
// OpenStreamSync opens a new QUIC stream, blocking until the peer's concurrent stream limit allows a new stream to be opened. // OpenStreamSync opens a new bidirectional QUIC stream.
// It always picks the smallest possible stream ID. // It blocks until the peer's concurrent stream limit allows a new stream to be opened.
OpenStreamSync() (Stream, error) OpenStreamSync() (Stream, error)
// OpenUniStream opens a new outgoing unidirectional QUIC stream.
// It returns a special error when the peer's concurrent stream limit is reached.
// TODO(#1152): Enable testing for the special error
OpenUniStream() (SendStream, error)
// OpenUniStreamSync opens a new outgoing unidirectional QUIC stream.
// It blocks until the peer's concurrent stream limit allows a new stream to be opened.
OpenUniStreamSync() (SendStream, error)
// LocalAddr returns the local address. // LocalAddr returns the local address.
LocalAddr() net.Addr LocalAddr() net.Addr
// RemoteAddr returns the address of the peer. // RemoteAddr returns the address of the peer.
...@@ -166,6 +174,17 @@ type Config struct { ...@@ -166,6 +174,17 @@ type Config struct {
// MaxReceiveConnectionFlowControlWindow is the connection-level flow control window for receiving data. // MaxReceiveConnectionFlowControlWindow is the connection-level flow control window for receiving data.
// If this value is zero, it will default to 1.5 MB for the server and 15 MB for the client. // If this value is zero, it will default to 1.5 MB for the server and 15 MB for the client.
MaxReceiveConnectionFlowControlWindow uint64 MaxReceiveConnectionFlowControlWindow uint64
// MaxIncomingStreams is the maximum number of concurrent bidirectional streams that a peer is allowed to open.
// If not set, it will default to 100.
// If set to a negative value, it doesn't allow any bidirectional streams.
// Values larger than 65535 (math.MaxUint16) are invalid.
MaxIncomingStreams int
// MaxIncomingUniStreams is the maximum number of concurrent unidirectional streams that a peer is allowed to open.
// This value doesn't have any effect in Google QUIC.
// If not set, it will default to 100.
// If set to a negative value, it doesn't allow any unidirectional streams.
// Values larger than 65535 (math.MaxUint16) are invalid.
MaxIncomingUniStreams int
// KeepAlive defines whether this peer will periodically send PING frames to keep the connection alive. // KeepAlive defines whether this peer will periodically send PING frames to keep the connection alive.
KeepAlive bool KeepAlive bool
} }
......
...@@ -10,15 +10,13 @@ import ( ...@@ -10,15 +10,13 @@ import (
// SentPacketHandler handles ACKs received for outgoing packets // SentPacketHandler handles ACKs received for outgoing packets
type SentPacketHandler interface { type SentPacketHandler interface {
// SentPacket may modify the packet // SentPacket may modify the packet
SentPacket(packet *Packet) error SentPacket(packet *Packet)
SentPacketsAsRetransmission(packets []*Packet, retransmissionOf protocol.PacketNumber)
ReceivedAck(ackFrame *wire.AckFrame, withPacketNumber protocol.PacketNumber, encLevel protocol.EncryptionLevel, recvTime time.Time) error ReceivedAck(ackFrame *wire.AckFrame, withPacketNumber protocol.PacketNumber, encLevel protocol.EncryptionLevel, recvTime time.Time) error
SetHandshakeComplete() SetHandshakeComplete()
// SendingAllowed says if a packet can be sent. // The SendMode determines if and what kind of packets can be sent.
// Sending packets might not be possible because: SendMode() SendMode
// * we're congestion limited
// * we're tracking the maximum number of sent packets
SendingAllowed() bool
// TimeUntilSend is the time when the next packet should be sent. // TimeUntilSend is the time when the next packet should be sent.
// It is used for pacing packets. // It is used for pacing packets.
TimeUntilSend() time.Time TimeUntilSend() time.Time
...@@ -32,10 +30,10 @@ type SentPacketHandler interface { ...@@ -32,10 +30,10 @@ type SentPacketHandler interface {
GetStopWaitingFrame(force bool) *wire.StopWaitingFrame GetStopWaitingFrame(force bool) *wire.StopWaitingFrame
GetLowestPacketNotConfirmedAcked() protocol.PacketNumber GetLowestPacketNotConfirmedAcked() protocol.PacketNumber
DequeuePacketForRetransmission() (packet *Packet) DequeuePacketForRetransmission() (packet *Packet)
GetLeastUnacked() protocol.PacketNumber GetPacketNumberLen(protocol.PacketNumber) protocol.PacketNumberLen
GetAlarmTimeout() time.Time GetAlarmTimeout() time.Time
OnAlarm() OnAlarm() error
} }
// ReceivedPacketHandler handles ACKs needed to send for incoming packets // ReceivedPacketHandler handles ACKs needed to send for incoming packets
......
...@@ -11,12 +11,19 @@ import ( ...@@ -11,12 +11,19 @@ import (
// +gen linkedlist // +gen linkedlist
type Packet struct { type Packet struct {
PacketNumber protocol.PacketNumber PacketNumber protocol.PacketNumber
PacketType protocol.PacketType
Frames []wire.Frame Frames []wire.Frame
Length protocol.ByteCount Length protocol.ByteCount
EncryptionLevel protocol.EncryptionLevel EncryptionLevel protocol.EncryptionLevel
largestAcked protocol.PacketNumber // if the packet contains an ACK, the LargestAcked value of that ACK largestAcked protocol.PacketNumber // if the packet contains an ACK, the LargestAcked value of that ACK
sendTime time.Time sendTime time.Time
queuedForRetransmission bool
includedInBytesInFlight bool
retransmittedAs []protocol.PacketNumber
isRetransmission bool // we need a separate bool here because 0 is a valid packet number
retransmissionOf protocol.PacketNumber
} }
// GetFramesForRetransmission gets all the frames for retransmission // GetFramesForRetransmission gets all the frames for retransmission
......
...@@ -3,7 +3,9 @@ package ackhandler ...@@ -3,7 +3,9 @@ package ackhandler
import ( import (
"time" "time"
"github.com/lucas-clemente/quic-go/internal/congestion"
"github.com/lucas-clemente/quic-go/internal/protocol" "github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
"github.com/lucas-clemente/quic-go/internal/wire" "github.com/lucas-clemente/quic-go/internal/wire"
) )
...@@ -15,6 +17,7 @@ type receivedPacketHandler struct { ...@@ -15,6 +17,7 @@ type receivedPacketHandler struct {
packetHistory *receivedPacketHistory packetHistory *receivedPacketHistory
ackSendDelay time.Duration ackSendDelay time.Duration
rttStats *congestion.RTTStats
packetsReceivedSinceLastAck int packetsReceivedSinceLastAck int
retransmittablePacketsReceivedSinceLastAck int retransmittablePacketsReceivedSinceLastAck int
...@@ -25,29 +28,54 @@ type receivedPacketHandler struct { ...@@ -25,29 +28,54 @@ type receivedPacketHandler struct {
version protocol.VersionNumber version protocol.VersionNumber
} }
const (
// maximum delay that can be applied to an ACK for a retransmittable packet
ackSendDelay = 25 * time.Millisecond
// initial maximum number of retransmittable packets received before sending an ack.
initialRetransmittablePacketsBeforeAck = 2
// number of retransmittable that an ACK is sent for
retransmittablePacketsBeforeAck = 10
// 1/5 RTT delay when doing ack decimation
ackDecimationDelay = 1.0 / 4
// 1/8 RTT delay when doing ack decimation
shortAckDecimationDelay = 1.0 / 8
// Minimum number of packets received before ack decimation is enabled.
// This intends to avoid the beginning of slow start, when CWNDs may be
// rapidly increasing.
minReceivedBeforeAckDecimation = 100
// Maximum number of packets to ack immediately after a missing packet for
// fast retransmission to kick in at the sender. This limit is created to
// reduce the number of acks sent that have no benefit for fast retransmission.
// Set to the number of nacks needed for fast retransmit plus one for protection
// against an ack loss
maxPacketsAfterNewMissing = 4
)
// NewReceivedPacketHandler creates a new receivedPacketHandler // NewReceivedPacketHandler creates a new receivedPacketHandler
func NewReceivedPacketHandler(version protocol.VersionNumber) ReceivedPacketHandler { func NewReceivedPacketHandler(rttStats *congestion.RTTStats, version protocol.VersionNumber) ReceivedPacketHandler {
return &receivedPacketHandler{ return &receivedPacketHandler{
packetHistory: newReceivedPacketHistory(), packetHistory: newReceivedPacketHistory(),
ackSendDelay: protocol.AckSendDelay, ackSendDelay: ackSendDelay,
rttStats: rttStats,
version: version, version: version,
} }
} }
func (h *receivedPacketHandler) ReceivedPacket(packetNumber protocol.PacketNumber, rcvTime time.Time, shouldInstigateAck bool) error { func (h *receivedPacketHandler) ReceivedPacket(packetNumber protocol.PacketNumber, rcvTime time.Time, shouldInstigateAck bool) error {
if packetNumber < h.ignoreBelow {
return nil
}
isMissing := h.isMissing(packetNumber)
if packetNumber > h.largestObserved { if packetNumber > h.largestObserved {
h.largestObserved = packetNumber h.largestObserved = packetNumber
h.largestObservedReceivedTime = rcvTime h.largestObservedReceivedTime = rcvTime
} }
if packetNumber < h.ignoreBelow {
return nil
}
if err := h.packetHistory.ReceivedPacket(packetNumber); err != nil { if err := h.packetHistory.ReceivedPacket(packetNumber); err != nil {
return err return err
} }
h.maybeQueueAck(packetNumber, rcvTime, shouldInstigateAck) h.maybeQueueAck(packetNumber, rcvTime, shouldInstigateAck, isMissing)
return nil return nil
} }
...@@ -58,35 +86,68 @@ func (h *receivedPacketHandler) IgnoreBelow(p protocol.PacketNumber) { ...@@ -58,35 +86,68 @@ func (h *receivedPacketHandler) IgnoreBelow(p protocol.PacketNumber) {
h.packetHistory.DeleteBelow(p) h.packetHistory.DeleteBelow(p)
} }
func (h *receivedPacketHandler) maybeQueueAck(packetNumber protocol.PacketNumber, rcvTime time.Time, shouldInstigateAck bool) { // isMissing says if a packet was reported missing in the last ACK.
h.packetsReceivedSinceLastAck++ func (h *receivedPacketHandler) isMissing(p protocol.PacketNumber) bool {
if h.lastAck == nil {
if shouldInstigateAck { return false
h.retransmittablePacketsReceivedSinceLastAck++
} }
return p < h.lastAck.LargestAcked && !h.lastAck.AcksPacket(p)
}
// always ack the first packet func (h *receivedPacketHandler) hasNewMissingPackets() bool {
if h.lastAck == nil { if h.lastAck == nil {
h.ackQueued = true return false
} }
highestRange := h.packetHistory.GetHighestAckRange()
return highestRange.First >= h.lastAck.LargestAcked && highestRange.Len() <= maxPacketsAfterNewMissing
}
// if the packet number is smaller than the largest acked packet, it must have been reported missing with the last ACK // maybeQueueAck queues an ACK, if necessary.
// note that it cannot be a duplicate because they're already filtered out by ReceivedPacket() // It is implemented analogously to Chrome's QuicConnection::MaybeQueueAck()
if h.lastAck != nil && packetNumber < h.lastAck.LargestAcked { // in ACK_DECIMATION_WITH_REORDERING mode.
func (h *receivedPacketHandler) maybeQueueAck(packetNumber protocol.PacketNumber, rcvTime time.Time, shouldInstigateAck, wasMissing bool) {
h.packetsReceivedSinceLastAck++
// always ack the first packet
if h.lastAck == nil {
h.ackQueued = true h.ackQueued = true
return
} }
// check if a new missing range above the previously was created // Send an ACK if this packet was reported missing in an ACK sent before.
if h.lastAck != nil && h.packetHistory.GetHighestAckRange().First > h.lastAck.LargestAcked { // Ack decimation with reordering relies on the timer to send an ACK, but if
// missing packets we reported in the previous ack, send an ACK immediately.
if wasMissing {
h.ackQueued = true h.ackQueued = true
} }
if !h.ackQueued && shouldInstigateAck { if !h.ackQueued && shouldInstigateAck {
if h.retransmittablePacketsReceivedSinceLastAck >= protocol.RetransmittablePacketsBeforeAck { h.retransmittablePacketsReceivedSinceLastAck++
h.ackQueued = true
if packetNumber > minReceivedBeforeAckDecimation {
// ack up to 10 packets at once
if h.retransmittablePacketsReceivedSinceLastAck >= retransmittablePacketsBeforeAck {
h.ackQueued = true
} else if h.ackAlarm.IsZero() {
// wait for the minimum of the ack decimation delay or the delayed ack time before sending an ack
ackDelay := utils.MinDuration(ackSendDelay, time.Duration(float64(h.rttStats.MinRTT())*float64(ackDecimationDelay)))
h.ackAlarm = rcvTime.Add(ackDelay)
}
} else { } else {
if h.ackAlarm.IsZero() { // send an ACK every 2 retransmittable packets
h.ackAlarm = rcvTime.Add(h.ackSendDelay) if h.retransmittablePacketsReceivedSinceLastAck >= initialRetransmittablePacketsBeforeAck {
h.ackQueued = true
} else if h.ackAlarm.IsZero() {
h.ackAlarm = rcvTime.Add(ackSendDelay)
}
}
// If there are new missing packets to report, set a short timer to send an ACK.
if h.hasNewMissingPackets() {
// wait the minimum of 1/8 min RTT and the existing ack time
ackDelay := float64(h.rttStats.MinRTT()) * float64(shortAckDecimationDelay)
ackTime := rcvTime.Add(time.Duration(ackDelay))
if h.ackAlarm.IsZero() || h.ackAlarm.After(ackTime) {
h.ackAlarm = ackTime
} }
} }
} }
...@@ -118,7 +179,6 @@ func (h *receivedPacketHandler) GetAckFrame() *wire.AckFrame { ...@@ -118,7 +179,6 @@ func (h *receivedPacketHandler) GetAckFrame() *wire.AckFrame {
h.ackQueued = false h.ackQueued = false
h.packetsReceivedSinceLastAck = 0 h.packetsReceivedSinceLastAck = 0
h.retransmittablePacketsReceivedSinceLastAck = 0 h.retransmittablePacketsReceivedSinceLastAck = 0
return ack return ack
} }
......
package ackhandler
import "fmt"
// The SendMode says what kind of packets can be sent.
type SendMode uint8
const (
// SendNone means that no packets should be sent
SendNone SendMode = iota
// SendAck means an ACK-only packet should be sent
SendAck
// SendRetransmission means that retransmissions should be sent
SendRetransmission
// SendAny packet should be sent
SendAny
)
func (s SendMode) String() string {
switch s {
case SendNone:
return "none"
case SendAck:
return "ack"
case SendRetransmission:
return "retransmission"
case SendAny:
return "any"
default:
return fmt.Sprintf("invalid send mode: %d", s)
}
}
package ackhandler package ackhandler
import ( import (
"errors"
"fmt" "fmt"
"math" "math"
"time" "time"
...@@ -30,13 +29,12 @@ const ( ...@@ -30,13 +29,12 @@ const (
maxRTOTimeout = 60 * time.Second maxRTOTimeout = 60 * time.Second
) )
// ErrDuplicateOrOutOfOrderAck occurs when a duplicate or an out-of-order ACK is received
var ErrDuplicateOrOutOfOrderAck = errors.New("SentPacketHandler: Duplicate or out-of-order ACK")
type sentPacketHandler struct { type sentPacketHandler struct {
lastSentPacketNumber protocol.PacketNumber lastSentPacketNumber protocol.PacketNumber
nextPacketSendTime time.Time lastSentRetransmittablePacketTime time.Time
skippedPackets []protocol.PacketNumber
nextPacketSendTime time.Time
skippedPackets []protocol.PacketNumber
largestAcked protocol.PacketNumber largestAcked protocol.PacketNumber
largestReceivedPacketWithAck protocol.PacketNumber largestReceivedPacketWithAck protocol.PacketNumber
...@@ -45,7 +43,7 @@ type sentPacketHandler struct { ...@@ -45,7 +43,7 @@ type sentPacketHandler struct {
// once we receive an ACK from the peer for packet 20, the lowestPacketNotConfirmedAcked is 101 // once we receive an ACK from the peer for packet 20, the lowestPacketNotConfirmedAcked is 101
lowestPacketNotConfirmedAcked protocol.PacketNumber lowestPacketNotConfirmedAcked protocol.PacketNumber
packetHistory *PacketList packetHistory *sentPacketHistory
stopWaitingManager stopWaitingManager stopWaitingManager stopWaitingManager
retransmissionQueue []*Packet retransmissionQueue []*Packet
...@@ -80,7 +78,7 @@ func NewSentPacketHandler(rttStats *congestion.RTTStats) SentPacketHandler { ...@@ -80,7 +78,7 @@ func NewSentPacketHandler(rttStats *congestion.RTTStats) SentPacketHandler {
) )
return &sentPacketHandler{ return &sentPacketHandler{
packetHistory: NewPacketList(), packetHistory: newSentPacketHistory(),
stopWaitingManager: stopWaitingManager{}, stopWaitingManager: stopWaitingManager{},
rttStats: rttStats, rttStats: rttStats,
congestion: congestion, congestion: congestion,
...@@ -88,8 +86,8 @@ func NewSentPacketHandler(rttStats *congestion.RTTStats) SentPacketHandler { ...@@ -88,8 +86,8 @@ func NewSentPacketHandler(rttStats *congestion.RTTStats) SentPacketHandler {
} }
func (h *sentPacketHandler) lowestUnacked() protocol.PacketNumber { func (h *sentPacketHandler) lowestUnacked() protocol.PacketNumber {
if f := h.packetHistory.Front(); f != nil { if p := h.packetHistory.FirstOutstanding(); p != nil {
return f.Value.PacketNumber return p.PacketNumber
} }
return h.largestAcked + 1 return h.largestAcked + 1
} }
...@@ -101,24 +99,49 @@ func (h *sentPacketHandler) SetHandshakeComplete() { ...@@ -101,24 +99,49 @@ func (h *sentPacketHandler) SetHandshakeComplete() {
queue = append(queue, packet) queue = append(queue, packet)
} }
} }
var handshakePackets []*Packet
h.packetHistory.Iterate(func(p *Packet) (bool, error) {
if p.EncryptionLevel != protocol.EncryptionForwardSecure {
handshakePackets = append(handshakePackets, p)
}
return true, nil
})
for _, p := range handshakePackets {
h.packetHistory.Remove(p.PacketNumber)
}
h.retransmissionQueue = queue h.retransmissionQueue = queue
h.handshakeComplete = true h.handshakeComplete = true
} }
func (h *sentPacketHandler) SentPacket(packet *Packet) error { func (h *sentPacketHandler) SentPacket(packet *Packet) {
if protocol.PacketNumber(len(h.retransmissionQueue)+h.packetHistory.Len()+1) > protocol.MaxTrackedSentPackets { packet.sendTime = time.Now()
return errors.New("Too many outstanding non-acked and non-retransmitted packets") if isRetransmittable := h.sentPacketImpl(packet); isRetransmittable {
h.packetHistory.SentPacket(packet)
h.updateLossDetectionAlarm()
}
}
func (h *sentPacketHandler) SentPacketsAsRetransmission(packets []*Packet, retransmissionOf protocol.PacketNumber) {
now := time.Now()
var p []*Packet
for _, packet := range packets {
packet.sendTime = now
if isRetransmittable := h.sentPacketImpl(packet); isRetransmittable {
p = append(p, packet)
}
} }
h.packetHistory.SentPacketsAsRetransmission(p, retransmissionOf)
h.updateLossDetectionAlarm()
}
func (h *sentPacketHandler) sentPacketImpl(packet *Packet) bool /* isRetransmittable */ {
for p := h.lastSentPacketNumber + 1; p < packet.PacketNumber; p++ { for p := h.lastSentPacketNumber + 1; p < packet.PacketNumber; p++ {
h.skippedPackets = append(h.skippedPackets, p) h.skippedPackets = append(h.skippedPackets, p)
if len(h.skippedPackets) > protocol.MaxTrackedSkippedPackets { if len(h.skippedPackets) > protocol.MaxTrackedSkippedPackets {
h.skippedPackets = h.skippedPackets[1:] h.skippedPackets = h.skippedPackets[1:]
} }
} }
now := time.Now()
h.lastSentPacketNumber = packet.PacketNumber h.lastSentPacketNumber = packet.PacketNumber
var largestAcked protocol.PacketNumber var largestAcked protocol.PacketNumber
...@@ -132,24 +155,15 @@ func (h *sentPacketHandler) SentPacket(packet *Packet) error { ...@@ -132,24 +155,15 @@ func (h *sentPacketHandler) SentPacket(packet *Packet) error {
isRetransmittable := len(packet.Frames) != 0 isRetransmittable := len(packet.Frames) != 0
if isRetransmittable { if isRetransmittable {
packet.sendTime = now
packet.largestAcked = largestAcked packet.largestAcked = largestAcked
h.lastSentRetransmittablePacketTime = packet.sendTime
packet.includedInBytesInFlight = true
h.bytesInFlight += packet.Length h.bytesInFlight += packet.Length
h.packetHistory.PushBack(*packet)
} }
h.congestion.OnPacketSent(packet.sendTime, h.bytesInFlight, packet.PacketNumber, packet.Length, isRetransmittable)
h.congestion.OnPacketSent( h.nextPacketSendTime = utils.MaxTime(h.nextPacketSendTime, packet.sendTime).Add(h.congestion.TimeUntilSend(h.bytesInFlight))
now, return isRetransmittable
h.bytesInFlight,
packet.PacketNumber,
packet.Length,
isRetransmittable,
)
h.nextPacketSendTime = utils.MaxTime(h.nextPacketSendTime, now).Add(h.congestion.TimeUntilSend(h.bytesInFlight))
h.updateLossDetectionAlarm(now)
return nil
} }
func (h *sentPacketHandler) ReceivedAck(ackFrame *wire.AckFrame, withPacketNumber protocol.PacketNumber, encLevel protocol.EncryptionLevel, rcvTime time.Time) error { func (h *sentPacketHandler) ReceivedAck(ackFrame *wire.AckFrame, withPacketNumber protocol.PacketNumber, encLevel protocol.EncryptionLevel, rcvTime time.Time) error {
...@@ -157,26 +171,19 @@ func (h *sentPacketHandler) ReceivedAck(ackFrame *wire.AckFrame, withPacketNumbe ...@@ -157,26 +171,19 @@ func (h *sentPacketHandler) ReceivedAck(ackFrame *wire.AckFrame, withPacketNumbe
return qerr.Error(qerr.InvalidAckData, "Received ACK for an unsent package") return qerr.Error(qerr.InvalidAckData, "Received ACK for an unsent package")
} }
// duplicate or out-of-order ACK // duplicate or out of order ACK
// if withPacketNumber <= h.largestReceivedPacketWithAck && withPacketNumber != 0 { if withPacketNumber != 0 && withPacketNumber <= h.largestReceivedPacketWithAck {
if withPacketNumber <= h.largestReceivedPacketWithAck { utils.Debugf("Ignoring ACK frame (duplicate or out of order).")
return ErrDuplicateOrOutOfOrderAck
}
h.largestReceivedPacketWithAck = withPacketNumber
// ignore repeated ACK (ACKs that don't have a higher LargestAcked than the last ACK)
if ackFrame.LargestAcked < h.lowestUnacked() {
return nil return nil
} }
h.largestAcked = ackFrame.LargestAcked h.largestReceivedPacketWithAck = withPacketNumber
h.largestAcked = utils.MaxPacketNumber(h.largestAcked, ackFrame.LargestAcked)
if h.skippedPacketsAcked(ackFrame) { if h.skippedPacketsAcked(ackFrame) {
return qerr.Error(qerr.InvalidAckData, "Received an ACK for a skipped packet number") return qerr.Error(qerr.InvalidAckData, "Received an ACK for a skipped packet number")
} }
rttUpdated := h.maybeUpdateRTT(ackFrame.LargestAcked, ackFrame.DelayTime, rcvTime) if rttUpdated := h.maybeUpdateRTT(ackFrame.LargestAcked, ackFrame.DelayTime, rcvTime); rttUpdated {
if rttUpdated {
h.congestion.MaybeExitSlowStart() h.congestion.MaybeExitSlowStart()
} }
...@@ -185,24 +192,28 @@ func (h *sentPacketHandler) ReceivedAck(ackFrame *wire.AckFrame, withPacketNumbe ...@@ -185,24 +192,28 @@ func (h *sentPacketHandler) ReceivedAck(ackFrame *wire.AckFrame, withPacketNumbe
return err return err
} }
if len(ackedPackets) > 0 { for _, p := range ackedPackets {
for _, p := range ackedPackets { if encLevel < p.EncryptionLevel {
if encLevel < p.Value.EncryptionLevel { return fmt.Errorf("Received ACK with encryption level %s that acks a packet %d (encryption level %s)", encLevel, p.PacketNumber, p.EncryptionLevel)
return fmt.Errorf("Received ACK with encryption level %s that acks a packet %d (encryption level %s)", encLevel, p.Value.PacketNumber, p.Value.EncryptionLevel) }
} // largestAcked == 0 either means that the packet didn't contain an ACK, or it just acked packet 0
// largestAcked == 0 either means that the packet didn't contain an ACK, or it just acked packet 0 // It is safe to ignore the corner case of packets that just acked packet 0, because
// It is safe to ignore the corner case of packets that just acked packet 0, because // the lowestPacketNotConfirmedAcked is only used to limit the number of ACK ranges we will send.
// the lowestPacketNotConfirmedAcked is only used to limit the number of ACK ranges we will send. if p.largestAcked != 0 {
if p.Value.largestAcked != 0 { h.lowestPacketNotConfirmedAcked = utils.MaxPacketNumber(h.lowestPacketNotConfirmedAcked, p.largestAcked+1)
h.lowestPacketNotConfirmedAcked = utils.MaxPacketNumber(h.lowestPacketNotConfirmedAcked, p.Value.largestAcked+1) }
} if err := h.onPacketAcked(p); err != nil {
h.onPacketAcked(p) return err
h.congestion.OnPacketAcked(p.Value.PacketNumber, p.Value.Length, h.bytesInFlight) }
if len(p.retransmittedAs) == 0 {
h.congestion.OnPacketAcked(p.PacketNumber, p.Length, h.bytesInFlight)
} }
} }
h.detectLostPackets(rcvTime) if err := h.detectLostPackets(rcvTime); err != nil {
h.updateLossDetectionAlarm(rcvTime) return err
}
h.updateLossDetectionAlarm()
h.garbageCollectSkippedPackets() h.garbageCollectSkippedPackets()
h.stopWaitingManager.ReceivedAck(ackFrame) h.stopWaitingManager.ReceivedAck(ackFrame)
...@@ -214,59 +225,50 @@ func (h *sentPacketHandler) GetLowestPacketNotConfirmedAcked() protocol.PacketNu ...@@ -214,59 +225,50 @@ func (h *sentPacketHandler) GetLowestPacketNotConfirmedAcked() protocol.PacketNu
return h.lowestPacketNotConfirmedAcked return h.lowestPacketNotConfirmedAcked
} }
func (h *sentPacketHandler) determineNewlyAckedPackets(ackFrame *wire.AckFrame) ([]*PacketElement, error) { func (h *sentPacketHandler) determineNewlyAckedPackets(ackFrame *wire.AckFrame) ([]*Packet, error) {
var ackedPackets []*PacketElement var ackedPackets []*Packet
ackRangeIndex := 0 ackRangeIndex := 0
for el := h.packetHistory.Front(); el != nil; el = el.Next() { err := h.packetHistory.Iterate(func(p *Packet) (bool, error) {
packet := el.Value
packetNumber := packet.PacketNumber
// Ignore packets below the LowestAcked // Ignore packets below the LowestAcked
if packetNumber < ackFrame.LowestAcked { if p.PacketNumber < ackFrame.LowestAcked {
continue return true, nil
} }
// Break after LargestAcked is reached // Break after LargestAcked is reached
if packetNumber > ackFrame.LargestAcked { if p.PacketNumber > ackFrame.LargestAcked {
break return false, nil
} }
if ackFrame.HasMissingRanges() { if ackFrame.HasMissingRanges() {
ackRange := ackFrame.AckRanges[len(ackFrame.AckRanges)-1-ackRangeIndex] ackRange := ackFrame.AckRanges[len(ackFrame.AckRanges)-1-ackRangeIndex]
for packetNumber > ackRange.Last && ackRangeIndex < len(ackFrame.AckRanges)-1 { for p.PacketNumber > ackRange.Last && ackRangeIndex < len(ackFrame.AckRanges)-1 {
ackRangeIndex++ ackRangeIndex++
ackRange = ackFrame.AckRanges[len(ackFrame.AckRanges)-1-ackRangeIndex] ackRange = ackFrame.AckRanges[len(ackFrame.AckRanges)-1-ackRangeIndex]
} }
if packetNumber >= ackRange.First { // packet i contained in ACK range if p.PacketNumber >= ackRange.First { // packet i contained in ACK range
if packetNumber > ackRange.Last { if p.PacketNumber > ackRange.Last {
return nil, fmt.Errorf("BUG: ackhandler would have acked wrong packet 0x%x, while evaluating range 0x%x -> 0x%x", packetNumber, ackRange.First, ackRange.Last) return false, fmt.Errorf("BUG: ackhandler would have acked wrong packet 0x%x, while evaluating range 0x%x -> 0x%x", p.PacketNumber, ackRange.First, ackRange.Last)
} }
ackedPackets = append(ackedPackets, el) ackedPackets = append(ackedPackets, p)
} }
} else { } else {
ackedPackets = append(ackedPackets, el) ackedPackets = append(ackedPackets, p)
} }
} return true, nil
return ackedPackets, nil })
return ackedPackets, err
} }
func (h *sentPacketHandler) maybeUpdateRTT(largestAcked protocol.PacketNumber, ackDelay time.Duration, rcvTime time.Time) bool { func (h *sentPacketHandler) maybeUpdateRTT(largestAcked protocol.PacketNumber, ackDelay time.Duration, rcvTime time.Time) bool {
for el := h.packetHistory.Front(); el != nil; el = el.Next() { if p := h.packetHistory.GetPacket(largestAcked); p != nil {
packet := el.Value h.rttStats.UpdateRTT(rcvTime.Sub(p.sendTime), ackDelay, rcvTime)
if packet.PacketNumber == largestAcked { return true
h.rttStats.UpdateRTT(rcvTime.Sub(packet.sendTime), ackDelay, rcvTime)
return true
}
// Packets are sorted by number, so we can stop searching
if packet.PacketNumber > largestAcked {
break
}
} }
return false return false
} }
func (h *sentPacketHandler) updateLossDetectionAlarm(now time.Time) { func (h *sentPacketHandler) updateLossDetectionAlarm() {
// Cancel the alarm if no packets are outstanding // Cancel the alarm if no packets are outstanding
if h.packetHistory.Len() == 0 { if h.packetHistory.Len() == 0 {
h.alarm = time.Time{} h.alarm = time.Time{}
...@@ -275,76 +277,137 @@ func (h *sentPacketHandler) updateLossDetectionAlarm(now time.Time) { ...@@ -275,76 +277,137 @@ func (h *sentPacketHandler) updateLossDetectionAlarm(now time.Time) {
// TODO(#497): TLP // TODO(#497): TLP
if !h.handshakeComplete { if !h.handshakeComplete {
h.alarm = now.Add(h.computeHandshakeTimeout()) h.alarm = h.lastSentRetransmittablePacketTime.Add(h.computeHandshakeTimeout())
} else if !h.lossTime.IsZero() { } else if !h.lossTime.IsZero() {
// Early retransmit timer or time loss detection. // Early retransmit timer or time loss detection.
h.alarm = h.lossTime h.alarm = h.lossTime
} else { } else {
// RTO // RTO
h.alarm = now.Add(h.computeRTOTimeout()) h.alarm = h.lastSentRetransmittablePacketTime.Add(h.computeRTOTimeout())
} }
} }
func (h *sentPacketHandler) detectLostPackets(now time.Time) { func (h *sentPacketHandler) detectLostPackets(now time.Time) error {
h.lossTime = time.Time{} h.lossTime = time.Time{}
maxRTT := float64(utils.MaxDuration(h.rttStats.LatestRTT(), h.rttStats.SmoothedRTT())) maxRTT := float64(utils.MaxDuration(h.rttStats.LatestRTT(), h.rttStats.SmoothedRTT()))
delayUntilLost := time.Duration((1.0 + timeReorderingFraction) * maxRTT) delayUntilLost := time.Duration((1.0 + timeReorderingFraction) * maxRTT)
var lostPackets []*PacketElement var lostPackets []*Packet
for el := h.packetHistory.Front(); el != nil; el = el.Next() { h.packetHistory.Iterate(func(packet *Packet) (bool, error) {
packet := el.Value
if packet.PacketNumber > h.largestAcked { if packet.PacketNumber > h.largestAcked {
break return false, nil
}
if packet.queuedForRetransmission { // don't retransmit packets twice
return true, nil
} }
timeSinceSent := now.Sub(packet.sendTime) timeSinceSent := now.Sub(packet.sendTime)
if timeSinceSent > delayUntilLost { if timeSinceSent > delayUntilLost {
lostPackets = append(lostPackets, el) lostPackets = append(lostPackets, packet)
} else if h.lossTime.IsZero() { } else if h.lossTime.IsZero() {
// Note: This conditional is only entered once per call // Note: This conditional is only entered once per call
h.lossTime = now.Add(delayUntilLost - timeSinceSent) h.lossTime = now.Add(delayUntilLost - timeSinceSent)
} }
} return true, nil
})
if len(lostPackets) > 0 { for _, p := range lostPackets {
for _, p := range lostPackets { if err := h.queuePacketForRetransmission(p); err != nil {
h.queuePacketForRetransmission(p) return err
h.congestion.OnPacketLost(p.Value.PacketNumber, p.Value.Length, h.bytesInFlight)
} }
h.bytesInFlight -= p.Length
p.includedInBytesInFlight = false
h.congestion.OnPacketLost(p.PacketNumber, p.Length, h.bytesInFlight)
} }
return nil
} }
func (h *sentPacketHandler) OnAlarm() { func (h *sentPacketHandler) OnAlarm() error {
now := time.Now() now := time.Now()
// TODO(#497): TLP // TODO(#497): TLP
var err error
if !h.handshakeComplete { if !h.handshakeComplete {
h.queueHandshakePacketsForRetransmission()
h.handshakeCount++ h.handshakeCount++
err = h.queueHandshakePacketsForRetransmission()
} else if !h.lossTime.IsZero() { } else if !h.lossTime.IsZero() {
// Early retransmit or time loss detection // Early retransmit or time loss detection
h.detectLostPackets(now) err = h.detectLostPackets(now)
} else { } else {
// RTO // RTO
h.retransmitOldestTwoPackets()
h.rtoCount++ h.rtoCount++
err = h.queueRTOs()
} }
if err != nil {
h.updateLossDetectionAlarm(now) return err
}
h.updateLossDetectionAlarm()
return nil
} }
func (h *sentPacketHandler) GetAlarmTimeout() time.Time { func (h *sentPacketHandler) GetAlarmTimeout() time.Time {
return h.alarm return h.alarm
} }
func (h *sentPacketHandler) onPacketAcked(packetElement *PacketElement) { func (h *sentPacketHandler) onPacketAcked(p *Packet) error {
h.bytesInFlight -= packetElement.Value.Length // This happens if a packet and its retransmissions is acked in the same ACK.
// As soon as we process the first one, this will remove all the retransmissions,
// so we won't find the retransmitted packet number later.
if packet := h.packetHistory.GetPacket(p.PacketNumber); packet == nil {
return nil
}
h.rtoCount = 0 h.rtoCount = 0
h.handshakeCount = 0 h.handshakeCount = 0
// TODO(#497): h.tlpCount = 0 // TODO(#497): h.tlpCount = 0
h.packetHistory.Remove(packetElement)
// find the first packet, from which on we can delete all retransmissions
// example: packet 10 was retransmitted as packet 11 and 12, and
// packet 12 was then retransmitted as 13.
// When receiving an ACK for packet 13, we can remove packets 12 and 13,
// but still need to keep 10 and 11.
first := p
for first.isRetransmission {
previous := h.packetHistory.GetPacket(first.retransmissionOf)
if previous == nil {
return fmt.Errorf("sent packet handler BUG: retransmitted packet for %d not found (should have been %d)", first.PacketNumber, first.retransmissionOf)
}
// if the retransmission of a packet was split, we can't remove it yet
if len(previous.retransmittedAs) > 1 {
break
}
first = previous
}
if first.isRetransmission {
root := h.packetHistory.GetPacket(first.retransmissionOf)
retransmittedAs := make([]protocol.PacketNumber, 0, len(root.retransmittedAs)-1)
for _, pn := range root.retransmittedAs {
if pn != first.PacketNumber {
retransmittedAs = append(retransmittedAs, pn)
}
}
root.retransmittedAs = retransmittedAs
}
return h.removeAllRetransmissions(first)
}
func (h *sentPacketHandler) removeAllRetransmissions(p *Packet) error {
if p.includedInBytesInFlight {
h.bytesInFlight -= p.Length
p.includedInBytesInFlight = false
}
if p.queuedForRetransmission {
for _, r := range p.retransmittedAs {
packet := h.packetHistory.GetPacket(r)
if packet == nil {
return fmt.Errorf("sent packet handler BUG: removing packet %d (retransmission of %d) not found in history", r, p.PacketNumber)
}
if err := h.removeAllRetransmissions(packet); err != nil {
return err
}
}
}
return h.packetHistory.Remove(p.PacketNumber)
} }
func (h *sentPacketHandler) DequeuePacketForRetransmission() *Packet { func (h *sentPacketHandler) DequeuePacketForRetransmission() *Packet {
...@@ -359,26 +422,39 @@ func (h *sentPacketHandler) DequeuePacketForRetransmission() *Packet { ...@@ -359,26 +422,39 @@ func (h *sentPacketHandler) DequeuePacketForRetransmission() *Packet {
return packet return packet
} }
func (h *sentPacketHandler) GetLeastUnacked() protocol.PacketNumber { func (h *sentPacketHandler) GetPacketNumberLen(p protocol.PacketNumber) protocol.PacketNumberLen {
return h.lowestUnacked() return protocol.GetPacketNumberLengthForHeader(p, h.lowestUnacked())
} }
func (h *sentPacketHandler) GetStopWaitingFrame(force bool) *wire.StopWaitingFrame { func (h *sentPacketHandler) GetStopWaitingFrame(force bool) *wire.StopWaitingFrame {
return h.stopWaitingManager.GetStopWaitingFrame(force) return h.stopWaitingManager.GetStopWaitingFrame(force)
} }
func (h *sentPacketHandler) SendingAllowed() bool { func (h *sentPacketHandler) SendMode() SendMode {
cwnd := h.congestion.GetCongestionWindow() numTrackedPackets := len(h.retransmissionQueue) + h.packetHistory.Len()
congestionLimited := h.bytesInFlight > cwnd
maxTrackedLimited := protocol.PacketNumber(len(h.retransmissionQueue)+h.packetHistory.Len()) >= protocol.MaxTrackedSentPackets // Don't send any packets if we're keeping track of the maximum number of packets.
if congestionLimited { // Note that since MaxOutstandingSentPackets is smaller than MaxTrackedSentPackets,
// we will stop sending out new data when reaching MaxOutstandingSentPackets,
// but still allow sending of retransmissions and ACKs.
if numTrackedPackets >= protocol.MaxTrackedSentPackets {
utils.Debugf("Limited by the number of tracked packets: tracking %d packets, maximum %d", numTrackedPackets, protocol.MaxTrackedSentPackets)
return SendNone
}
// Send retransmissions first, if there are any.
if len(h.retransmissionQueue) > 0 {
return SendRetransmission
}
// Only send ACKs if we're congestion limited.
if cwnd := h.congestion.GetCongestionWindow(); h.bytesInFlight > cwnd {
utils.Debugf("Congestion limited: bytes in flight %d, window %d", h.bytesInFlight, cwnd) utils.Debugf("Congestion limited: bytes in flight %d, window %d", h.bytesInFlight, cwnd)
return SendAck
}
if numTrackedPackets >= protocol.MaxOutstandingSentPackets {
utils.Debugf("Max outstanding limited: tracking %d packets, maximum: %d", numTrackedPackets, protocol.MaxOutstandingSentPackets)
return SendAck
} }
// Workaround for #555: return SendAny
// Always allow sending of retransmissions. This should probably be limited
// to RTOs, but we currently don't have a nice way of distinguishing them.
haveRetransmissions := len(h.retransmissionQueue) > 0
return !maxTrackedLimited && (!congestionLimited || haveRetransmissions)
} }
func (h *sentPacketHandler) TimeUntilSend() time.Time { func (h *sentPacketHandler) TimeUntilSend() time.Time {
...@@ -393,45 +469,44 @@ func (h *sentPacketHandler) ShouldSendNumPackets() int { ...@@ -393,45 +469,44 @@ func (h *sentPacketHandler) ShouldSendNumPackets() int {
return int(math.Ceil(float64(protocol.MinPacingDelay) / float64(delay))) return int(math.Ceil(float64(protocol.MinPacingDelay) / float64(delay)))
} }
func (h *sentPacketHandler) retransmitOldestTwoPackets() { // retransmit the oldest two packets
if p := h.packetHistory.Front(); p != nil { func (h *sentPacketHandler) queueRTOs() error {
h.queueRTO(p) for i := 0; i < 2; i++ {
} if p := h.packetHistory.FirstOutstanding(); p != nil {
if p := h.packetHistory.Front(); p != nil { utils.Debugf("\tQueueing packet %#x for retransmission (RTO), %d outstanding", p.PacketNumber, h.packetHistory.Len())
h.queueRTO(p) if err := h.queuePacketForRetransmission(p); err != nil {
return err
}
h.congestion.OnPacketLost(p.PacketNumber, p.Length, h.bytesInFlight)
h.congestion.OnRetransmissionTimeout(true)
}
} }
return nil
} }
func (h *sentPacketHandler) queueRTO(el *PacketElement) { func (h *sentPacketHandler) queueHandshakePacketsForRetransmission() error {
packet := &el.Value var handshakePackets []*Packet
utils.Debugf( h.packetHistory.Iterate(func(p *Packet) (bool, error) {
"\tQueueing packet 0x%x for retransmission (RTO), %d outstanding", if !p.queuedForRetransmission && p.EncryptionLevel < protocol.EncryptionForwardSecure {
packet.PacketNumber, handshakePackets = append(handshakePackets, p)
h.packetHistory.Len(), }
) return true, nil
h.queuePacketForRetransmission(el) })
h.congestion.OnPacketLost(packet.PacketNumber, packet.Length, h.bytesInFlight) for _, p := range handshakePackets {
h.congestion.OnRetransmissionTimeout(true) if err := h.queuePacketForRetransmission(p); err != nil {
} return err
func (h *sentPacketHandler) queueHandshakePacketsForRetransmission() {
var handshakePackets []*PacketElement
for el := h.packetHistory.Front(); el != nil; el = el.Next() {
if el.Value.EncryptionLevel < protocol.EncryptionForwardSecure {
handshakePackets = append(handshakePackets, el)
} }
} }
for _, el := range handshakePackets { return nil
h.queuePacketForRetransmission(el)
}
} }
func (h *sentPacketHandler) queuePacketForRetransmission(packetElement *PacketElement) { func (h *sentPacketHandler) queuePacketForRetransmission(p *Packet) error {
packet := &packetElement.Value if _, err := h.packetHistory.QueuePacketForRetransmission(p.PacketNumber); err != nil {
h.bytesInFlight -= packet.Length return err
h.retransmissionQueue = append(h.retransmissionQueue, packet) }
h.packetHistory.Remove(packetElement) h.retransmissionQueue = append(h.retransmissionQueue, p)
h.stopWaitingManager.QueuedRetransmissionForPacketNumber(packet.PacketNumber) h.stopWaitingManager.QueuedRetransmissionForPacketNumber(p.PacketNumber)
return nil
} }
func (h *sentPacketHandler) computeHandshakeTimeout() time.Duration { func (h *sentPacketHandler) computeHandshakeTimeout() time.Duration {
......
package ackhandler
import (
"fmt"
"github.com/lucas-clemente/quic-go/internal/protocol"
)
type sentPacketHistory struct {
packetList *PacketList
packetMap map[protocol.PacketNumber]*PacketElement
firstOutstanding *PacketElement
}
func newSentPacketHistory() *sentPacketHistory {
return &sentPacketHistory{
packetList: NewPacketList(),
packetMap: make(map[protocol.PacketNumber]*PacketElement),
}
}
func (h *sentPacketHistory) SentPacket(p *Packet) {
h.sentPacketImpl(p)
}
func (h *sentPacketHistory) sentPacketImpl(p *Packet) *PacketElement {
el := h.packetList.PushBack(*p)
h.packetMap[p.PacketNumber] = el
if h.firstOutstanding == nil {
h.firstOutstanding = el
}
return el
}
func (h *sentPacketHistory) SentPacketsAsRetransmission(packets []*Packet, retransmissionOf protocol.PacketNumber) {
retransmission, ok := h.packetMap[retransmissionOf]
// The retransmitted packet is not present anymore.
// This can happen if it was acked in between dequeueing of the retransmission and sending.
// Just treat the retransmissions as normal packets.
// TODO: This won't happen if we clear packets queued for retransmission on new ACKs.
if !ok {
for _, packet := range packets {
h.sentPacketImpl(packet)
}
return
}
retransmission.Value.retransmittedAs = make([]protocol.PacketNumber, len(packets))
for i, packet := range packets {
retransmission.Value.retransmittedAs[i] = packet.PacketNumber
el := h.sentPacketImpl(packet)
el.Value.isRetransmission = true
el.Value.retransmissionOf = retransmissionOf
}
}
func (h *sentPacketHistory) GetPacket(p protocol.PacketNumber) *Packet {
if el, ok := h.packetMap[p]; ok {
return &el.Value
}
return nil
}
// Iterate iterates through all packets.
// The callback must not modify the history.
func (h *sentPacketHistory) Iterate(cb func(*Packet) (cont bool, err error)) error {
cont := true
for el := h.packetList.Front(); cont && el != nil; el = el.Next() {
var err error
cont, err = cb(&el.Value)
if err != nil {
return err
}
}
return nil
}
// FirstOutStanding returns the first outstanding packet.
// It must not be modified (e.g. retransmitted).
// Use DequeueFirstPacketForRetransmission() to retransmit it.
func (h *sentPacketHistory) FirstOutstanding() *Packet {
if h.firstOutstanding == nil {
return nil
}
return &h.firstOutstanding.Value
}
// QueuePacketForRetransmission marks a packet for retransmission.
// A packet can only be queued once.
func (h *sentPacketHistory) QueuePacketForRetransmission(pn protocol.PacketNumber) (*Packet, error) {
el, ok := h.packetMap[pn]
if !ok {
return nil, fmt.Errorf("sent packet history: packet %d not found", pn)
}
if el.Value.queuedForRetransmission {
return nil, fmt.Errorf("sent packet history BUG: packet %d already queued for retransmission", pn)
}
el.Value.queuedForRetransmission = true
if el == h.firstOutstanding {
h.readjustFirstOutstanding()
}
return &el.Value, nil
}
// readjustFirstOutstanding readjusts the pointer to the first outstanding packet.
// This is necessary every time the first outstanding packet is deleted or retransmitted.
func (h *sentPacketHistory) readjustFirstOutstanding() {
el := h.firstOutstanding.Next()
for el != nil && el.Value.queuedForRetransmission {
el = el.Next()
}
h.firstOutstanding = el
}
func (h *sentPacketHistory) Len() int {
return len(h.packetMap)
}
func (h *sentPacketHistory) Remove(p protocol.PacketNumber) error {
el, ok := h.packetMap[p]
if !ok {
return fmt.Errorf("packet %d not found in sent packet history", p)
}
if el == h.firstOutstanding {
h.readjustFirstOutstanding()
}
h.packetList.Remove(el)
delete(h.packetMap, p)
return nil
}
...@@ -55,28 +55,28 @@ func (c *certChain) GetLeafCert(sni string) ([]byte, error) { ...@@ -55,28 +55,28 @@ func (c *certChain) GetLeafCert(sni string) ([]byte, error) {
return cert.Certificate[0], nil return cert.Certificate[0], nil
} }
func (cc *certChain) getCertForSNI(sni string) (*tls.Certificate, error) { func (c *certChain) getCertForSNI(sni string) (*tls.Certificate, error) {
c := cc.config conf := c.config
c, err := maybeGetConfigForClient(c, sni) conf, err := maybeGetConfigForClient(conf, sni)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// The rest of this function is mostly copied from crypto/tls.getCertificate // The rest of this function is mostly copied from crypto/tls.getCertificate
if c.GetCertificate != nil { if conf.GetCertificate != nil {
cert, err := c.GetCertificate(&tls.ClientHelloInfo{ServerName: sni}) cert, err := conf.GetCertificate(&tls.ClientHelloInfo{ServerName: sni})
if cert != nil || err != nil { if cert != nil || err != nil {
return cert, err return cert, err
} }
} }
if len(c.Certificates) == 0 { if len(conf.Certificates) == 0 {
return nil, errNoMatchingCertificate return nil, errNoMatchingCertificate
} }
if len(c.Certificates) == 1 || c.NameToCertificate == nil { if len(conf.Certificates) == 1 || conf.NameToCertificate == nil {
// There's only one choice, so no point doing any work. // There's only one choice, so no point doing any work.
return &c.Certificates[0], nil return &conf.Certificates[0], nil
} }
name := strings.ToLower(sni) name := strings.ToLower(sni)
...@@ -84,7 +84,7 @@ func (cc *certChain) getCertForSNI(sni string) (*tls.Certificate, error) { ...@@ -84,7 +84,7 @@ func (cc *certChain) getCertForSNI(sni string) (*tls.Certificate, error) {
name = name[:len(name)-1] name = name[:len(name)-1]
} }
if cert, ok := c.NameToCertificate[name]; ok { if cert, ok := conf.NameToCertificate[name]; ok {
return cert, nil return cert, nil
} }
...@@ -94,13 +94,13 @@ func (cc *certChain) getCertForSNI(sni string) (*tls.Certificate, error) { ...@@ -94,13 +94,13 @@ func (cc *certChain) getCertForSNI(sni string) (*tls.Certificate, error) {
for i := range labels { for i := range labels {
labels[i] = "*" labels[i] = "*"
candidate := strings.Join(labels, ".") candidate := strings.Join(labels, ".")
if cert, ok := c.NameToCertificate[candidate]; ok { if cert, ok := conf.NameToCertificate[candidate]; ok {
return cert, nil return cert, nil
} }
} }
// If nothing matches, return the first certificate. // If nothing matches, return the first certificate.
return &c.Certificates[0], nil return &conf.Certificates[0], nil
} }
func maybeGetConfigForClient(c *tls.Config, sni string) (*tls.Config, error) { func maybeGetConfigForClient(c *tls.Config, sni string) (*tls.Config, error) {
......
package crypto package crypto
import ( import (
"crypto"
"encoding/binary"
"github.com/bifurcation/mint" "github.com/bifurcation/mint"
"github.com/lucas-clemente/quic-go/internal/protocol" "github.com/lucas-clemente/quic-go/internal/protocol"
) )
const ( const (
clientExporterLabel = "EXPORTER-QUIC client 1-RTT Secret" clientExporterLabel = "EXPORTER-QUIC client 1rtt"
serverExporterLabel = "EXPORTER-QUIC server 1-RTT Secret" serverExporterLabel = "EXPORTER-QUIC server 1rtt"
) )
// A TLSExporter gets the negotiated ciphersuite and computes exporter // A TLSExporter gets the negotiated ciphersuite and computes exporter
...@@ -16,6 +19,16 @@ type TLSExporter interface { ...@@ -16,6 +19,16 @@ type TLSExporter interface {
ComputeExporter(label string, context []byte, keyLength int) ([]byte, error) ComputeExporter(label string, context []byte, keyLength int) ([]byte, error)
} }
func qhkdfExpand(secret []byte, label string, length int) []byte {
// The last byte should be 0x0.
// Since Go initializes the slice to 0, we don't need to set it explicitly.
qlabel := make([]byte, 2+1+5+len(label)+1)
binary.BigEndian.PutUint16(qlabel[0:2], uint16(length))
qlabel[2] = uint8(5 + len(label))
copy(qlabel[3:], []byte("QUIC "+label))
return mint.HkdfExpand(crypto.SHA256, secret, qlabel, length)
}
// DeriveAESKeys derives the AES keys and creates a matching AES-GCM AEAD instance // DeriveAESKeys derives the AES keys and creates a matching AES-GCM AEAD instance
func DeriveAESKeys(tls TLSExporter, pers protocol.Perspective) (AEAD, error) { func DeriveAESKeys(tls TLSExporter, pers protocol.Perspective) (AEAD, error) {
var myLabel, otherLabel string var myLabel, otherLabel string
...@@ -43,7 +56,7 @@ func computeKeyAndIV(tls TLSExporter, label string) (key, iv []byte, err error) ...@@ -43,7 +56,7 @@ func computeKeyAndIV(tls TLSExporter, label string) (key, iv []byte, err error)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
key = mint.HkdfExpandLabel(cs.Hash, secret, "key", nil, cs.KeyLen) key = qhkdfExpand(secret, "key", cs.KeyLen)
iv = mint.HkdfExpandLabel(cs.Hash, secret, "iv", nil, cs.IvLen) iv = qhkdfExpand(secret, "iv", cs.IvLen)
return key, iv, nil return key, iv, nil
} }
...@@ -31,14 +31,14 @@ func newNullAEADAESGCM(connectionID protocol.ConnectionID, pers protocol.Perspec ...@@ -31,14 +31,14 @@ func newNullAEADAESGCM(connectionID protocol.ConnectionID, pers protocol.Perspec
func computeSecrets(connectionID protocol.ConnectionID) (clientSecret, serverSecret []byte) { func computeSecrets(connectionID protocol.ConnectionID) (clientSecret, serverSecret []byte) {
connID := make([]byte, 8) connID := make([]byte, 8)
binary.BigEndian.PutUint64(connID, uint64(connectionID)) binary.BigEndian.PutUint64(connID, uint64(connectionID))
cleartextSecret := mint.HkdfExtract(crypto.SHA256, []byte(quicVersion1Salt), connID) handshakeSecret := mint.HkdfExtract(crypto.SHA256, quicVersion1Salt, connID)
clientSecret = mint.HkdfExpandLabel(crypto.SHA256, cleartextSecret, "QUIC client cleartext Secret", []byte{}, crypto.SHA256.Size()) clientSecret = qhkdfExpand(handshakeSecret, "client hs", crypto.SHA256.Size())
serverSecret = mint.HkdfExpandLabel(crypto.SHA256, cleartextSecret, "QUIC server cleartext Secret", []byte{}, crypto.SHA256.Size()) serverSecret = qhkdfExpand(handshakeSecret, "server hs", crypto.SHA256.Size())
return return
} }
func computeNullAEADKeyAndIV(secret []byte) (key, iv []byte) { func computeNullAEADKeyAndIV(secret []byte) (key, iv []byte) {
key = mint.HkdfExpandLabel(crypto.SHA256, secret, "key", nil, 16) key = qhkdfExpand(secret, "key", 16)
iv = mint.HkdfExpandLabel(crypto.SHA256, secret, "iv", nil, 12) iv = qhkdfExpand(secret, "iv", 12)
return return
} }
...@@ -7,6 +7,9 @@ import ( ...@@ -7,6 +7,9 @@ import (
"github.com/lucas-clemente/quic-go/internal/utils" "github.com/lucas-clemente/quic-go/internal/utils"
) )
// A CookieHandler generates and validates cookies.
// The cookie is sent in the TLS Retry.
// By including the cookie in its ClientHello, a client can proof ownership of its source address.
type CookieHandler struct { type CookieHandler struct {
callback func(net.Addr, *Cookie) bool callback func(net.Addr, *Cookie) bool
...@@ -15,6 +18,7 @@ type CookieHandler struct { ...@@ -15,6 +18,7 @@ type CookieHandler struct {
var _ mint.CookieHandler = &CookieHandler{} var _ mint.CookieHandler = &CookieHandler{}
// NewCookieHandler creates a new CookieHandler.
func NewCookieHandler(callback func(net.Addr, *Cookie) bool) (*CookieHandler, error) { func NewCookieHandler(callback func(net.Addr, *Cookie) bool) (*CookieHandler, error) {
cookieGenerator, err := NewCookieGenerator() cookieGenerator, err := NewCookieGenerator()
if err != nil { if err != nil {
...@@ -26,6 +30,7 @@ func NewCookieHandler(callback func(net.Addr, *Cookie) bool) (*CookieHandler, er ...@@ -26,6 +30,7 @@ func NewCookieHandler(callback func(net.Addr, *Cookie) bool) (*CookieHandler, er
}, nil }, nil
} }
// Generate a new cookie for a mint connection.
func (h *CookieHandler) Generate(conn *mint.Conn) ([]byte, error) { func (h *CookieHandler) Generate(conn *mint.Conn) ([]byte, error) {
if h.callback(conn.RemoteAddr(), nil) { if h.callback(conn.RemoteAddr(), nil) {
return nil, nil return nil, nil
...@@ -33,6 +38,7 @@ func (h *CookieHandler) Generate(conn *mint.Conn) ([]byte, error) { ...@@ -33,6 +38,7 @@ func (h *CookieHandler) Generate(conn *mint.Conn) ([]byte, error) {
return h.cookieGenerator.NewToken(conn.RemoteAddr()) return h.cookieGenerator.NewToken(conn.RemoteAddr())
} }
// Validate a cookie.
func (h *CookieHandler) Validate(conn *mint.Conn, token []byte) bool { func (h *CookieHandler) Validate(conn *mint.Conn, token []byte) bool {
data, err := h.cookieGenerator.DecodeToken(token) data, err := h.cookieGenerator.DecodeToken(token)
if err != nil { if err != nil {
......
...@@ -429,7 +429,7 @@ func (h *cryptoSetupServer) handleCHLO(sni string, data []byte, cryptoData map[T ...@@ -429,7 +429,7 @@ func (h *cryptoSetupServer) handleCHLO(sni string, data []byte, cryptoData map[T
replyMap := h.params.getHelloMap() replyMap := h.params.getHelloMap()
// add crypto parameters // add crypto parameters
verTag := &bytes.Buffer{} verTag := &bytes.Buffer{}
for _, v := range protocol.GetGreasedVersions(h.supportedVersions) { for _, v := range h.supportedVersions {
utils.BigEndian.WriteUint32(verTag, uint32(v)) utils.BigEndian.WriteUint32(verTag, uint32(v))
} }
replyMap[TagPUBS] = ephermalKex.PublicKey() replyMap[TagPUBS] = ephermalKex.PublicKey()
......
...@@ -84,7 +84,7 @@ func (h HandshakeMessage) Write(b *bytes.Buffer) { ...@@ -84,7 +84,7 @@ func (h HandshakeMessage) Write(b *bytes.Buffer) {
offset := uint32(0) offset := uint32(0)
for i, t := range h.getTagsSorted() { for i, t := range h.getTagsSorted() {
v := data[Tag(t)] v := data[t]
b.Write(v) b.Write(v)
offset += uint32(len(v)) offset += uint32(len(v))
binary.LittleEndian.PutUint32(indexData[i*8:], uint32(t)) binary.LittleEndian.PutUint32(indexData[i*8:], uint32(t))
...@@ -111,8 +111,7 @@ func (h *HandshakeMessage) getTagsSorted() []Tag { ...@@ -111,8 +111,7 @@ func (h *HandshakeMessage) getTagsSorted() []Tag {
func (h HandshakeMessage) String() string { func (h HandshakeMessage) String() string {
var pad string var pad string
res := tagToString(h.Tag) + ":\n" res := tagToString(h.Tag) + ":\n"
for _, t := range h.getTagsSorted() { for _, tag := range h.getTagsSorted() {
tag := Tag(t)
if tag == TagPAD { if tag == TagPAD {
pad = fmt.Sprintf("\t%s: (%d bytes)\n", tagToString(tag), len(h.Data[tag])) pad = fmt.Sprintf("\t%s: (%d bytes)\n", tagToString(tag), len(h.Data[tag]))
} else { } else {
......
...@@ -9,10 +9,10 @@ import ( ...@@ -9,10 +9,10 @@ import (
// ServerConfig is a server config // ServerConfig is a server config
type ServerConfig struct { type ServerConfig struct {
kex crypto.KeyExchange kex crypto.KeyExchange
certChain crypto.CertChain certChain crypto.CertChain
ID []byte ID []byte
obit []byte obit []byte
cookieGenerator *CookieGenerator cookieGenerator *CookieGenerator
} }
...@@ -36,10 +36,10 @@ func NewServerConfig(kex crypto.KeyExchange, certChain crypto.CertChain) (*Serve ...@@ -36,10 +36,10 @@ func NewServerConfig(kex crypto.KeyExchange, certChain crypto.CertChain) (*Serve
} }
return &ServerConfig{ return &ServerConfig{
kex: kex, kex: kex,
certChain: certChain, certChain: certChain,
ID: id, ID: id,
obit: obit, obit: obit,
cookieGenerator: cookieGenerator, cookieGenerator: cookieGenerator,
}, nil }, nil
} }
......
...@@ -102,32 +102,37 @@ func (s *serverConfigClient) parseValues(tagMap map[Tag][]byte) error { ...@@ -102,32 +102,37 @@ func (s *serverConfigClient) parseValues(tagMap map[Tag][]byte) error {
return qerr.Error(qerr.CryptoMessageParameterNotFound, "PUBS") return qerr.Error(qerr.CryptoMessageParameterNotFound, "PUBS")
} }
var pubs_kexs []struct{Length uint32; Value []byte} var pubsKexs []struct {
var last_len uint32 Length uint32
Value []byte
for i := 0; i < len(pubs)-3; i += int(last_len)+3 { }
var lastLen uint32
for i := 0; i < len(pubs)-3; i += int(lastLen) + 3 {
// the PUBS value is always prepended by 3 byte little endian length field // the PUBS value is always prepended by 3 byte little endian length field
err := binary.Read(bytes.NewReader([]byte{pubs[i], pubs[i+1], pubs[i+2], 0x00}), binary.LittleEndian, &last_len); err := binary.Read(bytes.NewReader([]byte{pubs[i], pubs[i+1], pubs[i+2], 0x00}), binary.LittleEndian, &lastLen)
if err != nil { if err != nil {
return qerr.Error(qerr.CryptoInvalidValueLength, "PUBS not decodable") return qerr.Error(qerr.CryptoInvalidValueLength, "PUBS not decodable")
} }
if last_len == 0 { if lastLen == 0 {
return qerr.Error(qerr.CryptoInvalidValueLength, "PUBS") return qerr.Error(qerr.CryptoInvalidValueLength, "PUBS")
} }
if i+3+int(last_len) > len(pubs) { if i+3+int(lastLen) > len(pubs) {
return qerr.Error(qerr.CryptoInvalidValueLength, "PUBS") return qerr.Error(qerr.CryptoInvalidValueLength, "PUBS")
} }
pubs_kexs = append(pubs_kexs, struct{Length uint32; Value []byte}{last_len, pubs[i+3:i+3+int(last_len)]}) pubsKexs = append(pubsKexs, struct {
Length uint32
Value []byte
}{lastLen, pubs[i+3 : i+3+int(lastLen)]})
} }
if c255Foundat >= len(pubs_kexs) { if c255Foundat >= len(pubsKexs) {
return qerr.Error(qerr.CryptoMessageParameterNotFound, "KEXS not in PUBS") return qerr.Error(qerr.CryptoMessageParameterNotFound, "KEXS not in PUBS")
} }
if pubs_kexs[c255Foundat].Length != 32 { if pubsKexs[c255Foundat].Length != 32 {
return qerr.Error(qerr.CryptoInvalidValueLength, "PUBS") return qerr.Error(qerr.CryptoInvalidValueLength, "PUBS")
} }
...@@ -137,8 +142,7 @@ func (s *serverConfigClient) parseValues(tagMap map[Tag][]byte) error { ...@@ -137,8 +142,7 @@ func (s *serverConfigClient) parseValues(tagMap map[Tag][]byte) error {
return err return err
} }
s.sharedSecret, err = s.kex.CalculateSharedKey(pubsKexs[c255Foundat].Value)
s.sharedSecret, err = s.kex.CalculateSharedKey(pubs_kexs[c255Foundat].Value)
if err != nil { if err != nil {
return err return err
} }
......
...@@ -9,14 +9,14 @@ type transportParameterID uint16 ...@@ -9,14 +9,14 @@ type transportParameterID uint16
const quicTLSExtensionType = 26 const quicTLSExtensionType = 26
const ( const (
initialMaxStreamDataParameterID transportParameterID = 0x0 initialMaxStreamDataParameterID transportParameterID = 0x0
initialMaxDataParameterID transportParameterID = 0x1 initialMaxDataParameterID transportParameterID = 0x1
initialMaxStreamIDBiDiParameterID transportParameterID = 0x2 initialMaxStreamsBiDiParameterID transportParameterID = 0x2
idleTimeoutParameterID transportParameterID = 0x3 idleTimeoutParameterID transportParameterID = 0x3
omitConnectionIDParameterID transportParameterID = 0x4 omitConnectionIDParameterID transportParameterID = 0x4
maxPacketSizeParameterID transportParameterID = 0x5 maxPacketSizeParameterID transportParameterID = 0x5
statelessResetTokenParameterID transportParameterID = 0x6 statelessResetTokenParameterID transportParameterID = 0x6
initialMaxStreamIDUniParameterID transportParameterID = 0x8 initialMaxStreamsUniParameterID transportParameterID = 0x8
) )
type transportParameter struct { type transportParameter struct {
......
...@@ -3,13 +3,13 @@ package handshake ...@@ -3,13 +3,13 @@ package handshake
import ( import (
"errors" "errors"
"fmt" "fmt"
"math"
"github.com/lucas-clemente/quic-go/qerr" "github.com/lucas-clemente/quic-go/qerr"
"github.com/bifurcation/mint" "github.com/bifurcation/mint"
"github.com/bifurcation/mint/syntax" "github.com/bifurcation/mint/syntax"
"github.com/lucas-clemente/quic-go/internal/protocol" "github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
) )
type extensionHandlerClient struct { type extensionHandlerClient struct {
...@@ -31,7 +31,10 @@ func NewExtensionHandlerClient( ...@@ -31,7 +31,10 @@ func NewExtensionHandlerClient(
supportedVersions []protocol.VersionNumber, supportedVersions []protocol.VersionNumber,
version protocol.VersionNumber, version protocol.VersionNumber,
) TLSExtensionHandler { ) TLSExtensionHandler {
paramsChan := make(chan TransportParameters, 1) // The client reads the transport parameters from the Encrypted Extensions message.
// The paramsChan is used in the session's run loop's select statement.
// We have to use an unbuffered channel here to make sure that the session actually processes the transport parameters immediately.
paramsChan := make(chan TransportParameters)
return &extensionHandlerClient{ return &extensionHandlerClient{
ourParams: params, ourParams: params,
paramsChan: paramsChan, paramsChan: paramsChan,
...@@ -46,6 +49,7 @@ func (h *extensionHandlerClient) Send(hType mint.HandshakeType, el *mint.Extensi ...@@ -46,6 +49,7 @@ func (h *extensionHandlerClient) Send(hType mint.HandshakeType, el *mint.Extensi
return nil return nil
} }
utils.Debugf("Sending Transport Parameters: %s", h.ourParams)
data, err := syntax.Marshal(clientHelloTransportParameters{ data, err := syntax.Marshal(clientHelloTransportParameters{
InitialVersion: uint32(h.initialVersion), InitialVersion: uint32(h.initialVersion),
Parameters: h.ourParams.getTransportParameters(), Parameters: h.ourParams.getTransportParameters(),
...@@ -63,17 +67,12 @@ func (h *extensionHandlerClient) Receive(hType mint.HandshakeType, el *mint.Exte ...@@ -63,17 +67,12 @@ func (h *extensionHandlerClient) Receive(hType mint.HandshakeType, el *mint.Exte
return err return err
} }
if hType != mint.HandshakeTypeEncryptedExtensions && hType != mint.HandshakeTypeNewSessionTicket { if hType != mint.HandshakeTypeEncryptedExtensions {
if found { if found {
return fmt.Errorf("Unexpected QUIC extension in handshake message %d", hType) return fmt.Errorf("Unexpected QUIC extension in handshake message %d", hType)
} }
return nil return nil
} }
if hType == mint.HandshakeTypeNewSessionTicket {
// the extension it's optional in the NewSessionTicket message
// TODO: handle this
return nil
}
// hType == mint.HandshakeTypeEncryptedExtensions // hType == mint.HandshakeTypeEncryptedExtensions
if !found { if !found {
...@@ -119,12 +118,11 @@ func (h *extensionHandlerClient) Receive(hType mint.HandshakeType, el *mint.Exte ...@@ -119,12 +118,11 @@ func (h *extensionHandlerClient) Receive(hType mint.HandshakeType, el *mint.Exte
// TODO: return the right error here // TODO: return the right error here
return errors.New("server didn't sent stateless_reset_token") return errors.New("server didn't sent stateless_reset_token")
} }
params, err := readTransportParamters(eetp.Parameters) params, err := readTransportParameters(eetp.Parameters)
if err != nil { if err != nil {
return err return err
} }
// TODO(#878): remove this when implementing the MAX_STREAM_ID frame utils.Debugf("Received Transport Parameters: %s", params)
params.MaxStreams = math.MaxUint32
h.paramsChan <- *params h.paramsChan <- *params
return nil return nil
} }
......
...@@ -10,6 +10,7 @@ import ( ...@@ -10,6 +10,7 @@ import (
"github.com/bifurcation/mint" "github.com/bifurcation/mint"
"github.com/bifurcation/mint/syntax" "github.com/bifurcation/mint/syntax"
"github.com/lucas-clemente/quic-go/internal/protocol" "github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
) )
type extensionHandlerServer struct { type extensionHandlerServer struct {
...@@ -29,6 +30,8 @@ func NewExtensionHandlerServer( ...@@ -29,6 +30,8 @@ func NewExtensionHandlerServer(
supportedVersions []protocol.VersionNumber, supportedVersions []protocol.VersionNumber,
version protocol.VersionNumber, version protocol.VersionNumber,
) TLSExtensionHandler { ) TLSExtensionHandler {
// Processing the ClientHello is performed statelessly (and from a single go-routine).
// Therefore, we have to use a buffered chan to pass the transport parameters to that go routine.
paramsChan := make(chan TransportParameters, 1) paramsChan := make(chan TransportParameters, 1)
return &extensionHandlerServer{ return &extensionHandlerServer{
ourParams: params, ourParams: params,
...@@ -53,6 +56,7 @@ func (h *extensionHandlerServer) Send(hType mint.HandshakeType, el *mint.Extensi ...@@ -53,6 +56,7 @@ func (h *extensionHandlerServer) Send(hType mint.HandshakeType, el *mint.Extensi
for i, v := range supportedVersions { for i, v := range supportedVersions {
versions[i] = uint32(v) versions[i] = uint32(v)
} }
utils.Debugf("Sending Transport Parameters: %s", h.ourParams)
data, err := syntax.Marshal(encryptedExtensionsTransportParameters{ data, err := syntax.Marshal(encryptedExtensionsTransportParameters{
NegotiatedVersion: uint32(h.version), NegotiatedVersion: uint32(h.version),
SupportedVersions: versions, SupportedVersions: versions,
...@@ -100,10 +104,11 @@ func (h *extensionHandlerServer) Receive(hType mint.HandshakeType, el *mint.Exte ...@@ -100,10 +104,11 @@ func (h *extensionHandlerServer) Receive(hType mint.HandshakeType, el *mint.Exte
return errors.New("client sent a stateless reset token") return errors.New("client sent a stateless reset token")
} }
} }
params, err := readTransportParamters(chtp.Parameters) params, err := readTransportParameters(chtp.Parameters)
if err != nil { if err != nil {
return err return err
} }
utils.Debugf("Received Transport Parameters: %s", params)
h.paramsChan <- *params h.paramsChan <- *params
return nil return nil
} }
......
...@@ -20,9 +20,11 @@ type TransportParameters struct { ...@@ -20,9 +20,11 @@ type TransportParameters struct {
StreamFlowControlWindow protocol.ByteCount StreamFlowControlWindow protocol.ByteCount
ConnectionFlowControlWindow protocol.ByteCount ConnectionFlowControlWindow protocol.ByteCount
MaxBidiStreamID protocol.StreamID // only used for IETF QUIC MaxPacketSize protocol.ByteCount
MaxUniStreamID protocol.StreamID // only used for IETF QUIC
MaxStreams uint32 // only used for gQUIC MaxUniStreams uint16 // only used for IETF QUIC
MaxBidiStreams uint16 // only used for IETF QUIC
MaxStreams uint32 // only used for gQUIC
OmitConnectionID bool OmitConnectionID bool
IdleTimeout time.Duration IdleTimeout time.Duration
...@@ -93,7 +95,7 @@ func (p *TransportParameters) getHelloMap() map[Tag][]byte { ...@@ -93,7 +95,7 @@ func (p *TransportParameters) getHelloMap() map[Tag][]byte {
} }
// readTransportParameters reads the transport parameters sent in the QUIC TLS extension // readTransportParameters reads the transport parameters sent in the QUIC TLS extension
func readTransportParamters(paramsList []transportParameter) (*TransportParameters, error) { func readTransportParameters(paramsList []transportParameter) (*TransportParameters, error) {
params := &TransportParameters{} params := &TransportParameters{}
var foundInitialMaxStreamData bool var foundInitialMaxStreamData bool
...@@ -114,18 +116,16 @@ func readTransportParamters(paramsList []transportParameter) (*TransportParamete ...@@ -114,18 +116,16 @@ func readTransportParamters(paramsList []transportParameter) (*TransportParamete
return nil, fmt.Errorf("wrong length for initial_max_data: %d (expected 4)", len(p.Value)) return nil, fmt.Errorf("wrong length for initial_max_data: %d (expected 4)", len(p.Value))
} }
params.ConnectionFlowControlWindow = protocol.ByteCount(binary.BigEndian.Uint32(p.Value)) params.ConnectionFlowControlWindow = protocol.ByteCount(binary.BigEndian.Uint32(p.Value))
case initialMaxStreamIDBiDiParameterID: case initialMaxStreamsBiDiParameterID:
if len(p.Value) != 4 { if len(p.Value) != 2 {
return nil, fmt.Errorf("wrong length for initial_max_stream_id_bidi: %d (expected 4)", len(p.Value)) return nil, fmt.Errorf("wrong length for initial_max_stream_id_bidi: %d (expected 2)", len(p.Value))
} }
// TODO(#1154): validate the stream ID params.MaxBidiStreams = binary.BigEndian.Uint16(p.Value)
params.MaxBidiStreamID = protocol.StreamID(binary.BigEndian.Uint32(p.Value)) case initialMaxStreamsUniParameterID:
case initialMaxStreamIDUniParameterID: if len(p.Value) != 2 {
if len(p.Value) != 4 { return nil, fmt.Errorf("wrong length for initial_max_stream_id_uni: %d (expected 2)", len(p.Value))
return nil, fmt.Errorf("wrong length for initial_max_stream_id_uni: %d (expected 4)", len(p.Value))
} }
// TODO(#1154): validate the stream ID params.MaxUniStreams = binary.BigEndian.Uint16(p.Value)
params.MaxUniStreamID = protocol.StreamID(binary.BigEndian.Uint32(p.Value))
case idleTimeoutParameterID: case idleTimeoutParameterID:
foundIdleTimeout = true foundIdleTimeout = true
if len(p.Value) != 2 { if len(p.Value) != 2 {
...@@ -137,6 +137,15 @@ func readTransportParamters(paramsList []transportParameter) (*TransportParamete ...@@ -137,6 +137,15 @@ func readTransportParamters(paramsList []transportParameter) (*TransportParamete
return nil, fmt.Errorf("wrong length for omit_connection_id: %d (expected empty)", len(p.Value)) return nil, fmt.Errorf("wrong length for omit_connection_id: %d (expected empty)", len(p.Value))
} }
params.OmitConnectionID = true params.OmitConnectionID = true
case maxPacketSizeParameterID:
if len(p.Value) != 2 {
return nil, fmt.Errorf("wrong length for max_packet_size: %d (expected 2)", len(p.Value))
}
maxPacketSize := protocol.ByteCount(binary.BigEndian.Uint16(p.Value))
if maxPacketSize < 1200 {
return nil, fmt.Errorf("invalid value for max_packet_size: %d (minimum 1200)", maxPacketSize)
}
params.MaxPacketSize = maxPacketSize
} }
} }
...@@ -153,10 +162,10 @@ func (p *TransportParameters) getTransportParameters() []transportParameter { ...@@ -153,10 +162,10 @@ func (p *TransportParameters) getTransportParameters() []transportParameter {
binary.BigEndian.PutUint32(initialMaxStreamData, uint32(p.StreamFlowControlWindow)) binary.BigEndian.PutUint32(initialMaxStreamData, uint32(p.StreamFlowControlWindow))
initialMaxData := make([]byte, 4) initialMaxData := make([]byte, 4)
binary.BigEndian.PutUint32(initialMaxData, uint32(p.ConnectionFlowControlWindow)) binary.BigEndian.PutUint32(initialMaxData, uint32(p.ConnectionFlowControlWindow))
initialMaxBidiStreamID := make([]byte, 4) initialMaxBidiStreamID := make([]byte, 2)
binary.BigEndian.PutUint32(initialMaxBidiStreamID, uint32(p.MaxBidiStreamID)) binary.BigEndian.PutUint16(initialMaxBidiStreamID, p.MaxBidiStreams)
initialMaxUniStreamID := make([]byte, 4) initialMaxUniStreamID := make([]byte, 2)
binary.BigEndian.PutUint32(initialMaxUniStreamID, uint32(p.MaxUniStreamID)) binary.BigEndian.PutUint16(initialMaxUniStreamID, p.MaxUniStreams)
idleTimeout := make([]byte, 2) idleTimeout := make([]byte, 2)
binary.BigEndian.PutUint16(idleTimeout, uint16(p.IdleTimeout/time.Second)) binary.BigEndian.PutUint16(idleTimeout, uint16(p.IdleTimeout/time.Second))
maxPacketSize := make([]byte, 2) maxPacketSize := make([]byte, 2)
...@@ -164,8 +173,8 @@ func (p *TransportParameters) getTransportParameters() []transportParameter { ...@@ -164,8 +173,8 @@ func (p *TransportParameters) getTransportParameters() []transportParameter {
params := []transportParameter{ params := []transportParameter{
{initialMaxStreamDataParameterID, initialMaxStreamData}, {initialMaxStreamDataParameterID, initialMaxStreamData},
{initialMaxDataParameterID, initialMaxData}, {initialMaxDataParameterID, initialMaxData},
{initialMaxStreamIDBiDiParameterID, initialMaxBidiStreamID}, {initialMaxStreamsBiDiParameterID, initialMaxBidiStreamID},
{initialMaxStreamIDUniParameterID, initialMaxUniStreamID}, {initialMaxStreamsUniParameterID, initialMaxUniStreamID},
{idleTimeoutParameterID, idleTimeout}, {idleTimeoutParameterID, idleTimeout},
{maxPacketSizeParameterID, maxPacketSize}, {maxPacketSizeParameterID, maxPacketSize},
} }
...@@ -174,3 +183,9 @@ func (p *TransportParameters) getTransportParameters() []transportParameter { ...@@ -174,3 +183,9 @@ func (p *TransportParameters) getTransportParameters() []transportParameter {
} }
return params return params
} }
// String returns a string representation, intended for logging.
// It should only used for IETF QUIC.
func (p *TransportParameters) String() string {
return fmt.Sprintf("&handshake.TransportParameters{StreamFlowControlWindow: %#x, ConnectionFlowControlWindow: %#x, MaxBidiStreams: %d, MaxUniStreams: %d, OmitConnectionID: %t, IdleTimeout: %s}", p.StreamFlowControlWindow, p.ConnectionFlowControlWindow, p.MaxBidiStreams, p.MaxUniStreams, p.OmitConnectionID, p.IdleTimeout)
}
...@@ -61,18 +61,6 @@ func (mr *MockSentPacketHandlerMockRecorder) GetAlarmTimeout() *gomock.Call { ...@@ -61,18 +61,6 @@ func (mr *MockSentPacketHandlerMockRecorder) GetAlarmTimeout() *gomock.Call {
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAlarmTimeout", reflect.TypeOf((*MockSentPacketHandler)(nil).GetAlarmTimeout)) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAlarmTimeout", reflect.TypeOf((*MockSentPacketHandler)(nil).GetAlarmTimeout))
} }
// GetLeastUnacked mocks base method
func (m *MockSentPacketHandler) GetLeastUnacked() protocol.PacketNumber {
ret := m.ctrl.Call(m, "GetLeastUnacked")
ret0, _ := ret[0].(protocol.PacketNumber)
return ret0
}
// GetLeastUnacked indicates an expected call of GetLeastUnacked
func (mr *MockSentPacketHandlerMockRecorder) GetLeastUnacked() *gomock.Call {
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLeastUnacked", reflect.TypeOf((*MockSentPacketHandler)(nil).GetLeastUnacked))
}
// GetLowestPacketNotConfirmedAcked mocks base method // GetLowestPacketNotConfirmedAcked mocks base method
func (m *MockSentPacketHandler) GetLowestPacketNotConfirmedAcked() protocol.PacketNumber { func (m *MockSentPacketHandler) GetLowestPacketNotConfirmedAcked() protocol.PacketNumber {
ret := m.ctrl.Call(m, "GetLowestPacketNotConfirmedAcked") ret := m.ctrl.Call(m, "GetLowestPacketNotConfirmedAcked")
...@@ -85,6 +73,18 @@ func (mr *MockSentPacketHandlerMockRecorder) GetLowestPacketNotConfirmedAcked() ...@@ -85,6 +73,18 @@ func (mr *MockSentPacketHandlerMockRecorder) GetLowestPacketNotConfirmedAcked()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLowestPacketNotConfirmedAcked", reflect.TypeOf((*MockSentPacketHandler)(nil).GetLowestPacketNotConfirmedAcked)) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLowestPacketNotConfirmedAcked", reflect.TypeOf((*MockSentPacketHandler)(nil).GetLowestPacketNotConfirmedAcked))
} }
// GetPacketNumberLen mocks base method
func (m *MockSentPacketHandler) GetPacketNumberLen(arg0 protocol.PacketNumber) protocol.PacketNumberLen {
ret := m.ctrl.Call(m, "GetPacketNumberLen", arg0)
ret0, _ := ret[0].(protocol.PacketNumberLen)
return ret0
}
// GetPacketNumberLen indicates an expected call of GetPacketNumberLen
func (mr *MockSentPacketHandlerMockRecorder) GetPacketNumberLen(arg0 interface{}) *gomock.Call {
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPacketNumberLen", reflect.TypeOf((*MockSentPacketHandler)(nil).GetPacketNumberLen), arg0)
}
// GetStopWaitingFrame mocks base method // GetStopWaitingFrame mocks base method
func (m *MockSentPacketHandler) GetStopWaitingFrame(arg0 bool) *wire.StopWaitingFrame { func (m *MockSentPacketHandler) GetStopWaitingFrame(arg0 bool) *wire.StopWaitingFrame {
ret := m.ctrl.Call(m, "GetStopWaitingFrame", arg0) ret := m.ctrl.Call(m, "GetStopWaitingFrame", arg0)
...@@ -98,8 +98,10 @@ func (mr *MockSentPacketHandlerMockRecorder) GetStopWaitingFrame(arg0 interface{ ...@@ -98,8 +98,10 @@ func (mr *MockSentPacketHandlerMockRecorder) GetStopWaitingFrame(arg0 interface{
} }
// OnAlarm mocks base method // OnAlarm mocks base method
func (m *MockSentPacketHandler) OnAlarm() { func (m *MockSentPacketHandler) OnAlarm() error {
m.ctrl.Call(m, "OnAlarm") ret := m.ctrl.Call(m, "OnAlarm")
ret0, _ := ret[0].(error)
return ret0
} }
// OnAlarm indicates an expected call of OnAlarm // OnAlarm indicates an expected call of OnAlarm
...@@ -119,23 +121,21 @@ func (mr *MockSentPacketHandlerMockRecorder) ReceivedAck(arg0, arg1, arg2, arg3 ...@@ -119,23 +121,21 @@ func (mr *MockSentPacketHandlerMockRecorder) ReceivedAck(arg0, arg1, arg2, arg3
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReceivedAck", reflect.TypeOf((*MockSentPacketHandler)(nil).ReceivedAck), arg0, arg1, arg2, arg3) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReceivedAck", reflect.TypeOf((*MockSentPacketHandler)(nil).ReceivedAck), arg0, arg1, arg2, arg3)
} }
// SendingAllowed mocks base method // SendMode mocks base method
func (m *MockSentPacketHandler) SendingAllowed() bool { func (m *MockSentPacketHandler) SendMode() ackhandler.SendMode {
ret := m.ctrl.Call(m, "SendingAllowed") ret := m.ctrl.Call(m, "SendMode")
ret0, _ := ret[0].(bool) ret0, _ := ret[0].(ackhandler.SendMode)
return ret0 return ret0
} }
// SendingAllowed indicates an expected call of SendingAllowed // SendMode indicates an expected call of SendMode
func (mr *MockSentPacketHandlerMockRecorder) SendingAllowed() *gomock.Call { func (mr *MockSentPacketHandlerMockRecorder) SendMode() *gomock.Call {
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendingAllowed", reflect.TypeOf((*MockSentPacketHandler)(nil).SendingAllowed)) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendMode", reflect.TypeOf((*MockSentPacketHandler)(nil).SendMode))
} }
// SentPacket mocks base method // SentPacket mocks base method
func (m *MockSentPacketHandler) SentPacket(arg0 *ackhandler.Packet) error { func (m *MockSentPacketHandler) SentPacket(arg0 *ackhandler.Packet) {
ret := m.ctrl.Call(m, "SentPacket", arg0) m.ctrl.Call(m, "SentPacket", arg0)
ret0, _ := ret[0].(error)
return ret0
} }
// SentPacket indicates an expected call of SentPacket // SentPacket indicates an expected call of SentPacket
...@@ -143,6 +143,16 @@ func (mr *MockSentPacketHandlerMockRecorder) SentPacket(arg0 interface{}) *gomoc ...@@ -143,6 +143,16 @@ func (mr *MockSentPacketHandlerMockRecorder) SentPacket(arg0 interface{}) *gomoc
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SentPacket", reflect.TypeOf((*MockSentPacketHandler)(nil).SentPacket), arg0) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SentPacket", reflect.TypeOf((*MockSentPacketHandler)(nil).SentPacket), arg0)
} }
// SentPacketsAsRetransmission mocks base method
func (m *MockSentPacketHandler) SentPacketsAsRetransmission(arg0 []*ackhandler.Packet, arg1 protocol.PacketNumber) {
m.ctrl.Call(m, "SentPacketsAsRetransmission", arg0, arg1)
}
// SentPacketsAsRetransmission indicates an expected call of SentPacketsAsRetransmission
func (mr *MockSentPacketHandlerMockRecorder) SentPacketsAsRetransmission(arg0, arg1 interface{}) *gomock.Call {
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SentPacketsAsRetransmission", reflect.TypeOf((*MockSentPacketHandler)(nil).SentPacketsAsRetransmission), arg0, arg1)
}
// SetHandshakeComplete mocks base method // SetHandshakeComplete mocks base method
func (m *MockSentPacketHandler) SetHandshakeComplete() { func (m *MockSentPacketHandler) SetHandshakeComplete() {
m.ctrl.Call(m, "SetHandshakeComplete") m.ctrl.Call(m, "SetHandshakeComplete")
......
...@@ -27,14 +27,14 @@ const ( ...@@ -27,14 +27,14 @@ const (
type PacketType uint8 type PacketType uint8
const ( const (
// PacketTypeInitial is the packet type of a Initial packet // PacketTypeInitial is the packet type of an Initial packet
PacketTypeInitial PacketType = 2 PacketTypeInitial PacketType = 0x7f
// PacketTypeRetry is the packet type of a Retry packet // PacketTypeRetry is the packet type of a Retry packet
PacketTypeRetry PacketType = 3 PacketTypeRetry PacketType = 0x7e
// PacketTypeHandshake is the packet type of a Cleartext packet // PacketTypeHandshake is the packet type of a Handshake packet
PacketTypeHandshake PacketType = 4 PacketTypeHandshake PacketType = 0x7d
// PacketType0RTT is the packet type of a 0-RTT packet // PacketType0RTT is the packet type of a 0-RTT packet
PacketType0RTT PacketType = 5 PacketType0RTT PacketType = 0x7c
) )
func (t PacketType) String() string { func (t PacketType) String() string {
...@@ -77,11 +77,11 @@ const DefaultTCPMSS ByteCount = 1460 ...@@ -77,11 +77,11 @@ const DefaultTCPMSS ByteCount = 1460
// MinClientHelloSize is the minimum size the server expects an inchoate CHLO to have (in gQUIC) // MinClientHelloSize is the minimum size the server expects an inchoate CHLO to have (in gQUIC)
const MinClientHelloSize = 1024 const MinClientHelloSize = 1024
// MinInitialPacketSize is the minimum size an Initial packet (in IETF QUIC) is requried to have. // MinInitialPacketSize is the minimum size an Initial packet (in IETF QUIC) is required to have.
const MinInitialPacketSize = 1200 const MinInitialPacketSize = 1200
// MaxClientHellos is the maximum number of times we'll send a client hello // MaxClientHellos is the maximum number of times we'll send a client hello
// The value 3 accounts for: // The value 3 accounts for:
// * one failure due to an incorrect or missing source-address token // * one failure due to an incorrect or missing source-address token
// * one failure due the server's certificate chain being unavailible and the server being unwilling to send it without a valid source-address token // * one failure due the server's certificate chain being unavailable and the server being unwilling to send it without a valid source-address token
const MaxClientHellos = 3 const MaxClientHellos = 3
...@@ -2,9 +2,11 @@ package protocol ...@@ -2,9 +2,11 @@ package protocol
import "time" import "time"
// MaxPacketSize is the maximum packet size that we use for sending packets. // MaxPacketSizeIPv4 is the maximum packet size that we use for sending IPv4 packets.
// It includes the QUIC packet header, but excludes the UDP and IP header. const MaxPacketSizeIPv4 = 1252
const MaxPacketSize ByteCount = 1200
// MaxPacketSizeIPv6 is the maximum packet size that we use for sending IPv6 packets.
const MaxPacketSizeIPv6 = 1232
// NonForwardSecurePacketSizeReduction is the number of bytes a non forward-secure packet has to be smaller than a forward-secure packet // NonForwardSecurePacketSizeReduction is the number of bytes a non forward-secure packet has to be smaller than a forward-secure packet
// This makes sure that those packets can always be retransmitted without splitting the contained StreamFrames // This makes sure that those packets can always be retransmitted without splitting the contained StreamFrames
...@@ -24,10 +26,6 @@ const MaxUndecryptablePackets = 10 ...@@ -24,10 +26,6 @@ const MaxUndecryptablePackets = 10
// This timeout allows the Go scheduler to switch to the Go rountine that reads the crypto stream and to escalate the crypto // This timeout allows the Go scheduler to switch to the Go rountine that reads the crypto stream and to escalate the crypto
const PublicResetTimeout = 500 * time.Millisecond const PublicResetTimeout = 500 * time.Millisecond
// AckSendDelay is the maximum delay that can be applied to an ACK for a retransmittable packet
// This is the value Chromium is using
const AckSendDelay = 25 * time.Millisecond
// ReceiveStreamFlowControlWindow is the stream-level flow control window for receiving data // ReceiveStreamFlowControlWindow is the stream-level flow control window for receiving data
// This is the value that Google servers are using // This is the value that Google servers are using
const ReceiveStreamFlowControlWindow = (1 << 10) * 32 // 32 kB const ReceiveStreamFlowControlWindow = (1 << 10) * 32 // 32 kB
...@@ -59,8 +57,11 @@ const ConnectionFlowControlMultiplier = 1.5 ...@@ -59,8 +57,11 @@ const ConnectionFlowControlMultiplier = 1.5
// WindowUpdateThreshold is the fraction of the receive window that has to be consumed before an higher offset is advertised to the client // WindowUpdateThreshold is the fraction of the receive window that has to be consumed before an higher offset is advertised to the client
const WindowUpdateThreshold = 0.25 const WindowUpdateThreshold = 0.25
// MaxIncomingStreams is the maximum number of streams that a peer may open // DefaultMaxIncomingStreams is the maximum number of streams that a peer may open
const MaxIncomingStreams = 100 const DefaultMaxIncomingStreams = 100
// DefaultMaxIncomingUniStreams is the maximum number of unidirectional streams that a peer may open
const DefaultMaxIncomingUniStreams = 100
// MaxStreamsMultiplier is the slack the client is allowed for the maximum number of streams per connection, needed e.g. when packets are out of order or dropped. The minimum of this procentual increase and the absolute increment specified by MaxStreamsMinimumIncrement is used. // MaxStreamsMultiplier is the slack the client is allowed for the maximum number of streams per connection, needed e.g. when packets are out of order or dropped. The minimum of this procentual increase and the absolute increment specified by MaxStreamsMinimumIncrement is used.
const MaxStreamsMultiplier = 1.1 const MaxStreamsMultiplier = 1.1
...@@ -68,10 +69,6 @@ const MaxStreamsMultiplier = 1.1 ...@@ -68,10 +69,6 @@ const MaxStreamsMultiplier = 1.1
// MaxStreamsMinimumIncrement is the slack the client is allowed for the maximum number of streams per connection, needed e.g. when packets are out of order or dropped. The minimum of this absolute increment and the procentual increase specified by MaxStreamsMultiplier is used. // MaxStreamsMinimumIncrement is the slack the client is allowed for the maximum number of streams per connection, needed e.g. when packets are out of order or dropped. The minimum of this absolute increment and the procentual increase specified by MaxStreamsMultiplier is used.
const MaxStreamsMinimumIncrement = 10 const MaxStreamsMinimumIncrement = 10
// MaxNewStreamIDDelta is the maximum difference between and a newly opened Stream and the highest StreamID that a client has ever opened
// note that the number of streams is half this value, since the client can only open streams with open StreamID
const MaxNewStreamIDDelta = 4 * MaxIncomingStreams
// MaxSessionUnprocessedPackets is the max number of packets stored in each session that are not yet processed. // MaxSessionUnprocessedPackets is the max number of packets stored in each session that are not yet processed.
const MaxSessionUnprocessedPackets = DefaultMaxCongestionWindow const MaxSessionUnprocessedPackets = DefaultMaxCongestionWindow
...@@ -84,8 +81,15 @@ const MaxTrackedSkippedPackets = 10 ...@@ -84,8 +81,15 @@ const MaxTrackedSkippedPackets = 10
// CookieExpiryTime is the valid time of a cookie // CookieExpiryTime is the valid time of a cookie
const CookieExpiryTime = 24 * time.Hour const CookieExpiryTime = 24 * time.Hour
// MaxTrackedSentPackets is maximum number of sent packets saved for either later retransmission or entropy calculation // MaxOutstandingSentPackets is maximum number of packets saved for retransmission.
const MaxTrackedSentPackets = 2 * DefaultMaxCongestionWindow // When reached, it imposes a soft limit on sending new packets:
// Sending ACKs and retransmission is still allowed, but now new regular packets can be sent.
const MaxOutstandingSentPackets = 2 * DefaultMaxCongestionWindow
// MaxTrackedSentPackets is maximum number of sent packets saved for retransmission.
// When reached, no more packets will be sent.
// This value *must* be larger than MaxOutstandingSentPackets.
const MaxTrackedSentPackets = MaxOutstandingSentPackets * 5 / 4
// MaxTrackedReceivedAckRanges is the maximum number of ACK ranges tracked // MaxTrackedReceivedAckRanges is the maximum number of ACK ranges tracked
const MaxTrackedReceivedAckRanges = DefaultMaxCongestionWindow const MaxTrackedReceivedAckRanges = DefaultMaxCongestionWindow
...@@ -93,9 +97,6 @@ const MaxTrackedReceivedAckRanges = DefaultMaxCongestionWindow ...@@ -93,9 +97,6 @@ const MaxTrackedReceivedAckRanges = DefaultMaxCongestionWindow
// MaxNonRetransmittableAcks is the maximum number of packets containing an ACK, but no retransmittable frames, that we send in a row // MaxNonRetransmittableAcks is the maximum number of packets containing an ACK, but no retransmittable frames, that we send in a row
const MaxNonRetransmittableAcks = 19 const MaxNonRetransmittableAcks = 19
// RetransmittablePacketsBeforeAck is the number of retransmittable that an ACK is sent for
const RetransmittablePacketsBeforeAck = 10
// MaxStreamFrameSorterGaps is the maximum number of gaps between received StreamFrames // MaxStreamFrameSorterGaps is the maximum number of gaps between received StreamFrames
// prevents DoS attacks against the streamFrameSorter // prevents DoS attacks against the streamFrameSorter
const MaxStreamFrameSorterGaps = 1000 const MaxStreamFrameSorterGaps = 1000
......
...@@ -4,10 +4,11 @@ import ( ...@@ -4,10 +4,11 @@ import (
"crypto/rand" "crypto/rand"
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"math"
) )
// VersionNumber is a version number as int // VersionNumber is a version number as int
type VersionNumber int32 type VersionNumber uint32
// gQUIC version range as defined in the wiki: https://github.com/quicwg/base-drafts/wiki/QUIC-Versions // gQUIC version range as defined in the wiki: https://github.com/quicwg/base-drafts/wiki/QUIC-Versions
const ( const (
...@@ -20,7 +21,7 @@ const ( ...@@ -20,7 +21,7 @@ const (
Version39 VersionNumber = gquicVersion0 + 3*0x100 + 0x9 + iota Version39 VersionNumber = gquicVersion0 + 3*0x100 + 0x9 + iota
VersionTLS VersionNumber = 101 VersionTLS VersionNumber = 101
VersionWhatever VersionNumber = 0 // for when the version doesn't matter VersionWhatever VersionNumber = 0 // for when the version doesn't matter
VersionUnknown VersionNumber = -1 VersionUnknown VersionNumber = math.MaxUint32
) )
// SupportedVersions lists the versions that the server supports // SupportedVersions lists the versions that the server supports
...@@ -29,6 +30,11 @@ var SupportedVersions = []VersionNumber{ ...@@ -29,6 +30,11 @@ var SupportedVersions = []VersionNumber{
Version39, Version39,
} }
// IsValidVersion says if the version is known to quic-go
func IsValidVersion(v VersionNumber) bool {
return v == VersionTLS || IsSupportedVersion(SupportedVersions, v)
}
// UsesTLS says if this QUIC version uses TLS 1.3 for the handshake // UsesTLS says if this QUIC version uses TLS 1.3 for the handshake
func (vn VersionNumber) UsesTLS() bool { func (vn VersionNumber) UsesTLS() bool {
return vn == VersionTLS return vn == VersionTLS
...@@ -46,7 +52,7 @@ func (vn VersionNumber) String() string { ...@@ -46,7 +52,7 @@ func (vn VersionNumber) String() string {
if vn.isGQUIC() { if vn.isGQUIC() {
return fmt.Sprintf("gQUIC %d", vn.toGQUICVersion()) return fmt.Sprintf("gQUIC %d", vn.toGQUICVersion())
} }
return fmt.Sprintf("%d", vn) return fmt.Sprintf("%#x", uint32(vn))
} }
} }
...@@ -71,6 +77,11 @@ func (vn VersionNumber) UsesIETFFrameFormat() bool { ...@@ -71,6 +77,11 @@ func (vn VersionNumber) UsesIETFFrameFormat() bool {
return vn != Version39 return vn != Version39
} }
// UsesStopWaitingFrames tells if this version uses STOP_WAITING frames
func (vn VersionNumber) UsesStopWaitingFrames() bool {
return vn == Version39
}
// StreamContributesToConnectionFlowControl says if a stream contributes to connection-level flow control // StreamContributesToConnectionFlowControl says if a stream contributes to connection-level flow control
func (vn VersionNumber) StreamContributesToConnectionFlowControl(id StreamID) bool { func (vn VersionNumber) StreamContributesToConnectionFlowControl(id StreamID) bool {
if id == vn.CryptoStreamID() { if id == vn.CryptoStreamID() {
......
...@@ -31,7 +31,7 @@ func (t *Timer) Reset(deadline time.Time) { ...@@ -31,7 +31,7 @@ func (t *Timer) Reset(deadline time.Time) {
if !t.t.Stop() && !t.read { if !t.t.Stop() && !t.read {
<-t.t.C <-t.t.C
} }
t.t.Reset(deadline.Sub(time.Now())) t.t.Reset(time.Until(deadline))
t.read = false t.read = false
t.deadline = deadline t.deadline = deadline
......
...@@ -60,7 +60,7 @@ func ParseAckFrame(r *bytes.Reader, version protocol.VersionNumber) (*AckFrame, ...@@ -60,7 +60,7 @@ func ParseAckFrame(r *bytes.Reader, version protocol.VersionNumber) (*AckFrame,
if ackBlock > frame.LargestAcked { if ackBlock > frame.LargestAcked {
return nil, errors.New("invalid first ACK range") return nil, errors.New("invalid first ACK range")
} }
smallest := frame.LargestAcked - protocol.PacketNumber(ackBlock) smallest := frame.LargestAcked - ackBlock
// read all the other ACK ranges // read all the other ACK ranges
if numBlocks > 0 { if numBlocks > 0 {
...@@ -86,7 +86,7 @@ func ParseAckFrame(r *bytes.Reader, version protocol.VersionNumber) (*AckFrame, ...@@ -86,7 +86,7 @@ func ParseAckFrame(r *bytes.Reader, version protocol.VersionNumber) (*AckFrame,
if ackBlock > largest { if ackBlock > largest {
return nil, errInvalidAckRanges return nil, errInvalidAckRanges
} }
smallest = largest - protocol.PacketNumber(ackBlock) smallest = largest - ackBlock
frame.AckRanges = append(frame.AckRanges, AckRange{First: smallest, Last: largest}) frame.AckRanges = append(frame.AckRanges, AckRange{First: smallest, Last: largest})
} }
...@@ -144,7 +144,7 @@ func (f *AckFrame) Length(version protocol.VersionNumber) protocol.ByteCount { ...@@ -144,7 +144,7 @@ func (f *AckFrame) Length(version protocol.VersionNumber) protocol.ByteCount {
return f.lengthLegacy(version) return f.lengthLegacy(version)
} }
length := 1 + utils.VarIntLen(uint64(f.LargestAcked)) + utils.VarIntLen(uint64(encodeAckDelay(f.DelayTime))) length := 1 + utils.VarIntLen(uint64(f.LargestAcked)) + utils.VarIntLen(encodeAckDelay(f.DelayTime))
var lowestInFirstRange protocol.PacketNumber var lowestInFirstRange protocol.PacketNumber
if f.HasMissingRanges() { if f.HasMissingRanges() {
......
...@@ -7,3 +7,8 @@ type AckRange struct { ...@@ -7,3 +7,8 @@ type AckRange struct {
First protocol.PacketNumber First protocol.PacketNumber
Last protocol.PacketNumber Last protocol.PacketNumber
} }
// Len returns the number of packets contained in this ACK range
func (r AckRange) Len() protocol.PacketNumber {
return r.Last - r.First + 1
}
...@@ -48,7 +48,7 @@ func ParseConnectionCloseFrame(r *bytes.Reader, version protocol.VersionNumber) ...@@ -48,7 +48,7 @@ func ParseConnectionCloseFrame(r *bytes.Reader, version protocol.VersionNumber)
reasonPhraseLen = uint64(length) reasonPhraseLen = uint64(length)
} }
// shortcut to prevent the unneccessary allocation of dataLen bytes // shortcut to prevent the unnecessary allocation of dataLen bytes
// if the dataLen is larger than the remaining length of the packet // if the dataLen is larger than the remaining length of the packet
// reading the whole reason phrase would result in EOF when attempting to READ // reading the whole reason phrase would result in EOF when attempting to READ
if int(reasonPhraseLen) > r.Len() { if int(reasonPhraseLen) > r.Len() {
...@@ -62,7 +62,7 @@ func ParseConnectionCloseFrame(r *bytes.Reader, version protocol.VersionNumber) ...@@ -62,7 +62,7 @@ func ParseConnectionCloseFrame(r *bytes.Reader, version protocol.VersionNumber)
} }
return &ConnectionCloseFrame{ return &ConnectionCloseFrame{
ErrorCode: qerr.ErrorCode(errorCode), ErrorCode: errorCode,
ReasonPhrase: string(reasonPhrase), ReasonPhrase: string(reasonPhrase),
}, nil }, nil
} }
......
...@@ -41,7 +41,7 @@ func ParseGoawayFrame(r *bytes.Reader, _ protocol.VersionNumber) (*GoawayFrame, ...@@ -41,7 +41,7 @@ func ParseGoawayFrame(r *bytes.Reader, _ protocol.VersionNumber) (*GoawayFrame,
return nil, err return nil, err
} }
if reasonPhraseLen > uint16(protocol.MaxPacketSize) { if reasonPhraseLen > uint16(protocol.MaxReceivePacketSize) {
return nil, qerr.Error(qerr.InvalidGoawayData, "reason phrase too long") return nil, qerr.Error(qerr.InvalidGoawayData, "reason phrase too long")
} }
......
...@@ -50,6 +50,7 @@ func ParseHeaderSentByServer(b *bytes.Reader, version protocol.VersionNumber) (* ...@@ -50,6 +50,7 @@ func ParseHeaderSentByServer(b *bytes.Reader, version protocol.VersionNumber) (*
// the client knows the version that this packet was sent with // the client knows the version that this packet was sent with
isPublicHeader = !version.UsesTLS() isPublicHeader = !version.UsesTLS()
} }
return parsePacketHeader(b, protocol.PerspectiveServer, isPublicHeader) return parsePacketHeader(b, protocol.PerspectiveServer, isPublicHeader)
} }
...@@ -61,12 +62,13 @@ func ParseHeaderSentByClient(b *bytes.Reader) (*Header, error) { ...@@ -61,12 +62,13 @@ func ParseHeaderSentByClient(b *bytes.Reader) (*Header, error) {
} }
_ = b.UnreadByte() // unread the type byte _ = b.UnreadByte() // unread the type byte
// If this is a gQUIC header 0x80 and 0x40 will be set to 0. // In an IETF QUIC packet header
// If this is an IETF QUIC header there are two options: // * either 0x80 is set (for the Long Header)
// * either 0x80 will be 1 (for the Long Header) // * or 0x8 is unset (for the Short Header)
// * or 0x40 (the Connection ID Flag) will be 0 (for the Short Header), since we don't the client to omit it // In a gQUIC Public Header
isPublicHeader := typeByte&0xc0 == 0 // * 0x80 is always unset and
// * and 0x8 is always set (this is the Connection ID flag, which the client always sets)
isPublicHeader := typeByte&0x88 == 0x8
return parsePacketHeader(b, protocol.PerspectiveClient, isPublicHeader) return parsePacketHeader(b, protocol.PerspectiveClient, isPublicHeader)
} }
......
...@@ -2,6 +2,7 @@ package wire ...@@ -2,6 +2,7 @@ package wire
import ( import (
"bytes" "bytes"
"errors"
"fmt" "fmt"
"github.com/lucas-clemente/quic-go/internal/protocol" "github.com/lucas-clemente/quic-go/internal/protocol"
...@@ -31,15 +32,9 @@ func parseLongHeader(b *bytes.Reader, sentBy protocol.Perspective, typeByte byte ...@@ -31,15 +32,9 @@ func parseLongHeader(b *bytes.Reader, sentBy protocol.Perspective, typeByte byte
if err != nil { if err != nil {
return nil, err return nil, err
} }
pn, err := utils.BigEndian.ReadUint32(b)
if err != nil {
return nil, err
}
h := &Header{ h := &Header{
ConnectionID: protocol.ConnectionID(connID), ConnectionID: protocol.ConnectionID(connID),
PacketNumber: protocol.PacketNumber(pn), Version: protocol.VersionNumber(v),
PacketNumberLen: protocol.PacketNumberLen4,
Version: protocol.VersionNumber(v),
} }
if v == 0 { // version negotiation packet if v == 0 { // version negotiation packet
if sentBy == protocol.PerspectiveClient { if sentBy == protocol.PerspectiveClient {
...@@ -60,6 +55,12 @@ func parseLongHeader(b *bytes.Reader, sentBy protocol.Perspective, typeByte byte ...@@ -60,6 +55,12 @@ func parseLongHeader(b *bytes.Reader, sentBy protocol.Perspective, typeByte byte
return h, nil return h, nil
} }
h.IsLongHeader = true h.IsLongHeader = true
pn, err := utils.BigEndian.ReadUint32(b)
if err != nil {
return nil, err
}
h.PacketNumber = protocol.PacketNumber(pn)
h.PacketNumberLen = protocol.PacketNumberLen4
h.Type = protocol.PacketType(typeByte & 0x7f) h.Type = protocol.PacketType(typeByte & 0x7f)
if sentBy == protocol.PerspectiveClient && (h.Type != protocol.PacketTypeInitial && h.Type != protocol.PacketTypeHandshake && h.Type != protocol.PacketType0RTT) { if sentBy == protocol.PerspectiveClient && (h.Type != protocol.PacketTypeInitial && h.Type != protocol.PacketTypeHandshake && h.Type != protocol.PacketType0RTT) {
return nil, qerr.Error(qerr.InvalidPacketHeader, fmt.Sprintf("Received packet with invalid packet type: %d", h.Type)) return nil, qerr.Error(qerr.InvalidPacketHeader, fmt.Sprintf("Received packet with invalid packet type: %d", h.Type))
...@@ -71,26 +72,40 @@ func parseLongHeader(b *bytes.Reader, sentBy protocol.Perspective, typeByte byte ...@@ -71,26 +72,40 @@ func parseLongHeader(b *bytes.Reader, sentBy protocol.Perspective, typeByte byte
} }
func parseShortHeader(b *bytes.Reader, typeByte byte) (*Header, error) { func parseShortHeader(b *bytes.Reader, typeByte byte) (*Header, error) {
hasConnID := typeByte&0x40 > 0 omitConnID := typeByte&0x40 > 0
var connID uint64 var connID uint64
if hasConnID { if !omitConnID {
var err error var err error
connID, err = utils.BigEndian.ReadUint64(b) connID, err = utils.BigEndian.ReadUint64(b)
if err != nil { if err != nil {
return nil, err return nil, err
} }
} }
pnLen := 1 << ((typeByte & 0x3) - 1) // bit 4 must be set, bit 5 must be unset
if typeByte&0x18 != 0x10 {
return nil, errors.New("invalid bit 4 and 5")
}
var pnLen protocol.PacketNumberLen
switch typeByte & 0x7 {
case 0x0:
pnLen = protocol.PacketNumberLen1
case 0x1:
pnLen = protocol.PacketNumberLen2
case 0x2:
pnLen = protocol.PacketNumberLen4
default:
return nil, errors.New("invalid short header type")
}
pn, err := utils.BigEndian.ReadUintN(b, uint8(pnLen)) pn, err := utils.BigEndian.ReadUintN(b, uint8(pnLen))
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &Header{ return &Header{
KeyPhase: int(typeByte&0x20) >> 5, KeyPhase: int(typeByte&0x20) >> 5,
OmitConnectionID: !hasConnID, OmitConnectionID: omitConnID,
ConnectionID: protocol.ConnectionID(connID), ConnectionID: protocol.ConnectionID(connID),
PacketNumber: protocol.PacketNumber(pn), PacketNumber: protocol.PacketNumber(pn),
PacketNumberLen: protocol.PacketNumberLen(pnLen), PacketNumberLen: pnLen,
}, nil }, nil
} }
...@@ -112,17 +127,17 @@ func (h *Header) writeLongHeader(b *bytes.Buffer) error { ...@@ -112,17 +127,17 @@ func (h *Header) writeLongHeader(b *bytes.Buffer) error {
} }
func (h *Header) writeShortHeader(b *bytes.Buffer) error { func (h *Header) writeShortHeader(b *bytes.Buffer) error {
typeByte := byte(h.KeyPhase << 5) typeByte := byte(0x10)
if !h.OmitConnectionID { typeByte ^= byte(h.KeyPhase << 5)
if h.OmitConnectionID {
typeByte ^= 0x40 typeByte ^= 0x40
} }
switch h.PacketNumberLen { switch h.PacketNumberLen {
case protocol.PacketNumberLen1: case protocol.PacketNumberLen1:
typeByte ^= 0x1
case protocol.PacketNumberLen2: case protocol.PacketNumberLen2:
typeByte ^= 0x2 typeByte ^= 0x1
case protocol.PacketNumberLen4: case protocol.PacketNumberLen4:
typeByte ^= 0x3 typeByte ^= 0x2
default: default:
return fmt.Errorf("invalid packet number length: %d", h.PacketNumberLen) return fmt.Errorf("invalid packet number length: %d", h.PacketNumberLen)
} }
......
...@@ -134,10 +134,9 @@ func parsePublicHeader(b *bytes.Reader, packetSentBy protocol.Perspective) (*Hea ...@@ -134,10 +134,9 @@ func parsePublicHeader(b *bytes.Reader, packetSentBy protocol.Perspective) (*Hea
} }
} }
// Contrary to what the gQUIC wire spec says, the 0x4 bit only indicates the presence of the diversification nonce for packets sent by the server.
// It doesn't have any meaning when sent by the client.
if packetSentBy == protocol.PerspectiveServer && publicFlagByte&0x04 > 0 { if packetSentBy == protocol.PerspectiveServer && publicFlagByte&0x04 > 0 {
// TODO: remove the if once the Google servers send the correct value
// assume that a packet doesn't contain a diversification nonce if the version flag or the reset flag is set, no matter what the public flag says
// see https://github.com/lucas-clemente/quic-go/issues/232
if !header.VersionFlag && !header.ResetFlag { if !header.VersionFlag && !header.ResetFlag {
header.DiversificationNonce = make([]byte, 32) header.DiversificationNonce = make([]byte, 32)
if _, err := io.ReadFull(b, header.DiversificationNonce); err != nil { if _, err := io.ReadFull(b, header.DiversificationNonce); err != nil {
...@@ -148,7 +147,7 @@ func parsePublicHeader(b *bytes.Reader, packetSentBy protocol.Perspective) (*Hea ...@@ -148,7 +147,7 @@ func parsePublicHeader(b *bytes.Reader, packetSentBy protocol.Perspective) (*Hea
// Version (optional) // Version (optional)
if !header.ResetFlag && header.VersionFlag { if !header.ResetFlag && header.VersionFlag {
if packetSentBy == protocol.PerspectiveServer { // parse the version negotiaton packet if packetSentBy == protocol.PerspectiveServer { // parse the version negotiation packet
if b.Len() == 0 { if b.Len() == 0 {
return nil, qerr.Error(qerr.InvalidVersionNegotiationPacket, "empty version list") return nil, qerr.Error(qerr.InvalidVersionNegotiationPacket, "empty version list")
} }
...@@ -236,7 +235,7 @@ func (h *Header) logPublicHeader() { ...@@ -236,7 +235,7 @@ func (h *Header) logPublicHeader() {
} }
ver := "(unset)" ver := "(unset)"
if h.Version != 0 { if h.Version != 0 {
ver = fmt.Sprintf("%s", h.Version) ver = h.Version.String()
} }
utils.Debugf(" Public Header{ConnectionID: %s, PacketNumber: %#x, PacketNumberLen: %d, Version: %s, DiversificationNonce: %#v}", connID, h.PacketNumber, h.PacketNumberLen, ver, h.DiversificationNonce) utils.Debugf(" Public Header{ConnectionID: %s, PacketNumber: %#x, PacketNumberLen: %d, Version: %s, DiversificationNonce: %#v}", connID, h.PacketNumber, h.PacketNumberLen, ver, h.DiversificationNonce)
} }
...@@ -56,7 +56,7 @@ func ParseStreamFrame(r *bytes.Reader, version protocol.VersionNumber) (*StreamF ...@@ -56,7 +56,7 @@ func ParseStreamFrame(r *bytes.Reader, version protocol.VersionNumber) (*StreamF
if err != nil { if err != nil {
return nil, err return nil, err
} }
// shortcut to prevent the unneccessary allocation of dataLen bytes // shortcut to prevent the unnecessary allocation of dataLen bytes
// if the dataLen is larger than the remaining length of the packet // if the dataLen is larger than the remaining length of the packet
// reading the packet contents would result in EOF when attempting to READ // reading the packet contents would result in EOF when attempting to READ
if dataLen > uint64(r.Len()) { if dataLen > uint64(r.Len()) {
......
...@@ -52,7 +52,7 @@ func parseLegacyStreamFrame(r *bytes.Reader, _ protocol.VersionNumber) (*StreamF ...@@ -52,7 +52,7 @@ func parseLegacyStreamFrame(r *bytes.Reader, _ protocol.VersionNumber) (*StreamF
} }
} }
// shortcut to prevent the unneccessary allocation of dataLen bytes // shortcut to prevent the unnecessary allocation of dataLen bytes
// if the dataLen is larger than the remaining length of the packet // if the dataLen is larger than the remaining length of the packet
// reading the packet contents would result in EOF when attempting to READ // reading the packet contents would result in EOF when attempting to READ
if int(dataLen) > r.Len() { if int(dataLen) > r.Len() {
......
...@@ -10,50 +10,37 @@ import ( ...@@ -10,50 +10,37 @@ import (
// ComposeGQUICVersionNegotiation composes a Version Negotiation Packet for gQUIC // ComposeGQUICVersionNegotiation composes a Version Negotiation Packet for gQUIC
func ComposeGQUICVersionNegotiation(connID protocol.ConnectionID, versions []protocol.VersionNumber) []byte { func ComposeGQUICVersionNegotiation(connID protocol.ConnectionID, versions []protocol.VersionNumber) []byte {
fullReply := &bytes.Buffer{} buf := &bytes.Buffer{}
ph := Header{ ph := Header{
ConnectionID: connID, ConnectionID: connID,
PacketNumber: 1, PacketNumber: 1,
VersionFlag: true, VersionFlag: true,
IsVersionNegotiation: true, IsVersionNegotiation: true,
} }
if err := ph.writePublicHeader(fullReply, protocol.PerspectiveServer, protocol.VersionWhatever); err != nil { if err := ph.writePublicHeader(buf, protocol.PerspectiveServer, protocol.VersionWhatever); err != nil {
utils.Errorf("error composing version negotiation packet: %s", err.Error()) utils.Errorf("error composing version negotiation packet: %s", err.Error())
return nil return nil
} }
writeVersions(fullReply, versions) for _, v := range versions {
return fullReply.Bytes() utils.BigEndian.WriteUint32(buf, uint32(v))
}
return buf.Bytes()
} }
// ComposeVersionNegotiation composes a Version Negotiation according to the IETF draft // ComposeVersionNegotiation composes a Version Negotiation according to the IETF draft
func ComposeVersionNegotiation( func ComposeVersionNegotiation(
connID protocol.ConnectionID, connID protocol.ConnectionID,
pn protocol.PacketNumber,
versions []protocol.VersionNumber, versions []protocol.VersionNumber,
) []byte { ) []byte {
fullReply := &bytes.Buffer{} greasedVersions := protocol.GetGreasedVersions(versions)
buf := bytes.NewBuffer(make([]byte, 0, 1+8+4+len(greasedVersions)*4))
r := make([]byte, 1) r := make([]byte, 1)
_, _ = rand.Read(r) // ignore the error here. It is not critical to have perfect random here. _, _ = rand.Read(r) // ignore the error here. It is not critical to have perfect random here.
h := Header{ buf.WriteByte(r[0] | 0x80)
IsLongHeader: true, utils.BigEndian.WriteUint64(buf, uint64(connID))
Type: protocol.PacketType(r[0] | 0x80), utils.BigEndian.WriteUint32(buf, 0) // version 0
ConnectionID: connID, for _, v := range greasedVersions {
PacketNumber: pn,
Version: 0,
IsVersionNegotiation: true,
}
if err := h.writeHeader(fullReply); err != nil {
utils.Errorf("error composing version negotiation packet: %s", err.Error())
return nil
}
writeVersions(fullReply, versions)
return fullReply.Bytes()
}
// writeVersions writes the versions for a Version Negotiation Packet.
// It inserts one reserved version number at a random position.
func writeVersions(buf *bytes.Buffer, supported []protocol.VersionNumber) {
for _, v := range protocol.GetGreasedVersions(supported) {
utils.BigEndian.WriteUint32(buf, uint32(v)) utils.BigEndian.WriteUint32(buf, uint32(v))
} }
return buf.Bytes()
} }
...@@ -139,8 +139,8 @@ func unpackInitialPacket(aead crypto.AEAD, hdr *wire.Header, data []byte, versio ...@@ -139,8 +139,8 @@ func unpackInitialPacket(aead crypto.AEAD, hdr *wire.Header, data []byte, versio
// packUnencryptedPacket provides a low-overhead way to pack a packet. // packUnencryptedPacket provides a low-overhead way to pack a packet.
// It is supposed to be used in the early stages of the handshake, before a session (which owns a packetPacker) is available. // It is supposed to be used in the early stages of the handshake, before a session (which owns a packetPacker) is available.
func packUnencryptedPacket(aead crypto.AEAD, hdr *wire.Header, f wire.Frame, pers protocol.Perspective) ([]byte, error) { func packUnencryptedPacket(aead crypto.AEAD, hdr *wire.Header, f wire.Frame, pers protocol.Perspective) ([]byte, error) {
raw := getPacketBuffer() raw := *getPacketBuffer()
buffer := bytes.NewBuffer(raw) buffer := bytes.NewBuffer(raw[:0])
if err := hdr.Write(buffer, pers, hdr.Version); err != nil { if err := hdr.Write(buffer, pers, hdr.Version); err != nil {
return nil, err return nil, err
} }
......
...@@ -4,11 +4,13 @@ import ( ...@@ -4,11 +4,13 @@ import (
"bytes" "bytes"
"errors" "errors"
"fmt" "fmt"
"net"
"sync" "sync"
"github.com/lucas-clemente/quic-go/internal/ackhandler" "github.com/lucas-clemente/quic-go/internal/ackhandler"
"github.com/lucas-clemente/quic-go/internal/handshake" "github.com/lucas-clemente/quic-go/internal/handshake"
"github.com/lucas-clemente/quic-go/internal/protocol" "github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
"github.com/lucas-clemente/quic-go/internal/wire" "github.com/lucas-clemente/quic-go/internal/wire"
) )
...@@ -19,6 +21,16 @@ type packedPacket struct { ...@@ -19,6 +21,16 @@ type packedPacket struct {
encryptionLevel protocol.EncryptionLevel encryptionLevel protocol.EncryptionLevel
} }
func (p *packedPacket) ToAckHandlerPacket() *ackhandler.Packet {
return &ackhandler.Packet{
PacketNumber: p.header.PacketNumber,
PacketType: p.header.Type,
Frames: p.frames,
Length: protocol.ByteCount(len(p.raw)),
EncryptionLevel: p.encryptionLevel,
}
}
type streamFrameSource interface { type streamFrameSource interface {
HasCryptoStreamData() bool HasCryptoStreamData() bool
PopCryptoStreamFrame(protocol.ByteCount) *wire.StreamFrame PopCryptoStreamFrame(protocol.ByteCount) *wire.StreamFrame
...@@ -32,6 +44,7 @@ type packetPacker struct { ...@@ -32,6 +44,7 @@ type packetPacker struct {
cryptoSetup handshake.CryptoSetup cryptoSetup handshake.CryptoSetup
packetNumberGenerator *packetNumberGenerator packetNumberGenerator *packetNumberGenerator
getPacketNumberLen func(protocol.PacketNumber) protocol.PacketNumberLen
streams streamFrameSource streams streamFrameSource
controlFrameMutex sync.Mutex controlFrameMutex sync.Mutex
...@@ -39,26 +52,43 @@ type packetPacker struct { ...@@ -39,26 +52,43 @@ type packetPacker struct {
stopWaiting *wire.StopWaitingFrame stopWaiting *wire.StopWaitingFrame
ackFrame *wire.AckFrame ackFrame *wire.AckFrame
leastUnacked protocol.PacketNumber
omitConnectionID bool omitConnectionID bool
maxPacketSize protocol.ByteCount
hasSentPacket bool // has the packetPacker already sent a packet hasSentPacket bool // has the packetPacker already sent a packet
numNonRetransmittableAcks int numNonRetransmittableAcks int
} }
func newPacketPacker(connectionID protocol.ConnectionID, func newPacketPacker(connectionID protocol.ConnectionID,
initialPacketNumber protocol.PacketNumber, initialPacketNumber protocol.PacketNumber,
getPacketNumberLen func(protocol.PacketNumber) protocol.PacketNumberLen,
remoteAddr net.Addr, // only used for determining the max packet size
cryptoSetup handshake.CryptoSetup, cryptoSetup handshake.CryptoSetup,
streamFramer streamFrameSource, streamFramer streamFrameSource,
perspective protocol.Perspective, perspective protocol.Perspective,
version protocol.VersionNumber, version protocol.VersionNumber,
) *packetPacker { ) *packetPacker {
maxPacketSize := protocol.ByteCount(protocol.MinInitialPacketSize)
// If this is not a UDP address, we don't know anything about the MTU.
// Use the minimum size of an Initial packet as the max packet size.
if udpAddr, ok := remoteAddr.(*net.UDPAddr); ok {
// If ip is not an IPv4 address, To4 returns nil.
// Note that there might be some corner cases, where this is not correct.
// See https://stackoverflow.com/questions/22751035/golang-distinguish-ipv4-ipv6.
if udpAddr.IP.To4() == nil {
maxPacketSize = protocol.MaxPacketSizeIPv6
} else {
maxPacketSize = protocol.MaxPacketSizeIPv4
}
}
return &packetPacker{ return &packetPacker{
cryptoSetup: cryptoSetup, cryptoSetup: cryptoSetup,
connectionID: connectionID, connectionID: connectionID,
perspective: perspective, perspective: perspective,
version: version, version: version,
streams: streamFramer, streams: streamFramer,
getPacketNumberLen: getPacketNumberLen,
packetNumberGenerator: newPacketNumberGenerator(initialPacketNumber, protocol.SkipPacketAveragePeriodLength), packetNumberGenerator: newPacketNumberGenerator(initialPacketNumber, protocol.SkipPacketAveragePeriodLength),
maxPacketSize: maxPacketSize,
} }
} }
...@@ -99,18 +129,124 @@ func (p *packetPacker) PackAckPacket() (*packedPacket, error) { ...@@ -99,18 +129,124 @@ func (p *packetPacker) PackAckPacket() (*packedPacket, error) {
}, err }, err
} }
// PackHandshakeRetransmission retransmits a handshake packet, that was sent with less than forward-secure encryption // PackRetransmission packs a retransmission
func (p *packetPacker) PackHandshakeRetransmission(packet *ackhandler.Packet) (*packedPacket, error) { // For packets sent after completion of the handshake, it might happen that 2 packets have to be sent.
if packet.EncryptionLevel == protocol.EncryptionForwardSecure { // This can happen e.g. when a longer packet number is used in the header.
return nil, errors.New("PacketPacker BUG: forward-secure encrypted handshake packets don't need special treatment") func (p *packetPacker) PackRetransmission(packet *ackhandler.Packet) ([]*packedPacket, error) {
if packet.EncryptionLevel != protocol.EncryptionForwardSecure {
p, err := p.packHandshakeRetransmission(packet)
return []*packedPacket{p}, err
}
var controlFrames []wire.Frame
var streamFrames []*wire.StreamFrame
for _, f := range packet.Frames {
if sf, ok := f.(*wire.StreamFrame); ok {
sf.DataLenPresent = true
streamFrames = append(streamFrames, sf)
} else {
controlFrames = append(controlFrames, f)
}
}
var packets []*packedPacket
encLevel, sealer := p.cryptoSetup.GetSealer()
for len(controlFrames) > 0 || len(streamFrames) > 0 {
var frames []wire.Frame
var payloadLength protocol.ByteCount
header := p.getHeader(encLevel)
headerLength, err := header.GetLength(p.perspective, p.version)
if err != nil {
return nil, err
}
maxSize := p.maxPacketSize - protocol.ByteCount(sealer.Overhead()) - headerLength
// for gQUIC: add a STOP_WAITING for *every* retransmission
if p.version.UsesStopWaitingFrames() {
if p.stopWaiting == nil {
return nil, errors.New("PacketPacker BUG: Handshake retransmissions must contain a STOP_WAITING frame")
}
// create a new StopWaitingFrame, since we might need to send more than one packet as a retransmission
swf := &wire.StopWaitingFrame{
LeastUnacked: p.stopWaiting.LeastUnacked,
PacketNumber: header.PacketNumber,
PacketNumberLen: header.PacketNumberLen,
}
payloadLength += swf.Length(p.version)
frames = append(frames, swf)
}
for len(controlFrames) > 0 {
frame := controlFrames[0]
length := frame.Length(p.version)
if payloadLength+length > maxSize {
break
}
payloadLength += length
frames = append(frames, frame)
controlFrames = controlFrames[1:]
}
// temporarily increase the maxFrameSize by the (minimum) length of the DataLen field
// this leads to a properly sized packet in all cases, since we do all the packet length calculations with StreamFrames that have the DataLen set
// however, for the last STREAM frame in the packet, we can omit the DataLen, thus yielding a packet of exactly the correct size
// for gQUIC STREAM frames, DataLen is always 2 bytes
// for IETF draft style STREAM frames, the length is encoded to either 1 or 2 bytes
if p.version.UsesIETFFrameFormat() {
maxSize++
} else {
maxSize += 2
}
for len(streamFrames) > 0 && payloadLength+protocol.MinStreamFrameSize < maxSize {
// TODO: optimize by setting DataLenPresent = false on all but the last STREAM frame
frame := streamFrames[0]
frameToAdd := frame
sf, err := frame.MaybeSplitOffFrame(maxSize-payloadLength, p.version)
if err != nil {
return nil, err
}
if sf != nil {
frameToAdd = sf
} else {
streamFrames = streamFrames[1:]
}
payloadLength += frameToAdd.Length(p.version)
frames = append(frames, frameToAdd)
}
if sf, ok := frames[len(frames)-1].(*wire.StreamFrame); ok {
sf.DataLenPresent = false
}
raw, err := p.writeAndSealPacket(header, frames, sealer)
if err != nil {
return nil, err
}
packets = append(packets, &packedPacket{
header: header,
raw: raw,
frames: frames,
encryptionLevel: encLevel,
})
} }
p.stopWaiting = nil
return packets, nil
}
// packHandshakeRetransmission retransmits a handshake packet, that was sent with less than forward-secure encryption
func (p *packetPacker) packHandshakeRetransmission(packet *ackhandler.Packet) (*packedPacket, error) {
sealer, err := p.cryptoSetup.GetSealerWithEncryptionLevel(packet.EncryptionLevel) sealer, err := p.cryptoSetup.GetSealerWithEncryptionLevel(packet.EncryptionLevel)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// make sure that the retransmission for an Initial packet is sent as an Initial packet
if packet.PacketType == protocol.PacketTypeInitial {
p.hasSentPacket = false
}
header := p.getHeader(packet.EncryptionLevel) header := p.getHeader(packet.EncryptionLevel)
header.Type = packet.PacketType
var frames []wire.Frame var frames []wire.Frame
if !p.version.UsesIETFFrameFormat() { // for gQUIC: pack a STOP_WAITING first if p.version.UsesStopWaitingFrames() { // for gQUIC: pack a STOP_WAITING first
if p.stopWaiting == nil { if p.stopWaiting == nil {
return nil, errors.New("PacketPacker BUG: Handshake retransmissions must contain a STOP_WAITING frame") return nil, errors.New("PacketPacker BUG: Handshake retransmissions must contain a STOP_WAITING frame")
} }
...@@ -155,7 +291,7 @@ func (p *packetPacker) PackPacket() (*packedPacket, error) { ...@@ -155,7 +291,7 @@ func (p *packetPacker) PackPacket() (*packedPacket, error) {
p.stopWaiting.PacketNumberLen = header.PacketNumberLen p.stopWaiting.PacketNumberLen = header.PacketNumberLen
} }
maxSize := protocol.MaxPacketSize - protocol.ByteCount(sealer.Overhead()) - headerLength maxSize := p.maxPacketSize - protocol.ByteCount(sealer.Overhead()) - headerLength
payloadFrames, err := p.composeNextPacket(maxSize, p.canSendData(encLevel)) payloadFrames, err := p.composeNextPacket(maxSize, p.canSendData(encLevel))
if err != nil { if err != nil {
return nil, err return nil, err
...@@ -204,7 +340,7 @@ func (p *packetPacker) packCryptoPacket() (*packedPacket, error) { ...@@ -204,7 +340,7 @@ func (p *packetPacker) packCryptoPacket() (*packedPacket, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
maxLen := protocol.MaxPacketSize - protocol.ByteCount(sealer.Overhead()) - protocol.NonForwardSecurePacketSizeReduction - headerLength maxLen := p.maxPacketSize - protocol.ByteCount(sealer.Overhead()) - protocol.NonForwardSecurePacketSizeReduction - headerLength
sf := p.streams.PopCryptoStreamFrame(maxLen) sf := p.streams.PopCryptoStreamFrame(maxLen)
sf.DataLenPresent = false sf.DataLenPresent = false
frames := []wire.Frame{sf} frames := []wire.Frame{sf}
...@@ -261,7 +397,7 @@ func (p *packetPacker) composeNextPacket( ...@@ -261,7 +397,7 @@ func (p *packetPacker) composeNextPacket(
// temporarily increase the maxFrameSize by the (minimum) length of the DataLen field // temporarily increase the maxFrameSize by the (minimum) length of the DataLen field
// this leads to a properly sized packet in all cases, since we do all the packet length calculations with StreamFrames that have the DataLen set // this leads to a properly sized packet in all cases, since we do all the packet length calculations with StreamFrames that have the DataLen set
// however, for the last StreamFrame in the packet, we can omit the DataLen, thus yielding a packet of exactly the correct size // however, for the last STREAM frame in the packet, we can omit the DataLen, thus yielding a packet of exactly the correct size
// for gQUIC STREAM frames, DataLen is always 2 bytes // for gQUIC STREAM frames, DataLen is always 2 bytes
// for IETF draft style STREAM frames, the length is encoded to either 1 or 2 bytes // for IETF draft style STREAM frames, the length is encoded to either 1 or 2 bytes
if p.version.UsesIETFFrameFormat() { if p.version.UsesIETFFrameFormat() {
...@@ -296,7 +432,7 @@ func (p *packetPacker) QueueControlFrame(frame wire.Frame) { ...@@ -296,7 +432,7 @@ func (p *packetPacker) QueueControlFrame(frame wire.Frame) {
func (p *packetPacker) getHeader(encLevel protocol.EncryptionLevel) *wire.Header { func (p *packetPacker) getHeader(encLevel protocol.EncryptionLevel) *wire.Header {
pnum := p.packetNumberGenerator.Peek() pnum := p.packetNumberGenerator.Peek()
packetNumberLen := protocol.GetPacketNumberLengthForHeader(pnum, p.leastUnacked) packetNumberLen := p.getPacketNumberLen(pnum)
header := &wire.Header{ header := &wire.Header{
ConnectionID: p.connectionID, ConnectionID: p.connectionID,
...@@ -338,8 +474,8 @@ func (p *packetPacker) writeAndSealPacket( ...@@ -338,8 +474,8 @@ func (p *packetPacker) writeAndSealPacket(
payloadFrames []wire.Frame, payloadFrames []wire.Frame,
sealer handshake.Sealer, sealer handshake.Sealer,
) ([]byte, error) { ) ([]byte, error) {
raw := getPacketBuffer() raw := *getPacketBuffer()
buffer := bytes.NewBuffer(raw) buffer := bytes.NewBuffer(raw[:0])
if err := header.Write(buffer, p.perspective, p.version); err != nil { if err := header.Write(buffer, p.perspective, p.version); err != nil {
return nil, err return nil, err
...@@ -367,8 +503,8 @@ func (p *packetPacker) writeAndSealPacket( ...@@ -367,8 +503,8 @@ func (p *packetPacker) writeAndSealPacket(
} }
} }
if size := protocol.ByteCount(buffer.Len() + sealer.Overhead()); size > protocol.MaxPacketSize { if size := protocol.ByteCount(buffer.Len() + sealer.Overhead()); size > p.maxPacketSize {
return nil, fmt.Errorf("PacketPacker BUG: packet too large (%d bytes, allowed %d bytes)", size, protocol.MaxPacketSize) return nil, fmt.Errorf("PacketPacker BUG: packet too large (%d bytes, allowed %d bytes)", size, p.maxPacketSize)
} }
raw = raw[0:buffer.Len()] raw = raw[0:buffer.Len()]
...@@ -390,10 +526,10 @@ func (p *packetPacker) canSendData(encLevel protocol.EncryptionLevel) bool { ...@@ -390,10 +526,10 @@ func (p *packetPacker) canSendData(encLevel protocol.EncryptionLevel) bool {
return encLevel == protocol.EncryptionForwardSecure return encLevel == protocol.EncryptionForwardSecure
} }
func (p *packetPacker) SetLeastUnacked(leastUnacked protocol.PacketNumber) {
p.leastUnacked = leastUnacked
}
func (p *packetPacker) SetOmitConnectionID() { func (p *packetPacker) SetOmitConnectionID() {
p.omitConnectionID = true p.omitConnectionID = true
} }
func (p *packetPacker) SetMaxPacketSize(size protocol.ByteCount) {
p.maxPacketSize = utils.MinByteCount(p.maxPacketSize, size)
}
...@@ -24,8 +24,9 @@ type packetUnpacker struct { ...@@ -24,8 +24,9 @@ type packetUnpacker struct {
} }
func (u *packetUnpacker) Unpack(headerBinary []byte, hdr *wire.Header, data []byte) (*unpackedPacket, error) { func (u *packetUnpacker) Unpack(headerBinary []byte, hdr *wire.Header, data []byte) (*unpackedPacket, error) {
buf := getPacketBuffer() buf := *getPacketBuffer()
defer putPacketBuffer(buf) buf = buf[:0]
defer putPacketBuffer(&buf)
decrypted, encryptionLevel, err := u.aead.Open(buf, data, hdr.PacketNumber, headerBinary) decrypted, encryptionLevel, err := u.aead.Open(buf, data, hdr.PacketNumber, headerBinary)
if err != nil { if err != nil {
// Wrap err in quicError so that public reset is sent by session // Wrap err in quicError so that public reset is sent by session
......
...@@ -31,6 +31,7 @@ func (e *QuicError) Error() string { ...@@ -31,6 +31,7 @@ func (e *QuicError) Error() string {
return fmt.Sprintf("%s: %s", e.ErrorCode.String(), e.ErrorMessage) return fmt.Sprintf("%s: %s", e.ErrorCode.String(), e.ErrorMessage)
} }
// Timeout says if this error is a timeout.
func (e *QuicError) Timeout() bool { func (e *QuicError) Timeout() bool {
switch e.ErrorCode { switch e.ErrorCode {
case NetworkIdleTimeout, case NetworkIdleTimeout,
......
...@@ -124,7 +124,7 @@ func (s *receiveStream) Read(p []byte) (int, error) { ...@@ -124,7 +124,7 @@ func (s *receiveStream) Read(p []byte) (int, error) {
} else { } else {
select { select {
case <-s.readChan: case <-s.readChan:
case <-time.After(deadline.Sub(time.Now())): case <-time.After(time.Until(deadline)):
} }
} }
s.mutex.Lock() s.mutex.Lock()
......
...@@ -116,7 +116,7 @@ func (s *sendStream) Write(p []byte) (int, error) { ...@@ -116,7 +116,7 @@ func (s *sendStream) Write(p []byte) (int, error) {
} else { } else {
select { select {
case <-s.writeChan: case <-s.writeChan:
case <-time.After(deadline.Sub(time.Now())): case <-time.After(time.Until(deadline)):
} }
} }
s.mutex.Lock() s.mutex.Lock()
......
...@@ -4,6 +4,7 @@ import ( ...@@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"crypto/tls" "crypto/tls"
"errors" "errors"
"fmt"
"net" "net"
"sync" "sync"
"time" "time"
...@@ -85,9 +86,12 @@ func Listen(conn net.PacketConn, tlsConf *tls.Config, config *Config) (Listener, ...@@ -85,9 +86,12 @@ func Listen(conn net.PacketConn, tlsConf *tls.Config, config *Config) (Listener,
} }
config = populateServerConfig(config) config = populateServerConfig(config)
// check if any of the supported versions supports TLS
var supportsTLS bool var supportsTLS bool
for _, v := range config.Versions { for _, v := range config.Versions {
if !protocol.IsValidVersion(v) {
return nil, fmt.Errorf("%s is not a valid QUIC version", v)
}
// check if any of the supported versions supports TLS
if v.UsesTLS() { if v.UsesTLS() {
supportsTLS = true supportsTLS = true
break break
...@@ -136,10 +140,11 @@ func (s *server) setupTLS() error { ...@@ -136,10 +140,11 @@ func (s *server) setupTLS() error {
case tlsSession := <-sessionChan: case tlsSession := <-sessionChan:
connID := tlsSession.connID connID := tlsSession.connID
sess := tlsSession.sess sess := tlsSession.sess
s.sessionsMutex.Lock()
if _, ok := s.sessions[connID]; ok { // drop this session if it already exists if _, ok := s.sessions[connID]; ok { // drop this session if it already exists
return s.sessionsMutex.Unlock()
continue
} }
s.sessionsMutex.Lock()
s.sessions[connID] = sess s.sessions[connID] = sess
s.sessionsMutex.Unlock() s.sessionsMutex.Unlock()
s.runHandshakeAndSession(sess, connID) s.runHandshakeAndSession(sess, connID)
...@@ -198,6 +203,18 @@ func populateServerConfig(config *Config) *Config { ...@@ -198,6 +203,18 @@ func populateServerConfig(config *Config) *Config {
if maxReceiveConnectionFlowControlWindow == 0 { if maxReceiveConnectionFlowControlWindow == 0 {
maxReceiveConnectionFlowControlWindow = protocol.DefaultMaxReceiveConnectionFlowControlWindowServer maxReceiveConnectionFlowControlWindow = protocol.DefaultMaxReceiveConnectionFlowControlWindowServer
} }
maxIncomingStreams := config.MaxIncomingStreams
if maxIncomingStreams == 0 {
maxIncomingStreams = protocol.DefaultMaxIncomingStreams
} else if maxIncomingStreams < 0 {
maxIncomingStreams = 0
}
maxIncomingUniStreams := config.MaxIncomingUniStreams
if maxIncomingUniStreams == 0 {
maxIncomingUniStreams = protocol.DefaultMaxIncomingUniStreams
} else if maxIncomingUniStreams < 0 {
maxIncomingUniStreams = 0
}
return &Config{ return &Config{
Versions: versions, Versions: versions,
...@@ -207,13 +224,15 @@ func populateServerConfig(config *Config) *Config { ...@@ -207,13 +224,15 @@ func populateServerConfig(config *Config) *Config {
KeepAlive: config.KeepAlive, KeepAlive: config.KeepAlive,
MaxReceiveStreamFlowControlWindow: maxReceiveStreamFlowControlWindow, MaxReceiveStreamFlowControlWindow: maxReceiveStreamFlowControlWindow,
MaxReceiveConnectionFlowControlWindow: maxReceiveConnectionFlowControlWindow, MaxReceiveConnectionFlowControlWindow: maxReceiveConnectionFlowControlWindow,
MaxIncomingStreams: maxIncomingStreams,
MaxIncomingUniStreams: maxIncomingUniStreams,
} }
} }
// serve listens on an existing PacketConn // serve listens on an existing PacketConn
func (s *server) serve() { func (s *server) serve() {
for { for {
data := getPacketBuffer() data := *getPacketBuffer()
data = data[:protocol.MaxReceivePacketSize] data = data[:protocol.MaxReceivePacketSize]
// The packet size should not exceed protocol.MaxReceivePacketSize bytes // The packet size should not exceed protocol.MaxReceivePacketSize bytes
// If it does, we only read a truncated packet, which will then end up undecryptable // If it does, we only read a truncated packet, which will then end up undecryptable
...@@ -309,7 +328,7 @@ func (s *server) handlePacket(pconn net.PacketConn, remoteAddr net.Addr, packet ...@@ -309,7 +328,7 @@ func (s *server) handlePacket(pconn net.PacketConn, remoteAddr net.Addr, packet
var pr *wire.PublicReset var pr *wire.PublicReset
pr, err = wire.ParsePublicReset(r) pr, err = wire.ParsePublicReset(r)
if err != nil { if err != nil {
utils.Infof("Received a Public Reset for connection %x. An error occurred parsing the packet.") utils.Infof("Received a Public Reset for connection %x. An error occurred parsing the packet.", hdr.ConnectionID)
} else { } else {
utils.Infof("Received a Public Reset for connection %x, rejected packet number: 0x%x.", hdr.ConnectionID, pr.RejectedPacketNumber) utils.Infof("Received a Public Reset for connection %x, rejected packet number: 0x%x.", hdr.ConnectionID, pr.RejectedPacketNumber)
} }
......
...@@ -36,7 +36,6 @@ type serverTLS struct { ...@@ -36,7 +36,6 @@ type serverTLS struct {
config *Config config *Config
supportedVersions []protocol.VersionNumber supportedVersions []protocol.VersionNumber
mintConf *mint.Config mintConf *mint.Config
cookieProtector mint.CookieProtector
params *handshake.TransportParameters params *handshake.TransportParameters
newMintConn func(*handshake.CryptoStreamConn, protocol.VersionNumber) (handshake.MintTLS, <-chan handshake.TransportParameters, error) newMintConn func(*handshake.CryptoStreamConn, protocol.VersionNumber) (handshake.MintTLS, <-chan handshake.TransportParameters, error)
...@@ -72,9 +71,8 @@ func newServerTLS( ...@@ -72,9 +71,8 @@ func newServerTLS(
StreamFlowControlWindow: protocol.ReceiveStreamFlowControlWindow, StreamFlowControlWindow: protocol.ReceiveStreamFlowControlWindow,
ConnectionFlowControlWindow: protocol.ReceiveConnectionFlowControlWindow, ConnectionFlowControlWindow: protocol.ReceiveConnectionFlowControlWindow,
IdleTimeout: config.IdleTimeout, IdleTimeout: config.IdleTimeout,
// TODO(#523): make these values configurable MaxBidiStreams: uint16(config.MaxIncomingStreams),
MaxBidiStreamID: protocol.MaxBidiStreamID(protocol.MaxIncomingStreams, protocol.PerspectiveServer), MaxUniStreams: uint16(config.MaxIncomingUniStreams),
MaxUniStreamID: protocol.MaxUniStreamID(protocol.MaxIncomingStreams, protocol.PerspectiveServer),
}, },
} }
s.newMintConn = s.newMintConnImpl s.newMintConn = s.newMintConnImpl
...@@ -85,7 +83,7 @@ func (s *serverTLS) HandleInitial(remoteAddr net.Addr, hdr *wire.Header, data [] ...@@ -85,7 +83,7 @@ func (s *serverTLS) HandleInitial(remoteAddr net.Addr, hdr *wire.Header, data []
utils.Debugf("Received a Packet. Handling it statelessly.") utils.Debugf("Received a Packet. Handling it statelessly.")
sess, err := s.handleInitialImpl(remoteAddr, hdr, data) sess, err := s.handleInitialImpl(remoteAddr, hdr, data)
if err != nil { if err != nil {
utils.Errorf("Error occured handling initial packet: %s", err) utils.Errorf("Error occurred handling initial packet: %s", err)
return return
} }
if sess == nil { // a stateless reset was done if sess == nil { // a stateless reset was done
...@@ -132,7 +130,7 @@ func (s *serverTLS) handleInitialImpl(remoteAddr net.Addr, hdr *wire.Header, dat ...@@ -132,7 +130,7 @@ func (s *serverTLS) handleInitialImpl(remoteAddr net.Addr, hdr *wire.Header, dat
// check version, if not matching send VNP // check version, if not matching send VNP
if !protocol.IsSupportedVersion(s.supportedVersions, hdr.Version) { if !protocol.IsSupportedVersion(s.supportedVersions, hdr.Version) {
utils.Debugf("Client offered version %s, sending VersionNegotiationPacket", hdr.Version) utils.Debugf("Client offered version %s, sending VersionNegotiationPacket", hdr.Version)
_, err := s.conn.WriteTo(wire.ComposeVersionNegotiation(hdr.ConnectionID, hdr.PacketNumber, s.supportedVersions), remoteAddr) _, err := s.conn.WriteTo(wire.ComposeVersionNegotiation(hdr.ConnectionID, s.supportedVersions), remoteAddr)
return nil, err return nil, err
} }
...@@ -149,7 +147,7 @@ func (s *serverTLS) handleInitialImpl(remoteAddr net.Addr, hdr *wire.Header, dat ...@@ -149,7 +147,7 @@ func (s *serverTLS) handleInitialImpl(remoteAddr net.Addr, hdr *wire.Header, dat
sess, err := s.handleUnpackedInitial(remoteAddr, hdr, frame, aead) sess, err := s.handleUnpackedInitial(remoteAddr, hdr, frame, aead)
if err != nil { if err != nil {
if ccerr := s.sendConnectionClose(remoteAddr, hdr, aead, err); ccerr != nil { if ccerr := s.sendConnectionClose(remoteAddr, hdr, aead, err); ccerr != nil {
utils.Debugf("Error sending CONNECTION_CLOSE: ", ccerr) utils.Debugf("Error sending CONNECTION_CLOSE: %s", ccerr)
} }
return nil, err return nil, err
} }
......
...@@ -33,8 +33,11 @@ type streamManager interface { ...@@ -33,8 +33,11 @@ type streamManager interface {
GetOrOpenSendStream(protocol.StreamID) (sendStreamI, error) GetOrOpenSendStream(protocol.StreamID) (sendStreamI, error)
GetOrOpenReceiveStream(protocol.StreamID) (receiveStreamI, error) GetOrOpenReceiveStream(protocol.StreamID) (receiveStreamI, error)
OpenStream() (Stream, error) OpenStream() (Stream, error)
OpenUniStream() (SendStream, error)
OpenStreamSync() (Stream, error) OpenStreamSync() (Stream, error)
OpenUniStreamSync() (SendStream, error)
AcceptStream() (Stream, error) AcceptStream() (Stream, error)
AcceptUniStream() (ReceiveStream, error)
DeleteStream(protocol.StreamID) error DeleteStream(protocol.StreamID) error
UpdateLimits(*handshake.TransportParameters) UpdateLimits(*handshake.TransportParameters)
HandleMaxStreamIDFrame(*wire.MaxStreamIDFrame) error HandleMaxStreamIDFrame(*wire.MaxStreamIDFrame) error
...@@ -108,7 +111,9 @@ type session struct { ...@@ -108,7 +111,9 @@ type session struct {
handshakeChan chan error handshakeChan chan error
handshakeComplete bool handshakeComplete bool
lastRcvdPacketNumber protocol.PacketNumber receivedFirstPacket bool // since packet numbers start at 0, we can't use largestRcvdPacketNumber != 0 for this
receivedFirstForwardSecurePacket bool
lastRcvdPacketNumber protocol.PacketNumber
// Used to calculate the next packet number from the truncated wire // Used to calculate the next packet number from the truncated wire
// representation, and sent back in public reset packets // representation, and sent back in public reset packets
largestRcvdPacketNumber protocol.PacketNumber largestRcvdPacketNumber protocol.PacketNumber
...@@ -153,7 +158,7 @@ func newSession( ...@@ -153,7 +158,7 @@ func newSession(
transportParams := &handshake.TransportParameters{ transportParams := &handshake.TransportParameters{
StreamFlowControlWindow: protocol.ReceiveStreamFlowControlWindow, StreamFlowControlWindow: protocol.ReceiveStreamFlowControlWindow,
ConnectionFlowControlWindow: protocol.ReceiveConnectionFlowControlWindow, ConnectionFlowControlWindow: protocol.ReceiveConnectionFlowControlWindow,
MaxStreams: protocol.MaxIncomingStreams, MaxStreams: uint32(s.config.MaxIncomingStreams),
IdleTimeout: s.config.IdleTimeout, IdleTimeout: s.config.IdleTimeout,
} }
cs, err := newCryptoSetup( cs, err := newCryptoSetup(
...@@ -184,7 +189,7 @@ var newClientSession = func( ...@@ -184,7 +189,7 @@ var newClientSession = func(
tlsConf *tls.Config, tlsConf *tls.Config,
config *Config, config *Config,
initialVersion protocol.VersionNumber, initialVersion protocol.VersionNumber,
negotiatedVersions []protocol.VersionNumber, // needed for validation of the GQUIC version negotiaton negotiatedVersions []protocol.VersionNumber, // needed for validation of the GQUIC version negotiation
) (packetHandler, error) { ) (packetHandler, error) {
paramsChan := make(chan handshake.TransportParameters) paramsChan := make(chan handshake.TransportParameters)
handshakeEvent := make(chan struct{}, 1) handshakeEvent := make(chan struct{}, 1)
...@@ -201,7 +206,7 @@ var newClientSession = func( ...@@ -201,7 +206,7 @@ var newClientSession = func(
transportParams := &handshake.TransportParameters{ transportParams := &handshake.TransportParameters{
StreamFlowControlWindow: protocol.ReceiveStreamFlowControlWindow, StreamFlowControlWindow: protocol.ReceiveStreamFlowControlWindow,
ConnectionFlowControlWindow: protocol.ReceiveConnectionFlowControlWindow, ConnectionFlowControlWindow: protocol.ReceiveConnectionFlowControlWindow,
MaxStreams: protocol.MaxIncomingStreams, MaxStreams: uint32(s.config.MaxIncomingStreams),
IdleTimeout: s.config.IdleTimeout, IdleTimeout: s.config.IdleTimeout,
OmitConnectionID: s.config.RequestConnectionIDOmission, OmitConnectionID: s.config.RequestConnectionIDOmission,
} }
...@@ -323,16 +328,18 @@ func (s *session) postSetup(initialPacketNumber protocol.PacketNumber) error { ...@@ -323,16 +328,18 @@ func (s *session) postSetup(initialPacketNumber protocol.PacketNumber) error {
s.sessionCreationTime = now s.sessionCreationTime = now
s.sentPacketHandler = ackhandler.NewSentPacketHandler(s.rttStats) s.sentPacketHandler = ackhandler.NewSentPacketHandler(s.rttStats)
s.receivedPacketHandler = ackhandler.NewReceivedPacketHandler(s.version) s.receivedPacketHandler = ackhandler.NewReceivedPacketHandler(s.rttStats, s.version)
if s.version.UsesTLS() { if s.version.UsesTLS() {
s.streamsMap = newStreamsMap(s, s.newFlowController, s.perspective, s.version) s.streamsMap = newStreamsMap(s, s.newFlowController, s.config.MaxIncomingStreams, s.config.MaxIncomingUniStreams, s.perspective, s.version)
} else { } else {
s.streamsMap = newStreamsMapLegacy(s.newStream, s.perspective) s.streamsMap = newStreamsMapLegacy(s.newStream, s.config.MaxIncomingStreams, s.perspective)
} }
s.streamFramer = newStreamFramer(s.cryptoStream, s.streamsMap, s.version) s.streamFramer = newStreamFramer(s.cryptoStream, s.streamsMap, s.version)
s.packer = newPacketPacker(s.connectionID, s.packer = newPacketPacker(s.connectionID,
initialPacketNumber, initialPacketNumber,
s.sentPacketHandler.GetPacketNumberLen,
s.RemoteAddr(),
s.cryptoSetup, s.cryptoSetup,
s.streamFramer, s.streamFramer,
s.perspective, s.perspective,
...@@ -390,14 +397,13 @@ runLoop: ...@@ -390,14 +397,13 @@ runLoop:
} }
// This is a bit unclean, but works properly, since the packet always // This is a bit unclean, but works properly, since the packet always
// begins with the public header and we never copy it. // begins with the public header and we never copy it.
putPacketBuffer(p.header.Raw) putPacketBuffer(&p.header.Raw)
case p := <-s.paramsChan: case p := <-s.paramsChan:
s.processTransportParameters(&p) s.processTransportParameters(&p)
case _, ok := <-handshakeEvent: case _, ok := <-handshakeEvent:
if !ok { // the aeadChanged chan was closed. This means that the handshake is completed. if !ok { // the aeadChanged chan was closed. This means that the handshake is completed.
s.handshakeComplete = true s.handshakeComplete = true
handshakeEvent = nil // prevent this case from ever being selected again handshakeEvent = nil // prevent this case from ever being selected again
s.sentPacketHandler.SetHandshakeComplete()
if !s.version.UsesTLS() && s.perspective == protocol.PerspectiveClient { if !s.version.UsesTLS() && s.perspective == protocol.PerspectiveClient {
// In gQUIC, there's no equivalent to the Finished message in TLS // In gQUIC, there's no equivalent to the Finished message in TLS
// The server knows that the handshake is complete when it receives the first forward-secure packet sent by the client. // The server knows that the handshake is complete when it receives the first forward-secure packet sent by the client.
...@@ -412,9 +418,11 @@ runLoop: ...@@ -412,9 +418,11 @@ runLoop:
now := time.Now() now := time.Now()
if timeout := s.sentPacketHandler.GetAlarmTimeout(); !timeout.IsZero() && timeout.Before(now) { if timeout := s.sentPacketHandler.GetAlarmTimeout(); !timeout.IsZero() && timeout.Before(now) {
// This could cause packets to be retransmitted, so check it before trying // This could cause packets to be retransmitted.
// to send packets. // Check it before trying to send packets.
s.sentPacketHandler.OnAlarm() if err := s.sentPacketHandler.OnAlarm(); err != nil {
s.closeLocal(err)
}
} }
var pacingDeadline time.Time var pacingDeadline time.Time
...@@ -506,6 +514,7 @@ func (s *session) handlePacketImpl(p *receivedPacket) error { ...@@ -506,6 +514,7 @@ func (s *session) handlePacketImpl(p *receivedPacket) error {
p.rcvTime = time.Now() p.rcvTime = time.Now()
} }
s.receivedFirstPacket = true
s.lastNetworkActivityTime = p.rcvTime s.lastNetworkActivityTime = p.rcvTime
s.keepAlivePingSent = false s.keepAlivePingSent = false
hdr := p.header hdr := p.header
...@@ -532,13 +541,26 @@ func (s *session) handlePacketImpl(p *receivedPacket) error { ...@@ -532,13 +541,26 @@ func (s *session) handlePacketImpl(p *receivedPacket) error {
return err return err
} }
// In TLS 1.3, the client considers the handshake complete as soon as
// it received the server's Finished message and sent its Finished.
// We have to wait for the first forward-secure packet from the server before
// deleting all handshake packets from the history.
if !s.receivedFirstForwardSecurePacket && packet.encryptionLevel == protocol.EncryptionForwardSecure {
s.receivedFirstForwardSecurePacket = true
s.sentPacketHandler.SetHandshakeComplete()
}
s.lastRcvdPacketNumber = hdr.PacketNumber s.lastRcvdPacketNumber = hdr.PacketNumber
// Only do this after decrypting, so we are sure the packet is not attacker-controlled // Only do this after decrypting, so we are sure the packet is not attacker-controlled
s.largestRcvdPacketNumber = utils.MaxPacketNumber(s.largestRcvdPacketNumber, hdr.PacketNumber) s.largestRcvdPacketNumber = utils.MaxPacketNumber(s.largestRcvdPacketNumber, hdr.PacketNumber)
isRetransmittable := ackhandler.HasRetransmittableFrames(packet.frames) // If this is a Retry packet, there's no need to send an ACK.
if err = s.receivedPacketHandler.ReceivedPacket(hdr.PacketNumber, p.rcvTime, isRetransmittable); err != nil { // The session will be closed and recreated as soon as the crypto setup processed the HRR.
return err if hdr.Type != protocol.PacketTypeRetry {
isRetransmittable := ackhandler.HasRetransmittableFrames(packet.frames)
if err := s.receivedPacketHandler.ReceivedPacket(hdr.PacketNumber, p.rcvTime, isRetransmittable); err != nil {
return err
}
} }
return s.handleFrames(packet.frames, packet.encryptionLevel) return s.handleFrames(packet.frames, packet.encryptionLevel)
...@@ -577,12 +599,7 @@ func (s *session) handleFrames(fs []wire.Frame, encLevel protocol.EncryptionLeve ...@@ -577,12 +599,7 @@ func (s *session) handleFrames(fs []wire.Frame, encLevel protocol.EncryptionLeve
} }
if err != nil { if err != nil {
switch err { return err
case ackhandler.ErrDuplicateOrOutOfOrderAck:
// Can happen e.g. when packets thought missing arrive late
default:
return err
}
} }
} }
return nil return nil
...@@ -744,6 +761,9 @@ func (s *session) processTransportParameters(params *handshake.TransportParamete ...@@ -744,6 +761,9 @@ func (s *session) processTransportParameters(params *handshake.TransportParamete
if params.OmitConnectionID { if params.OmitConnectionID {
s.packer.SetOmitConnectionID() s.packer.SetOmitConnectionID()
} }
if params.MaxPacketSize != 0 {
s.packer.SetMaxPacketSize(params.MaxPacketSize)
}
s.connFlowController.UpdateSendWindow(params.ConnectionFlowControlWindow) s.connFlowController.UpdateSendWindow(params.ConnectionFlowControlWindow)
// the crypto stream is the only open stream at this moment // the crypto stream is the only open stream at this moment
// so we don't need to update stream flow control windows // so we don't need to update stream flow control windows
...@@ -751,23 +771,56 @@ func (s *session) processTransportParameters(params *handshake.TransportParamete ...@@ -751,23 +771,56 @@ func (s *session) processTransportParameters(params *handshake.TransportParamete
func (s *session) sendPackets() error { func (s *session) sendPackets() error {
s.pacingDeadline = time.Time{} s.pacingDeadline = time.Time{}
if !s.sentPacketHandler.SendingAllowed() { // if congestion limited, at least try sending an ACK frame
return s.maybeSendAckOnlyPacket() sendMode := s.sentPacketHandler.SendMode()
if sendMode == ackhandler.SendNone { // shortcut: return immediately if there's nothing to send
return nil
} }
numPackets := s.sentPacketHandler.ShouldSendNumPackets() numPackets := s.sentPacketHandler.ShouldSendNumPackets()
for i := 0; i < numPackets; i++ { var numPacketsSent int
sentPacket, err := s.sendPacket() sendLoop:
if err != nil { for {
return err switch sendMode {
case ackhandler.SendNone:
break sendLoop
case ackhandler.SendAck:
// We can at most send a single ACK only packet.
// There will only be a new ACK after receiving new packets.
// SendAck is only returned when we're congestion limited, so we don't need to set the pacingt timer.
return s.maybeSendAckOnlyPacket()
case ackhandler.SendRetransmission:
sentPacket, err := s.maybeSendRetransmission()
if err != nil {
return err
}
if sentPacket {
numPacketsSent++
// This can happen if a retransmission queued, but it wasn't necessary to send it.
// e.g. when an Initial is queued, but we already received a packet from the server.
}
case ackhandler.SendAny:
sentPacket, err := s.sendPacket()
if err != nil {
return err
}
if !sentPacket {
break sendLoop
}
numPacketsSent++
default:
return fmt.Errorf("BUG: invalid send mode %d", sendMode)
} }
// If no packet was sent, or we're congestion limit, we're done here. if numPacketsSent >= numPackets {
if !sentPacket || !s.sentPacketHandler.SendingAllowed() { break
return nil
} }
sendMode = s.sentPacketHandler.SendMode()
} }
// Only start the pacing timer if we sent as many packets as we were allowed. // Only start the pacing timer if we sent as many packets as we were allowed.
// There will probably be more to send when calling sendPacket again. // There will probably be more to send when calling sendPacket again.
s.pacingDeadline = s.sentPacketHandler.TimeUntilSend() if numPacketsSent == numPackets {
s.pacingDeadline = s.sentPacketHandler.TimeUntilSend()
}
return nil return nil
} }
...@@ -778,7 +831,7 @@ func (s *session) maybeSendAckOnlyPacket() error { ...@@ -778,7 +831,7 @@ func (s *session) maybeSendAckOnlyPacket() error {
} }
s.packer.QueueControlFrame(ack) s.packer.QueueControlFrame(ack)
if !s.version.UsesIETFFrameFormat() { // for gQUIC, maybe add a STOP_WAITING if s.version.UsesStopWaitingFrames() { // for gQUIC, maybe add a STOP_WAITING
if swf := s.sentPacketHandler.GetStopWaitingFrame(false); swf != nil { if swf := s.sentPacketHandler.GetStopWaitingFrame(false); swf != nil {
s.packer.QueueControlFrame(swf) s.packer.QueueControlFrame(swf)
} }
...@@ -787,12 +840,57 @@ func (s *session) maybeSendAckOnlyPacket() error { ...@@ -787,12 +840,57 @@ func (s *session) maybeSendAckOnlyPacket() error {
if err != nil { if err != nil {
return err return err
} }
s.sentPacketHandler.SentPacket(packet.ToAckHandlerPacket())
return s.sendPackedPacket(packet) return s.sendPackedPacket(packet)
} }
func (s *session) sendPacket() (bool, error) { // maybeSendRetransmission sends retransmissions for at most one packet.
s.packer.SetLeastUnacked(s.sentPacketHandler.GetLeastUnacked()) // It takes care that Initials aren't retransmitted, if a packet from the server was already received.
func (s *session) maybeSendRetransmission() (bool, error) {
var retransmitPacket *ackhandler.Packet
for {
retransmitPacket = s.sentPacketHandler.DequeuePacketForRetransmission()
if retransmitPacket == nil {
return false, nil
}
// Don't retransmit Initial packets if we already received a response.
// An Initial might have been retransmitted multiple times before we receive a response.
// As soon as we receive one response, we don't need to send any more Initials.
if s.receivedFirstPacket && retransmitPacket.PacketType == protocol.PacketTypeInitial {
utils.Debugf("Skipping retransmission of packet %d. Already received a response to an Initial.", retransmitPacket.PacketNumber)
continue
}
break
}
if retransmitPacket.EncryptionLevel != protocol.EncryptionForwardSecure {
utils.Debugf("\tDequeueing handshake retransmission for packet 0x%x", retransmitPacket.PacketNumber)
} else {
utils.Debugf("\tDequeueing retransmission for packet 0x%x", retransmitPacket.PacketNumber)
}
if s.version.UsesStopWaitingFrames() {
s.packer.QueueControlFrame(s.sentPacketHandler.GetStopWaitingFrame(true))
}
packets, err := s.packer.PackRetransmission(retransmitPacket)
if err != nil {
return false, err
}
ackhandlerPackets := make([]*ackhandler.Packet, len(packets))
for i, packet := range packets {
ackhandlerPackets[i] = packet.ToAckHandlerPacket()
}
s.sentPacketHandler.SentPacketsAsRetransmission(ackhandlerPackets, retransmitPacket.PacketNumber)
for _, packet := range packets {
if err := s.sendPackedPacket(packet); err != nil {
return false, err
}
}
return true, nil
}
func (s *session) sendPacket() (bool, error) {
if offset := s.connFlowController.GetWindowUpdate(); offset != 0 { if offset := s.connFlowController.GetWindowUpdate(); offset != 0 {
s.packer.QueueControlFrame(&wire.MaxDataFrame{ByteOffset: offset}) s.packer.QueueControlFrame(&wire.MaxDataFrame{ByteOffset: offset})
} }
...@@ -801,58 +899,20 @@ func (s *session) sendPacket() (bool, error) { ...@@ -801,58 +899,20 @@ func (s *session) sendPacket() (bool, error) {
} }
s.windowUpdateQueue.QueueAll() s.windowUpdateQueue.QueueAll()
ack := s.receivedPacketHandler.GetAckFrame() if ack := s.receivedPacketHandler.GetAckFrame(); ack != nil {
if ack != nil {
s.packer.QueueControlFrame(ack) s.packer.QueueControlFrame(ack)
} if s.version.UsesStopWaitingFrames() {
if swf := s.sentPacketHandler.GetStopWaitingFrame(false); swf != nil {
// check for retransmissions first s.packer.QueueControlFrame(swf)
for {
retransmitPacket := s.sentPacketHandler.DequeuePacketForRetransmission()
if retransmitPacket == nil {
break
}
// retransmit handshake packets
if retransmitPacket.EncryptionLevel != protocol.EncryptionForwardSecure {
utils.Debugf("\tDequeueing handshake retransmission for packet 0x%x", retransmitPacket.PacketNumber)
if !s.version.UsesIETFFrameFormat() {
s.packer.QueueControlFrame(s.sentPacketHandler.GetStopWaitingFrame(true))
}
packet, err := s.packer.PackHandshakeRetransmission(retransmitPacket)
if err != nil {
return false, err
}
if err := s.sendPackedPacket(packet); err != nil {
return false, err
}
return true, nil
}
// queue all retransmittable frames sent in forward-secure packets
utils.Debugf("\tDequeueing retransmission for packet 0x%x", retransmitPacket.PacketNumber)
// resend the frames that were in the packet
for _, frame := range retransmitPacket.GetFramesForRetransmission() {
// TODO: only retransmit WINDOW_UPDATEs if they actually enlarge the window
switch f := frame.(type) {
case *wire.StreamFrame:
s.streamFramer.AddFrameForRetransmission(f)
default:
s.packer.QueueControlFrame(frame)
} }
} }
} }
hasRetransmission := s.streamFramer.HasFramesForRetransmission()
if !s.version.UsesIETFFrameFormat() && (ack != nil || hasRetransmission) {
if swf := s.sentPacketHandler.GetStopWaitingFrame(hasRetransmission); swf != nil {
s.packer.QueueControlFrame(swf)
}
}
packet, err := s.packer.PackPacket() packet, err := s.packer.PackPacket()
if err != nil || packet == nil { if err != nil || packet == nil {
return false, err return false, err
} }
s.sentPacketHandler.SentPacket(packet.ToAckHandlerPacket())
if err := s.sendPackedPacket(packet); err != nil { if err := s.sendPackedPacket(packet); err != nil {
return false, err return false, err
} }
...@@ -860,22 +920,12 @@ func (s *session) sendPacket() (bool, error) { ...@@ -860,22 +920,12 @@ func (s *session) sendPacket() (bool, error) {
} }
func (s *session) sendPackedPacket(packet *packedPacket) error { func (s *session) sendPackedPacket(packet *packedPacket) error {
defer putPacketBuffer(packet.raw) defer putPacketBuffer(&packet.raw)
err := s.sentPacketHandler.SentPacket(&ackhandler.Packet{
PacketNumber: packet.header.PacketNumber,
Frames: packet.frames,
Length: protocol.ByteCount(len(packet.raw)),
EncryptionLevel: packet.encryptionLevel,
})
if err != nil {
return err
}
s.logPacket(packet) s.logPacket(packet)
return s.conn.Write(packet.raw) return s.conn.Write(packet.raw)
} }
func (s *session) sendConnectionClose(quicErr *qerr.QuicError) error { func (s *session) sendConnectionClose(quicErr *qerr.QuicError) error {
s.packer.SetLeastUnacked(s.sentPacketHandler.GetLeastUnacked())
packet, err := s.packer.PackConnectionClose(&wire.ConnectionCloseFrame{ packet, err := s.packer.PackConnectionClose(&wire.ConnectionCloseFrame{
ErrorCode: quicErr.ErrorCode, ErrorCode: quicErr.ErrorCode,
ReasonPhrase: quicErr.ErrorMessage, ReasonPhrase: quicErr.ErrorMessage,
...@@ -919,6 +969,10 @@ func (s *session) AcceptStream() (Stream, error) { ...@@ -919,6 +969,10 @@ func (s *session) AcceptStream() (Stream, error) {
return s.streamsMap.AcceptStream() return s.streamsMap.AcceptStream()
} }
func (s *session) AcceptUniStream() (ReceiveStream, error) {
return s.streamsMap.AcceptUniStream()
}
// OpenStream opens a stream // OpenStream opens a stream
func (s *session) OpenStream() (Stream, error) { func (s *session) OpenStream() (Stream, error) {
return s.streamsMap.OpenStream() return s.streamsMap.OpenStream()
...@@ -928,6 +982,14 @@ func (s *session) OpenStreamSync() (Stream, error) { ...@@ -928,6 +982,14 @@ func (s *session) OpenStreamSync() (Stream, error) {
return s.streamsMap.OpenStreamSync() return s.streamsMap.OpenStreamSync()
} }
func (s *session) OpenUniStream() (SendStream, error) {
return s.streamsMap.OpenUniStream()
}
func (s *session) OpenUniStreamSync() (SendStream, error) {
return s.streamsMap.OpenUniStreamSync()
}
func (s *session) newStream(id protocol.StreamID) streamI { func (s *session) newStream(id protocol.StreamID) streamI {
flowController := s.newFlowController(id) flowController := s.newFlowController(id)
return newStream(id, s, flowController, s.version) return newStream(id, s, flowController, s.version)
...@@ -1026,7 +1088,6 @@ func (s *session) LocalAddr() net.Addr { ...@@ -1026,7 +1088,6 @@ func (s *session) LocalAddr() net.Addr {
return s.conn.LocalAddr() return s.conn.LocalAddr()
} }
// RemoteAddr returns the net.Addr of the client
func (s *session) RemoteAddr() net.Addr { func (s *session) RemoteAddr() net.Addr {
return s.conn.RemoteAddr() return s.conn.RemoteAddr()
} }
......
...@@ -12,8 +12,6 @@ type streamFramer struct { ...@@ -12,8 +12,6 @@ type streamFramer struct {
cryptoStream cryptoStreamI cryptoStream cryptoStreamI
version protocol.VersionNumber version protocol.VersionNumber
retransmissionQueue []*wire.StreamFrame
streamQueueMutex sync.Mutex streamQueueMutex sync.Mutex
activeStreams map[protocol.StreamID]struct{} activeStreams map[protocol.StreamID]struct{}
streamQueue []protocol.StreamID streamQueue []protocol.StreamID
...@@ -33,10 +31,6 @@ func newStreamFramer( ...@@ -33,10 +31,6 @@ func newStreamFramer(
} }
} }
func (f *streamFramer) AddFrameForRetransmission(frame *wire.StreamFrame) {
f.retransmissionQueue = append(f.retransmissionQueue, frame)
}
func (f *streamFramer) AddActiveStream(id protocol.StreamID) { func (f *streamFramer) AddActiveStream(id protocol.StreamID) {
if id == f.version.CryptoStreamID() { // the crypto stream is handled separately if id == f.version.CryptoStreamID() { // the crypto stream is handled separately
f.streamQueueMutex.Lock() f.streamQueueMutex.Lock()
...@@ -52,15 +46,6 @@ func (f *streamFramer) AddActiveStream(id protocol.StreamID) { ...@@ -52,15 +46,6 @@ func (f *streamFramer) AddActiveStream(id protocol.StreamID) {
f.streamQueueMutex.Unlock() f.streamQueueMutex.Unlock()
} }
func (f *streamFramer) PopStreamFrames(maxLen protocol.ByteCount) []*wire.StreamFrame {
fs, currentLen := f.maybePopFramesForRetransmission(maxLen)
return append(fs, f.maybePopNormalFrames(maxLen-currentLen)...)
}
func (f *streamFramer) HasFramesForRetransmission() bool {
return len(f.retransmissionQueue) > 0
}
func (f *streamFramer) HasCryptoStreamData() bool { func (f *streamFramer) HasCryptoStreamData() bool {
f.streamQueueMutex.Lock() f.streamQueueMutex.Lock()
hasCryptoStreamData := f.hasCryptoStreamData hasCryptoStreamData := f.hasCryptoStreamData
...@@ -76,34 +61,7 @@ func (f *streamFramer) PopCryptoStreamFrame(maxLen protocol.ByteCount) *wire.Str ...@@ -76,34 +61,7 @@ func (f *streamFramer) PopCryptoStreamFrame(maxLen protocol.ByteCount) *wire.Str
return frame return frame
} }
func (f *streamFramer) maybePopFramesForRetransmission(maxTotalLen protocol.ByteCount) (res []*wire.StreamFrame, currentLen protocol.ByteCount) { func (f *streamFramer) PopStreamFrames(maxTotalLen protocol.ByteCount) []*wire.StreamFrame {
for len(f.retransmissionQueue) > 0 {
frame := f.retransmissionQueue[0]
frame.DataLenPresent = true
maxLen := maxTotalLen - currentLen
if frame.Length(f.version) > maxLen && maxLen < protocol.MinStreamFrameSize {
break
}
splitFrame, err := frame.MaybeSplitOffFrame(maxLen, f.version)
if err != nil { // maxLen is too small. Can't split frame
break
}
if splitFrame != nil { // frame was split
res = append(res, splitFrame)
currentLen += splitFrame.Length(f.version)
break
}
f.retransmissionQueue = f.retransmissionQueue[1:]
res = append(res, frame)
currentLen += frame.Length(f.version)
}
return
}
func (f *streamFramer) maybePopNormalFrames(maxTotalLen protocol.ByteCount) []*wire.StreamFrame {
var currentLen protocol.ByteCount var currentLen protocol.ByteCount
var frames []*wire.StreamFrame var frames []*wire.StreamFrame
f.streamQueueMutex.Lock() f.streamQueueMutex.Lock()
......
...@@ -35,6 +35,8 @@ var _ streamManager = &streamsMap{} ...@@ -35,6 +35,8 @@ var _ streamManager = &streamsMap{}
func newStreamsMap( func newStreamsMap(
sender streamSender, sender streamSender,
newFlowController func(protocol.StreamID) flowcontrol.StreamFlowController, newFlowController func(protocol.StreamID) flowcontrol.StreamFlowController,
maxIncomingStreams int,
maxIncomingUniStreams int,
perspective protocol.Perspective, perspective protocol.Perspective,
version protocol.VersionNumber, version protocol.VersionNumber,
) streamManager { ) streamManager {
...@@ -46,7 +48,7 @@ func newStreamsMap( ...@@ -46,7 +48,7 @@ func newStreamsMap(
var firstOutgoingBidiStream, firstOutgoingUniStream, firstIncomingBidiStream, firstIncomingUniStream protocol.StreamID var firstOutgoingBidiStream, firstOutgoingUniStream, firstIncomingBidiStream, firstIncomingUniStream protocol.StreamID
if perspective == protocol.PerspectiveServer { if perspective == protocol.PerspectiveServer {
firstOutgoingBidiStream = 1 firstOutgoingBidiStream = 1
firstIncomingBidiStream = 4 // the crypto stream is handled separatedly firstIncomingBidiStream = 4 // the crypto stream is handled separately
firstOutgoingUniStream = 3 firstOutgoingUniStream = 3
firstIncomingUniStream = 2 firstIncomingUniStream = 2
} else { } else {
...@@ -69,11 +71,10 @@ func newStreamsMap( ...@@ -69,11 +71,10 @@ func newStreamsMap(
newBidiStream, newBidiStream,
sender.queueControlFrame, sender.queueControlFrame,
) )
// TODO(#523): make these values configurable
m.incomingBidiStreams = newIncomingBidiStreamsMap( m.incomingBidiStreams = newIncomingBidiStreamsMap(
firstIncomingBidiStream, firstIncomingBidiStream,
protocol.MaxBidiStreamID(protocol.MaxIncomingStreams, perspective), protocol.MaxBidiStreamID(maxIncomingStreams, perspective),
protocol.MaxIncomingStreams, maxIncomingStreams,
sender.queueControlFrame, sender.queueControlFrame,
newBidiStream, newBidiStream,
) )
...@@ -82,11 +83,10 @@ func newStreamsMap( ...@@ -82,11 +83,10 @@ func newStreamsMap(
newUniSendStream, newUniSendStream,
sender.queueControlFrame, sender.queueControlFrame,
) )
// TODO(#523): make these values configurable
m.incomingUniStreams = newIncomingUniStreamsMap( m.incomingUniStreams = newIncomingUniStreamsMap(
firstIncomingUniStream, firstIncomingUniStream,
protocol.MaxUniStreamID(protocol.MaxIncomingStreams, perspective), protocol.MaxUniStreamID(maxIncomingUniStreams, perspective),
protocol.MaxIncomingStreams, maxIncomingUniStreams,
sender.queueControlFrame, sender.queueControlFrame,
newUniReceiveStream, newUniReceiveStream,
) )
...@@ -206,8 +206,14 @@ func (m *streamsMap) HandleMaxStreamIDFrame(f *wire.MaxStreamIDFrame) error { ...@@ -206,8 +206,14 @@ func (m *streamsMap) HandleMaxStreamIDFrame(f *wire.MaxStreamIDFrame) error {
} }
func (m *streamsMap) UpdateLimits(p *handshake.TransportParameters) { func (m *streamsMap) UpdateLimits(p *handshake.TransportParameters) {
m.outgoingBidiStreams.SetMaxStream(p.MaxBidiStreamID) // Max{Uni,Bidi}StreamID returns the highest stream ID that the peer is allowed to open.
m.outgoingUniStreams.SetMaxStream(p.MaxUniStreamID) // Invert the perspective to determine the value that we are allowed to open.
peerPers := protocol.PerspectiveServer
if m.perspective == protocol.PerspectiveServer {
peerPers = protocol.PerspectiveClient
}
m.outgoingBidiStreams.SetMaxStream(protocol.MaxBidiStreamID(int(p.MaxBidiStreams), peerPers))
m.outgoingUniStreams.SetMaxStream(protocol.MaxUniStreamID(int(p.MaxUniStreams), peerPers))
} }
func (m *streamsMap) CloseWithError(err error) { func (m *streamsMap) CloseWithError(err error) {
......
...@@ -69,20 +69,25 @@ func (m *incomingBidiStreamsMap) AcceptStream() (streamI, error) { ...@@ -69,20 +69,25 @@ func (m *incomingBidiStreamsMap) AcceptStream() (streamI, error) {
} }
func (m *incomingBidiStreamsMap) GetOrOpenStream(id protocol.StreamID) (streamI, error) { func (m *incomingBidiStreamsMap) GetOrOpenStream(id protocol.StreamID) (streamI, error) {
m.mutex.RLock()
if id > m.maxStream { if id > m.maxStream {
m.mutex.RUnlock()
return nil, fmt.Errorf("peer tried to open stream %d (current limit: %d)", id, m.maxStream) return nil, fmt.Errorf("peer tried to open stream %d (current limit: %d)", id, m.maxStream)
} }
// if the id is smaller than the highest we accepted // if the id is smaller than the highest we accepted
// * this stream exists in the map, and we can return it, or // * this stream exists in the map, and we can return it, or
// * this stream was already closed, then we can return the nil // * this stream was already closed, then we can return the nil
if id <= m.highestStream { if id <= m.highestStream {
m.mutex.RLock()
s := m.streams[id] s := m.streams[id]
m.mutex.RUnlock() m.mutex.RUnlock()
return s, nil return s, nil
} }
m.mutex.RUnlock()
m.mutex.Lock() m.mutex.Lock()
// no need to check the two error conditions from above again
// * maxStream can only increase, so if the id was valid before, it definitely is valid now
// * highestStream is only modified by this function
var start protocol.StreamID var start protocol.StreamID
if m.highestStream == 0 { if m.highestStream == 0 {
start = m.nextStream start = m.nextStream
......
...@@ -67,20 +67,25 @@ func (m *incomingItemsMap) AcceptStream() (item, error) { ...@@ -67,20 +67,25 @@ func (m *incomingItemsMap) AcceptStream() (item, error) {
} }
func (m *incomingItemsMap) GetOrOpenStream(id protocol.StreamID) (item, error) { func (m *incomingItemsMap) GetOrOpenStream(id protocol.StreamID) (item, error) {
m.mutex.RLock()
if id > m.maxStream { if id > m.maxStream {
m.mutex.RUnlock()
return nil, fmt.Errorf("peer tried to open stream %d (current limit: %d)", id, m.maxStream) return nil, fmt.Errorf("peer tried to open stream %d (current limit: %d)", id, m.maxStream)
} }
// if the id is smaller than the highest we accepted // if the id is smaller than the highest we accepted
// * this stream exists in the map, and we can return it, or // * this stream exists in the map, and we can return it, or
// * this stream was already closed, then we can return the nil // * this stream was already closed, then we can return the nil
if id <= m.highestStream { if id <= m.highestStream {
m.mutex.RLock()
s := m.streams[id] s := m.streams[id]
m.mutex.RUnlock() m.mutex.RUnlock()
return s, nil return s, nil
} }
m.mutex.RUnlock()
m.mutex.Lock() m.mutex.Lock()
// no need to check the two error conditions from above again
// * maxStream can only increase, so if the id was valid before, it definitely is valid now
// * highestStream is only modified by this function
var start protocol.StreamID var start protocol.StreamID
if m.highestStream == 0 { if m.highestStream == 0 {
start = m.nextStream start = m.nextStream
......
...@@ -69,20 +69,25 @@ func (m *incomingUniStreamsMap) AcceptStream() (receiveStreamI, error) { ...@@ -69,20 +69,25 @@ func (m *incomingUniStreamsMap) AcceptStream() (receiveStreamI, error) {
} }
func (m *incomingUniStreamsMap) GetOrOpenStream(id protocol.StreamID) (receiveStreamI, error) { func (m *incomingUniStreamsMap) GetOrOpenStream(id protocol.StreamID) (receiveStreamI, error) {
m.mutex.RLock()
if id > m.maxStream { if id > m.maxStream {
m.mutex.RUnlock()
return nil, fmt.Errorf("peer tried to open stream %d (current limit: %d)", id, m.maxStream) return nil, fmt.Errorf("peer tried to open stream %d (current limit: %d)", id, m.maxStream)
} }
// if the id is smaller than the highest we accepted // if the id is smaller than the highest we accepted
// * this stream exists in the map, and we can return it, or // * this stream exists in the map, and we can return it, or
// * this stream was already closed, then we can return the nil // * this stream was already closed, then we can return the nil
if id <= m.highestStream { if id <= m.highestStream {
m.mutex.RLock()
s := m.streams[id] s := m.streams[id]
m.mutex.RUnlock() m.mutex.RUnlock()
return s, nil return s, nil
} }
m.mutex.RUnlock()
m.mutex.Lock() m.mutex.Lock()
// no need to check the two error conditions from above again
// * maxStream can only increase, so if the id was valid before, it definitely is valid now
// * highestStream is only modified by this function
var start protocol.StreamID var start protocol.StreamID
if m.highestStream == 0 { if m.highestStream == 0 {
start = m.nextStream start = m.nextStream
......
...@@ -39,11 +39,10 @@ var _ streamManager = &streamsMapLegacy{} ...@@ -39,11 +39,10 @@ var _ streamManager = &streamsMapLegacy{}
var errMapAccess = errors.New("streamsMap: Error accessing the streams map") var errMapAccess = errors.New("streamsMap: Error accessing the streams map")
func newStreamsMapLegacy(newStream func(protocol.StreamID) streamI, pers protocol.Perspective) streamManager { func newStreamsMapLegacy(newStream func(protocol.StreamID) streamI, maxStreams int, pers protocol.Perspective) streamManager {
// add some tolerance to the maximum incoming streams value // add some tolerance to the maximum incoming streams value
maxStreams := uint32(protocol.MaxIncomingStreams)
maxIncomingStreams := utils.MaxUint32( maxIncomingStreams := utils.MaxUint32(
maxStreams+protocol.MaxStreamsMinimumIncrement, uint32(maxStreams)+protocol.MaxStreamsMinimumIncrement,
uint32(float64(maxStreams)*float64(protocol.MaxStreamsMultiplier)), uint32(float64(maxStreams)*float64(protocol.MaxStreamsMultiplier)),
) )
sm := streamsMapLegacy{ sm := streamsMapLegacy{
...@@ -131,7 +130,10 @@ func (m *streamsMapLegacy) openRemoteStream(id protocol.StreamID) (streamI, erro ...@@ -131,7 +130,10 @@ func (m *streamsMapLegacy) openRemoteStream(id protocol.StreamID) (streamI, erro
if m.numIncomingStreams >= m.maxIncomingStreams { if m.numIncomingStreams >= m.maxIncomingStreams {
return nil, qerr.TooManyOpenStreams return nil, qerr.TooManyOpenStreams
} }
if id+protocol.MaxNewStreamIDDelta < m.highestStreamOpenedByPeer { // maxNewStreamIDDelta is the maximum difference between and a newly opened Stream and the highest StreamID that a client has ever opened
// note that the number of streams is half this value, since the client can only open streams with open StreamID
maxStreamIDDelta := protocol.StreamID(4 * m.maxIncomingStreams)
if id+maxStreamIDDelta < m.highestStreamOpenedByPeer {
return nil, qerr.Error(qerr.InvalidStreamID, fmt.Sprintf("attempted to open stream %d, which is a lot smaller than the highest opened stream, %d", id, m.highestStreamOpenedByPeer)) return nil, qerr.Error(qerr.InvalidStreamID, fmt.Sprintf("attempted to open stream %d, which is a lot smaller than the highest opened stream, %d", id, m.highestStreamOpenedByPeer))
} }
...@@ -185,6 +187,14 @@ func (m *streamsMapLegacy) OpenStreamSync() (Stream, error) { ...@@ -185,6 +187,14 @@ func (m *streamsMapLegacy) OpenStreamSync() (Stream, error) {
} }
} }
func (m *streamsMapLegacy) OpenUniStream() (SendStream, error) {
return nil, errors.New("gQUIC doesn't support unidirectional streams")
}
func (m *streamsMapLegacy) OpenUniStreamSync() (SendStream, error) {
return nil, errors.New("gQUIC doesn't support unidirectional streams")
}
// AcceptStream returns the next stream opened by the peer // AcceptStream returns the next stream opened by the peer
// it blocks until a new stream is opened // it blocks until a new stream is opened
func (m *streamsMapLegacy) AcceptStream() (Stream, error) { func (m *streamsMapLegacy) AcceptStream() (Stream, error) {
...@@ -206,6 +216,10 @@ func (m *streamsMapLegacy) AcceptStream() (Stream, error) { ...@@ -206,6 +216,10 @@ func (m *streamsMapLegacy) AcceptStream() (Stream, error) {
return str, nil return str, nil
} }
func (m *streamsMapLegacy) AcceptUniStream() (ReceiveStream, error) {
return nil, errors.New("gQUIC doesn't support unidirectional streams")
}
func (m *streamsMapLegacy) DeleteStream(id protocol.StreamID) error { func (m *streamsMapLegacy) DeleteStream(id protocol.StreamID) error {
m.mutex.Lock() m.mutex.Lock()
defer m.mutex.Unlock() defer m.mutex.Unlock()
......
...@@ -85,10 +85,11 @@ func (m *outgoingBidiStreamsMap) openStreamImpl() (streamI, error) { ...@@ -85,10 +85,11 @@ func (m *outgoingBidiStreamsMap) openStreamImpl() (streamI, error) {
} }
func (m *outgoingBidiStreamsMap) GetStream(id protocol.StreamID) (streamI, error) { func (m *outgoingBidiStreamsMap) GetStream(id protocol.StreamID) (streamI, error) {
m.mutex.RLock()
if id >= m.nextStream { if id >= m.nextStream {
m.mutex.RUnlock()
return nil, qerr.Error(qerr.InvalidStreamID, fmt.Sprintf("peer attempted to open stream %d", id)) return nil, qerr.Error(qerr.InvalidStreamID, fmt.Sprintf("peer attempted to open stream %d", id))
} }
m.mutex.RLock()
s := m.streams[id] s := m.streams[id]
m.mutex.RUnlock() m.mutex.RUnlock()
return s, nil return s, nil
......
...@@ -86,10 +86,11 @@ func (m *outgoingItemsMap) openStreamImpl() (item, error) { ...@@ -86,10 +86,11 @@ func (m *outgoingItemsMap) openStreamImpl() (item, error) {
} }
func (m *outgoingItemsMap) GetStream(id protocol.StreamID) (item, error) { func (m *outgoingItemsMap) GetStream(id protocol.StreamID) (item, error) {
m.mutex.RLock()
if id >= m.nextStream { if id >= m.nextStream {
m.mutex.RUnlock()
return nil, qerr.Error(qerr.InvalidStreamID, fmt.Sprintf("peer attempted to open stream %d", id)) return nil, qerr.Error(qerr.InvalidStreamID, fmt.Sprintf("peer attempted to open stream %d", id))
} }
m.mutex.RLock()
s := m.streams[id] s := m.streams[id]
m.mutex.RUnlock() m.mutex.RUnlock()
return s, nil return s, nil
......
...@@ -85,10 +85,11 @@ func (m *outgoingUniStreamsMap) openStreamImpl() (sendStreamI, error) { ...@@ -85,10 +85,11 @@ func (m *outgoingUniStreamsMap) openStreamImpl() (sendStreamI, error) {
} }
func (m *outgoingUniStreamsMap) GetStream(id protocol.StreamID) (sendStreamI, error) { func (m *outgoingUniStreamsMap) GetStream(id protocol.StreamID) (sendStreamI, error) {
m.mutex.RLock()
if id >= m.nextStream { if id >= m.nextStream {
m.mutex.RUnlock()
return nil, qerr.Error(qerr.InvalidStreamID, fmt.Sprintf("peer attempted to open stream %d", id)) return nil, qerr.Error(qerr.InvalidStreamID, fmt.Sprintf("peer attempted to open stream %d", id))
} }
m.mutex.RLock()
s := m.streams[id] s := m.streams[id]
m.mutex.RUnlock() m.mutex.RUnlock()
return s, nil return s, nil
......
...@@ -50,7 +50,7 @@ import ( ...@@ -50,7 +50,7 @@ import (
// WAIT_FINISHED RekeyIn; [Send(EOED);] RekeyOut; [SendCert; SendCV;] SendFin; RekeyOut; // WAIT_FINISHED RekeyIn; [Send(EOED);] RekeyOut; [SendCert; SendCV;] SendFin; RekeyOut;
// CONNECTED StoreTicket || (RekeyIn; [RekeyOut]) // CONNECTED StoreTicket || (RekeyIn; [RekeyOut])
type ClientStateStart struct { type clientStateStart struct {
Config *Config Config *Config
Opts ConnectionOptions Opts ConnectionOptions
Params ConnectionParameters Params ConnectionParameters
...@@ -61,13 +61,13 @@ type ClientStateStart struct { ...@@ -61,13 +61,13 @@ type ClientStateStart struct {
hsCtx HandshakeContext hsCtx HandshakeContext
} }
var _ HandshakeState = &ClientStateStart{} var _ HandshakeState = &clientStateStart{}
func (state ClientStateStart) State() State { func (state clientStateStart) State() State {
return StateClientStart return StateClientStart
} }
func (state ClientStateStart) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) { func (state clientStateStart) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) {
// key_shares // key_shares
offeredDH := map[NamedGroup][]byte{} offeredDH := map[NamedGroup][]byte{}
ks := KeyShareExtension{ ks := KeyShareExtension{
...@@ -268,7 +268,7 @@ func (state ClientStateStart) Next(hr handshakeMessageReader) (HandshakeState, [ ...@@ -268,7 +268,7 @@ func (state ClientStateStart) Next(hr handshakeMessageReader) (HandshakeState, [
logf(logTypeHandshake, "[ClientStateStart] -> [ClientStateWaitSH]") logf(logTypeHandshake, "[ClientStateStart] -> [ClientStateWaitSH]")
state.hsCtx.SetVersion(tls12Version) // Everything after this should be 1.2. state.hsCtx.SetVersion(tls12Version) // Everything after this should be 1.2.
nextState := ClientStateWaitSH{ nextState := clientStateWaitSH{
Config: state.Config, Config: state.Config,
Opts: state.Opts, Opts: state.Opts,
Params: state.Params, Params: state.Params,
...@@ -298,7 +298,7 @@ func (state ClientStateStart) Next(hr handshakeMessageReader) (HandshakeState, [ ...@@ -298,7 +298,7 @@ func (state ClientStateStart) Next(hr handshakeMessageReader) (HandshakeState, [
return nextState, toSend, AlertNoAlert return nextState, toSend, AlertNoAlert
} }
type ClientStateWaitSH struct { type clientStateWaitSH struct {
Config *Config Config *Config
Opts ConnectionOptions Opts ConnectionOptions
Params ConnectionParameters Params ConnectionParameters
...@@ -315,13 +315,13 @@ type ClientStateWaitSH struct { ...@@ -315,13 +315,13 @@ type ClientStateWaitSH struct {
clientHello *HandshakeMessage clientHello *HandshakeMessage
} }
var _ HandshakeState = &ClientStateWaitSH{} var _ HandshakeState = &clientStateWaitSH{}
func (state ClientStateWaitSH) State() State { func (state clientStateWaitSH) State() State {
return StateClientWaitSH return StateClientWaitSH
} }
func (state ClientStateWaitSH) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) { func (state clientStateWaitSH) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) {
hm, alert := hr.ReadMessage() hm, alert := hr.ReadMessage()
if alert != AlertNoAlert { if alert != AlertNoAlert {
return nil, nil, alert return nil, nil, alert
...@@ -413,7 +413,7 @@ func (state ClientStateWaitSH) Next(hr handshakeMessageReader) (HandshakeState, ...@@ -413,7 +413,7 @@ func (state ClientStateWaitSH) Next(hr handshakeMessageReader) (HandshakeState,
} }
logf(logTypeHandshake, "[ClientStateWaitSH] -> [ClientStateStart]") logf(logTypeHandshake, "[ClientStateWaitSH] -> [ClientStateStart]")
return ClientStateStart{ return clientStateStart{
Config: state.Config, Config: state.Config,
Opts: state.Opts, Opts: state.Opts,
hsCtx: state.hsCtx, hsCtx: state.hsCtx,
...@@ -517,7 +517,7 @@ func (state ClientStateWaitSH) Next(hr handshakeMessageReader) (HandshakeState, ...@@ -517,7 +517,7 @@ func (state ClientStateWaitSH) Next(hr handshakeMessageReader) (HandshakeState,
serverHandshakeKeys := makeTrafficKeys(params, serverHandshakeTrafficSecret) serverHandshakeKeys := makeTrafficKeys(params, serverHandshakeTrafficSecret)
logf(logTypeHandshake, "[ClientStateWaitSH] -> [ClientStateWaitEE]") logf(logTypeHandshake, "[ClientStateWaitSH] -> [ClientStateWaitEE]")
nextState := ClientStateWaitEE{ nextState := clientStateWaitEE{
Config: state.Config, Config: state.Config,
Params: state.Params, Params: state.Params,
hsCtx: state.hsCtx, hsCtx: state.hsCtx,
...@@ -533,7 +533,7 @@ func (state ClientStateWaitSH) Next(hr handshakeMessageReader) (HandshakeState, ...@@ -533,7 +533,7 @@ func (state ClientStateWaitSH) Next(hr handshakeMessageReader) (HandshakeState,
return nextState, toSend, AlertNoAlert return nextState, toSend, AlertNoAlert
} }
type ClientStateWaitEE struct { type clientStateWaitEE struct {
Config *Config Config *Config
Params ConnectionParameters Params ConnectionParameters
hsCtx HandshakeContext hsCtx HandshakeContext
...@@ -544,13 +544,13 @@ type ClientStateWaitEE struct { ...@@ -544,13 +544,13 @@ type ClientStateWaitEE struct {
serverHandshakeTrafficSecret []byte serverHandshakeTrafficSecret []byte
} }
var _ HandshakeState = &ClientStateWaitEE{} var _ HandshakeState = &clientStateWaitEE{}
func (state ClientStateWaitEE) State() State { func (state clientStateWaitEE) State() State {
return StateClientWaitEE return StateClientWaitEE
} }
func (state ClientStateWaitEE) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) { func (state clientStateWaitEE) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) {
hm, alert := hr.ReadMessage() hm, alert := hr.ReadMessage()
if alert != AlertNoAlert { if alert != AlertNoAlert {
return nil, nil, alert return nil, nil, alert
...@@ -598,7 +598,7 @@ func (state ClientStateWaitEE) Next(hr handshakeMessageReader) (HandshakeState, ...@@ -598,7 +598,7 @@ func (state ClientStateWaitEE) Next(hr handshakeMessageReader) (HandshakeState,
if state.Params.UsingPSK { if state.Params.UsingPSK {
logf(logTypeHandshake, "[ClientStateWaitEE] -> [ClientStateWaitFinished]") logf(logTypeHandshake, "[ClientStateWaitEE] -> [ClientStateWaitFinished]")
nextState := ClientStateWaitFinished{ nextState := clientStateWaitFinished{
Params: state.Params, Params: state.Params,
hsCtx: state.hsCtx, hsCtx: state.hsCtx,
cryptoParams: state.cryptoParams, cryptoParams: state.cryptoParams,
...@@ -612,7 +612,7 @@ func (state ClientStateWaitEE) Next(hr handshakeMessageReader) (HandshakeState, ...@@ -612,7 +612,7 @@ func (state ClientStateWaitEE) Next(hr handshakeMessageReader) (HandshakeState,
} }
logf(logTypeHandshake, "[ClientStateWaitEE] -> [ClientStateWaitCertCR]") logf(logTypeHandshake, "[ClientStateWaitEE] -> [ClientStateWaitCertCR]")
nextState := ClientStateWaitCertCR{ nextState := clientStateWaitCertCR{
Config: state.Config, Config: state.Config,
Params: state.Params, Params: state.Params,
hsCtx: state.hsCtx, hsCtx: state.hsCtx,
...@@ -625,7 +625,7 @@ func (state ClientStateWaitEE) Next(hr handshakeMessageReader) (HandshakeState, ...@@ -625,7 +625,7 @@ func (state ClientStateWaitEE) Next(hr handshakeMessageReader) (HandshakeState,
return nextState, nil, AlertNoAlert return nextState, nil, AlertNoAlert
} }
type ClientStateWaitCertCR struct { type clientStateWaitCertCR struct {
Config *Config Config *Config
Params ConnectionParameters Params ConnectionParameters
hsCtx HandshakeContext hsCtx HandshakeContext
...@@ -636,13 +636,13 @@ type ClientStateWaitCertCR struct { ...@@ -636,13 +636,13 @@ type ClientStateWaitCertCR struct {
serverHandshakeTrafficSecret []byte serverHandshakeTrafficSecret []byte
} }
var _ HandshakeState = &ClientStateWaitCertCR{} var _ HandshakeState = &clientStateWaitCertCR{}
func (state ClientStateWaitCertCR) State() State { func (state clientStateWaitCertCR) State() State {
return StateClientWaitCertCR return StateClientWaitCertCR
} }
func (state ClientStateWaitCertCR) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) { func (state clientStateWaitCertCR) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) {
hm, alert := hr.ReadMessage() hm, alert := hr.ReadMessage()
if alert != AlertNoAlert { if alert != AlertNoAlert {
return nil, nil, alert return nil, nil, alert
...@@ -663,7 +663,7 @@ func (state ClientStateWaitCertCR) Next(hr handshakeMessageReader) (HandshakeSta ...@@ -663,7 +663,7 @@ func (state ClientStateWaitCertCR) Next(hr handshakeMessageReader) (HandshakeSta
switch body := bodyGeneric.(type) { switch body := bodyGeneric.(type) {
case *CertificateBody: case *CertificateBody:
logf(logTypeHandshake, "[ClientStateWaitCertCR] -> [ClientStateWaitCV]") logf(logTypeHandshake, "[ClientStateWaitCertCR] -> [ClientStateWaitCV]")
nextState := ClientStateWaitCV{ nextState := clientStateWaitCV{
Config: state.Config, Config: state.Config,
Params: state.Params, Params: state.Params,
hsCtx: state.hsCtx, hsCtx: state.hsCtx,
...@@ -686,7 +686,7 @@ func (state ClientStateWaitCertCR) Next(hr handshakeMessageReader) (HandshakeSta ...@@ -686,7 +686,7 @@ func (state ClientStateWaitCertCR) Next(hr handshakeMessageReader) (HandshakeSta
state.Params.UsingClientAuth = true state.Params.UsingClientAuth = true
logf(logTypeHandshake, "[ClientStateWaitCertCR] -> [ClientStateWaitCert]") logf(logTypeHandshake, "[ClientStateWaitCertCR] -> [ClientStateWaitCert]")
nextState := ClientStateWaitCert{ nextState := clientStateWaitCert{
Config: state.Config, Config: state.Config,
Params: state.Params, Params: state.Params,
hsCtx: state.hsCtx, hsCtx: state.hsCtx,
...@@ -703,7 +703,7 @@ func (state ClientStateWaitCertCR) Next(hr handshakeMessageReader) (HandshakeSta ...@@ -703,7 +703,7 @@ func (state ClientStateWaitCertCR) Next(hr handshakeMessageReader) (HandshakeSta
return nil, nil, AlertUnexpectedMessage return nil, nil, AlertUnexpectedMessage
} }
type ClientStateWaitCert struct { type clientStateWaitCert struct {
Config *Config Config *Config
Params ConnectionParameters Params ConnectionParameters
hsCtx HandshakeContext hsCtx HandshakeContext
...@@ -717,13 +717,13 @@ type ClientStateWaitCert struct { ...@@ -717,13 +717,13 @@ type ClientStateWaitCert struct {
serverHandshakeTrafficSecret []byte serverHandshakeTrafficSecret []byte
} }
var _ HandshakeState = &ClientStateWaitCert{} var _ HandshakeState = &clientStateWaitCert{}
func (state ClientStateWaitCert) State() State { func (state clientStateWaitCert) State() State {
return StateClientWaitCert return StateClientWaitCert
} }
func (state ClientStateWaitCert) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) { func (state clientStateWaitCert) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) {
hm, alert := hr.ReadMessage() hm, alert := hr.ReadMessage()
if alert != AlertNoAlert { if alert != AlertNoAlert {
return nil, nil, alert return nil, nil, alert
...@@ -742,7 +742,7 @@ func (state ClientStateWaitCert) Next(hr handshakeMessageReader) (HandshakeState ...@@ -742,7 +742,7 @@ func (state ClientStateWaitCert) Next(hr handshakeMessageReader) (HandshakeState
state.handshakeHash.Write(hm.Marshal()) state.handshakeHash.Write(hm.Marshal())
logf(logTypeHandshake, "[ClientStateWaitCert] -> [ClientStateWaitCV]") logf(logTypeHandshake, "[ClientStateWaitCert] -> [ClientStateWaitCV]")
nextState := ClientStateWaitCV{ nextState := clientStateWaitCV{
Config: state.Config, Config: state.Config,
Params: state.Params, Params: state.Params,
hsCtx: state.hsCtx, hsCtx: state.hsCtx,
...@@ -757,7 +757,7 @@ func (state ClientStateWaitCert) Next(hr handshakeMessageReader) (HandshakeState ...@@ -757,7 +757,7 @@ func (state ClientStateWaitCert) Next(hr handshakeMessageReader) (HandshakeState
return nextState, nil, AlertNoAlert return nextState, nil, AlertNoAlert
} }
type ClientStateWaitCV struct { type clientStateWaitCV struct {
Config *Config Config *Config
Params ConnectionParameters Params ConnectionParameters
hsCtx HandshakeContext hsCtx HandshakeContext
...@@ -772,13 +772,13 @@ type ClientStateWaitCV struct { ...@@ -772,13 +772,13 @@ type ClientStateWaitCV struct {
serverHandshakeTrafficSecret []byte serverHandshakeTrafficSecret []byte
} }
var _ HandshakeState = &ClientStateWaitCV{} var _ HandshakeState = &clientStateWaitCV{}
func (state ClientStateWaitCV) State() State { func (state clientStateWaitCV) State() State {
return StateClientWaitCV return StateClientWaitCV
} }
func (state ClientStateWaitCV) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) { func (state clientStateWaitCV) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) {
hm, alert := hr.ReadMessage() hm, alert := hr.ReadMessage()
if alert != AlertNoAlert { if alert != AlertNoAlert {
return nil, nil, alert return nil, nil, alert
...@@ -843,7 +843,7 @@ func (state ClientStateWaitCV) Next(hr handshakeMessageReader) (HandshakeState, ...@@ -843,7 +843,7 @@ func (state ClientStateWaitCV) Next(hr handshakeMessageReader) (HandshakeState,
state.handshakeHash.Write(hm.Marshal()) state.handshakeHash.Write(hm.Marshal())
logf(logTypeHandshake, "[ClientStateWaitCV] -> [ClientStateWaitFinished]") logf(logTypeHandshake, "[ClientStateWaitCV] -> [ClientStateWaitFinished]")
nextState := ClientStateWaitFinished{ nextState := clientStateWaitFinished{
Params: state.Params, Params: state.Params,
hsCtx: state.hsCtx, hsCtx: state.hsCtx,
cryptoParams: state.cryptoParams, cryptoParams: state.cryptoParams,
...@@ -859,7 +859,7 @@ func (state ClientStateWaitCV) Next(hr handshakeMessageReader) (HandshakeState, ...@@ -859,7 +859,7 @@ func (state ClientStateWaitCV) Next(hr handshakeMessageReader) (HandshakeState,
return nextState, nil, AlertNoAlert return nextState, nil, AlertNoAlert
} }
type ClientStateWaitFinished struct { type clientStateWaitFinished struct {
Params ConnectionParameters Params ConnectionParameters
hsCtx HandshakeContext hsCtx HandshakeContext
cryptoParams CipherSuiteParams cryptoParams CipherSuiteParams
...@@ -875,13 +875,13 @@ type ClientStateWaitFinished struct { ...@@ -875,13 +875,13 @@ type ClientStateWaitFinished struct {
serverHandshakeTrafficSecret []byte serverHandshakeTrafficSecret []byte
} }
var _ HandshakeState = &ClientStateWaitFinished{} var _ HandshakeState = &clientStateWaitFinished{}
func (state ClientStateWaitFinished) State() State { func (state clientStateWaitFinished) State() State {
return StateClientWaitFinished return StateClientWaitFinished
} }
func (state ClientStateWaitFinished) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) { func (state clientStateWaitFinished) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) {
hm, alert := hr.ReadMessage() hm, alert := hr.ReadMessage()
if alert != AlertNoAlert { if alert != AlertNoAlert {
return nil, nil, alert return nil, nil, alert
...@@ -1046,7 +1046,7 @@ func (state ClientStateWaitFinished) Next(hr handshakeMessageReader) (HandshakeS ...@@ -1046,7 +1046,7 @@ func (state ClientStateWaitFinished) Next(hr handshakeMessageReader) (HandshakeS
}...) }...)
logf(logTypeHandshake, "[ClientStateWaitFinished] -> [StateConnected]") logf(logTypeHandshake, "[ClientStateWaitFinished] -> [StateConnected]")
nextState := StateConnected{ nextState := stateConnected{
Params: state.Params, Params: state.Params,
hsCtx: state.hsCtx, hsCtx: state.hsCtx,
isClient: true, isClient: true,
......
...@@ -201,6 +201,8 @@ func (s State) String() string { ...@@ -201,6 +201,8 @@ func (s State) String() string {
return "Client WAIT_CV" return "Client WAIT_CV"
case StateClientWaitFinished: case StateClientWaitFinished:
return "Client WAIT_FINISHED" return "Client WAIT_FINISHED"
case StateClientWaitCertCR:
return "Client WAIT_CERT_CR"
case StateClientConnected: case StateClientConnected:
return "Client CONNECTED" return "Client CONNECTED"
case StateServerStart: case StateServerStart:
......
...@@ -265,7 +265,7 @@ type Conn struct { ...@@ -265,7 +265,7 @@ type Conn struct {
EarlyData []byte EarlyData []byte
state StateConnected state stateConnected
hState HandshakeState hState HandshakeState
handshakeMutex sync.Mutex handshakeMutex sync.Mutex
handshakeAlert Alert handshakeAlert Alert
...@@ -345,7 +345,7 @@ func (c *Conn) consumeRecord() error { ...@@ -345,7 +345,7 @@ func (c *Conn) consumeRecord() error {
} }
var connected bool var connected bool
c.state, connected = state.(StateConnected) c.state, connected = state.(stateConnected)
if !connected { if !connected {
logf(logTypeHandshake, "Disconnected after state transition: %v", alert) logf(logTypeHandshake, "Disconnected after state transition: %v", alert)
c.sendAlert(alert) c.sendAlert(alert)
...@@ -385,7 +385,7 @@ func (c *Conn) consumeRecord() error { ...@@ -385,7 +385,7 @@ func (c *Conn) consumeRecord() error {
// Read application data up to the size of buffer. Handshake and alert records // Read application data up to the size of buffer. Handshake and alert records
// are consumed by the Conn object directly. // are consumed by the Conn object directly.
func (c *Conn) Read(buffer []byte) (int, error) { func (c *Conn) Read(buffer []byte) (int, error) {
if _, connected := c.hState.(StateConnected); !connected && c.config.NonBlocking { if _, connected := c.hState.(stateConnected); !connected {
return 0, errors.New("Read called before the handshake completed") return 0, errors.New("Read called before the handshake completed")
} }
logf(logTypeHandshake, "conn.Read with buffer = %d", len(buffer)) logf(logTypeHandshake, "conn.Read with buffer = %d", len(buffer))
...@@ -661,7 +661,7 @@ func (c *Conn) HandshakeSetup() Alert { ...@@ -661,7 +661,7 @@ func (c *Conn) HandshakeSetup() Alert {
} }
if c.isClient { if c.isClient {
state, actions, alert = ClientStateStart{Config: c.config, Opts: opts, hsCtx: c.hsCtx}.Next(nil) state, actions, alert = clientStateStart{Config: c.config, Opts: opts, hsCtx: c.hsCtx}.Next(nil)
if alert != AlertNoAlert { if alert != AlertNoAlert {
logf(logTypeHandshake, "Error initializing client state: %v", alert) logf(logTypeHandshake, "Error initializing client state: %v", alert)
return alert return alert
...@@ -688,7 +688,7 @@ func (c *Conn) HandshakeSetup() Alert { ...@@ -688,7 +688,7 @@ func (c *Conn) HandshakeSetup() Alert {
return AlertInternalError return AlertInternalError
} }
} }
state = ServerStateStart{Config: c.config, conn: c, hsCtx: c.hsCtx} state = serverStateStart{Config: c.config, conn: c, hsCtx: c.hsCtx}
} }
c.hState = state c.hState = state
...@@ -751,7 +751,7 @@ func (c *Conn) Handshake() Alert { ...@@ -751,7 +751,7 @@ func (c *Conn) Handshake() Alert {
logf(logTypeHandshake, "(Re-)entering handshake, state=%v", c.hState) logf(logTypeHandshake, "(Re-)entering handshake, state=%v", c.hState)
state := c.hState state := c.hState
_, connected := state.(StateConnected) _, connected := state.(stateConnected)
hmr := &handshakeMessageReaderImpl{hsCtx: &c.hsCtx} hmr := &handshakeMessageReaderImpl{hsCtx: &c.hsCtx}
for !connected { for !connected {
...@@ -784,9 +784,9 @@ func (c *Conn) Handshake() Alert { ...@@ -784,9 +784,9 @@ func (c *Conn) Handshake() Alert {
c.hState = state c.hState = state
logf(logTypeHandshake, "state is now %s", c.GetHsState()) logf(logTypeHandshake, "state is now %s", c.GetHsState())
_, connected = state.(StateConnected) _, connected = state.(stateConnected)
if connected { if connected {
c.state = state.(StateConnected) c.state = state.(stateConnected)
c.handshakeComplete = true c.handshakeComplete = true
} }
...@@ -852,7 +852,7 @@ func (c *Conn) GetHsState() State { ...@@ -852,7 +852,7 @@ func (c *Conn) GetHsState() State {
} }
func (c *Conn) ComputeExporter(label string, context []byte, keyLength int) ([]byte, error) { func (c *Conn) ComputeExporter(label string, context []byte, keyLength int) ([]byte, error) {
_, connected := c.hState.(StateConnected) _, connected := c.hState.(stateConnected)
if !connected { if !connected {
return nil, fmt.Errorf("Cannot compute exporter when state is not connected") return nil, fmt.Errorf("Cannot compute exporter when state is not connected")
} }
......
...@@ -11,9 +11,11 @@ import ( ...@@ -11,9 +11,11 @@ import (
"crypto/rand" "crypto/rand"
"crypto/rsa" "crypto/rsa"
"crypto/x509" "crypto/x509"
"crypto/x509/pkix"
"encoding/asn1" "encoding/asn1"
"fmt" "fmt"
"math/big" "math/big"
"time"
"golang.org/x/crypto/curve25519" "golang.org/x/crypto/curve25519"
...@@ -616,3 +618,50 @@ func makeTrafficKeys(params CipherSuiteParams, secret []byte) keySet { ...@@ -616,3 +618,50 @@ func makeTrafficKeys(params CipherSuiteParams, secret []byte) keySet {
iv: HkdfExpandLabel(params.Hash, secret, "iv", []byte{}, params.IvLen), iv: HkdfExpandLabel(params.Hash, secret, "iv", []byte{}, params.IvLen),
} }
} }
func MakeNewSelfSignedCert(name string, alg SignatureScheme) (crypto.Signer, *x509.Certificate, error) {
priv, err := newSigningKey(alg)
if err != nil {
return nil, nil, err
}
cert, err := newSelfSigned(name, alg, priv)
if err != nil {
return nil, nil, err
}
return priv, cert, nil
}
func newSelfSigned(name string, alg SignatureScheme, priv crypto.Signer) (*x509.Certificate, error) {
sigAlg, ok := x509AlgMap[alg]
if !ok {
return nil, fmt.Errorf("tls.selfsigned: Unknown signature algorithm [%04x]", alg)
}
if len(name) == 0 {
return nil, fmt.Errorf("tls.selfsigned: No name provided")
}
serial, err := rand.Int(rand.Reader, big.NewInt(0xA0A0A0A0))
if err != nil {
return nil, err
}
template := &x509.Certificate{
SerialNumber: serial,
NotBefore: time.Now(),
NotAfter: time.Now().AddDate(0, 0, 1),
SignatureAlgorithm: sigAlg,
Subject: pkix.Name{CommonName: name},
DNSNames: []string{name},
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyAgreement | x509.KeyUsageKeyEncipherment,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
}
der, err := x509.CreateCertificate(prng, template, template, priv.Public(), priv)
if err != nil {
return nil, err
}
// It is safe to ignore the error here because we're parsing known-good data
cert, _ := x509.ParseCertificate(der)
return cert, nil
}
...@@ -71,19 +71,19 @@ type cookie struct { ...@@ -71,19 +71,19 @@ type cookie struct {
ApplicationCookie []byte `tls:"head=2"` ApplicationCookie []byte `tls:"head=2"`
} }
type ServerStateStart struct { type serverStateStart struct {
Config *Config Config *Config
conn *Conn conn *Conn
hsCtx HandshakeContext hsCtx HandshakeContext
} }
var _ HandshakeState = &ServerStateStart{} var _ HandshakeState = &serverStateStart{}
func (state ServerStateStart) State() State { func (state serverStateStart) State() State {
return StateServerStart return StateServerStart
} }
func (state ServerStateStart) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) { func (state serverStateStart) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) {
hm, alert := hr.ReadMessage() hm, alert := hr.ReadMessage()
if alert != AlertNoAlert { if alert != AlertNoAlert {
return nil, nil, alert return nil, nil, alert
...@@ -381,7 +381,7 @@ func (state ServerStateStart) Next(hr handshakeMessageReader) (HandshakeState, [ ...@@ -381,7 +381,7 @@ func (state ServerStateStart) Next(hr handshakeMessageReader) (HandshakeState, [
logf(logTypeHandshake, "[ServerStateStart] -> [ServerStateNegotiated]") logf(logTypeHandshake, "[ServerStateStart] -> [ServerStateNegotiated]")
state.hsCtx.SetVersion(tls12Version) // Everything after this should be 1.2. state.hsCtx.SetVersion(tls12Version) // Everything after this should be 1.2.
return ServerStateNegotiated{ return serverStateNegotiated{
Config: state.Config, Config: state.Config,
Params: connParams, Params: connParams,
hsCtx: state.hsCtx, hsCtx: state.hsCtx,
...@@ -401,7 +401,7 @@ func (state ServerStateStart) Next(hr handshakeMessageReader) (HandshakeState, [ ...@@ -401,7 +401,7 @@ func (state ServerStateStart) Next(hr handshakeMessageReader) (HandshakeState, [
}, nil, AlertNoAlert }, nil, AlertNoAlert
} }
func (state *ServerStateStart) generateHRR(cs CipherSuite, legacySessionId []byte, func (state *serverStateStart) generateHRR(cs CipherSuite, legacySessionId []byte,
cookieExt *CookieExtension) (*HandshakeMessage, error) { cookieExt *CookieExtension) (*HandshakeMessage, error) {
var helloRetryRequest *HandshakeMessage var helloRetryRequest *HandshakeMessage
hrr := &ServerHelloBody{ hrr := &ServerHelloBody{
...@@ -442,7 +442,7 @@ func (state *ServerStateStart) generateHRR(cs CipherSuite, legacySessionId []byt ...@@ -442,7 +442,7 @@ func (state *ServerStateStart) generateHRR(cs CipherSuite, legacySessionId []byt
return helloRetryRequest, nil return helloRetryRequest, nil
} }
type ServerStateNegotiated struct { type serverStateNegotiated struct {
Config *Config Config *Config
Params ConnectionParameters Params ConnectionParameters
hsCtx HandshakeContext hsCtx HandshakeContext
...@@ -460,13 +460,13 @@ type ServerStateNegotiated struct { ...@@ -460,13 +460,13 @@ type ServerStateNegotiated struct {
clientHello *HandshakeMessage clientHello *HandshakeMessage
} }
var _ HandshakeState = &ServerStateNegotiated{} var _ HandshakeState = &serverStateNegotiated{}
func (state ServerStateNegotiated) State() State { func (state serverStateNegotiated) State() State {
return StateServerNegotiated return StateServerNegotiated
} }
func (state ServerStateNegotiated) Next(_ handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) { func (state serverStateNegotiated) Next(_ handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) {
// Create the ServerHello // Create the ServerHello
sh := &ServerHelloBody{ sh := &ServerHelloBody{
Version: tls12Version, Version: tls12Version,
...@@ -717,7 +717,7 @@ func (state ServerStateNegotiated) Next(_ handshakeMessageReader) (HandshakeStat ...@@ -717,7 +717,7 @@ func (state ServerStateNegotiated) Next(_ handshakeMessageReader) (HandshakeStat
clientEarlyTrafficKeys := makeTrafficKeys(params, state.clientEarlyTrafficSecret) clientEarlyTrafficKeys := makeTrafficKeys(params, state.clientEarlyTrafficSecret)
logf(logTypeHandshake, "[ServerStateNegotiated] -> [ServerStateWaitEOED]") logf(logTypeHandshake, "[ServerStateNegotiated] -> [ServerStateWaitEOED]")
nextState := ServerStateWaitEOED{ nextState := serverStateWaitEOED{
Config: state.Config, Config: state.Config,
Params: state.Params, Params: state.Params,
hsCtx: state.hsCtx, hsCtx: state.hsCtx,
...@@ -741,7 +741,7 @@ func (state ServerStateNegotiated) Next(_ handshakeMessageReader) (HandshakeStat ...@@ -741,7 +741,7 @@ func (state ServerStateNegotiated) Next(_ handshakeMessageReader) (HandshakeStat
RekeyIn{epoch: EpochHandshakeData, KeySet: clientHandshakeKeys}, RekeyIn{epoch: EpochHandshakeData, KeySet: clientHandshakeKeys},
ReadPastEarlyData{}, ReadPastEarlyData{},
}...) }...)
waitFlight2 := ServerStateWaitFlight2{ waitFlight2 := serverStateWaitFlight2{
Config: state.Config, Config: state.Config,
Params: state.Params, Params: state.Params,
hsCtx: state.hsCtx, hsCtx: state.hsCtx,
...@@ -756,7 +756,7 @@ func (state ServerStateNegotiated) Next(_ handshakeMessageReader) (HandshakeStat ...@@ -756,7 +756,7 @@ func (state ServerStateNegotiated) Next(_ handshakeMessageReader) (HandshakeStat
return waitFlight2, toSend, AlertNoAlert return waitFlight2, toSend, AlertNoAlert
} }
type ServerStateWaitEOED struct { type serverStateWaitEOED struct {
Config *Config Config *Config
Params ConnectionParameters Params ConnectionParameters
hsCtx HandshakeContext hsCtx HandshakeContext
...@@ -769,13 +769,13 @@ type ServerStateWaitEOED struct { ...@@ -769,13 +769,13 @@ type ServerStateWaitEOED struct {
exporterSecret []byte exporterSecret []byte
} }
var _ HandshakeState = &ServerStateWaitEOED{} var _ HandshakeState = &serverStateWaitEOED{}
func (state ServerStateWaitEOED) State() State { func (state serverStateWaitEOED) State() State {
return StateServerWaitEOED return StateServerWaitEOED
} }
func (state ServerStateWaitEOED) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) { func (state serverStateWaitEOED) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) {
hm, alert := hr.ReadMessage() hm, alert := hr.ReadMessage()
if alert != AlertNoAlert { if alert != AlertNoAlert {
return nil, nil, alert return nil, nil, alert
...@@ -798,7 +798,7 @@ func (state ServerStateWaitEOED) Next(hr handshakeMessageReader) (HandshakeState ...@@ -798,7 +798,7 @@ func (state ServerStateWaitEOED) Next(hr handshakeMessageReader) (HandshakeState
toSend := []HandshakeAction{ toSend := []HandshakeAction{
RekeyIn{epoch: EpochHandshakeData, KeySet: clientHandshakeKeys}, RekeyIn{epoch: EpochHandshakeData, KeySet: clientHandshakeKeys},
} }
waitFlight2 := ServerStateWaitFlight2{ waitFlight2 := serverStateWaitFlight2{
Config: state.Config, Config: state.Config,
Params: state.Params, Params: state.Params,
hsCtx: state.hsCtx, hsCtx: state.hsCtx,
...@@ -813,7 +813,7 @@ func (state ServerStateWaitEOED) Next(hr handshakeMessageReader) (HandshakeState ...@@ -813,7 +813,7 @@ func (state ServerStateWaitEOED) Next(hr handshakeMessageReader) (HandshakeState
return waitFlight2, toSend, AlertNoAlert return waitFlight2, toSend, AlertNoAlert
} }
type ServerStateWaitFlight2 struct { type serverStateWaitFlight2 struct {
Config *Config Config *Config
Params ConnectionParameters Params ConnectionParameters
hsCtx HandshakeContext hsCtx HandshakeContext
...@@ -826,16 +826,16 @@ type ServerStateWaitFlight2 struct { ...@@ -826,16 +826,16 @@ type ServerStateWaitFlight2 struct {
exporterSecret []byte exporterSecret []byte
} }
var _ HandshakeState = &ServerStateWaitFlight2{} var _ HandshakeState = &serverStateWaitFlight2{}
func (state ServerStateWaitFlight2) State() State { func (state serverStateWaitFlight2) State() State {
return StateServerWaitFlight2 return StateServerWaitFlight2
} }
func (state ServerStateWaitFlight2) Next(_ handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) { func (state serverStateWaitFlight2) Next(_ handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) {
if state.Params.UsingClientAuth { if state.Params.UsingClientAuth {
logf(logTypeHandshake, "[ServerStateWaitFlight2] -> [ServerStateWaitCert]") logf(logTypeHandshake, "[ServerStateWaitFlight2] -> [ServerStateWaitCert]")
nextState := ServerStateWaitCert{ nextState := serverStateWaitCert{
Config: state.Config, Config: state.Config,
Params: state.Params, Params: state.Params,
hsCtx: state.hsCtx, hsCtx: state.hsCtx,
...@@ -851,7 +851,7 @@ func (state ServerStateWaitFlight2) Next(_ handshakeMessageReader) (HandshakeSta ...@@ -851,7 +851,7 @@ func (state ServerStateWaitFlight2) Next(_ handshakeMessageReader) (HandshakeSta
} }
logf(logTypeHandshake, "[ServerStateWaitFlight2] -> [ServerStateWaitFinished]") logf(logTypeHandshake, "[ServerStateWaitFlight2] -> [ServerStateWaitFinished]")
nextState := ServerStateWaitFinished{ nextState := serverStateWaitFinished{
Params: state.Params, Params: state.Params,
hsCtx: state.hsCtx, hsCtx: state.hsCtx,
cryptoParams: state.cryptoParams, cryptoParams: state.cryptoParams,
...@@ -865,7 +865,7 @@ func (state ServerStateWaitFlight2) Next(_ handshakeMessageReader) (HandshakeSta ...@@ -865,7 +865,7 @@ func (state ServerStateWaitFlight2) Next(_ handshakeMessageReader) (HandshakeSta
return nextState, nil, AlertNoAlert return nextState, nil, AlertNoAlert
} }
type ServerStateWaitCert struct { type serverStateWaitCert struct {
Config *Config Config *Config
Params ConnectionParameters Params ConnectionParameters
hsCtx HandshakeContext hsCtx HandshakeContext
...@@ -878,13 +878,13 @@ type ServerStateWaitCert struct { ...@@ -878,13 +878,13 @@ type ServerStateWaitCert struct {
exporterSecret []byte exporterSecret []byte
} }
var _ HandshakeState = &ServerStateWaitCert{} var _ HandshakeState = &serverStateWaitCert{}
func (state ServerStateWaitCert) State() State { func (state serverStateWaitCert) State() State {
return StateServerWaitCert return StateServerWaitCert
} }
func (state ServerStateWaitCert) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) { func (state serverStateWaitCert) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) {
hm, alert := hr.ReadMessage() hm, alert := hr.ReadMessage()
if alert != AlertNoAlert { if alert != AlertNoAlert {
return nil, nil, alert return nil, nil, alert
...@@ -906,7 +906,7 @@ func (state ServerStateWaitCert) Next(hr handshakeMessageReader) (HandshakeState ...@@ -906,7 +906,7 @@ func (state ServerStateWaitCert) Next(hr handshakeMessageReader) (HandshakeState
logf(logTypeHandshake, "[ServerStateWaitCert] WARNING client did not provide a certificate") logf(logTypeHandshake, "[ServerStateWaitCert] WARNING client did not provide a certificate")
logf(logTypeHandshake, "[ServerStateWaitCert] -> [ServerStateWaitFinished]") logf(logTypeHandshake, "[ServerStateWaitCert] -> [ServerStateWaitFinished]")
nextState := ServerStateWaitFinished{ nextState := serverStateWaitFinished{
Params: state.Params, Params: state.Params,
hsCtx: state.hsCtx, hsCtx: state.hsCtx,
cryptoParams: state.cryptoParams, cryptoParams: state.cryptoParams,
...@@ -921,7 +921,7 @@ func (state ServerStateWaitCert) Next(hr handshakeMessageReader) (HandshakeState ...@@ -921,7 +921,7 @@ func (state ServerStateWaitCert) Next(hr handshakeMessageReader) (HandshakeState
} }
logf(logTypeHandshake, "[ServerStateWaitCert] -> [ServerStateWaitCV]") logf(logTypeHandshake, "[ServerStateWaitCert] -> [ServerStateWaitCV]")
nextState := ServerStateWaitCV{ nextState := serverStateWaitCV{
Config: state.Config, Config: state.Config,
Params: state.Params, Params: state.Params,
hsCtx: state.hsCtx, hsCtx: state.hsCtx,
...@@ -937,7 +937,7 @@ func (state ServerStateWaitCert) Next(hr handshakeMessageReader) (HandshakeState ...@@ -937,7 +937,7 @@ func (state ServerStateWaitCert) Next(hr handshakeMessageReader) (HandshakeState
return nextState, nil, AlertNoAlert return nextState, nil, AlertNoAlert
} }
type ServerStateWaitCV struct { type serverStateWaitCV struct {
Config *Config Config *Config
Params ConnectionParameters Params ConnectionParameters
hsCtx HandshakeContext hsCtx HandshakeContext
...@@ -954,13 +954,13 @@ type ServerStateWaitCV struct { ...@@ -954,13 +954,13 @@ type ServerStateWaitCV struct {
clientCertificate *CertificateBody clientCertificate *CertificateBody
} }
var _ HandshakeState = &ServerStateWaitCV{} var _ HandshakeState = &serverStateWaitCV{}
func (state ServerStateWaitCV) State() State { func (state serverStateWaitCV) State() State {
return StateServerWaitCV return StateServerWaitCV
} }
func (state ServerStateWaitCV) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) { func (state serverStateWaitCV) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) {
hm, alert := hr.ReadMessage() hm, alert := hr.ReadMessage()
if alert != AlertNoAlert { if alert != AlertNoAlert {
return nil, nil, alert return nil, nil, alert
...@@ -1005,7 +1005,7 @@ func (state ServerStateWaitCV) Next(hr handshakeMessageReader) (HandshakeState, ...@@ -1005,7 +1005,7 @@ func (state ServerStateWaitCV) Next(hr handshakeMessageReader) (HandshakeState,
state.handshakeHash.Write(hm.Marshal()) state.handshakeHash.Write(hm.Marshal())
logf(logTypeHandshake, "[ServerStateWaitCV] -> [ServerStateWaitFinished]") logf(logTypeHandshake, "[ServerStateWaitCV] -> [ServerStateWaitFinished]")
nextState := ServerStateWaitFinished{ nextState := serverStateWaitFinished{
Params: state.Params, Params: state.Params,
hsCtx: state.hsCtx, hsCtx: state.hsCtx,
cryptoParams: state.cryptoParams, cryptoParams: state.cryptoParams,
...@@ -1021,7 +1021,7 @@ func (state ServerStateWaitCV) Next(hr handshakeMessageReader) (HandshakeState, ...@@ -1021,7 +1021,7 @@ func (state ServerStateWaitCV) Next(hr handshakeMessageReader) (HandshakeState,
return nextState, nil, AlertNoAlert return nextState, nil, AlertNoAlert
} }
type ServerStateWaitFinished struct { type serverStateWaitFinished struct {
Params ConnectionParameters Params ConnectionParameters
hsCtx HandshakeContext hsCtx HandshakeContext
cryptoParams CipherSuiteParams cryptoParams CipherSuiteParams
...@@ -1037,13 +1037,13 @@ type ServerStateWaitFinished struct { ...@@ -1037,13 +1037,13 @@ type ServerStateWaitFinished struct {
exporterSecret []byte exporterSecret []byte
} }
var _ HandshakeState = &ServerStateWaitFinished{} var _ HandshakeState = &serverStateWaitFinished{}
func (state ServerStateWaitFinished) State() State { func (state serverStateWaitFinished) State() State {
return StateServerWaitFinished return StateServerWaitFinished
} }
func (state ServerStateWaitFinished) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) { func (state serverStateWaitFinished) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) {
hm, alert := hr.ReadMessage() hm, alert := hr.ReadMessage()
if alert != AlertNoAlert { if alert != AlertNoAlert {
return nil, nil, alert return nil, nil, alert
...@@ -1083,7 +1083,7 @@ func (state ServerStateWaitFinished) Next(hr handshakeMessageReader) (HandshakeS ...@@ -1083,7 +1083,7 @@ func (state ServerStateWaitFinished) Next(hr handshakeMessageReader) (HandshakeS
clientTrafficKeys := makeTrafficKeys(state.cryptoParams, state.clientTrafficSecret) clientTrafficKeys := makeTrafficKeys(state.cryptoParams, state.clientTrafficSecret)
logf(logTypeHandshake, "[ServerStateWaitFinished] -> [StateConnected]") logf(logTypeHandshake, "[ServerStateWaitFinished] -> [StateConnected]")
nextState := StateConnected{ nextState := stateConnected{
Params: state.Params, Params: state.Params,
hsCtx: state.hsCtx, hsCtx: state.hsCtx,
isClient: false, isClient: false,
......
...@@ -81,8 +81,8 @@ func (hc *HandshakeContext) SetVersion(version uint16) { ...@@ -81,8 +81,8 @@ func (hc *HandshakeContext) SetVersion(version uint16) {
} }
} }
// StateConnected is symmetric between client and server // stateConnected is symmetric between client and server
type StateConnected struct { type stateConnected struct {
Params ConnectionParameters Params ConnectionParameters
hsCtx HandshakeContext hsCtx HandshakeContext
isClient bool isClient bool
...@@ -95,16 +95,16 @@ type StateConnected struct { ...@@ -95,16 +95,16 @@ type StateConnected struct {
verifiedChains [][]*x509.Certificate verifiedChains [][]*x509.Certificate
} }
var _ HandshakeState = &StateConnected{} var _ HandshakeState = &stateConnected{}
func (state StateConnected) State() State { func (state stateConnected) State() State {
if state.isClient { if state.isClient {
return StateClientConnected return StateClientConnected
} }
return StateServerConnected return StateServerConnected
} }
func (state *StateConnected) KeyUpdate(request KeyUpdateRequest) ([]HandshakeAction, Alert) { func (state *stateConnected) KeyUpdate(request KeyUpdateRequest) ([]HandshakeAction, Alert) {
var trafficKeys keySet var trafficKeys keySet
if state.isClient { if state.isClient {
state.clientTrafficSecret = HkdfExpandLabel(state.cryptoParams.Hash, state.clientTrafficSecret, state.clientTrafficSecret = HkdfExpandLabel(state.cryptoParams.Hash, state.clientTrafficSecret,
...@@ -130,7 +130,7 @@ func (state *StateConnected) KeyUpdate(request KeyUpdateRequest) ([]HandshakeAct ...@@ -130,7 +130,7 @@ func (state *StateConnected) KeyUpdate(request KeyUpdateRequest) ([]HandshakeAct
return toSend, AlertNoAlert return toSend, AlertNoAlert
} }
func (state *StateConnected) NewSessionTicket(length int, lifetime, earlyDataLifetime uint32) ([]HandshakeAction, Alert) { func (state *stateConnected) NewSessionTicket(length int, lifetime, earlyDataLifetime uint32) ([]HandshakeAction, Alert) {
tkt, err := NewSessionTicket(length, lifetime) tkt, err := NewSessionTicket(length, lifetime)
if err != nil { if err != nil {
logf(logTypeHandshake, "[StateConnected] Error generating NewSessionTicket: %v", err) logf(logTypeHandshake, "[StateConnected] Error generating NewSessionTicket: %v", err)
...@@ -172,11 +172,11 @@ func (state *StateConnected) NewSessionTicket(length int, lifetime, earlyDataLif ...@@ -172,11 +172,11 @@ func (state *StateConnected) NewSessionTicket(length int, lifetime, earlyDataLif
} }
// Next does nothing for this state. // Next does nothing for this state.
func (state StateConnected) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) { func (state stateConnected) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) {
return state, nil, AlertNoAlert return state, nil, AlertNoAlert
} }
func (state StateConnected) ProcessMessage(hm *HandshakeMessage) (HandshakeState, []HandshakeAction, Alert) { func (state stateConnected) ProcessMessage(hm *HandshakeMessage) (HandshakeState, []HandshakeAction, Alert) {
if hm == nil { if hm == nil {
logf(logTypeHandshake, "[StateConnected] Unexpected message") logf(logTypeHandshake, "[StateConnected] Unexpected message")
return nil, nil, AlertUnexpectedMessage return nil, nil, AlertUnexpectedMessage
......
...@@ -145,7 +145,7 @@ ...@@ -145,7 +145,7 @@
"importpath": "github.com/lucas-clemente/quic-go", "importpath": "github.com/lucas-clemente/quic-go",
"repository": "https://github.com/lucas-clemente/quic-go", "repository": "https://github.com/lucas-clemente/quic-go",
"vcs": "git", "vcs": "git",
"revision": "d71850eb2ff581620f2f5742b558a97de22c13f6", "revision": "9fa739409e6edddbbd47c8031cb7bb3d1a209cc8",
"branch": "master", "branch": "master",
"notests": true "notests": true
}, },
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment