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

vendor: Update quic-go

parent 95514da9
......@@ -8,19 +8,20 @@ import (
var bufferPool sync.Pool
func getPacketBuffer() []byte {
return bufferPool.Get().([]byte)
func getPacketBuffer() *[]byte {
return bufferPool.Get().(*[]byte)
}
func putPacketBuffer(buf []byte) {
if cap(buf) != int(protocol.MaxReceivePacketSize) {
func putPacketBuffer(buf *[]byte) {
if cap(*buf) != int(protocol.MaxReceivePacketSize) {
panic("putPacketBuffer called with packet of wrong size!")
}
bufferPool.Put(buf[:0])
bufferPool.Put(buf)
}
func init() {
bufferPool.New = func() interface{} {
return make([]byte, 0, protocol.MaxReceivePacketSize)
b := make([]byte, 0, protocol.MaxReceivePacketSize)
return &b
}
}
......@@ -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)
c := &client{
conn: &conn{pconn: pconn, currentAddr: remoteAddr},
......@@ -132,6 +140,18 @@ func populateClientConfig(config *Config) *Config {
if maxReceiveConnectionFlowControlWindow == 0 {
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{
Versions: versions,
......@@ -140,7 +160,9 @@ func populateClientConfig(config *Config) *Config {
RequestConnectionIDOmission: config.RequestConnectionIDOmission,
MaxReceiveStreamFlowControlWindow: maxReceiveStreamFlowControlWindow,
MaxReceiveConnectionFlowControlWindow: maxReceiveConnectionFlowControlWindow,
KeepAlive: config.KeepAlive,
MaxIncomingStreams: maxIncomingStreams,
MaxIncomingUniStreams: maxIncomingUniStreams,
KeepAlive: config.KeepAlive,
}
}
......@@ -171,9 +193,8 @@ func (c *client) dialTLS() error {
ConnectionFlowControlWindow: protocol.ReceiveConnectionFlowControlWindow,
IdleTimeout: c.config.IdleTimeout,
OmitConnectionID: c.config.RequestConnectionIDOmission,
// TODO(#523): make these values configurable
MaxBidiStreamID: protocol.MaxBidiStreamID(protocol.MaxIncomingStreams, protocol.PerspectiveClient),
MaxUniStreamID: protocol.MaxUniStreamID(protocol.MaxIncomingStreams, protocol.PerspectiveClient),
MaxBidiStreams: uint16(c.config.MaxIncomingStreams),
MaxUniStreams: uint16(c.config.MaxIncomingUniStreams),
}
csc := handshake.NewCryptoStreamConn(nil)
extHandler := handshake.NewExtensionHandlerClient(params, c.initialVersion, c.config.Versions, c.version)
......@@ -245,7 +266,7 @@ func (c *client) listen() {
for {
var n int
var addr net.Addr
data := getPacketBuffer()
data := *getPacketBuffer()
data = data[:protocol.MaxReceivePacketSize]
// The packet size should not exceed protocol.MaxReceivePacketSize bytes
// 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 {
}
}
utils.Infof("Received a Version Negotiation Packet. Supported Versions: %s", hdr.SupportedVersions)
newVersion, ok := protocol.ChooseSupportedVersion(c.config.Versions, hdr.SupportedVersions)
if !ok {
return qerr.InvalidVersion
......
......@@ -108,7 +108,9 @@ func (c *client) handleHeaderStream() {
for err == nil {
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())
// stop all running request
close(c.headerErrored)
......@@ -202,6 +204,7 @@ func (c *client) RoundTrip(req *http.Request) (*http.Response, error) {
bodySent = true
}
ctx := req.Context()
for !(bodySent && receivedResponse) {
select {
case res = <-responseChan:
......@@ -214,8 +217,16 @@ func (c *client) RoundTrip(req *http.Request) (*http.Response, error) {
if err != nil {
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:
// an error occured on the header stream
// an error occurred on the header stream
_ = c.CloseWithError(c.headerErr)
return nil, c.headerErr
}
......
......@@ -76,9 +76,8 @@ func (w *requestWriter) encodeHeaders(req *http.Request, addGzipHeader bool, tra
if !validPseudoPath(path) {
if 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
import (
"bytes"
"errors"
"io"
"io/ioutil"
"net/http"
"net/textproto"
......@@ -16,7 +15,7 @@ import (
// copied from net/http2/transport.go
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
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")
}
if 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
}
// TODO: handle statusCode == 100
header := make(http.Header)
res := &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 clen64, err := strconv.ParseInt(clens[0], 10, 64); err == nil {
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
......
......@@ -7,6 +7,7 @@ import (
"time"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
)
// Connection is a UDP connection
......@@ -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 {
if d == DirectionBoth || dir == DirectionBoth {
return true
......@@ -131,12 +134,20 @@ func NewQuicProxy(local string, version protocol.VersionNumber, opts *Opts) (*Qu
version: version,
}
utils.Debugf("Starting UDP Proxy %s <-> %s", conn.LocalAddr(), raddr)
go p.runProxy()
return &p, nil
}
// Close stops the UDP Proxy
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()
}
......@@ -189,19 +200,27 @@ func (p *QuicProxy) runProxy() error {
packetCount := atomic.AddUint64(&conn.incomingPacketCounter, 1)
if p.dropPacket(DirectionIncoming, packetCount) {
if utils.Debug() {
utils.Debugf("dropping incoming packet %d (%d bytes)", packetCount, n)
}
continue
}
// Send the packet to the server
delay := p.delayPacket(DirectionIncoming, packetCount)
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() {
// TODO: handle error
_, _ = conn.ServerConn.Write(raw)
})
} else {
_, err := conn.ServerConn.Write(raw)
if err != nil {
if utils.Debug() {
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
}
}
......@@ -221,18 +240,26 @@ func (p *QuicProxy) runConnection(conn *connection) error {
packetCount := atomic.AddUint64(&conn.outgoingPacketCounter, 1)
if p.dropPacket(DirectionOutgoing, packetCount) {
if utils.Debug() {
utils.Debugf("dropping outgoing packet %d (%d bytes)", packetCount, n)
}
continue
}
delay := p.delayPacket(DirectionOutgoing, packetCount)
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() {
// TODO: handle error
_, _ = p.conn.WriteToUDP(raw, conn.ClientAddr)
})
} else {
_, err := p.conn.WriteToUDP(raw, conn.ClientAddr)
if err != nil {
if utils.Debug() {
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
}
}
......
......@@ -22,7 +22,9 @@ const (
)
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)
server *h2quic.Server
......@@ -105,11 +107,13 @@ func StartQuicServer(versions []protocol.VersionNumber) {
}()
}
// StopQuicServer stops the h2quic.Server.
func StopQuicServer() {
Expect(server.Close()).NotTo(HaveOccurred())
Eventually(stoppedServing).Should(BeClosed())
}
// Port returns the UDP port of the QUIC server.
func Port() string {
return port
}
......@@ -113,15 +113,23 @@ type StreamError interface {
// A Session is a QUIC connection between two peers.
type Session interface {
// 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)
// OpenStream opens a new QUIC stream, returning a special error when the peer's concurrent stream limit is reached.
// New streams always have the smallest possible stream ID.
// TODO: Enable testing for the special error
// AcceptUniStream returns the next unidirectional stream opened by the peer, blocking until one is available.
AcceptUniStream() (ReceiveStream, 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)
// OpenStreamSync opens a new QUIC stream, blocking until the peer's concurrent stream limit allows a new stream to be opened.
// It always picks the smallest possible stream ID.
// OpenStreamSync opens a new bidirectional QUIC stream.
// It blocks until the peer's concurrent stream limit allows a new stream to be opened.
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() net.Addr
// RemoteAddr returns the address of the peer.
......@@ -166,6 +174,17 @@ type Config struct {
// 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.
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 bool
}
......
......@@ -10,15 +10,13 @@ import (
// SentPacketHandler handles ACKs received for outgoing packets
type SentPacketHandler interface {
// 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
SetHandshakeComplete()
// SendingAllowed says if a packet can be sent.
// Sending packets might not be possible because:
// * we're congestion limited
// * we're tracking the maximum number of sent packets
SendingAllowed() bool
// The SendMode determines if and what kind of packets can be sent.
SendMode() SendMode
// TimeUntilSend is the time when the next packet should be sent.
// It is used for pacing packets.
TimeUntilSend() time.Time
......@@ -32,10 +30,10 @@ type SentPacketHandler interface {
GetStopWaitingFrame(force bool) *wire.StopWaitingFrame
GetLowestPacketNotConfirmedAcked() protocol.PacketNumber
DequeuePacketForRetransmission() (packet *Packet)
GetLeastUnacked() protocol.PacketNumber
GetPacketNumberLen(protocol.PacketNumber) protocol.PacketNumberLen
GetAlarmTimeout() time.Time
OnAlarm()
OnAlarm() error
}
// ReceivedPacketHandler handles ACKs needed to send for incoming packets
......
......@@ -11,12 +11,19 @@ import (
// +gen linkedlist
type Packet struct {
PacketNumber protocol.PacketNumber
PacketType protocol.PacketType
Frames []wire.Frame
Length protocol.ByteCount
EncryptionLevel protocol.EncryptionLevel
largestAcked protocol.PacketNumber // if the packet contains an ACK, the LargestAcked value of that ACK
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
......
......@@ -3,7 +3,9 @@ package ackhandler
import (
"time"
"github.com/lucas-clemente/quic-go/internal/congestion"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
"github.com/lucas-clemente/quic-go/internal/wire"
)
......@@ -15,6 +17,7 @@ type receivedPacketHandler struct {
packetHistory *receivedPacketHistory
ackSendDelay time.Duration
rttStats *congestion.RTTStats
packetsReceivedSinceLastAck int
retransmittablePacketsReceivedSinceLastAck int
......@@ -25,29 +28,54 @@ type receivedPacketHandler struct {
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
func NewReceivedPacketHandler(version protocol.VersionNumber) ReceivedPacketHandler {
func NewReceivedPacketHandler(rttStats *congestion.RTTStats, version protocol.VersionNumber) ReceivedPacketHandler {
return &receivedPacketHandler{
packetHistory: newReceivedPacketHistory(),
ackSendDelay: protocol.AckSendDelay,
ackSendDelay: ackSendDelay,
rttStats: rttStats,
version: version,
}
}
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 {
h.largestObserved = packetNumber
h.largestObservedReceivedTime = rcvTime
}
if packetNumber < h.ignoreBelow {
return nil
}
if err := h.packetHistory.ReceivedPacket(packetNumber); err != nil {
return err
}
h.maybeQueueAck(packetNumber, rcvTime, shouldInstigateAck)
h.maybeQueueAck(packetNumber, rcvTime, shouldInstigateAck, isMissing)
return nil
}
......@@ -58,35 +86,68 @@ func (h *receivedPacketHandler) IgnoreBelow(p protocol.PacketNumber) {
h.packetHistory.DeleteBelow(p)
}
func (h *receivedPacketHandler) maybeQueueAck(packetNumber protocol.PacketNumber, rcvTime time.Time, shouldInstigateAck bool) {
h.packetsReceivedSinceLastAck++
if shouldInstigateAck {
h.retransmittablePacketsReceivedSinceLastAck++
// isMissing says if a packet was reported missing in the last ACK.
func (h *receivedPacketHandler) isMissing(p protocol.PacketNumber) bool {
if h.lastAck == nil {
return false
}
return p < h.lastAck.LargestAcked && !h.lastAck.AcksPacket(p)
}
// always ack the first packet
func (h *receivedPacketHandler) hasNewMissingPackets() bool {
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
// note that it cannot be a duplicate because they're already filtered out by ReceivedPacket()
if h.lastAck != nil && packetNumber < h.lastAck.LargestAcked {
// maybeQueueAck queues an ACK, if necessary.
// It is implemented analogously to Chrome's QuicConnection::MaybeQueueAck()
// 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
return
}
// check if a new missing range above the previously was created
if h.lastAck != nil && h.packetHistory.GetHighestAckRange().First > h.lastAck.LargestAcked {
// Send an ACK if this packet was reported missing in an ACK sent before.
// 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
}
if !h.ackQueued && shouldInstigateAck {
if h.retransmittablePacketsReceivedSinceLastAck >= protocol.RetransmittablePacketsBeforeAck {
h.ackQueued = true
h.retransmittablePacketsReceivedSinceLastAck++
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 {
if h.ackAlarm.IsZero() {
h.ackAlarm = rcvTime.Add(h.ackSendDelay)
// send an ACK every 2 retransmittable packets
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 {
h.ackQueued = false
h.packetsReceivedSinceLastAck = 0
h.retransmittablePacketsReceivedSinceLastAck = 0
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
import (
"errors"
"fmt"
"math"
"time"
......@@ -30,13 +29,12 @@ const (
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 {
lastSentPacketNumber protocol.PacketNumber
nextPacketSendTime time.Time
skippedPackets []protocol.PacketNumber
lastSentPacketNumber protocol.PacketNumber
lastSentRetransmittablePacketTime time.Time
nextPacketSendTime time.Time
skippedPackets []protocol.PacketNumber
largestAcked protocol.PacketNumber
largestReceivedPacketWithAck protocol.PacketNumber
......@@ -45,7 +43,7 @@ type sentPacketHandler struct {
// once we receive an ACK from the peer for packet 20, the lowestPacketNotConfirmedAcked is 101
lowestPacketNotConfirmedAcked protocol.PacketNumber
packetHistory *PacketList
packetHistory *sentPacketHistory
stopWaitingManager stopWaitingManager
retransmissionQueue []*Packet
......@@ -80,7 +78,7 @@ func NewSentPacketHandler(rttStats *congestion.RTTStats) SentPacketHandler {
)
return &sentPacketHandler{
packetHistory: NewPacketList(),
packetHistory: newSentPacketHistory(),
stopWaitingManager: stopWaitingManager{},
rttStats: rttStats,
congestion: congestion,
......@@ -88,8 +86,8 @@ func NewSentPacketHandler(rttStats *congestion.RTTStats) SentPacketHandler {
}
func (h *sentPacketHandler) lowestUnacked() protocol.PacketNumber {
if f := h.packetHistory.Front(); f != nil {
return f.Value.PacketNumber
if p := h.packetHistory.FirstOutstanding(); p != nil {
return p.PacketNumber
}
return h.largestAcked + 1
}
......@@ -101,24 +99,49 @@ func (h *sentPacketHandler) SetHandshakeComplete() {
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.handshakeComplete = true
}
func (h *sentPacketHandler) SentPacket(packet *Packet) error {
if protocol.PacketNumber(len(h.retransmissionQueue)+h.packetHistory.Len()+1) > protocol.MaxTrackedSentPackets {
return errors.New("Too many outstanding non-acked and non-retransmitted packets")
func (h *sentPacketHandler) SentPacket(packet *Packet) {
packet.sendTime = time.Now()
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++ {
h.skippedPackets = append(h.skippedPackets, p)
if len(h.skippedPackets) > protocol.MaxTrackedSkippedPackets {
h.skippedPackets = h.skippedPackets[1:]
}
}
now := time.Now()
h.lastSentPacketNumber = packet.PacketNumber
var largestAcked protocol.PacketNumber
......@@ -132,24 +155,15 @@ func (h *sentPacketHandler) SentPacket(packet *Packet) error {
isRetransmittable := len(packet.Frames) != 0
if isRetransmittable {
packet.sendTime = now
packet.largestAcked = largestAcked
h.lastSentRetransmittablePacketTime = packet.sendTime
packet.includedInBytesInFlight = true
h.bytesInFlight += packet.Length
h.packetHistory.PushBack(*packet)
}
h.congestion.OnPacketSent(packet.sendTime, h.bytesInFlight, packet.PacketNumber, packet.Length, isRetransmittable)
h.congestion.OnPacketSent(
now,
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
h.nextPacketSendTime = utils.MaxTime(h.nextPacketSendTime, packet.sendTime).Add(h.congestion.TimeUntilSend(h.bytesInFlight))
return isRetransmittable
}
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
return qerr.Error(qerr.InvalidAckData, "Received ACK for an unsent package")
}
// duplicate or out-of-order ACK
// if withPacketNumber <= h.largestReceivedPacketWithAck && withPacketNumber != 0 {
if withPacketNumber <= h.largestReceivedPacketWithAck {
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() {
// duplicate or out of order ACK
if withPacketNumber != 0 && withPacketNumber <= h.largestReceivedPacketWithAck {
utils.Debugf("Ignoring ACK frame (duplicate or out of order).")
return nil
}
h.largestAcked = ackFrame.LargestAcked
h.largestReceivedPacketWithAck = withPacketNumber
h.largestAcked = utils.MaxPacketNumber(h.largestAcked, ackFrame.LargestAcked)
if h.skippedPacketsAcked(ackFrame) {
return qerr.Error(qerr.InvalidAckData, "Received an ACK for a skipped packet number")
}
rttUpdated := h.maybeUpdateRTT(ackFrame.LargestAcked, ackFrame.DelayTime, rcvTime)
if rttUpdated {
if rttUpdated := h.maybeUpdateRTT(ackFrame.LargestAcked, ackFrame.DelayTime, rcvTime); rttUpdated {
h.congestion.MaybeExitSlowStart()
}
......@@ -185,24 +192,28 @@ func (h *sentPacketHandler) ReceivedAck(ackFrame *wire.AckFrame, withPacketNumbe
return err
}
if len(ackedPackets) > 0 {
for _, p := range ackedPackets {
if encLevel < p.Value.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
// 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.
if p.Value.largestAcked != 0 {
h.lowestPacketNotConfirmedAcked = utils.MaxPacketNumber(h.lowestPacketNotConfirmedAcked, p.Value.largestAcked+1)
}
h.onPacketAcked(p)
h.congestion.OnPacketAcked(p.Value.PacketNumber, p.Value.Length, h.bytesInFlight)
for _, p := range ackedPackets {
if encLevel < p.EncryptionLevel {
return fmt.Errorf("Received ACK with encryption level %s that acks a packet %d (encryption level %s)", encLevel, p.PacketNumber, p.EncryptionLevel)
}
// 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
// the lowestPacketNotConfirmedAcked is only used to limit the number of ACK ranges we will send.
if p.largestAcked != 0 {
h.lowestPacketNotConfirmedAcked = utils.MaxPacketNumber(h.lowestPacketNotConfirmedAcked, p.largestAcked+1)
}
if err := h.onPacketAcked(p); err != nil {
return err
}
if len(p.retransmittedAs) == 0 {
h.congestion.OnPacketAcked(p.PacketNumber, p.Length, h.bytesInFlight)
}
}
h.detectLostPackets(rcvTime)
h.updateLossDetectionAlarm(rcvTime)
if err := h.detectLostPackets(rcvTime); err != nil {
return err
}
h.updateLossDetectionAlarm()
h.garbageCollectSkippedPackets()
h.stopWaitingManager.ReceivedAck(ackFrame)
......@@ -214,59 +225,50 @@ func (h *sentPacketHandler) GetLowestPacketNotConfirmedAcked() protocol.PacketNu
return h.lowestPacketNotConfirmedAcked
}
func (h *sentPacketHandler) determineNewlyAckedPackets(ackFrame *wire.AckFrame) ([]*PacketElement, error) {
var ackedPackets []*PacketElement
func (h *sentPacketHandler) determineNewlyAckedPackets(ackFrame *wire.AckFrame) ([]*Packet, error) {
var ackedPackets []*Packet
ackRangeIndex := 0
for el := h.packetHistory.Front(); el != nil; el = el.Next() {
packet := el.Value
packetNumber := packet.PacketNumber
err := h.packetHistory.Iterate(func(p *Packet) (bool, error) {
// Ignore packets below the LowestAcked
if packetNumber < ackFrame.LowestAcked {
continue
if p.PacketNumber < ackFrame.LowestAcked {
return true, nil
}
// Break after LargestAcked is reached
if packetNumber > ackFrame.LargestAcked {
break
if p.PacketNumber > ackFrame.LargestAcked {
return false, nil
}
if ackFrame.HasMissingRanges() {
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++
ackRange = ackFrame.AckRanges[len(ackFrame.AckRanges)-1-ackRangeIndex]
}
if packetNumber >= ackRange.First { // packet i contained in ACK range
if 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)
if p.PacketNumber >= ackRange.First { // packet i contained in ACK range
if p.PacketNumber > 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 {
ackedPackets = append(ackedPackets, el)
ackedPackets = append(ackedPackets, p)
}
}
return ackedPackets, nil
return true, nil
})
return ackedPackets, err
}
func (h *sentPacketHandler) maybeUpdateRTT(largestAcked protocol.PacketNumber, ackDelay time.Duration, rcvTime time.Time) bool {
for el := h.packetHistory.Front(); el != nil; el = el.Next() {
packet := el.Value
if packet.PacketNumber == largestAcked {
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
}
if p := h.packetHistory.GetPacket(largestAcked); p != nil {
h.rttStats.UpdateRTT(rcvTime.Sub(p.sendTime), ackDelay, rcvTime)
return true
}
return false
}
func (h *sentPacketHandler) updateLossDetectionAlarm(now time.Time) {
func (h *sentPacketHandler) updateLossDetectionAlarm() {
// Cancel the alarm if no packets are outstanding
if h.packetHistory.Len() == 0 {
h.alarm = time.Time{}
......@@ -275,76 +277,137 @@ func (h *sentPacketHandler) updateLossDetectionAlarm(now time.Time) {
// TODO(#497): TLP
if !h.handshakeComplete {
h.alarm = now.Add(h.computeHandshakeTimeout())
h.alarm = h.lastSentRetransmittablePacketTime.Add(h.computeHandshakeTimeout())
} else if !h.lossTime.IsZero() {
// Early retransmit timer or time loss detection.
h.alarm = h.lossTime
} else {
// 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{}
maxRTT := float64(utils.MaxDuration(h.rttStats.LatestRTT(), h.rttStats.SmoothedRTT()))
delayUntilLost := time.Duration((1.0 + timeReorderingFraction) * maxRTT)
var lostPackets []*PacketElement
for el := h.packetHistory.Front(); el != nil; el = el.Next() {
packet := el.Value
var lostPackets []*Packet
h.packetHistory.Iterate(func(packet *Packet) (bool, error) {
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)
if timeSinceSent > delayUntilLost {
lostPackets = append(lostPackets, el)
lostPackets = append(lostPackets, packet)
} else if h.lossTime.IsZero() {
// Note: This conditional is only entered once per call
h.lossTime = now.Add(delayUntilLost - timeSinceSent)
}
}
return true, nil
})
if len(lostPackets) > 0 {
for _, p := range lostPackets {
h.queuePacketForRetransmission(p)
h.congestion.OnPacketLost(p.Value.PacketNumber, p.Value.Length, h.bytesInFlight)
for _, p := range lostPackets {
if err := h.queuePacketForRetransmission(p); err != nil {
return err
}
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()
// TODO(#497): TLP
var err error
if !h.handshakeComplete {
h.queueHandshakePacketsForRetransmission()
h.handshakeCount++
err = h.queueHandshakePacketsForRetransmission()
} else if !h.lossTime.IsZero() {
// Early retransmit or time loss detection
h.detectLostPackets(now)
err = h.detectLostPackets(now)
} else {
// RTO
h.retransmitOldestTwoPackets()
h.rtoCount++
err = h.queueRTOs()
}
h.updateLossDetectionAlarm(now)
if err != nil {
return err
}
h.updateLossDetectionAlarm()
return nil
}
func (h *sentPacketHandler) GetAlarmTimeout() time.Time {
return h.alarm
}
func (h *sentPacketHandler) onPacketAcked(packetElement *PacketElement) {
h.bytesInFlight -= packetElement.Value.Length
func (h *sentPacketHandler) onPacketAcked(p *Packet) error {
// 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.handshakeCount = 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 {
......@@ -359,26 +422,39 @@ func (h *sentPacketHandler) DequeuePacketForRetransmission() *Packet {
return packet
}
func (h *sentPacketHandler) GetLeastUnacked() protocol.PacketNumber {
return h.lowestUnacked()
func (h *sentPacketHandler) GetPacketNumberLen(p protocol.PacketNumber) protocol.PacketNumberLen {
return protocol.GetPacketNumberLengthForHeader(p, h.lowestUnacked())
}
func (h *sentPacketHandler) GetStopWaitingFrame(force bool) *wire.StopWaitingFrame {
return h.stopWaitingManager.GetStopWaitingFrame(force)
}
func (h *sentPacketHandler) SendingAllowed() bool {
cwnd := h.congestion.GetCongestionWindow()
congestionLimited := h.bytesInFlight > cwnd
maxTrackedLimited := protocol.PacketNumber(len(h.retransmissionQueue)+h.packetHistory.Len()) >= protocol.MaxTrackedSentPackets
if congestionLimited {
func (h *sentPacketHandler) SendMode() SendMode {
numTrackedPackets := len(h.retransmissionQueue) + h.packetHistory.Len()
// Don't send any packets if we're keeping track of the maximum number of packets.
// 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)
return SendAck
}
if numTrackedPackets >= protocol.MaxOutstandingSentPackets {
utils.Debugf("Max outstanding limited: tracking %d packets, maximum: %d", numTrackedPackets, protocol.MaxOutstandingSentPackets)
return SendAck
}
// Workaround for #555:
// 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)
return SendAny
}
func (h *sentPacketHandler) TimeUntilSend() time.Time {
......@@ -393,45 +469,44 @@ func (h *sentPacketHandler) ShouldSendNumPackets() int {
return int(math.Ceil(float64(protocol.MinPacingDelay) / float64(delay)))
}
func (h *sentPacketHandler) retransmitOldestTwoPackets() {
if p := h.packetHistory.Front(); p != nil {
h.queueRTO(p)
}
if p := h.packetHistory.Front(); p != nil {
h.queueRTO(p)
// retransmit the oldest two packets
func (h *sentPacketHandler) queueRTOs() error {
for i := 0; i < 2; i++ {
if p := h.packetHistory.FirstOutstanding(); p != nil {
utils.Debugf("\tQueueing packet %#x for retransmission (RTO), %d outstanding", p.PacketNumber, h.packetHistory.Len())
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) {
packet := &el.Value
utils.Debugf(
"\tQueueing packet 0x%x for retransmission (RTO), %d outstanding",
packet.PacketNumber,
h.packetHistory.Len(),
)
h.queuePacketForRetransmission(el)
h.congestion.OnPacketLost(packet.PacketNumber, packet.Length, h.bytesInFlight)
h.congestion.OnRetransmissionTimeout(true)
}
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)
func (h *sentPacketHandler) queueHandshakePacketsForRetransmission() error {
var handshakePackets []*Packet
h.packetHistory.Iterate(func(p *Packet) (bool, error) {
if !p.queuedForRetransmission && p.EncryptionLevel < protocol.EncryptionForwardSecure {
handshakePackets = append(handshakePackets, p)
}
return true, nil
})
for _, p := range handshakePackets {
if err := h.queuePacketForRetransmission(p); err != nil {
return err
}
}
for _, el := range handshakePackets {
h.queuePacketForRetransmission(el)
}
return nil
}
func (h *sentPacketHandler) queuePacketForRetransmission(packetElement *PacketElement) {
packet := &packetElement.Value
h.bytesInFlight -= packet.Length
h.retransmissionQueue = append(h.retransmissionQueue, packet)
h.packetHistory.Remove(packetElement)
h.stopWaitingManager.QueuedRetransmissionForPacketNumber(packet.PacketNumber)
func (h *sentPacketHandler) queuePacketForRetransmission(p *Packet) error {
if _, err := h.packetHistory.QueuePacketForRetransmission(p.PacketNumber); err != nil {
return err
}
h.retransmissionQueue = append(h.retransmissionQueue, p)
h.stopWaitingManager.QueuedRetransmissionForPacketNumber(p.PacketNumber)
return nil
}
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) {
return cert.Certificate[0], nil
}
func (cc *certChain) getCertForSNI(sni string) (*tls.Certificate, error) {
c := cc.config
c, err := maybeGetConfigForClient(c, sni)
func (c *certChain) getCertForSNI(sni string) (*tls.Certificate, error) {
conf := c.config
conf, err := maybeGetConfigForClient(conf, sni)
if err != nil {
return nil, err
}
// The rest of this function is mostly copied from crypto/tls.getCertificate
if c.GetCertificate != nil {
cert, err := c.GetCertificate(&tls.ClientHelloInfo{ServerName: sni})
if conf.GetCertificate != nil {
cert, err := conf.GetCertificate(&tls.ClientHelloInfo{ServerName: sni})
if cert != nil || err != nil {
return cert, err
}
}
if len(c.Certificates) == 0 {
if len(conf.Certificates) == 0 {
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.
return &c.Certificates[0], nil
return &conf.Certificates[0], nil
}
name := strings.ToLower(sni)
......@@ -84,7 +84,7 @@ func (cc *certChain) getCertForSNI(sni string) (*tls.Certificate, error) {
name = name[:len(name)-1]
}
if cert, ok := c.NameToCertificate[name]; ok {
if cert, ok := conf.NameToCertificate[name]; ok {
return cert, nil
}
......@@ -94,13 +94,13 @@ func (cc *certChain) getCertForSNI(sni string) (*tls.Certificate, error) {
for i := range labels {
labels[i] = "*"
candidate := strings.Join(labels, ".")
if cert, ok := c.NameToCertificate[candidate]; ok {
if cert, ok := conf.NameToCertificate[candidate]; ok {
return cert, nil
}
}
// 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) {
......
package crypto
import (
"crypto"
"encoding/binary"
"github.com/bifurcation/mint"
"github.com/lucas-clemente/quic-go/internal/protocol"
)
const (
clientExporterLabel = "EXPORTER-QUIC client 1-RTT Secret"
serverExporterLabel = "EXPORTER-QUIC server 1-RTT Secret"
clientExporterLabel = "EXPORTER-QUIC client 1rtt"
serverExporterLabel = "EXPORTER-QUIC server 1rtt"
)
// A TLSExporter gets the negotiated ciphersuite and computes exporter
......@@ -16,6 +19,16 @@ type TLSExporter interface {
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
func DeriveAESKeys(tls TLSExporter, pers protocol.Perspective) (AEAD, error) {
var myLabel, otherLabel string
......@@ -43,7 +56,7 @@ func computeKeyAndIV(tls TLSExporter, label string) (key, iv []byte, err error)
if err != nil {
return nil, nil, err
}
key = mint.HkdfExpandLabel(cs.Hash, secret, "key", nil, cs.KeyLen)
iv = mint.HkdfExpandLabel(cs.Hash, secret, "iv", nil, cs.IvLen)
key = qhkdfExpand(secret, "key", cs.KeyLen)
iv = qhkdfExpand(secret, "iv", cs.IvLen)
return key, iv, nil
}
......@@ -31,14 +31,14 @@ func newNullAEADAESGCM(connectionID protocol.ConnectionID, pers protocol.Perspec
func computeSecrets(connectionID protocol.ConnectionID) (clientSecret, serverSecret []byte) {
connID := make([]byte, 8)
binary.BigEndian.PutUint64(connID, uint64(connectionID))
cleartextSecret := mint.HkdfExtract(crypto.SHA256, []byte(quicVersion1Salt), connID)
clientSecret = mint.HkdfExpandLabel(crypto.SHA256, cleartextSecret, "QUIC client cleartext Secret", []byte{}, crypto.SHA256.Size())
serverSecret = mint.HkdfExpandLabel(crypto.SHA256, cleartextSecret, "QUIC server cleartext Secret", []byte{}, crypto.SHA256.Size())
handshakeSecret := mint.HkdfExtract(crypto.SHA256, quicVersion1Salt, connID)
clientSecret = qhkdfExpand(handshakeSecret, "client hs", crypto.SHA256.Size())
serverSecret = qhkdfExpand(handshakeSecret, "server hs", crypto.SHA256.Size())
return
}
func computeNullAEADKeyAndIV(secret []byte) (key, iv []byte) {
key = mint.HkdfExpandLabel(crypto.SHA256, secret, "key", nil, 16)
iv = mint.HkdfExpandLabel(crypto.SHA256, secret, "iv", nil, 12)
key = qhkdfExpand(secret, "key", 16)
iv = qhkdfExpand(secret, "iv", 12)
return
}
......@@ -7,6 +7,9 @@ import (
"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 {
callback func(net.Addr, *Cookie) bool
......@@ -15,6 +18,7 @@ type CookieHandler struct {
var _ mint.CookieHandler = &CookieHandler{}
// NewCookieHandler creates a new CookieHandler.
func NewCookieHandler(callback func(net.Addr, *Cookie) bool) (*CookieHandler, error) {
cookieGenerator, err := NewCookieGenerator()
if err != nil {
......@@ -26,6 +30,7 @@ func NewCookieHandler(callback func(net.Addr, *Cookie) bool) (*CookieHandler, er
}, nil
}
// Generate a new cookie for a mint connection.
func (h *CookieHandler) Generate(conn *mint.Conn) ([]byte, error) {
if h.callback(conn.RemoteAddr(), nil) {
return nil, nil
......@@ -33,6 +38,7 @@ func (h *CookieHandler) Generate(conn *mint.Conn) ([]byte, error) {
return h.cookieGenerator.NewToken(conn.RemoteAddr())
}
// Validate a cookie.
func (h *CookieHandler) Validate(conn *mint.Conn, token []byte) bool {
data, err := h.cookieGenerator.DecodeToken(token)
if err != nil {
......
......@@ -429,7 +429,7 @@ func (h *cryptoSetupServer) handleCHLO(sni string, data []byte, cryptoData map[T
replyMap := h.params.getHelloMap()
// add crypto parameters
verTag := &bytes.Buffer{}
for _, v := range protocol.GetGreasedVersions(h.supportedVersions) {
for _, v := range h.supportedVersions {
utils.BigEndian.WriteUint32(verTag, uint32(v))
}
replyMap[TagPUBS] = ephermalKex.PublicKey()
......
......@@ -84,7 +84,7 @@ func (h HandshakeMessage) Write(b *bytes.Buffer) {
offset := uint32(0)
for i, t := range h.getTagsSorted() {
v := data[Tag(t)]
v := data[t]
b.Write(v)
offset += uint32(len(v))
binary.LittleEndian.PutUint32(indexData[i*8:], uint32(t))
......@@ -111,8 +111,7 @@ func (h *HandshakeMessage) getTagsSorted() []Tag {
func (h HandshakeMessage) String() string {
var pad string
res := tagToString(h.Tag) + ":\n"
for _, t := range h.getTagsSorted() {
tag := Tag(t)
for _, tag := range h.getTagsSorted() {
if tag == TagPAD {
pad = fmt.Sprintf("\t%s: (%d bytes)\n", tagToString(tag), len(h.Data[tag]))
} else {
......
......@@ -9,10 +9,10 @@ import (
// ServerConfig is a server config
type ServerConfig struct {
kex crypto.KeyExchange
certChain crypto.CertChain
ID []byte
obit []byte
kex crypto.KeyExchange
certChain crypto.CertChain
ID []byte
obit []byte
cookieGenerator *CookieGenerator
}
......@@ -36,10 +36,10 @@ func NewServerConfig(kex crypto.KeyExchange, certChain crypto.CertChain) (*Serve
}
return &ServerConfig{
kex: kex,
certChain: certChain,
ID: id,
obit: obit,
kex: kex,
certChain: certChain,
ID: id,
obit: obit,
cookieGenerator: cookieGenerator,
}, nil
}
......
......@@ -102,32 +102,37 @@ func (s *serverConfigClient) parseValues(tagMap map[Tag][]byte) error {
return qerr.Error(qerr.CryptoMessageParameterNotFound, "PUBS")
}
var pubs_kexs []struct{Length uint32; Value []byte}
var last_len uint32
for i := 0; i < len(pubs)-3; i += int(last_len)+3 {
var pubsKexs []struct {
Length uint32
Value []byte
}
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
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 {
return qerr.Error(qerr.CryptoInvalidValueLength, "PUBS not decodable")
}
if last_len == 0 {
if lastLen == 0 {
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")
}
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")
}
if pubs_kexs[c255Foundat].Length != 32 {
if pubsKexs[c255Foundat].Length != 32 {
return qerr.Error(qerr.CryptoInvalidValueLength, "PUBS")
}
......@@ -137,8 +142,7 @@ func (s *serverConfigClient) parseValues(tagMap map[Tag][]byte) error {
return err
}
s.sharedSecret, err = s.kex.CalculateSharedKey(pubs_kexs[c255Foundat].Value)
s.sharedSecret, err = s.kex.CalculateSharedKey(pubsKexs[c255Foundat].Value)
if err != nil {
return err
}
......
......@@ -9,14 +9,14 @@ type transportParameterID uint16
const quicTLSExtensionType = 26
const (
initialMaxStreamDataParameterID transportParameterID = 0x0
initialMaxDataParameterID transportParameterID = 0x1
initialMaxStreamIDBiDiParameterID transportParameterID = 0x2
idleTimeoutParameterID transportParameterID = 0x3
omitConnectionIDParameterID transportParameterID = 0x4
maxPacketSizeParameterID transportParameterID = 0x5
statelessResetTokenParameterID transportParameterID = 0x6
initialMaxStreamIDUniParameterID transportParameterID = 0x8
initialMaxStreamDataParameterID transportParameterID = 0x0
initialMaxDataParameterID transportParameterID = 0x1
initialMaxStreamsBiDiParameterID transportParameterID = 0x2
idleTimeoutParameterID transportParameterID = 0x3
omitConnectionIDParameterID transportParameterID = 0x4
maxPacketSizeParameterID transportParameterID = 0x5
statelessResetTokenParameterID transportParameterID = 0x6
initialMaxStreamsUniParameterID transportParameterID = 0x8
)
type transportParameter struct {
......
......@@ -3,13 +3,13 @@ package handshake
import (
"errors"
"fmt"
"math"
"github.com/lucas-clemente/quic-go/qerr"
"github.com/bifurcation/mint"
"github.com/bifurcation/mint/syntax"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
)
type extensionHandlerClient struct {
......@@ -31,7 +31,10 @@ func NewExtensionHandlerClient(
supportedVersions []protocol.VersionNumber,
version protocol.VersionNumber,
) 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{
ourParams: params,
paramsChan: paramsChan,
......@@ -46,6 +49,7 @@ func (h *extensionHandlerClient) Send(hType mint.HandshakeType, el *mint.Extensi
return nil
}
utils.Debugf("Sending Transport Parameters: %s", h.ourParams)
data, err := syntax.Marshal(clientHelloTransportParameters{
InitialVersion: uint32(h.initialVersion),
Parameters: h.ourParams.getTransportParameters(),
......@@ -63,17 +67,12 @@ func (h *extensionHandlerClient) Receive(hType mint.HandshakeType, el *mint.Exte
return err
}
if hType != mint.HandshakeTypeEncryptedExtensions && hType != mint.HandshakeTypeNewSessionTicket {
if hType != mint.HandshakeTypeEncryptedExtensions {
if found {
return fmt.Errorf("Unexpected QUIC extension in handshake message %d", hType)
}
return nil
}
if hType == mint.HandshakeTypeNewSessionTicket {
// the extension it's optional in the NewSessionTicket message
// TODO: handle this
return nil
}
// hType == mint.HandshakeTypeEncryptedExtensions
if !found {
......@@ -119,12 +118,11 @@ func (h *extensionHandlerClient) Receive(hType mint.HandshakeType, el *mint.Exte
// TODO: return the right error here
return errors.New("server didn't sent stateless_reset_token")
}
params, err := readTransportParamters(eetp.Parameters)
params, err := readTransportParameters(eetp.Parameters)
if err != nil {
return err
}
// TODO(#878): remove this when implementing the MAX_STREAM_ID frame
params.MaxStreams = math.MaxUint32
utils.Debugf("Received Transport Parameters: %s", params)
h.paramsChan <- *params
return nil
}
......
......@@ -10,6 +10,7 @@ import (
"github.com/bifurcation/mint"
"github.com/bifurcation/mint/syntax"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
)
type extensionHandlerServer struct {
......@@ -29,6 +30,8 @@ func NewExtensionHandlerServer(
supportedVersions []protocol.VersionNumber,
version protocol.VersionNumber,
) 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)
return &extensionHandlerServer{
ourParams: params,
......@@ -53,6 +56,7 @@ func (h *extensionHandlerServer) Send(hType mint.HandshakeType, el *mint.Extensi
for i, v := range supportedVersions {
versions[i] = uint32(v)
}
utils.Debugf("Sending Transport Parameters: %s", h.ourParams)
data, err := syntax.Marshal(encryptedExtensionsTransportParameters{
NegotiatedVersion: uint32(h.version),
SupportedVersions: versions,
......@@ -100,10 +104,11 @@ func (h *extensionHandlerServer) Receive(hType mint.HandshakeType, el *mint.Exte
return errors.New("client sent a stateless reset token")
}
}
params, err := readTransportParamters(chtp.Parameters)
params, err := readTransportParameters(chtp.Parameters)
if err != nil {
return err
}
utils.Debugf("Received Transport Parameters: %s", params)
h.paramsChan <- *params
return nil
}
......
......@@ -20,9 +20,11 @@ type TransportParameters struct {
StreamFlowControlWindow protocol.ByteCount
ConnectionFlowControlWindow protocol.ByteCount
MaxBidiStreamID protocol.StreamID // only used for IETF QUIC
MaxUniStreamID protocol.StreamID // only used for IETF QUIC
MaxStreams uint32 // only used for gQUIC
MaxPacketSize protocol.ByteCount
MaxUniStreams uint16 // only used for IETF QUIC
MaxBidiStreams uint16 // only used for IETF QUIC
MaxStreams uint32 // only used for gQUIC
OmitConnectionID bool
IdleTimeout time.Duration
......@@ -93,7 +95,7 @@ func (p *TransportParameters) getHelloMap() map[Tag][]byte {
}
// 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{}
var foundInitialMaxStreamData bool
......@@ -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))
}
params.ConnectionFlowControlWindow = protocol.ByteCount(binary.BigEndian.Uint32(p.Value))
case initialMaxStreamIDBiDiParameterID:
if len(p.Value) != 4 {
return nil, fmt.Errorf("wrong length for initial_max_stream_id_bidi: %d (expected 4)", len(p.Value))
case initialMaxStreamsBiDiParameterID:
if len(p.Value) != 2 {
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.MaxBidiStreamID = protocol.StreamID(binary.BigEndian.Uint32(p.Value))
case initialMaxStreamIDUniParameterID:
if len(p.Value) != 4 {
return nil, fmt.Errorf("wrong length for initial_max_stream_id_uni: %d (expected 4)", len(p.Value))
params.MaxBidiStreams = binary.BigEndian.Uint16(p.Value)
case initialMaxStreamsUniParameterID:
if len(p.Value) != 2 {
return nil, fmt.Errorf("wrong length for initial_max_stream_id_uni: %d (expected 2)", len(p.Value))
}
// TODO(#1154): validate the stream ID
params.MaxUniStreamID = protocol.StreamID(binary.BigEndian.Uint32(p.Value))
params.MaxUniStreams = binary.BigEndian.Uint16(p.Value)
case idleTimeoutParameterID:
foundIdleTimeout = true
if len(p.Value) != 2 {
......@@ -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))
}
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 {
binary.BigEndian.PutUint32(initialMaxStreamData, uint32(p.StreamFlowControlWindow))
initialMaxData := make([]byte, 4)
binary.BigEndian.PutUint32(initialMaxData, uint32(p.ConnectionFlowControlWindow))
initialMaxBidiStreamID := make([]byte, 4)
binary.BigEndian.PutUint32(initialMaxBidiStreamID, uint32(p.MaxBidiStreamID))
initialMaxUniStreamID := make([]byte, 4)
binary.BigEndian.PutUint32(initialMaxUniStreamID, uint32(p.MaxUniStreamID))
initialMaxBidiStreamID := make([]byte, 2)
binary.BigEndian.PutUint16(initialMaxBidiStreamID, p.MaxBidiStreams)
initialMaxUniStreamID := make([]byte, 2)
binary.BigEndian.PutUint16(initialMaxUniStreamID, p.MaxUniStreams)
idleTimeout := make([]byte, 2)
binary.BigEndian.PutUint16(idleTimeout, uint16(p.IdleTimeout/time.Second))
maxPacketSize := make([]byte, 2)
......@@ -164,8 +173,8 @@ func (p *TransportParameters) getTransportParameters() []transportParameter {
params := []transportParameter{
{initialMaxStreamDataParameterID, initialMaxStreamData},
{initialMaxDataParameterID, initialMaxData},
{initialMaxStreamIDBiDiParameterID, initialMaxBidiStreamID},
{initialMaxStreamIDUniParameterID, initialMaxUniStreamID},
{initialMaxStreamsBiDiParameterID, initialMaxBidiStreamID},
{initialMaxStreamsUniParameterID, initialMaxUniStreamID},
{idleTimeoutParameterID, idleTimeout},
{maxPacketSizeParameterID, maxPacketSize},
}
......@@ -174,3 +183,9 @@ func (p *TransportParameters) getTransportParameters() []transportParameter {
}
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 {
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
func (m *MockSentPacketHandler) GetLowestPacketNotConfirmedAcked() protocol.PacketNumber {
ret := m.ctrl.Call(m, "GetLowestPacketNotConfirmedAcked")
......@@ -85,6 +73,18 @@ func (mr *MockSentPacketHandlerMockRecorder) 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
func (m *MockSentPacketHandler) GetStopWaitingFrame(arg0 bool) *wire.StopWaitingFrame {
ret := m.ctrl.Call(m, "GetStopWaitingFrame", arg0)
......@@ -98,8 +98,10 @@ func (mr *MockSentPacketHandlerMockRecorder) GetStopWaitingFrame(arg0 interface{
}
// OnAlarm mocks base method
func (m *MockSentPacketHandler) OnAlarm() {
m.ctrl.Call(m, "OnAlarm")
func (m *MockSentPacketHandler) OnAlarm() error {
ret := m.ctrl.Call(m, "OnAlarm")
ret0, _ := ret[0].(error)
return ret0
}
// OnAlarm indicates an expected call of OnAlarm
......@@ -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)
}
// SendingAllowed mocks base method
func (m *MockSentPacketHandler) SendingAllowed() bool {
ret := m.ctrl.Call(m, "SendingAllowed")
ret0, _ := ret[0].(bool)
// SendMode mocks base method
func (m *MockSentPacketHandler) SendMode() ackhandler.SendMode {
ret := m.ctrl.Call(m, "SendMode")
ret0, _ := ret[0].(ackhandler.SendMode)
return ret0
}
// SendingAllowed indicates an expected call of SendingAllowed
func (mr *MockSentPacketHandlerMockRecorder) SendingAllowed() *gomock.Call {
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendingAllowed", reflect.TypeOf((*MockSentPacketHandler)(nil).SendingAllowed))
// SendMode indicates an expected call of SendMode
func (mr *MockSentPacketHandlerMockRecorder) SendMode() *gomock.Call {
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendMode", reflect.TypeOf((*MockSentPacketHandler)(nil).SendMode))
}
// SentPacket mocks base method
func (m *MockSentPacketHandler) SentPacket(arg0 *ackhandler.Packet) error {
ret := m.ctrl.Call(m, "SentPacket", arg0)
ret0, _ := ret[0].(error)
return ret0
func (m *MockSentPacketHandler) SentPacket(arg0 *ackhandler.Packet) {
m.ctrl.Call(m, "SentPacket", arg0)
}
// SentPacket indicates an expected call of SentPacket
......@@ -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)
}
// 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
func (m *MockSentPacketHandler) SetHandshakeComplete() {
m.ctrl.Call(m, "SetHandshakeComplete")
......
......@@ -27,14 +27,14 @@ const (
type PacketType uint8
const (
// PacketTypeInitial is the packet type of a Initial packet
PacketTypeInitial PacketType = 2
// PacketTypeInitial is the packet type of an Initial packet
PacketTypeInitial PacketType = 0x7f
// PacketTypeRetry is the packet type of a Retry packet
PacketTypeRetry PacketType = 3
// PacketTypeHandshake is the packet type of a Cleartext packet
PacketTypeHandshake PacketType = 4
PacketTypeRetry PacketType = 0x7e
// PacketTypeHandshake is the packet type of a Handshake packet
PacketTypeHandshake PacketType = 0x7d
// PacketType0RTT is the packet type of a 0-RTT packet
PacketType0RTT PacketType = 5
PacketType0RTT PacketType = 0x7c
)
func (t PacketType) String() string {
......@@ -77,11 +77,11 @@ const DefaultTCPMSS ByteCount = 1460
// MinClientHelloSize is the minimum size the server expects an inchoate CHLO to have (in gQUIC)
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
// MaxClientHellos is the maximum number of times we'll send a client hello
// The value 3 accounts for:
// * 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
......@@ -2,9 +2,11 @@ package protocol
import "time"
// MaxPacketSize is the maximum packet size that we use for sending packets.
// It includes the QUIC packet header, but excludes the UDP and IP header.
const MaxPacketSize ByteCount = 1200
// MaxPacketSizeIPv4 is the maximum packet size that we use for sending IPv4 packets.
const MaxPacketSizeIPv4 = 1252
// 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
// This makes sure that those packets can always be retransmitted without splitting the contained StreamFrames
......@@ -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
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
// This is the value that Google servers are using
const ReceiveStreamFlowControlWindow = (1 << 10) * 32 // 32 kB
......@@ -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
const WindowUpdateThreshold = 0.25
// MaxIncomingStreams is the maximum number of streams that a peer may open
const MaxIncomingStreams = 100
// DefaultMaxIncomingStreams is the maximum number of streams that a peer may open
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.
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.
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.
const MaxSessionUnprocessedPackets = DefaultMaxCongestionWindow
......@@ -84,8 +81,15 @@ const MaxTrackedSkippedPackets = 10
// CookieExpiryTime is the valid time of a cookie
const CookieExpiryTime = 24 * time.Hour
// MaxTrackedSentPackets is maximum number of sent packets saved for either later retransmission or entropy calculation
const MaxTrackedSentPackets = 2 * DefaultMaxCongestionWindow
// MaxOutstandingSentPackets is maximum number of packets saved for retransmission.
// 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
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
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
// prevents DoS attacks against the streamFrameSorter
const MaxStreamFrameSorterGaps = 1000
......
......@@ -4,10 +4,11 @@ import (
"crypto/rand"
"encoding/binary"
"fmt"
"math"
)
// 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
const (
......@@ -20,7 +21,7 @@ const (
Version39 VersionNumber = gquicVersion0 + 3*0x100 + 0x9 + iota
VersionTLS VersionNumber = 101
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
......@@ -29,6 +30,11 @@ var SupportedVersions = []VersionNumber{
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
func (vn VersionNumber) UsesTLS() bool {
return vn == VersionTLS
......@@ -46,7 +52,7 @@ func (vn VersionNumber) String() string {
if vn.isGQUIC() {
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 {
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
func (vn VersionNumber) StreamContributesToConnectionFlowControl(id StreamID) bool {
if id == vn.CryptoStreamID() {
......
......@@ -31,7 +31,7 @@ func (t *Timer) Reset(deadline time.Time) {
if !t.t.Stop() && !t.read {
<-t.t.C
}
t.t.Reset(deadline.Sub(time.Now()))
t.t.Reset(time.Until(deadline))
t.read = false
t.deadline = deadline
......
......@@ -60,7 +60,7 @@ func ParseAckFrame(r *bytes.Reader, version protocol.VersionNumber) (*AckFrame,
if ackBlock > frame.LargestAcked {
return nil, errors.New("invalid first ACK range")
}
smallest := frame.LargestAcked - protocol.PacketNumber(ackBlock)
smallest := frame.LargestAcked - ackBlock
// read all the other ACK ranges
if numBlocks > 0 {
......@@ -86,7 +86,7 @@ func ParseAckFrame(r *bytes.Reader, version protocol.VersionNumber) (*AckFrame,
if ackBlock > largest {
return nil, errInvalidAckRanges
}
smallest = largest - protocol.PacketNumber(ackBlock)
smallest = largest - ackBlock
frame.AckRanges = append(frame.AckRanges, AckRange{First: smallest, Last: largest})
}
......@@ -144,7 +144,7 @@ func (f *AckFrame) Length(version protocol.VersionNumber) protocol.ByteCount {
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
if f.HasMissingRanges() {
......
......@@ -7,3 +7,8 @@ type AckRange struct {
First 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)
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
// reading the whole reason phrase would result in EOF when attempting to READ
if int(reasonPhraseLen) > r.Len() {
......@@ -62,7 +62,7 @@ func ParseConnectionCloseFrame(r *bytes.Reader, version protocol.VersionNumber)
}
return &ConnectionCloseFrame{
ErrorCode: qerr.ErrorCode(errorCode),
ErrorCode: errorCode,
ReasonPhrase: string(reasonPhrase),
}, nil
}
......
......@@ -41,7 +41,7 @@ func ParseGoawayFrame(r *bytes.Reader, _ protocol.VersionNumber) (*GoawayFrame,
return nil, err
}
if reasonPhraseLen > uint16(protocol.MaxPacketSize) {
if reasonPhraseLen > uint16(protocol.MaxReceivePacketSize) {
return nil, qerr.Error(qerr.InvalidGoawayData, "reason phrase too long")
}
......
......@@ -50,6 +50,7 @@ func ParseHeaderSentByServer(b *bytes.Reader, version protocol.VersionNumber) (*
// the client knows the version that this packet was sent with
isPublicHeader = !version.UsesTLS()
}
return parsePacketHeader(b, protocol.PerspectiveServer, isPublicHeader)
}
......@@ -61,12 +62,13 @@ func ParseHeaderSentByClient(b *bytes.Reader) (*Header, error) {
}
_ = b.UnreadByte() // unread the type byte
// If this is a gQUIC header 0x80 and 0x40 will be set to 0.
// If this is an IETF QUIC header there are two options:
// * either 0x80 will be 1 (for the Long Header)
// * or 0x40 (the Connection ID Flag) will be 0 (for the Short Header), since we don't the client to omit it
isPublicHeader := typeByte&0xc0 == 0
// In an IETF QUIC packet header
// * either 0x80 is set (for the Long Header)
// * or 0x8 is unset (for the Short Header)
// In a gQUIC Public Header
// * 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)
}
......
......@@ -2,6 +2,7 @@ package wire
import (
"bytes"
"errors"
"fmt"
"github.com/lucas-clemente/quic-go/internal/protocol"
......@@ -31,15 +32,9 @@ func parseLongHeader(b *bytes.Reader, sentBy protocol.Perspective, typeByte byte
if err != nil {
return nil, err
}
pn, err := utils.BigEndian.ReadUint32(b)
if err != nil {
return nil, err
}
h := &Header{
ConnectionID: protocol.ConnectionID(connID),
PacketNumber: protocol.PacketNumber(pn),
PacketNumberLen: protocol.PacketNumberLen4,
Version: protocol.VersionNumber(v),
ConnectionID: protocol.ConnectionID(connID),
Version: protocol.VersionNumber(v),
}
if v == 0 { // version negotiation packet
if sentBy == protocol.PerspectiveClient {
......@@ -60,6 +55,12 @@ func parseLongHeader(b *bytes.Reader, sentBy protocol.Perspective, typeByte byte
return h, nil
}
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)
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))
......@@ -71,26 +72,40 @@ func parseLongHeader(b *bytes.Reader, sentBy protocol.Perspective, typeByte byte
}
func parseShortHeader(b *bytes.Reader, typeByte byte) (*Header, error) {
hasConnID := typeByte&0x40 > 0
omitConnID := typeByte&0x40 > 0
var connID uint64
if hasConnID {
if !omitConnID {
var err error
connID, err = utils.BigEndian.ReadUint64(b)
if err != nil {
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))
if err != nil {
return nil, err
}
return &Header{
KeyPhase: int(typeByte&0x20) >> 5,
OmitConnectionID: !hasConnID,
OmitConnectionID: omitConnID,
ConnectionID: protocol.ConnectionID(connID),
PacketNumber: protocol.PacketNumber(pn),
PacketNumberLen: protocol.PacketNumberLen(pnLen),
PacketNumberLen: pnLen,
}, nil
}
......@@ -112,17 +127,17 @@ func (h *Header) writeLongHeader(b *bytes.Buffer) error {
}
func (h *Header) writeShortHeader(b *bytes.Buffer) error {
typeByte := byte(h.KeyPhase << 5)
if !h.OmitConnectionID {
typeByte := byte(0x10)
typeByte ^= byte(h.KeyPhase << 5)
if h.OmitConnectionID {
typeByte ^= 0x40
}
switch h.PacketNumberLen {
case protocol.PacketNumberLen1:
typeByte ^= 0x1
case protocol.PacketNumberLen2:
typeByte ^= 0x2
typeByte ^= 0x1
case protocol.PacketNumberLen4:
typeByte ^= 0x3
typeByte ^= 0x2
default:
return fmt.Errorf("invalid packet number length: %d", h.PacketNumberLen)
}
......
......@@ -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 {
// 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 {
header.DiversificationNonce = make([]byte, 32)
if _, err := io.ReadFull(b, header.DiversificationNonce); err != nil {
......@@ -148,7 +147,7 @@ func parsePublicHeader(b *bytes.Reader, packetSentBy protocol.Perspective) (*Hea
// Version (optional)
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 {
return nil, qerr.Error(qerr.InvalidVersionNegotiationPacket, "empty version list")
}
......@@ -236,7 +235,7 @@ func (h *Header) logPublicHeader() {
}
ver := "(unset)"
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)
}
......@@ -56,7 +56,7 @@ func ParseStreamFrame(r *bytes.Reader, version protocol.VersionNumber) (*StreamF
if err != nil {
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
// reading the packet contents would result in EOF when attempting to READ
if dataLen > uint64(r.Len()) {
......
......@@ -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
// reading the packet contents would result in EOF when attempting to READ
if int(dataLen) > r.Len() {
......
......@@ -10,50 +10,37 @@ import (
// ComposeGQUICVersionNegotiation composes a Version Negotiation Packet for gQUIC
func ComposeGQUICVersionNegotiation(connID protocol.ConnectionID, versions []protocol.VersionNumber) []byte {
fullReply := &bytes.Buffer{}
buf := &bytes.Buffer{}
ph := Header{
ConnectionID: connID,
PacketNumber: 1,
VersionFlag: 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())
return nil
}
writeVersions(fullReply, versions)
return fullReply.Bytes()
for _, v := range versions {
utils.BigEndian.WriteUint32(buf, uint32(v))
}
return buf.Bytes()
}
// ComposeVersionNegotiation composes a Version Negotiation according to the IETF draft
func ComposeVersionNegotiation(
connID protocol.ConnectionID,
pn protocol.PacketNumber,
versions []protocol.VersionNumber,
) []byte {
fullReply := &bytes.Buffer{}
greasedVersions := protocol.GetGreasedVersions(versions)
buf := bytes.NewBuffer(make([]byte, 0, 1+8+4+len(greasedVersions)*4))
r := make([]byte, 1)
_, _ = rand.Read(r) // ignore the error here. It is not critical to have perfect random here.
h := Header{
IsLongHeader: true,
Type: protocol.PacketType(r[0] | 0x80),
ConnectionID: connID,
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) {
buf.WriteByte(r[0] | 0x80)
utils.BigEndian.WriteUint64(buf, uint64(connID))
utils.BigEndian.WriteUint32(buf, 0) // version 0
for _, v := range greasedVersions {
utils.BigEndian.WriteUint32(buf, uint32(v))
}
return buf.Bytes()
}
......@@ -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.
// 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) {
raw := getPacketBuffer()
buffer := bytes.NewBuffer(raw)
raw := *getPacketBuffer()
buffer := bytes.NewBuffer(raw[:0])
if err := hdr.Write(buffer, pers, hdr.Version); err != nil {
return nil, err
}
......
......@@ -4,11 +4,13 @@ import (
"bytes"
"errors"
"fmt"
"net"
"sync"
"github.com/lucas-clemente/quic-go/internal/ackhandler"
"github.com/lucas-clemente/quic-go/internal/handshake"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
"github.com/lucas-clemente/quic-go/internal/wire"
)
......@@ -19,6 +21,16 @@ type packedPacket struct {
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 {
HasCryptoStreamData() bool
PopCryptoStreamFrame(protocol.ByteCount) *wire.StreamFrame
......@@ -32,6 +44,7 @@ type packetPacker struct {
cryptoSetup handshake.CryptoSetup
packetNumberGenerator *packetNumberGenerator
getPacketNumberLen func(protocol.PacketNumber) protocol.PacketNumberLen
streams streamFrameSource
controlFrameMutex sync.Mutex
......@@ -39,26 +52,43 @@ type packetPacker struct {
stopWaiting *wire.StopWaitingFrame
ackFrame *wire.AckFrame
leastUnacked protocol.PacketNumber
omitConnectionID bool
maxPacketSize protocol.ByteCount
hasSentPacket bool // has the packetPacker already sent a packet
numNonRetransmittableAcks int
}
func newPacketPacker(connectionID protocol.ConnectionID,
initialPacketNumber protocol.PacketNumber,
getPacketNumberLen func(protocol.PacketNumber) protocol.PacketNumberLen,
remoteAddr net.Addr, // only used for determining the max packet size
cryptoSetup handshake.CryptoSetup,
streamFramer streamFrameSource,
perspective protocol.Perspective,
version protocol.VersionNumber,
) *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{
cryptoSetup: cryptoSetup,
connectionID: connectionID,
perspective: perspective,
version: version,
streams: streamFramer,
getPacketNumberLen: getPacketNumberLen,
packetNumberGenerator: newPacketNumberGenerator(initialPacketNumber, protocol.SkipPacketAveragePeriodLength),
maxPacketSize: maxPacketSize,
}
}
......@@ -99,18 +129,124 @@ func (p *packetPacker) PackAckPacket() (*packedPacket, error) {
}, err
}
// PackHandshakeRetransmission retransmits a handshake packet, that was sent with less than forward-secure encryption
func (p *packetPacker) PackHandshakeRetransmission(packet *ackhandler.Packet) (*packedPacket, error) {
if packet.EncryptionLevel == protocol.EncryptionForwardSecure {
return nil, errors.New("PacketPacker BUG: forward-secure encrypted handshake packets don't need special treatment")
// PackRetransmission packs a retransmission
// For packets sent after completion of the handshake, it might happen that 2 packets have to be sent.
// This can happen e.g. when a longer packet number is used in the header.
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)
if err != nil {
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.Type = packet.PacketType
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 {
return nil, errors.New("PacketPacker BUG: Handshake retransmissions must contain a STOP_WAITING frame")
}
......@@ -155,7 +291,7 @@ func (p *packetPacker) PackPacket() (*packedPacket, error) {
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))
if err != nil {
return nil, err
......@@ -204,7 +340,7 @@ func (p *packetPacker) packCryptoPacket() (*packedPacket, error) {
if err != nil {
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.DataLenPresent = false
frames := []wire.Frame{sf}
......@@ -261,7 +397,7 @@ func (p *packetPacker) composeNextPacket(
// 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 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 IETF draft style STREAM frames, the length is encoded to either 1 or 2 bytes
if p.version.UsesIETFFrameFormat() {
......@@ -296,7 +432,7 @@ func (p *packetPacker) QueueControlFrame(frame wire.Frame) {
func (p *packetPacker) getHeader(encLevel protocol.EncryptionLevel) *wire.Header {
pnum := p.packetNumberGenerator.Peek()
packetNumberLen := protocol.GetPacketNumberLengthForHeader(pnum, p.leastUnacked)
packetNumberLen := p.getPacketNumberLen(pnum)
header := &wire.Header{
ConnectionID: p.connectionID,
......@@ -338,8 +474,8 @@ func (p *packetPacker) writeAndSealPacket(
payloadFrames []wire.Frame,
sealer handshake.Sealer,
) ([]byte, error) {
raw := getPacketBuffer()
buffer := bytes.NewBuffer(raw)
raw := *getPacketBuffer()
buffer := bytes.NewBuffer(raw[:0])
if err := header.Write(buffer, p.perspective, p.version); err != nil {
return nil, err
......@@ -367,8 +503,8 @@ func (p *packetPacker) writeAndSealPacket(
}
}
if size := protocol.ByteCount(buffer.Len() + sealer.Overhead()); size > protocol.MaxPacketSize {
return nil, fmt.Errorf("PacketPacker BUG: packet too large (%d bytes, allowed %d bytes)", 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, p.maxPacketSize)
}
raw = raw[0:buffer.Len()]
......@@ -390,10 +526,10 @@ func (p *packetPacker) canSendData(encLevel protocol.EncryptionLevel) bool {
return encLevel == protocol.EncryptionForwardSecure
}
func (p *packetPacker) SetLeastUnacked(leastUnacked protocol.PacketNumber) {
p.leastUnacked = leastUnacked
}
func (p *packetPacker) SetOmitConnectionID() {
p.omitConnectionID = true
}
func (p *packetPacker) SetMaxPacketSize(size protocol.ByteCount) {
p.maxPacketSize = utils.MinByteCount(p.maxPacketSize, size)
}
......@@ -24,8 +24,9 @@ type packetUnpacker struct {
}
func (u *packetUnpacker) Unpack(headerBinary []byte, hdr *wire.Header, data []byte) (*unpackedPacket, error) {
buf := getPacketBuffer()
defer putPacketBuffer(buf)
buf := *getPacketBuffer()
buf = buf[:0]
defer putPacketBuffer(&buf)
decrypted, encryptionLevel, err := u.aead.Open(buf, data, hdr.PacketNumber, headerBinary)
if err != nil {
// Wrap err in quicError so that public reset is sent by session
......
......@@ -31,6 +31,7 @@ func (e *QuicError) Error() string {
return fmt.Sprintf("%s: %s", e.ErrorCode.String(), e.ErrorMessage)
}
// Timeout says if this error is a timeout.
func (e *QuicError) Timeout() bool {
switch e.ErrorCode {
case NetworkIdleTimeout,
......
......@@ -124,7 +124,7 @@ func (s *receiveStream) Read(p []byte) (int, error) {
} else {
select {
case <-s.readChan:
case <-time.After(deadline.Sub(time.Now())):
case <-time.After(time.Until(deadline)):
}
}
s.mutex.Lock()
......
......@@ -116,7 +116,7 @@ func (s *sendStream) Write(p []byte) (int, error) {
} else {
select {
case <-s.writeChan:
case <-time.After(deadline.Sub(time.Now())):
case <-time.After(time.Until(deadline)):
}
}
s.mutex.Lock()
......
......@@ -4,6 +4,7 @@ import (
"bytes"
"crypto/tls"
"errors"
"fmt"
"net"
"sync"
"time"
......@@ -85,9 +86,12 @@ func Listen(conn net.PacketConn, tlsConf *tls.Config, config *Config) (Listener,
}
config = populateServerConfig(config)
// check if any of the supported versions supports TLS
var supportsTLS bool
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() {
supportsTLS = true
break
......@@ -136,10 +140,11 @@ func (s *server) setupTLS() error {
case tlsSession := <-sessionChan:
connID := tlsSession.connID
sess := tlsSession.sess
s.sessionsMutex.Lock()
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.sessionsMutex.Unlock()
s.runHandshakeAndSession(sess, connID)
......@@ -198,6 +203,18 @@ func populateServerConfig(config *Config) *Config {
if maxReceiveConnectionFlowControlWindow == 0 {
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{
Versions: versions,
......@@ -207,13 +224,15 @@ func populateServerConfig(config *Config) *Config {
KeepAlive: config.KeepAlive,
MaxReceiveStreamFlowControlWindow: maxReceiveStreamFlowControlWindow,
MaxReceiveConnectionFlowControlWindow: maxReceiveConnectionFlowControlWindow,
MaxIncomingStreams: maxIncomingStreams,
MaxIncomingUniStreams: maxIncomingUniStreams,
}
}
// serve listens on an existing PacketConn
func (s *server) serve() {
for {
data := getPacketBuffer()
data := *getPacketBuffer()
data = data[:protocol.MaxReceivePacketSize]
// The packet size should not exceed protocol.MaxReceivePacketSize bytes
// 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
var pr *wire.PublicReset
pr, err = wire.ParsePublicReset(r)
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 {
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 {
config *Config
supportedVersions []protocol.VersionNumber
mintConf *mint.Config
cookieProtector mint.CookieProtector
params *handshake.TransportParameters
newMintConn func(*handshake.CryptoStreamConn, protocol.VersionNumber) (handshake.MintTLS, <-chan handshake.TransportParameters, error)
......@@ -72,9 +71,8 @@ func newServerTLS(
StreamFlowControlWindow: protocol.ReceiveStreamFlowControlWindow,
ConnectionFlowControlWindow: protocol.ReceiveConnectionFlowControlWindow,
IdleTimeout: config.IdleTimeout,
// TODO(#523): make these values configurable
MaxBidiStreamID: protocol.MaxBidiStreamID(protocol.MaxIncomingStreams, protocol.PerspectiveServer),
MaxUniStreamID: protocol.MaxUniStreamID(protocol.MaxIncomingStreams, protocol.PerspectiveServer),
MaxBidiStreams: uint16(config.MaxIncomingStreams),
MaxUniStreams: uint16(config.MaxIncomingUniStreams),
},
}
s.newMintConn = s.newMintConnImpl
......@@ -85,7 +83,7 @@ func (s *serverTLS) HandleInitial(remoteAddr net.Addr, hdr *wire.Header, data []
utils.Debugf("Received a Packet. Handling it statelessly.")
sess, err := s.handleInitialImpl(remoteAddr, hdr, data)
if err != nil {
utils.Errorf("Error occured handling initial packet: %s", err)
utils.Errorf("Error occurred handling initial packet: %s", err)
return
}
if sess == nil { // a stateless reset was done
......@@ -132,7 +130,7 @@ func (s *serverTLS) handleInitialImpl(remoteAddr net.Addr, hdr *wire.Header, dat
// check version, if not matching send VNP
if !protocol.IsSupportedVersion(s.supportedVersions, 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
}
......@@ -149,7 +147,7 @@ func (s *serverTLS) handleInitialImpl(remoteAddr net.Addr, hdr *wire.Header, dat
sess, err := s.handleUnpackedInitial(remoteAddr, hdr, frame, aead)
if err != 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
}
......
......@@ -33,8 +33,11 @@ type streamManager interface {
GetOrOpenSendStream(protocol.StreamID) (sendStreamI, error)
GetOrOpenReceiveStream(protocol.StreamID) (receiveStreamI, error)
OpenStream() (Stream, error)
OpenUniStream() (SendStream, error)
OpenStreamSync() (Stream, error)
OpenUniStreamSync() (SendStream, error)
AcceptStream() (Stream, error)
AcceptUniStream() (ReceiveStream, error)
DeleteStream(protocol.StreamID) error
UpdateLimits(*handshake.TransportParameters)
HandleMaxStreamIDFrame(*wire.MaxStreamIDFrame) error
......@@ -108,7 +111,9 @@ type session struct {
handshakeChan chan error
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
// representation, and sent back in public reset packets
largestRcvdPacketNumber protocol.PacketNumber
......@@ -153,7 +158,7 @@ func newSession(
transportParams := &handshake.TransportParameters{
StreamFlowControlWindow: protocol.ReceiveStreamFlowControlWindow,
ConnectionFlowControlWindow: protocol.ReceiveConnectionFlowControlWindow,
MaxStreams: protocol.MaxIncomingStreams,
MaxStreams: uint32(s.config.MaxIncomingStreams),
IdleTimeout: s.config.IdleTimeout,
}
cs, err := newCryptoSetup(
......@@ -184,7 +189,7 @@ var newClientSession = func(
tlsConf *tls.Config,
config *Config,
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) {
paramsChan := make(chan handshake.TransportParameters)
handshakeEvent := make(chan struct{}, 1)
......@@ -201,7 +206,7 @@ var newClientSession = func(
transportParams := &handshake.TransportParameters{
StreamFlowControlWindow: protocol.ReceiveStreamFlowControlWindow,
ConnectionFlowControlWindow: protocol.ReceiveConnectionFlowControlWindow,
MaxStreams: protocol.MaxIncomingStreams,
MaxStreams: uint32(s.config.MaxIncomingStreams),
IdleTimeout: s.config.IdleTimeout,
OmitConnectionID: s.config.RequestConnectionIDOmission,
}
......@@ -323,16 +328,18 @@ func (s *session) postSetup(initialPacketNumber protocol.PacketNumber) error {
s.sessionCreationTime = now
s.sentPacketHandler = ackhandler.NewSentPacketHandler(s.rttStats)
s.receivedPacketHandler = ackhandler.NewReceivedPacketHandler(s.version)
s.receivedPacketHandler = ackhandler.NewReceivedPacketHandler(s.rttStats, s.version)
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 {
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.packer = newPacketPacker(s.connectionID,
initialPacketNumber,
s.sentPacketHandler.GetPacketNumberLen,
s.RemoteAddr(),
s.cryptoSetup,
s.streamFramer,
s.perspective,
......@@ -390,14 +397,13 @@ runLoop:
}
// This is a bit unclean, but works properly, since the packet always
// begins with the public header and we never copy it.
putPacketBuffer(p.header.Raw)
putPacketBuffer(&p.header.Raw)
case p := <-s.paramsChan:
s.processTransportParameters(&p)
case _, ok := <-handshakeEvent:
if !ok { // the aeadChanged chan was closed. This means that the handshake is completed.
s.handshakeComplete = true
handshakeEvent = nil // prevent this case from ever being selected again
s.sentPacketHandler.SetHandshakeComplete()
if !s.version.UsesTLS() && s.perspective == protocol.PerspectiveClient {
// 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.
......@@ -412,9 +418,11 @@ runLoop:
now := time.Now()
if timeout := s.sentPacketHandler.GetAlarmTimeout(); !timeout.IsZero() && timeout.Before(now) {
// This could cause packets to be retransmitted, so check it before trying
// to send packets.
s.sentPacketHandler.OnAlarm()
// This could cause packets to be retransmitted.
// Check it before trying to send packets.
if err := s.sentPacketHandler.OnAlarm(); err != nil {
s.closeLocal(err)
}
}
var pacingDeadline time.Time
......@@ -506,6 +514,7 @@ func (s *session) handlePacketImpl(p *receivedPacket) error {
p.rcvTime = time.Now()
}
s.receivedFirstPacket = true
s.lastNetworkActivityTime = p.rcvTime
s.keepAlivePingSent = false
hdr := p.header
......@@ -532,13 +541,26 @@ func (s *session) handlePacketImpl(p *receivedPacket) error {
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
// Only do this after decrypting, so we are sure the packet is not attacker-controlled
s.largestRcvdPacketNumber = utils.MaxPacketNumber(s.largestRcvdPacketNumber, hdr.PacketNumber)
isRetransmittable := ackhandler.HasRetransmittableFrames(packet.frames)
if err = s.receivedPacketHandler.ReceivedPacket(hdr.PacketNumber, p.rcvTime, isRetransmittable); err != nil {
return err
// If this is a Retry packet, there's no need to send an ACK.
// The session will be closed and recreated as soon as the crypto setup processed the HRR.
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)
......@@ -577,12 +599,7 @@ func (s *session) handleFrames(fs []wire.Frame, encLevel protocol.EncryptionLeve
}
if err != nil {
switch err {
case ackhandler.ErrDuplicateOrOutOfOrderAck:
// Can happen e.g. when packets thought missing arrive late
default:
return err
}
return err
}
}
return nil
......@@ -744,6 +761,9 @@ func (s *session) processTransportParameters(params *handshake.TransportParamete
if params.OmitConnectionID {
s.packer.SetOmitConnectionID()
}
if params.MaxPacketSize != 0 {
s.packer.SetMaxPacketSize(params.MaxPacketSize)
}
s.connFlowController.UpdateSendWindow(params.ConnectionFlowControlWindow)
// the crypto stream is the only open stream at this moment
// so we don't need to update stream flow control windows
......@@ -751,23 +771,56 @@ func (s *session) processTransportParameters(params *handshake.TransportParamete
func (s *session) sendPackets() error {
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()
for i := 0; i < numPackets; i++ {
sentPacket, err := s.sendPacket()
if err != nil {
return err
var numPacketsSent int
sendLoop:
for {
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 !sentPacket || !s.sentPacketHandler.SendingAllowed() {
return nil
if numPacketsSent >= numPackets {
break
}
sendMode = s.sentPacketHandler.SendMode()
}
// 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.
s.pacingDeadline = s.sentPacketHandler.TimeUntilSend()
if numPacketsSent == numPackets {
s.pacingDeadline = s.sentPacketHandler.TimeUntilSend()
}
return nil
}
......@@ -778,7 +831,7 @@ func (s *session) maybeSendAckOnlyPacket() error {
}
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 {
s.packer.QueueControlFrame(swf)
}
......@@ -787,12 +840,57 @@ func (s *session) maybeSendAckOnlyPacket() error {
if err != nil {
return err
}
s.sentPacketHandler.SentPacket(packet.ToAckHandlerPacket())
return s.sendPackedPacket(packet)
}
func (s *session) sendPacket() (bool, error) {
s.packer.SetLeastUnacked(s.sentPacketHandler.GetLeastUnacked())
// maybeSendRetransmission sends retransmissions for at most one packet.
// 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 {
s.packer.QueueControlFrame(&wire.MaxDataFrame{ByteOffset: offset})
}
......@@ -801,58 +899,20 @@ func (s *session) sendPacket() (bool, error) {
}
s.windowUpdateQueue.QueueAll()
ack := s.receivedPacketHandler.GetAckFrame()
if ack != nil {
if ack := s.receivedPacketHandler.GetAckFrame(); ack != nil {
s.packer.QueueControlFrame(ack)
}
// check for retransmissions first
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)
if s.version.UsesStopWaitingFrames() {
if swf := s.sentPacketHandler.GetStopWaitingFrame(false); swf != nil {
s.packer.QueueControlFrame(swf)
}
}
}
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()
if err != nil || packet == nil {
return false, err
}
s.sentPacketHandler.SentPacket(packet.ToAckHandlerPacket())
if err := s.sendPackedPacket(packet); err != nil {
return false, err
}
......@@ -860,22 +920,12 @@ func (s *session) sendPacket() (bool, error) {
}
func (s *session) sendPackedPacket(packet *packedPacket) error {
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
}
defer putPacketBuffer(&packet.raw)
s.logPacket(packet)
return s.conn.Write(packet.raw)
}
func (s *session) sendConnectionClose(quicErr *qerr.QuicError) error {
s.packer.SetLeastUnacked(s.sentPacketHandler.GetLeastUnacked())
packet, err := s.packer.PackConnectionClose(&wire.ConnectionCloseFrame{
ErrorCode: quicErr.ErrorCode,
ReasonPhrase: quicErr.ErrorMessage,
......@@ -919,6 +969,10 @@ func (s *session) AcceptStream() (Stream, error) {
return s.streamsMap.AcceptStream()
}
func (s *session) AcceptUniStream() (ReceiveStream, error) {
return s.streamsMap.AcceptUniStream()
}
// OpenStream opens a stream
func (s *session) OpenStream() (Stream, error) {
return s.streamsMap.OpenStream()
......@@ -928,6 +982,14 @@ func (s *session) OpenStreamSync() (Stream, error) {
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 {
flowController := s.newFlowController(id)
return newStream(id, s, flowController, s.version)
......@@ -1026,7 +1088,6 @@ func (s *session) LocalAddr() net.Addr {
return s.conn.LocalAddr()
}
// RemoteAddr returns the net.Addr of the client
func (s *session) RemoteAddr() net.Addr {
return s.conn.RemoteAddr()
}
......
......@@ -12,8 +12,6 @@ type streamFramer struct {
cryptoStream cryptoStreamI
version protocol.VersionNumber
retransmissionQueue []*wire.StreamFrame
streamQueueMutex sync.Mutex
activeStreams map[protocol.StreamID]struct{}
streamQueue []protocol.StreamID
......@@ -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) {
if id == f.version.CryptoStreamID() { // the crypto stream is handled separately
f.streamQueueMutex.Lock()
......@@ -52,15 +46,6 @@ func (f *streamFramer) AddActiveStream(id protocol.StreamID) {
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 {
f.streamQueueMutex.Lock()
hasCryptoStreamData := f.hasCryptoStreamData
......@@ -76,34 +61,7 @@ func (f *streamFramer) PopCryptoStreamFrame(maxLen protocol.ByteCount) *wire.Str
return frame
}
func (f *streamFramer) maybePopFramesForRetransmission(maxTotalLen protocol.ByteCount) (res []*wire.StreamFrame, currentLen protocol.ByteCount) {
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 {
func (f *streamFramer) PopStreamFrames(maxTotalLen protocol.ByteCount) []*wire.StreamFrame {
var currentLen protocol.ByteCount
var frames []*wire.StreamFrame
f.streamQueueMutex.Lock()
......
......@@ -35,6 +35,8 @@ var _ streamManager = &streamsMap{}
func newStreamsMap(
sender streamSender,
newFlowController func(protocol.StreamID) flowcontrol.StreamFlowController,
maxIncomingStreams int,
maxIncomingUniStreams int,
perspective protocol.Perspective,
version protocol.VersionNumber,
) streamManager {
......@@ -46,7 +48,7 @@ func newStreamsMap(
var firstOutgoingBidiStream, firstOutgoingUniStream, firstIncomingBidiStream, firstIncomingUniStream protocol.StreamID
if perspective == protocol.PerspectiveServer {
firstOutgoingBidiStream = 1
firstIncomingBidiStream = 4 // the crypto stream is handled separatedly
firstIncomingBidiStream = 4 // the crypto stream is handled separately
firstOutgoingUniStream = 3
firstIncomingUniStream = 2
} else {
......@@ -69,11 +71,10 @@ func newStreamsMap(
newBidiStream,
sender.queueControlFrame,
)
// TODO(#523): make these values configurable
m.incomingBidiStreams = newIncomingBidiStreamsMap(
firstIncomingBidiStream,
protocol.MaxBidiStreamID(protocol.MaxIncomingStreams, perspective),
protocol.MaxIncomingStreams,
protocol.MaxBidiStreamID(maxIncomingStreams, perspective),
maxIncomingStreams,
sender.queueControlFrame,
newBidiStream,
)
......@@ -82,11 +83,10 @@ func newStreamsMap(
newUniSendStream,
sender.queueControlFrame,
)
// TODO(#523): make these values configurable
m.incomingUniStreams = newIncomingUniStreamsMap(
firstIncomingUniStream,
protocol.MaxUniStreamID(protocol.MaxIncomingStreams, perspective),
protocol.MaxIncomingStreams,
protocol.MaxUniStreamID(maxIncomingUniStreams, perspective),
maxIncomingUniStreams,
sender.queueControlFrame,
newUniReceiveStream,
)
......@@ -206,8 +206,14 @@ func (m *streamsMap) HandleMaxStreamIDFrame(f *wire.MaxStreamIDFrame) error {
}
func (m *streamsMap) UpdateLimits(p *handshake.TransportParameters) {
m.outgoingBidiStreams.SetMaxStream(p.MaxBidiStreamID)
m.outgoingUniStreams.SetMaxStream(p.MaxUniStreamID)
// Max{Uni,Bidi}StreamID returns the highest stream ID that the peer is allowed to open.
// 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) {
......
......@@ -69,20 +69,25 @@ func (m *incomingBidiStreamsMap) AcceptStream() (streamI, error) {
}
func (m *incomingBidiStreamsMap) GetOrOpenStream(id protocol.StreamID) (streamI, error) {
m.mutex.RLock()
if id > m.maxStream {
m.mutex.RUnlock()
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
// * this stream exists in the map, and we can return it, or
// * this stream was already closed, then we can return the nil
if id <= m.highestStream {
m.mutex.RLock()
s := m.streams[id]
m.mutex.RUnlock()
return s, nil
}
m.mutex.RUnlock()
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
if m.highestStream == 0 {
start = m.nextStream
......
......@@ -67,20 +67,25 @@ func (m *incomingItemsMap) AcceptStream() (item, error) {
}
func (m *incomingItemsMap) GetOrOpenStream(id protocol.StreamID) (item, error) {
m.mutex.RLock()
if id > m.maxStream {
m.mutex.RUnlock()
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
// * this stream exists in the map, and we can return it, or
// * this stream was already closed, then we can return the nil
if id <= m.highestStream {
m.mutex.RLock()
s := m.streams[id]
m.mutex.RUnlock()
return s, nil
}
m.mutex.RUnlock()
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
if m.highestStream == 0 {
start = m.nextStream
......
......@@ -69,20 +69,25 @@ func (m *incomingUniStreamsMap) AcceptStream() (receiveStreamI, error) {
}
func (m *incomingUniStreamsMap) GetOrOpenStream(id protocol.StreamID) (receiveStreamI, error) {
m.mutex.RLock()
if id > m.maxStream {
m.mutex.RUnlock()
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
// * this stream exists in the map, and we can return it, or
// * this stream was already closed, then we can return the nil
if id <= m.highestStream {
m.mutex.RLock()
s := m.streams[id]
m.mutex.RUnlock()
return s, nil
}
m.mutex.RUnlock()
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
if m.highestStream == 0 {
start = m.nextStream
......
......@@ -39,11 +39,10 @@ var _ streamManager = &streamsMapLegacy{}
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
maxStreams := uint32(protocol.MaxIncomingStreams)
maxIncomingStreams := utils.MaxUint32(
maxStreams+protocol.MaxStreamsMinimumIncrement,
uint32(maxStreams)+protocol.MaxStreamsMinimumIncrement,
uint32(float64(maxStreams)*float64(protocol.MaxStreamsMultiplier)),
)
sm := streamsMapLegacy{
......@@ -131,7 +130,10 @@ func (m *streamsMapLegacy) openRemoteStream(id protocol.StreamID) (streamI, erro
if m.numIncomingStreams >= m.maxIncomingStreams {
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))
}
......@@ -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
// it blocks until a new stream is opened
func (m *streamsMapLegacy) AcceptStream() (Stream, error) {
......@@ -206,6 +216,10 @@ func (m *streamsMapLegacy) AcceptStream() (Stream, error) {
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 {
m.mutex.Lock()
defer m.mutex.Unlock()
......
......@@ -85,10 +85,11 @@ func (m *outgoingBidiStreamsMap) openStreamImpl() (streamI, error) {
}
func (m *outgoingBidiStreamsMap) GetStream(id protocol.StreamID) (streamI, error) {
m.mutex.RLock()
if id >= m.nextStream {
m.mutex.RUnlock()
return nil, qerr.Error(qerr.InvalidStreamID, fmt.Sprintf("peer attempted to open stream %d", id))
}
m.mutex.RLock()
s := m.streams[id]
m.mutex.RUnlock()
return s, nil
......
......@@ -86,10 +86,11 @@ func (m *outgoingItemsMap) openStreamImpl() (item, error) {
}
func (m *outgoingItemsMap) GetStream(id protocol.StreamID) (item, error) {
m.mutex.RLock()
if id >= m.nextStream {
m.mutex.RUnlock()
return nil, qerr.Error(qerr.InvalidStreamID, fmt.Sprintf("peer attempted to open stream %d", id))
}
m.mutex.RLock()
s := m.streams[id]
m.mutex.RUnlock()
return s, nil
......
......@@ -85,10 +85,11 @@ func (m *outgoingUniStreamsMap) openStreamImpl() (sendStreamI, error) {
}
func (m *outgoingUniStreamsMap) GetStream(id protocol.StreamID) (sendStreamI, error) {
m.mutex.RLock()
if id >= m.nextStream {
m.mutex.RUnlock()
return nil, qerr.Error(qerr.InvalidStreamID, fmt.Sprintf("peer attempted to open stream %d", id))
}
m.mutex.RLock()
s := m.streams[id]
m.mutex.RUnlock()
return s, nil
......
......@@ -50,7 +50,7 @@ import (
// WAIT_FINISHED RekeyIn; [Send(EOED);] RekeyOut; [SendCert; SendCV;] SendFin; RekeyOut;
// CONNECTED StoreTicket || (RekeyIn; [RekeyOut])
type ClientStateStart struct {
type clientStateStart struct {
Config *Config
Opts ConnectionOptions
Params ConnectionParameters
......@@ -61,13 +61,13 @@ type ClientStateStart struct {
hsCtx HandshakeContext
}
var _ HandshakeState = &ClientStateStart{}
var _ HandshakeState = &clientStateStart{}
func (state ClientStateStart) State() State {
func (state clientStateStart) State() State {
return StateClientStart
}
func (state ClientStateStart) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) {
func (state clientStateStart) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) {
// key_shares
offeredDH := map[NamedGroup][]byte{}
ks := KeyShareExtension{
......@@ -268,7 +268,7 @@ func (state ClientStateStart) Next(hr handshakeMessageReader) (HandshakeState, [
logf(logTypeHandshake, "[ClientStateStart] -> [ClientStateWaitSH]")
state.hsCtx.SetVersion(tls12Version) // Everything after this should be 1.2.
nextState := ClientStateWaitSH{
nextState := clientStateWaitSH{
Config: state.Config,
Opts: state.Opts,
Params: state.Params,
......@@ -298,7 +298,7 @@ func (state ClientStateStart) Next(hr handshakeMessageReader) (HandshakeState, [
return nextState, toSend, AlertNoAlert
}
type ClientStateWaitSH struct {
type clientStateWaitSH struct {
Config *Config
Opts ConnectionOptions
Params ConnectionParameters
......@@ -315,13 +315,13 @@ type ClientStateWaitSH struct {
clientHello *HandshakeMessage
}
var _ HandshakeState = &ClientStateWaitSH{}
var _ HandshakeState = &clientStateWaitSH{}
func (state ClientStateWaitSH) State() State {
func (state clientStateWaitSH) State() State {
return StateClientWaitSH
}
func (state ClientStateWaitSH) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) {
func (state clientStateWaitSH) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) {
hm, alert := hr.ReadMessage()
if alert != AlertNoAlert {
return nil, nil, alert
......@@ -413,7 +413,7 @@ func (state ClientStateWaitSH) Next(hr handshakeMessageReader) (HandshakeState,
}
logf(logTypeHandshake, "[ClientStateWaitSH] -> [ClientStateStart]")
return ClientStateStart{
return clientStateStart{
Config: state.Config,
Opts: state.Opts,
hsCtx: state.hsCtx,
......@@ -517,7 +517,7 @@ func (state ClientStateWaitSH) Next(hr handshakeMessageReader) (HandshakeState,
serverHandshakeKeys := makeTrafficKeys(params, serverHandshakeTrafficSecret)
logf(logTypeHandshake, "[ClientStateWaitSH] -> [ClientStateWaitEE]")
nextState := ClientStateWaitEE{
nextState := clientStateWaitEE{
Config: state.Config,
Params: state.Params,
hsCtx: state.hsCtx,
......@@ -533,7 +533,7 @@ func (state ClientStateWaitSH) Next(hr handshakeMessageReader) (HandshakeState,
return nextState, toSend, AlertNoAlert
}
type ClientStateWaitEE struct {
type clientStateWaitEE struct {
Config *Config
Params ConnectionParameters
hsCtx HandshakeContext
......@@ -544,13 +544,13 @@ type ClientStateWaitEE struct {
serverHandshakeTrafficSecret []byte
}
var _ HandshakeState = &ClientStateWaitEE{}
var _ HandshakeState = &clientStateWaitEE{}
func (state ClientStateWaitEE) State() State {
func (state clientStateWaitEE) State() State {
return StateClientWaitEE
}
func (state ClientStateWaitEE) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) {
func (state clientStateWaitEE) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) {
hm, alert := hr.ReadMessage()
if alert != AlertNoAlert {
return nil, nil, alert
......@@ -598,7 +598,7 @@ func (state ClientStateWaitEE) Next(hr handshakeMessageReader) (HandshakeState,
if state.Params.UsingPSK {
logf(logTypeHandshake, "[ClientStateWaitEE] -> [ClientStateWaitFinished]")
nextState := ClientStateWaitFinished{
nextState := clientStateWaitFinished{
Params: state.Params,
hsCtx: state.hsCtx,
cryptoParams: state.cryptoParams,
......@@ -612,7 +612,7 @@ func (state ClientStateWaitEE) Next(hr handshakeMessageReader) (HandshakeState,
}
logf(logTypeHandshake, "[ClientStateWaitEE] -> [ClientStateWaitCertCR]")
nextState := ClientStateWaitCertCR{
nextState := clientStateWaitCertCR{
Config: state.Config,
Params: state.Params,
hsCtx: state.hsCtx,
......@@ -625,7 +625,7 @@ func (state ClientStateWaitEE) Next(hr handshakeMessageReader) (HandshakeState,
return nextState, nil, AlertNoAlert
}
type ClientStateWaitCertCR struct {
type clientStateWaitCertCR struct {
Config *Config
Params ConnectionParameters
hsCtx HandshakeContext
......@@ -636,13 +636,13 @@ type ClientStateWaitCertCR struct {
serverHandshakeTrafficSecret []byte
}
var _ HandshakeState = &ClientStateWaitCertCR{}
var _ HandshakeState = &clientStateWaitCertCR{}
func (state ClientStateWaitCertCR) State() State {
func (state clientStateWaitCertCR) State() State {
return StateClientWaitCertCR
}
func (state ClientStateWaitCertCR) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) {
func (state clientStateWaitCertCR) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) {
hm, alert := hr.ReadMessage()
if alert != AlertNoAlert {
return nil, nil, alert
......@@ -663,7 +663,7 @@ func (state ClientStateWaitCertCR) Next(hr handshakeMessageReader) (HandshakeSta
switch body := bodyGeneric.(type) {
case *CertificateBody:
logf(logTypeHandshake, "[ClientStateWaitCertCR] -> [ClientStateWaitCV]")
nextState := ClientStateWaitCV{
nextState := clientStateWaitCV{
Config: state.Config,
Params: state.Params,
hsCtx: state.hsCtx,
......@@ -686,7 +686,7 @@ func (state ClientStateWaitCertCR) Next(hr handshakeMessageReader) (HandshakeSta
state.Params.UsingClientAuth = true
logf(logTypeHandshake, "[ClientStateWaitCertCR] -> [ClientStateWaitCert]")
nextState := ClientStateWaitCert{
nextState := clientStateWaitCert{
Config: state.Config,
Params: state.Params,
hsCtx: state.hsCtx,
......@@ -703,7 +703,7 @@ func (state ClientStateWaitCertCR) Next(hr handshakeMessageReader) (HandshakeSta
return nil, nil, AlertUnexpectedMessage
}
type ClientStateWaitCert struct {
type clientStateWaitCert struct {
Config *Config
Params ConnectionParameters
hsCtx HandshakeContext
......@@ -717,13 +717,13 @@ type ClientStateWaitCert struct {
serverHandshakeTrafficSecret []byte
}
var _ HandshakeState = &ClientStateWaitCert{}
var _ HandshakeState = &clientStateWaitCert{}
func (state ClientStateWaitCert) State() State {
func (state clientStateWaitCert) State() State {
return StateClientWaitCert
}
func (state ClientStateWaitCert) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) {
func (state clientStateWaitCert) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) {
hm, alert := hr.ReadMessage()
if alert != AlertNoAlert {
return nil, nil, alert
......@@ -742,7 +742,7 @@ func (state ClientStateWaitCert) Next(hr handshakeMessageReader) (HandshakeState
state.handshakeHash.Write(hm.Marshal())
logf(logTypeHandshake, "[ClientStateWaitCert] -> [ClientStateWaitCV]")
nextState := ClientStateWaitCV{
nextState := clientStateWaitCV{
Config: state.Config,
Params: state.Params,
hsCtx: state.hsCtx,
......@@ -757,7 +757,7 @@ func (state ClientStateWaitCert) Next(hr handshakeMessageReader) (HandshakeState
return nextState, nil, AlertNoAlert
}
type ClientStateWaitCV struct {
type clientStateWaitCV struct {
Config *Config
Params ConnectionParameters
hsCtx HandshakeContext
......@@ -772,13 +772,13 @@ type ClientStateWaitCV struct {
serverHandshakeTrafficSecret []byte
}
var _ HandshakeState = &ClientStateWaitCV{}
var _ HandshakeState = &clientStateWaitCV{}
func (state ClientStateWaitCV) State() State {
func (state clientStateWaitCV) State() State {
return StateClientWaitCV
}
func (state ClientStateWaitCV) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) {
func (state clientStateWaitCV) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) {
hm, alert := hr.ReadMessage()
if alert != AlertNoAlert {
return nil, nil, alert
......@@ -843,7 +843,7 @@ func (state ClientStateWaitCV) Next(hr handshakeMessageReader) (HandshakeState,
state.handshakeHash.Write(hm.Marshal())
logf(logTypeHandshake, "[ClientStateWaitCV] -> [ClientStateWaitFinished]")
nextState := ClientStateWaitFinished{
nextState := clientStateWaitFinished{
Params: state.Params,
hsCtx: state.hsCtx,
cryptoParams: state.cryptoParams,
......@@ -859,7 +859,7 @@ func (state ClientStateWaitCV) Next(hr handshakeMessageReader) (HandshakeState,
return nextState, nil, AlertNoAlert
}
type ClientStateWaitFinished struct {
type clientStateWaitFinished struct {
Params ConnectionParameters
hsCtx HandshakeContext
cryptoParams CipherSuiteParams
......@@ -875,13 +875,13 @@ type ClientStateWaitFinished struct {
serverHandshakeTrafficSecret []byte
}
var _ HandshakeState = &ClientStateWaitFinished{}
var _ HandshakeState = &clientStateWaitFinished{}
func (state ClientStateWaitFinished) State() State {
func (state clientStateWaitFinished) State() State {
return StateClientWaitFinished
}
func (state ClientStateWaitFinished) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) {
func (state clientStateWaitFinished) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) {
hm, alert := hr.ReadMessage()
if alert != AlertNoAlert {
return nil, nil, alert
......@@ -1046,7 +1046,7 @@ func (state ClientStateWaitFinished) Next(hr handshakeMessageReader) (HandshakeS
}...)
logf(logTypeHandshake, "[ClientStateWaitFinished] -> [StateConnected]")
nextState := StateConnected{
nextState := stateConnected{
Params: state.Params,
hsCtx: state.hsCtx,
isClient: true,
......
......@@ -201,6 +201,8 @@ func (s State) String() string {
return "Client WAIT_CV"
case StateClientWaitFinished:
return "Client WAIT_FINISHED"
case StateClientWaitCertCR:
return "Client WAIT_CERT_CR"
case StateClientConnected:
return "Client CONNECTED"
case StateServerStart:
......
......@@ -265,7 +265,7 @@ type Conn struct {
EarlyData []byte
state StateConnected
state stateConnected
hState HandshakeState
handshakeMutex sync.Mutex
handshakeAlert Alert
......@@ -345,7 +345,7 @@ func (c *Conn) consumeRecord() error {
}
var connected bool
c.state, connected = state.(StateConnected)
c.state, connected = state.(stateConnected)
if !connected {
logf(logTypeHandshake, "Disconnected after state transition: %v", alert)
c.sendAlert(alert)
......@@ -385,7 +385,7 @@ func (c *Conn) consumeRecord() error {
// Read application data up to the size of buffer. Handshake and alert records
// are consumed by the Conn object directly.
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")
}
logf(logTypeHandshake, "conn.Read with buffer = %d", len(buffer))
......@@ -661,7 +661,7 @@ func (c *Conn) HandshakeSetup() Alert {
}
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 {
logf(logTypeHandshake, "Error initializing client state: %v", alert)
return alert
......@@ -688,7 +688,7 @@ func (c *Conn) HandshakeSetup() Alert {
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
......@@ -751,7 +751,7 @@ func (c *Conn) Handshake() Alert {
logf(logTypeHandshake, "(Re-)entering handshake, state=%v", c.hState)
state := c.hState
_, connected := state.(StateConnected)
_, connected := state.(stateConnected)
hmr := &handshakeMessageReaderImpl{hsCtx: &c.hsCtx}
for !connected {
......@@ -784,9 +784,9 @@ func (c *Conn) Handshake() Alert {
c.hState = state
logf(logTypeHandshake, "state is now %s", c.GetHsState())
_, connected = state.(StateConnected)
_, connected = state.(stateConnected)
if connected {
c.state = state.(StateConnected)
c.state = state.(stateConnected)
c.handshakeComplete = true
}
......@@ -852,7 +852,7 @@ func (c *Conn) GetHsState() State {
}
func (c *Conn) ComputeExporter(label string, context []byte, keyLength int) ([]byte, error) {
_, connected := c.hState.(StateConnected)
_, connected := c.hState.(stateConnected)
if !connected {
return nil, fmt.Errorf("Cannot compute exporter when state is not connected")
}
......
......@@ -11,9 +11,11 @@ import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"encoding/asn1"
"fmt"
"math/big"
"time"
"golang.org/x/crypto/curve25519"
......@@ -616,3 +618,50 @@ func makeTrafficKeys(params CipherSuiteParams, secret []byte) keySet {
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 {
ApplicationCookie []byte `tls:"head=2"`
}
type ServerStateStart struct {
type serverStateStart struct {
Config *Config
conn *Conn
hsCtx HandshakeContext
}
var _ HandshakeState = &ServerStateStart{}
var _ HandshakeState = &serverStateStart{}
func (state ServerStateStart) State() State {
func (state serverStateStart) State() State {
return StateServerStart
}
func (state ServerStateStart) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) {
func (state serverStateStart) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) {
hm, alert := hr.ReadMessage()
if alert != AlertNoAlert {
return nil, nil, alert
......@@ -381,7 +381,7 @@ func (state ServerStateStart) Next(hr handshakeMessageReader) (HandshakeState, [
logf(logTypeHandshake, "[ServerStateStart] -> [ServerStateNegotiated]")
state.hsCtx.SetVersion(tls12Version) // Everything after this should be 1.2.
return ServerStateNegotiated{
return serverStateNegotiated{
Config: state.Config,
Params: connParams,
hsCtx: state.hsCtx,
......@@ -401,7 +401,7 @@ func (state ServerStateStart) Next(hr handshakeMessageReader) (HandshakeState, [
}, nil, AlertNoAlert
}
func (state *ServerStateStart) generateHRR(cs CipherSuite, legacySessionId []byte,
func (state *serverStateStart) generateHRR(cs CipherSuite, legacySessionId []byte,
cookieExt *CookieExtension) (*HandshakeMessage, error) {
var helloRetryRequest *HandshakeMessage
hrr := &ServerHelloBody{
......@@ -442,7 +442,7 @@ func (state *ServerStateStart) generateHRR(cs CipherSuite, legacySessionId []byt
return helloRetryRequest, nil
}
type ServerStateNegotiated struct {
type serverStateNegotiated struct {
Config *Config
Params ConnectionParameters
hsCtx HandshakeContext
......@@ -460,13 +460,13 @@ type ServerStateNegotiated struct {
clientHello *HandshakeMessage
}
var _ HandshakeState = &ServerStateNegotiated{}
var _ HandshakeState = &serverStateNegotiated{}
func (state ServerStateNegotiated) State() State {
func (state serverStateNegotiated) State() State {
return StateServerNegotiated
}
func (state ServerStateNegotiated) Next(_ handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) {
func (state serverStateNegotiated) Next(_ handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) {
// Create the ServerHello
sh := &ServerHelloBody{
Version: tls12Version,
......@@ -717,7 +717,7 @@ func (state ServerStateNegotiated) Next(_ handshakeMessageReader) (HandshakeStat
clientEarlyTrafficKeys := makeTrafficKeys(params, state.clientEarlyTrafficSecret)
logf(logTypeHandshake, "[ServerStateNegotiated] -> [ServerStateWaitEOED]")
nextState := ServerStateWaitEOED{
nextState := serverStateWaitEOED{
Config: state.Config,
Params: state.Params,
hsCtx: state.hsCtx,
......@@ -741,7 +741,7 @@ func (state ServerStateNegotiated) Next(_ handshakeMessageReader) (HandshakeStat
RekeyIn{epoch: EpochHandshakeData, KeySet: clientHandshakeKeys},
ReadPastEarlyData{},
}...)
waitFlight2 := ServerStateWaitFlight2{
waitFlight2 := serverStateWaitFlight2{
Config: state.Config,
Params: state.Params,
hsCtx: state.hsCtx,
......@@ -756,7 +756,7 @@ func (state ServerStateNegotiated) Next(_ handshakeMessageReader) (HandshakeStat
return waitFlight2, toSend, AlertNoAlert
}
type ServerStateWaitEOED struct {
type serverStateWaitEOED struct {
Config *Config
Params ConnectionParameters
hsCtx HandshakeContext
......@@ -769,13 +769,13 @@ type ServerStateWaitEOED struct {
exporterSecret []byte
}
var _ HandshakeState = &ServerStateWaitEOED{}
var _ HandshakeState = &serverStateWaitEOED{}
func (state ServerStateWaitEOED) State() State {
func (state serverStateWaitEOED) State() State {
return StateServerWaitEOED
}
func (state ServerStateWaitEOED) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) {
func (state serverStateWaitEOED) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) {
hm, alert := hr.ReadMessage()
if alert != AlertNoAlert {
return nil, nil, alert
......@@ -798,7 +798,7 @@ func (state ServerStateWaitEOED) Next(hr handshakeMessageReader) (HandshakeState
toSend := []HandshakeAction{
RekeyIn{epoch: EpochHandshakeData, KeySet: clientHandshakeKeys},
}
waitFlight2 := ServerStateWaitFlight2{
waitFlight2 := serverStateWaitFlight2{
Config: state.Config,
Params: state.Params,
hsCtx: state.hsCtx,
......@@ -813,7 +813,7 @@ func (state ServerStateWaitEOED) Next(hr handshakeMessageReader) (HandshakeState
return waitFlight2, toSend, AlertNoAlert
}
type ServerStateWaitFlight2 struct {
type serverStateWaitFlight2 struct {
Config *Config
Params ConnectionParameters
hsCtx HandshakeContext
......@@ -826,16 +826,16 @@ type ServerStateWaitFlight2 struct {
exporterSecret []byte
}
var _ HandshakeState = &ServerStateWaitFlight2{}
var _ HandshakeState = &serverStateWaitFlight2{}
func (state ServerStateWaitFlight2) State() State {
func (state serverStateWaitFlight2) State() State {
return StateServerWaitFlight2
}
func (state ServerStateWaitFlight2) Next(_ handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) {
func (state serverStateWaitFlight2) Next(_ handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) {
if state.Params.UsingClientAuth {
logf(logTypeHandshake, "[ServerStateWaitFlight2] -> [ServerStateWaitCert]")
nextState := ServerStateWaitCert{
nextState := serverStateWaitCert{
Config: state.Config,
Params: state.Params,
hsCtx: state.hsCtx,
......@@ -851,7 +851,7 @@ func (state ServerStateWaitFlight2) Next(_ handshakeMessageReader) (HandshakeSta
}
logf(logTypeHandshake, "[ServerStateWaitFlight2] -> [ServerStateWaitFinished]")
nextState := ServerStateWaitFinished{
nextState := serverStateWaitFinished{
Params: state.Params,
hsCtx: state.hsCtx,
cryptoParams: state.cryptoParams,
......@@ -865,7 +865,7 @@ func (state ServerStateWaitFlight2) Next(_ handshakeMessageReader) (HandshakeSta
return nextState, nil, AlertNoAlert
}
type ServerStateWaitCert struct {
type serverStateWaitCert struct {
Config *Config
Params ConnectionParameters
hsCtx HandshakeContext
......@@ -878,13 +878,13 @@ type ServerStateWaitCert struct {
exporterSecret []byte
}
var _ HandshakeState = &ServerStateWaitCert{}
var _ HandshakeState = &serverStateWaitCert{}
func (state ServerStateWaitCert) State() State {
func (state serverStateWaitCert) State() State {
return StateServerWaitCert
}
func (state ServerStateWaitCert) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) {
func (state serverStateWaitCert) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) {
hm, alert := hr.ReadMessage()
if alert != AlertNoAlert {
return nil, nil, alert
......@@ -906,7 +906,7 @@ func (state ServerStateWaitCert) Next(hr handshakeMessageReader) (HandshakeState
logf(logTypeHandshake, "[ServerStateWaitCert] WARNING client did not provide a certificate")
logf(logTypeHandshake, "[ServerStateWaitCert] -> [ServerStateWaitFinished]")
nextState := ServerStateWaitFinished{
nextState := serverStateWaitFinished{
Params: state.Params,
hsCtx: state.hsCtx,
cryptoParams: state.cryptoParams,
......@@ -921,7 +921,7 @@ func (state ServerStateWaitCert) Next(hr handshakeMessageReader) (HandshakeState
}
logf(logTypeHandshake, "[ServerStateWaitCert] -> [ServerStateWaitCV]")
nextState := ServerStateWaitCV{
nextState := serverStateWaitCV{
Config: state.Config,
Params: state.Params,
hsCtx: state.hsCtx,
......@@ -937,7 +937,7 @@ func (state ServerStateWaitCert) Next(hr handshakeMessageReader) (HandshakeState
return nextState, nil, AlertNoAlert
}
type ServerStateWaitCV struct {
type serverStateWaitCV struct {
Config *Config
Params ConnectionParameters
hsCtx HandshakeContext
......@@ -954,13 +954,13 @@ type ServerStateWaitCV struct {
clientCertificate *CertificateBody
}
var _ HandshakeState = &ServerStateWaitCV{}
var _ HandshakeState = &serverStateWaitCV{}
func (state ServerStateWaitCV) State() State {
func (state serverStateWaitCV) State() State {
return StateServerWaitCV
}
func (state ServerStateWaitCV) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) {
func (state serverStateWaitCV) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) {
hm, alert := hr.ReadMessage()
if alert != AlertNoAlert {
return nil, nil, alert
......@@ -1005,7 +1005,7 @@ func (state ServerStateWaitCV) Next(hr handshakeMessageReader) (HandshakeState,
state.handshakeHash.Write(hm.Marshal())
logf(logTypeHandshake, "[ServerStateWaitCV] -> [ServerStateWaitFinished]")
nextState := ServerStateWaitFinished{
nextState := serverStateWaitFinished{
Params: state.Params,
hsCtx: state.hsCtx,
cryptoParams: state.cryptoParams,
......@@ -1021,7 +1021,7 @@ func (state ServerStateWaitCV) Next(hr handshakeMessageReader) (HandshakeState,
return nextState, nil, AlertNoAlert
}
type ServerStateWaitFinished struct {
type serverStateWaitFinished struct {
Params ConnectionParameters
hsCtx HandshakeContext
cryptoParams CipherSuiteParams
......@@ -1037,13 +1037,13 @@ type ServerStateWaitFinished struct {
exporterSecret []byte
}
var _ HandshakeState = &ServerStateWaitFinished{}
var _ HandshakeState = &serverStateWaitFinished{}
func (state ServerStateWaitFinished) State() State {
func (state serverStateWaitFinished) State() State {
return StateServerWaitFinished
}
func (state ServerStateWaitFinished) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) {
func (state serverStateWaitFinished) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) {
hm, alert := hr.ReadMessage()
if alert != AlertNoAlert {
return nil, nil, alert
......@@ -1083,7 +1083,7 @@ func (state ServerStateWaitFinished) Next(hr handshakeMessageReader) (HandshakeS
clientTrafficKeys := makeTrafficKeys(state.cryptoParams, state.clientTrafficSecret)
logf(logTypeHandshake, "[ServerStateWaitFinished] -> [StateConnected]")
nextState := StateConnected{
nextState := stateConnected{
Params: state.Params,
hsCtx: state.hsCtx,
isClient: false,
......
......@@ -81,8 +81,8 @@ func (hc *HandshakeContext) SetVersion(version uint16) {
}
}
// StateConnected is symmetric between client and server
type StateConnected struct {
// stateConnected is symmetric between client and server
type stateConnected struct {
Params ConnectionParameters
hsCtx HandshakeContext
isClient bool
......@@ -95,16 +95,16 @@ type StateConnected struct {
verifiedChains [][]*x509.Certificate
}
var _ HandshakeState = &StateConnected{}
var _ HandshakeState = &stateConnected{}
func (state StateConnected) State() State {
func (state stateConnected) State() State {
if state.isClient {
return StateClientConnected
}
return StateServerConnected
}
func (state *StateConnected) KeyUpdate(request KeyUpdateRequest) ([]HandshakeAction, Alert) {
func (state *stateConnected) KeyUpdate(request KeyUpdateRequest) ([]HandshakeAction, Alert) {
var trafficKeys keySet
if state.isClient {
state.clientTrafficSecret = HkdfExpandLabel(state.cryptoParams.Hash, state.clientTrafficSecret,
......@@ -130,7 +130,7 @@ func (state *StateConnected) KeyUpdate(request KeyUpdateRequest) ([]HandshakeAct
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)
if err != nil {
logf(logTypeHandshake, "[StateConnected] Error generating NewSessionTicket: %v", err)
......@@ -172,11 +172,11 @@ func (state *StateConnected) NewSessionTicket(length int, lifetime, earlyDataLif
}
// 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
}
func (state StateConnected) ProcessMessage(hm *HandshakeMessage) (HandshakeState, []HandshakeAction, Alert) {
func (state stateConnected) ProcessMessage(hm *HandshakeMessage) (HandshakeState, []HandshakeAction, Alert) {
if hm == nil {
logf(logTypeHandshake, "[StateConnected] Unexpected message")
return nil, nil, AlertUnexpectedMessage
......
......@@ -145,7 +145,7 @@
"importpath": "github.com/lucas-clemente/quic-go",
"repository": "https://github.com/lucas-clemente/quic-go",
"vcs": "git",
"revision": "d71850eb2ff581620f2f5742b558a97de22c13f6",
"revision": "9fa739409e6edddbbd47c8031cb7bb3d1a209cc8",
"branch": "master",
"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