2017-05-27 14:30:11 -05:00
package quic
import (
"bytes"
"errors"
"fmt"
"github.com/lucas-clemente/quic-go/ackhandler"
"github.com/lucas-clemente/quic-go/frames"
"github.com/lucas-clemente/quic-go/handshake"
"github.com/lucas-clemente/quic-go/protocol"
)
type packedPacket struct {
number protocol . PacketNumber
raw [ ] byte
frames [ ] frames . Frame
encryptionLevel protocol . EncryptionLevel
}
type packetPacker struct {
connectionID protocol . ConnectionID
perspective protocol . Perspective
version protocol . VersionNumber
cryptoSetup handshake . CryptoSetup
packetNumberGenerator * packetNumberGenerator
2017-07-27 17:11:56 -05:00
connectionParameters handshake . ConnectionParametersManager
streamFramer * streamFramer
2017-05-27 14:30:11 -05:00
controlFrames [ ] frames . Frame
2017-07-27 17:11:56 -05:00
stopWaiting * frames . StopWaitingFrame
ackFrame * frames . AckFrame
leastUnacked protocol . PacketNumber
2017-05-27 14:30:11 -05:00
}
2017-07-27 17:11:56 -05:00
func newPacketPacker ( connectionID protocol . ConnectionID ,
cryptoSetup handshake . CryptoSetup ,
connectionParameters handshake . ConnectionParametersManager ,
streamFramer * streamFramer ,
perspective protocol . Perspective ,
version protocol . VersionNumber ,
) * packetPacker {
2017-05-27 14:30:11 -05:00
return & packetPacker {
cryptoSetup : cryptoSetup ,
connectionID : connectionID ,
connectionParameters : connectionParameters ,
perspective : perspective ,
version : version ,
streamFramer : streamFramer ,
packetNumberGenerator : newPacketNumberGenerator ( protocol . SkipPacketAveragePeriodLength ) ,
}
}
// PackConnectionClose packs a packet that ONLY contains a ConnectionCloseFrame
2017-07-27 17:11:56 -05:00
func ( p * packetPacker ) PackConnectionClose ( ccf * frames . ConnectionCloseFrame ) ( * packedPacket , error ) {
frames := [ ] frames . Frame { ccf }
encLevel , sealer := p . cryptoSetup . GetSealer ( )
ph := p . getPublicHeader ( encLevel )
raw , err := p . writeAndSealPacket ( ph , frames , sealer )
return & packedPacket {
number : ph . PacketNumber ,
raw : raw ,
frames : frames ,
encryptionLevel : encLevel ,
} , err
}
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 ( )
ph := p . getPublicHeader ( encLevel )
frames := [ ] frames . Frame { p . ackFrame }
if p . stopWaiting != nil {
p . stopWaiting . PacketNumber = ph . PacketNumber
p . stopWaiting . PacketNumberLen = ph . PacketNumberLen
frames = append ( frames , p . stopWaiting )
p . stopWaiting = nil
}
p . ackFrame = nil
raw , err := p . writeAndSealPacket ( ph , frames , sealer )
return & packedPacket {
number : ph . PacketNumber ,
raw : raw ,
frames : frames ,
encryptionLevel : encLevel ,
} , err
2017-05-27 14:30:11 -05:00
}
2017-07-27 17:11:56 -05:00
// PackHandshakeRetransmission retransmits a handshake packet, that was sent with less than forward-secure encryption
func ( p * packetPacker ) PackHandshakeRetransmission ( packet * ackhandler . Packet ) ( * packedPacket , error ) {
2017-05-27 14:30:11 -05:00
if packet . EncryptionLevel == protocol . EncryptionForwardSecure {
return nil , errors . New ( "PacketPacker BUG: forward-secure encrypted handshake packets don't need special treatment" )
}
2017-07-27 17:11:56 -05:00
sealer , err := p . cryptoSetup . GetSealerWithEncryptionLevel ( packet . EncryptionLevel )
if err != nil {
return nil , err
}
if p . stopWaiting == nil {
2017-05-27 14:30:11 -05:00
return nil , errors . New ( "PacketPacker BUG: Handshake retransmissions must contain a StopWaitingFrame" )
}
2017-07-27 17:11:56 -05:00
ph := p . getPublicHeader ( packet . EncryptionLevel )
p . stopWaiting . PacketNumber = ph . PacketNumber
p . stopWaiting . PacketNumberLen = ph . PacketNumberLen
frames := append ( [ ] frames . Frame { p . stopWaiting } , packet . Frames ... )
p . stopWaiting = nil
raw , err := p . writeAndSealPacket ( ph , frames , sealer )
return & packedPacket {
number : ph . PacketNumber ,
raw : raw ,
frames : frames ,
encryptionLevel : packet . EncryptionLevel ,
} , err
2017-05-27 14:30:11 -05: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
2017-07-27 17:11:56 -05:00
func ( p * packetPacker ) PackPacket ( ) ( * packedPacket , error ) {
if p . streamFramer . HasCryptoStreamFrame ( ) {
return p . packCryptoPacket ( )
2017-05-27 14:30:11 -05:00
}
2017-07-27 17:11:56 -05:00
encLevel , sealer := p . cryptoSetup . GetSealer ( )
2017-05-27 14:30:11 -05:00
2017-07-27 17:11:56 -05:00
publicHeader := p . getPublicHeader ( encLevel )
publicHeaderLength , err := publicHeader . GetLength ( p . perspective )
2017-05-27 14:30:11 -05:00
if err != nil {
return nil , err
}
2017-07-27 17:11:56 -05:00
if p . stopWaiting != nil {
p . stopWaiting . PacketNumber = publicHeader . PacketNumber
p . stopWaiting . PacketNumberLen = publicHeader . PacketNumberLen
2017-05-27 14:30:11 -05:00
}
2017-07-27 17:11:56 -05:00
maxSize := protocol . MaxFrameAndPublicHeaderSize - publicHeaderLength
payloadFrames , err := p . composeNextPacket ( maxSize , p . canSendData ( encLevel ) )
if err != nil {
return nil , err
2017-05-27 14:30:11 -05: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
2017-07-27 17:11:56 -05:00
if len ( payloadFrames ) == 1 && p . stopWaiting != nil {
2017-05-27 14:30:11 -05:00
return nil , nil
}
2017-07-27 17:11:56 -05:00
p . stopWaiting = nil
p . ackFrame = nil
2017-05-27 14:30:11 -05:00
2017-07-27 17:11:56 -05:00
raw , err := p . writeAndSealPacket ( publicHeader , payloadFrames , sealer )
if err != nil {
2017-05-27 14:30:11 -05:00
return nil , err
}
2017-07-27 17:11:56 -05:00
return & packedPacket {
number : publicHeader . PacketNumber ,
raw : raw ,
frames : payloadFrames ,
encryptionLevel : encLevel ,
} , nil
}
2017-05-27 14:30:11 -05:00
2017-07-27 17:11:56 -05:00
func ( p * packetPacker ) packCryptoPacket ( ) ( * packedPacket , error ) {
encLevel , sealer := p . cryptoSetup . GetSealerForCryptoStream ( )
publicHeader := p . getPublicHeader ( encLevel )
publicHeaderLength , err := publicHeader . GetLength ( p . perspective )
if err != nil {
return nil , err
2017-05-27 14:30:11 -05:00
}
2017-07-27 17:11:56 -05:00
maxLen := protocol . MaxFrameAndPublicHeaderSize - protocol . NonForwardSecurePacketSizeReduction - publicHeaderLength
frames := [ ] frames . Frame { p . streamFramer . PopCryptoStreamFrame ( maxLen ) }
raw , err := p . writeAndSealPacket ( publicHeader , frames , sealer )
if err != nil {
return nil , err
2017-05-27 14:30:11 -05:00
}
return & packedPacket {
2017-07-27 17:11:56 -05:00
number : publicHeader . PacketNumber ,
2017-05-27 14:30:11 -05:00
raw : raw ,
2017-07-27 17:11:56 -05:00
frames : frames ,
2017-05-27 14:30:11 -05:00
encryptionLevel : encLevel ,
} , nil
}
2017-07-27 17:11:56 -05:00
func ( p * packetPacker ) composeNextPacket (
maxFrameSize protocol . ByteCount ,
canSendStreamFrames bool ,
) ( [ ] frames . Frame , error ) {
2017-05-27 14:30:11 -05:00
var payloadLength protocol . ByteCount
var payloadFrames [ ] frames . Frame
2017-07-27 17:11:56 -05: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-05-27 14:30:11 -05:00
if err != nil {
return nil , err
}
2017-07-27 17:11:56 -05: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-05-27 14:30:11 -05:00
}
for len ( p . controlFrames ) > 0 {
frame := p . controlFrames [ len ( p . controlFrames ) - 1 ]
2017-07-27 17:11:56 -05:00
minLength , err := frame . MinLength ( p . version )
if err != nil {
return nil , err
}
2017-05-27 14:30:11 -05: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 )
}
2017-07-27 17:11:56 -05:00
if ! canSendStreamFrames {
return payloadFrames , nil
}
2017-05-27 14:30:11 -05:00
// temporarily increase the maxFrameSize by 2 bytes
// 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 saving 2 bytes and yielding a packet of exactly the correct size
maxFrameSize += 2
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
}
2017-07-27 17:11:56 -05:00
func ( p * packetPacker ) QueueControlFrame ( frame frames . Frame ) {
switch f := frame . ( type ) {
case * frames . StopWaitingFrame :
p . stopWaiting = f
case * frames . AckFrame :
p . ackFrame = f
default :
p . controlFrames = append ( p . controlFrames , f )
}
}
func ( p * packetPacker ) getPublicHeader ( encLevel protocol . EncryptionLevel ) * PublicHeader {
pnum := p . packetNumberGenerator . Peek ( )
packetNumberLen := protocol . GetPacketNumberLengthForPublicHeader ( pnum , p . leastUnacked )
publicHeader := & PublicHeader {
ConnectionID : p . connectionID ,
PacketNumber : pnum ,
PacketNumberLen : packetNumberLen ,
TruncateConnectionID : p . connectionParameters . TruncateConnectionID ( ) ,
}
if p . perspective == protocol . PerspectiveServer && encLevel == protocol . EncryptionSecure {
publicHeader . DiversificationNonce = p . cryptoSetup . DiversificationNonce ( )
}
if p . perspective == protocol . PerspectiveClient && encLevel != protocol . EncryptionForwardSecure {
publicHeader . VersionFlag = true
publicHeader . VersionNumber = p . version
}
return publicHeader
}
func ( p * packetPacker ) writeAndSealPacket (
publicHeader * PublicHeader ,
payloadFrames [ ] frames . Frame ,
sealer handshake . Sealer ,
) ( [ ] byte , error ) {
raw := getPacketBuffer ( )
buffer := bytes . NewBuffer ( raw )
if err := publicHeader . Write ( buffer , p . version , p . perspective ) ; err != nil {
return nil , err
}
payloadStartIndex := buffer . Len ( )
for _ , frame := range payloadFrames {
err := frame . Write ( buffer , p . version )
if err != nil {
return nil , err
}
}
if protocol . ByteCount ( buffer . Len ( ) + 12 ) > protocol . MaxPacketSize {
return nil , errors . New ( "PacketPacker BUG: packet too large" )
}
raw = raw [ 0 : buffer . Len ( ) ]
_ = sealer ( raw [ payloadStartIndex : payloadStartIndex ] , raw [ payloadStartIndex : ] , publicHeader . PacketNumber , raw [ : payloadStartIndex ] )
raw = raw [ 0 : buffer . Len ( ) + 12 ]
num := p . packetNumberGenerator . Pop ( )
if num != publicHeader . PacketNumber {
return nil , errors . New ( "packetPacker BUG: Peeked and Popped packet numbers do not match" )
}
return raw , nil
}
func ( p * packetPacker ) canSendData ( encLevel protocol . EncryptionLevel ) bool {
if p . perspective == protocol . PerspectiveClient {
return encLevel >= protocol . EncryptionSecure
}
return encLevel == protocol . EncryptionForwardSecure
2017-05-27 14:30:11 -05:00
}
2017-07-27 17:11:56 -05:00
func ( p * packetPacker ) SetLeastUnacked ( leastUnacked protocol . PacketNumber ) {
p . leastUnacked = leastUnacked
2017-05-27 14:30:11 -05:00
}