2017-12-12 02:51:45 +00:00
package quic
import (
"bytes"
"errors"
"fmt"
"github.com/lucas-clemente/quic-go/ackhandler"
2018-01-03 19:19:49 +00:00
"github.com/lucas-clemente/quic-go/internal/handshake"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/wire"
2017-12-12 02:51:45 +00:00
)
type packedPacket struct {
2018-01-03 19:19:49 +00:00
header * wire . Header
2017-12-12 02:51:45 +00:00
raw [ ] byte
2018-01-03 19:19:49 +00:00
frames [ ] wire . Frame
2017-12-12 02:51:45 +00:00
encryptionLevel protocol . EncryptionLevel
}
type packetPacker struct {
connectionID protocol . ConnectionID
perspective protocol . Perspective
version protocol . VersionNumber
cryptoSetup handshake . CryptoSetup
packetNumberGenerator * packetNumberGenerator
2018-01-03 19:19:49 +00:00
streamFramer * streamFramer
controlFrames [ ] wire . Frame
stopWaiting * wire . StopWaitingFrame
ackFrame * wire . AckFrame
leastUnacked protocol . PacketNumber
omitConnectionID bool
hasSentPacket bool // has the packetPacker already sent a packet
2017-12-12 02:51:45 +00:00
}
2018-01-03 19:19:49 +00:00
func newPacketPacker ( connectionID protocol . ConnectionID ,
initialPacketNumber protocol . PacketNumber ,
cryptoSetup handshake . CryptoSetup ,
streamFramer * streamFramer ,
perspective protocol . Perspective ,
version protocol . VersionNumber ,
) * packetPacker {
2017-12-12 02:51:45 +00:00
return & packetPacker {
cryptoSetup : cryptoSetup ,
connectionID : connectionID ,
perspective : perspective ,
version : version ,
streamFramer : streamFramer ,
2018-01-03 19:19:49 +00:00
packetNumberGenerator : newPacketNumberGenerator ( initialPacketNumber , protocol . SkipPacketAveragePeriodLength ) ,
2017-12-12 02:51:45 +00:00
}
}
// PackConnectionClose packs a packet that ONLY contains a ConnectionCloseFrame
2018-01-03 19:19:49 +00:00
func ( p * packetPacker ) PackConnectionClose ( ccf * wire . ConnectionCloseFrame ) ( * packedPacket , error ) {
frames := [ ] wire . Frame { ccf }
encLevel , sealer := p . cryptoSetup . GetSealer ( )
header := p . getHeader ( encLevel )
raw , err := p . writeAndSealPacket ( header , frames , sealer )
return & packedPacket {
header : header ,
raw : raw ,
frames : frames ,
encryptionLevel : encLevel ,
} , err
2017-12-12 02:51:45 +00:00
}
2018-01-03 19:19:49 +00:00
func ( p * packetPacker ) PackAckPacket ( ) ( * packedPacket , error ) {
if p . ackFrame == nil {
return nil , errors . New ( "packet packer BUG: no ack frame queued" )
}
encLevel , sealer := p . cryptoSetup . GetSealer ( )
header := p . getHeader ( encLevel )
frames := [ ] wire . Frame { p . ackFrame }
if p . stopWaiting != nil {
p . stopWaiting . PacketNumber = header . PacketNumber
p . stopWaiting . PacketNumberLen = header . PacketNumberLen
frames = append ( frames , p . stopWaiting )
p . stopWaiting = nil
}
p . ackFrame = nil
raw , err := p . writeAndSealPacket ( header , frames , sealer )
return & packedPacket {
header : header ,
raw : raw ,
frames : frames ,
encryptionLevel : encLevel ,
} , err
}
// PackHandshakeRetransmission retransmits a handshake packet, that was sent with less than forward-secure encryption
func ( p * packetPacker ) PackHandshakeRetransmission ( packet * ackhandler . Packet ) ( * packedPacket , error ) {
2017-12-12 02:51:45 +00:00
if packet . EncryptionLevel == protocol . EncryptionForwardSecure {
return nil , errors . New ( "PacketPacker BUG: forward-secure encrypted handshake packets don't need special treatment" )
}
2018-01-03 19:19:49 +00:00
sealer , err := p . cryptoSetup . GetSealerWithEncryptionLevel ( packet . EncryptionLevel )
if err != nil {
return nil , err
}
if p . stopWaiting == nil {
2017-12-12 02:51:45 +00:00
return nil , errors . New ( "PacketPacker BUG: Handshake retransmissions must contain a StopWaitingFrame" )
}
2018-01-03 19:19:49 +00:00
header := p . getHeader ( packet . EncryptionLevel )
p . stopWaiting . PacketNumber = header . PacketNumber
p . stopWaiting . PacketNumberLen = header . PacketNumberLen
frames := append ( [ ] wire . Frame { p . stopWaiting } , packet . Frames ... )
p . stopWaiting = nil
raw , err := p . writeAndSealPacket ( header , frames , sealer )
return & packedPacket {
header : header ,
raw : raw ,
frames : frames ,
encryptionLevel : packet . EncryptionLevel ,
} , err
2017-12-12 02:51:45 +00:00
}
// PackPacket packs a new packet
// the other controlFrames are sent in the next packet, but might be queued and sent in the next packet if the packet would overflow MaxPacketSize otherwise
2018-01-03 19:19:49 +00:00
func ( p * packetPacker ) PackPacket ( ) ( * packedPacket , error ) {
hasCryptoStreamFrame := p . streamFramer . HasCryptoStreamFrame ( )
// if this is the first packet to be send, make sure it contains stream data
if ! p . hasSentPacket && ! hasCryptoStreamFrame {
return nil , nil
2017-12-12 02:51:45 +00:00
}
2018-01-03 19:19:49 +00:00
if hasCryptoStreamFrame {
return p . packCryptoPacket ( )
2017-12-12 02:51:45 +00:00
}
2018-01-03 19:19:49 +00:00
encLevel , sealer := p . cryptoSetup . GetSealer ( )
2017-12-12 02:51:45 +00:00
2018-01-03 19:19:49 +00:00
header := p . getHeader ( encLevel )
headerLength , err := header . GetLength ( p . perspective , p . version )
2017-12-12 02:51:45 +00:00
if err != nil {
return nil , err
}
2018-01-03 19:19:49 +00:00
if p . stopWaiting != nil {
p . stopWaiting . PacketNumber = header . PacketNumber
p . stopWaiting . PacketNumberLen = header . PacketNumberLen
2017-12-12 02:51:45 +00:00
}
2018-01-03 19:19:49 +00:00
maxSize := protocol . MaxPacketSize - protocol . ByteCount ( sealer . Overhead ( ) ) - headerLength
payloadFrames , err := p . composeNextPacket ( maxSize , p . canSendData ( encLevel ) )
if err != nil {
return nil , err
2017-12-12 02:51:45 +00:00
}
// Check if we have enough frames to send
if len ( payloadFrames ) == 0 {
return nil , nil
}
// Don't send out packets that only contain a StopWaitingFrame
2018-01-03 19:19:49 +00:00
if len ( payloadFrames ) == 1 && p . stopWaiting != nil {
2017-12-12 02:51:45 +00:00
return nil , nil
}
2018-01-03 19:19:49 +00:00
p . stopWaiting = nil
p . ackFrame = nil
2017-12-12 02:51:45 +00:00
2018-01-03 19:19:49 +00:00
raw , err := p . writeAndSealPacket ( header , payloadFrames , sealer )
if err != nil {
2017-12-12 02:51:45 +00:00
return nil , err
}
2018-01-03 19:19:49 +00:00
return & packedPacket {
header : header ,
raw : raw ,
frames : payloadFrames ,
encryptionLevel : encLevel ,
} , nil
}
2017-12-12 02:51:45 +00:00
2018-01-03 19:19:49 +00:00
func ( p * packetPacker ) packCryptoPacket ( ) ( * packedPacket , error ) {
encLevel , sealer := p . cryptoSetup . GetSealerForCryptoStream ( )
header := p . getHeader ( encLevel )
headerLength , err := header . GetLength ( p . perspective , p . version )
if err != nil {
return nil , err
2017-12-12 02:51:45 +00:00
}
2018-01-03 19:19:49 +00:00
maxLen := protocol . MaxPacketSize - protocol . ByteCount ( sealer . Overhead ( ) ) - protocol . NonForwardSecurePacketSizeReduction - headerLength
frames := [ ] wire . Frame { p . streamFramer . PopCryptoStreamFrame ( maxLen ) }
raw , err := p . writeAndSealPacket ( header , frames , sealer )
if err != nil {
return nil , err
2017-12-12 02:51:45 +00:00
}
return & packedPacket {
2018-01-03 19:19:49 +00:00
header : header ,
2017-12-12 02:51:45 +00:00
raw : raw ,
2018-01-03 19:19:49 +00:00
frames : frames ,
2017-12-12 02:51:45 +00:00
encryptionLevel : encLevel ,
} , nil
}
2018-01-03 19:19:49 +00:00
func ( p * packetPacker ) composeNextPacket (
maxFrameSize protocol . ByteCount ,
canSendStreamFrames bool ,
) ( [ ] wire . Frame , error ) {
2017-12-12 02:51:45 +00:00
var payloadLength protocol . ByteCount
2018-01-03 19:19:49 +00:00
var payloadFrames [ ] wire . Frame
2017-12-12 02:51:45 +00:00
2018-01-03 19:19:49 +00:00
// STOP_WAITING and ACK will always fit
if p . stopWaiting != nil {
payloadFrames = append ( payloadFrames , p . stopWaiting )
l , err := p . stopWaiting . MinLength ( p . version )
2017-12-12 02:51:45 +00:00
if err != nil {
return nil , err
}
2018-01-03 19:19:49 +00:00
payloadLength += l
}
if p . ackFrame != nil {
payloadFrames = append ( payloadFrames , p . ackFrame )
l , err := p . ackFrame . MinLength ( p . version )
if err != nil {
return nil , err
}
payloadLength += l
2017-12-12 02:51:45 +00:00
}
for len ( p . controlFrames ) > 0 {
frame := p . controlFrames [ len ( p . controlFrames ) - 1 ]
2018-01-03 19:19:49 +00:00
minLength , err := frame . MinLength ( p . version )
if err != nil {
return nil , err
}
2017-12-12 02:51:45 +00:00
if payloadLength + minLength > maxFrameSize {
break
}
payloadFrames = append ( payloadFrames , frame )
payloadLength += minLength
p . controlFrames = p . controlFrames [ : len ( p . controlFrames ) - 1 ]
}
if payloadLength > maxFrameSize {
return nil , fmt . Errorf ( "Packet Packer BUG: packet payload (%d) too large (%d)" , payloadLength , maxFrameSize )
}
2018-01-03 19:19:49 +00:00
if ! canSendStreamFrames {
return payloadFrames , nil
}
// temporarily increase the maxFrameSize by the (minimum) length of the DataLen field
2017-12-12 02:51:45 +00:00
// 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
2018-01-03 19:19:49 +00:00
// however, for the last StreamFrame 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 ( ) {
maxFrameSize ++
} else {
maxFrameSize += 2
}
2017-12-12 02:51:45 +00:00
fs := p . streamFramer . PopStreamFrames ( maxFrameSize - payloadLength )
if len ( fs ) != 0 {
fs [ len ( fs ) - 1 ] . DataLenPresent = false
}
// TODO: Simplify
for _ , f := range fs {
payloadFrames = append ( payloadFrames , f )
}
for b := p . streamFramer . PopBlockedFrame ( ) ; b != nil ; b = p . streamFramer . PopBlockedFrame ( ) {
p . controlFrames = append ( p . controlFrames , b )
}
return payloadFrames , nil
}
2018-01-03 19:19:49 +00:00
func ( p * packetPacker ) QueueControlFrame ( frame wire . Frame ) {
switch f := frame . ( type ) {
case * wire . StopWaitingFrame :
p . stopWaiting = f
case * wire . AckFrame :
p . ackFrame = f
default :
p . controlFrames = append ( p . controlFrames , f )
}
}
func ( p * packetPacker ) getHeader ( encLevel protocol . EncryptionLevel ) * wire . Header {
pnum := p . packetNumberGenerator . Peek ( )
packetNumberLen := protocol . GetPacketNumberLengthForHeader ( pnum , p . leastUnacked )
header := & wire . Header {
ConnectionID : p . connectionID ,
PacketNumber : pnum ,
PacketNumberLen : packetNumberLen ,
}
if p . version . UsesTLS ( ) && encLevel != protocol . EncryptionForwardSecure {
header . PacketNumberLen = protocol . PacketNumberLen4
header . IsLongHeader = true
if ! p . hasSentPacket && p . perspective == protocol . PerspectiveClient {
header . Type = protocol . PacketTypeInitial
} else {
header . Type = protocol . PacketTypeHandshake
}
}
if p . omitConnectionID && encLevel == protocol . EncryptionForwardSecure {
header . OmitConnectionID = true
}
if ! p . version . UsesTLS ( ) {
if p . perspective == protocol . PerspectiveServer && encLevel == protocol . EncryptionSecure {
header . DiversificationNonce = p . cryptoSetup . DiversificationNonce ( )
}
if p . perspective == protocol . PerspectiveClient && encLevel != protocol . EncryptionForwardSecure {
header . VersionFlag = true
header . Version = p . version
}
} else {
if encLevel != protocol . EncryptionForwardSecure {
header . Version = p . version
}
}
return header
}
func ( p * packetPacker ) writeAndSealPacket (
header * wire . Header ,
payloadFrames [ ] wire . Frame ,
sealer handshake . Sealer ,
) ( [ ] byte , error ) {
raw := getPacketBuffer ( )
buffer := bytes . NewBuffer ( raw )
if err := header . Write ( buffer , p . perspective , p . version ) ; err != nil {
return nil , err
}
payloadStartIndex := buffer . Len ( )
// the Initial packet needs to be padded, so the last STREAM frame must have the data length present
if header . Type == protocol . PacketTypeInitial {
lastFrame := payloadFrames [ len ( payloadFrames ) - 1 ]
if sf , ok := lastFrame . ( * wire . StreamFrame ) ; ok {
sf . DataLenPresent = true
}
}
for _ , frame := range payloadFrames {
if err := frame . Write ( buffer , p . version ) ; err != nil {
return nil , err
}
}
// if this is an IETF QUIC Initial packet, we need to pad it to fulfill the minimum size requirement
// in gQUIC, padding is handled in the CHLO
if header . Type == protocol . PacketTypeInitial {
paddingLen := protocol . MinInitialPacketSize - sealer . Overhead ( ) - buffer . Len ( )
if paddingLen > 0 {
buffer . Write ( bytes . Repeat ( [ ] byte { 0 } , paddingLen ) )
}
}
if protocol . ByteCount ( buffer . Len ( ) + sealer . Overhead ( ) ) > protocol . MaxPacketSize {
return nil , errors . New ( "PacketPacker BUG: packet too large" )
}
raw = raw [ 0 : buffer . Len ( ) ]
_ = sealer . Seal ( raw [ payloadStartIndex : payloadStartIndex ] , raw [ payloadStartIndex : ] , header . PacketNumber , raw [ : payloadStartIndex ] )
raw = raw [ 0 : buffer . Len ( ) + sealer . Overhead ( ) ]
num := p . packetNumberGenerator . Pop ( )
if num != header . PacketNumber {
return nil , errors . New ( "packetPacker BUG: Peeked and Popped packet numbers do not match" )
}
p . hasSentPacket = true
return raw , nil
}
func ( p * packetPacker ) canSendData ( encLevel protocol . EncryptionLevel ) bool {
if p . perspective == protocol . PerspectiveClient {
return encLevel >= protocol . EncryptionSecure
}
return encLevel == protocol . EncryptionForwardSecure
}
func ( p * packetPacker ) SetLeastUnacked ( leastUnacked protocol . PacketNumber ) {
p . leastUnacked = leastUnacked
2017-12-12 02:51:45 +00:00
}
2018-01-03 19:19:49 +00:00
func ( p * packetPacker ) SetOmitConnectionID ( ) {
p . omitConnectionID = true
2017-12-12 02:51:45 +00:00
}