package wire
import (
"encoding/binary"
"errors"
"fmt"
"io"
"github.com/quic-go/quic-go/internal/protocol"
"github.com/quic-go/quic-go/internal/utils"
"github.com/quic-go/quic-go/quicvarint"
)
var ErrInvalidReservedBits = errors .New ("invalid reserved bits" )
type ExtendedHeader struct {
Header
typeByte byte
KeyPhase protocol .KeyPhaseBit
PacketNumberLen protocol .PacketNumberLen
PacketNumber protocol .PacketNumber
parsedLen protocol .ByteCount
}
func (h *ExtendedHeader ) parse (data []byte ) (bool , error ) {
h .typeByte = data [0 ]
h .PacketNumberLen = protocol .PacketNumberLen (h .typeByte &0x3 ) + 1
if protocol .ByteCount (len (data )) < h .Header .ParsedLen ()+protocol .ByteCount (h .PacketNumberLen ) {
return false , io .EOF
}
pn , err := readPacketNumber (data [h .Header .ParsedLen ():], h .PacketNumberLen )
if err != nil {
return true , nil
}
h .PacketNumber = pn
reservedBitsValid := h .typeByte &0xc == 0
h .parsedLen = h .Header .ParsedLen () + protocol .ByteCount (h .PacketNumberLen )
return reservedBitsValid , err
}
func (h *ExtendedHeader ) Append (b []byte , v protocol .Version ) ([]byte , error ) {
if h .DestConnectionID .Len () > protocol .MaxConnIDLen {
return nil , fmt .Errorf ("invalid connection ID length: %d bytes" , h .DestConnectionID .Len ())
}
if h .SrcConnectionID .Len () > protocol .MaxConnIDLen {
return nil , fmt .Errorf ("invalid connection ID length: %d bytes" , h .SrcConnectionID .Len ())
}
var packetType uint8
if v == protocol .Version2 {
switch h .Type {
case protocol .PacketTypeInitial :
packetType = 0b01
case protocol .PacketType0RTT :
packetType = 0b10
case protocol .PacketTypeHandshake :
packetType = 0b11
case protocol .PacketTypeRetry :
packetType = 0b00
}
} else {
switch h .Type {
case protocol .PacketTypeInitial :
packetType = 0b00
case protocol .PacketType0RTT :
packetType = 0b01
case protocol .PacketTypeHandshake :
packetType = 0b10
case protocol .PacketTypeRetry :
packetType = 0b11
}
}
firstByte := 0xc0 | packetType <<4
if h .Type != protocol .PacketTypeRetry {
firstByte |= uint8 (h .PacketNumberLen - 1 )
}
b = append (b , firstByte )
b = append (b , make ([]byte , 4 )...)
binary .BigEndian .PutUint32 (b [len (b )-4 :], uint32 (h .Version ))
b = append (b , uint8 (h .DestConnectionID .Len ()))
b = append (b , h .DestConnectionID .Bytes ()...)
b = append (b , uint8 (h .SrcConnectionID .Len ()))
b = append (b , h .SrcConnectionID .Bytes ()...)
switch h .Type {
case protocol .PacketTypeRetry :
b = append (b , h .Token ...)
return b , nil
case protocol .PacketTypeInitial :
b = quicvarint .Append (b , uint64 (len (h .Token )))
b = append (b , h .Token ...)
}
b = quicvarint .AppendWithLen (b , uint64 (h .Length ), 2 )
return appendPacketNumber (b , h .PacketNumber , h .PacketNumberLen )
}
func (h *ExtendedHeader ) ParsedLen () protocol .ByteCount {
return h .parsedLen
}
func (h *ExtendedHeader ) GetLength (_ protocol .Version ) protocol .ByteCount {
length := 1 + 4 + 1 + protocol .ByteCount (h .DestConnectionID .Len ()) + 1 + protocol .ByteCount (h .SrcConnectionID .Len ()) + protocol .ByteCount (h .PacketNumberLen ) + 2
if h .Type == protocol .PacketTypeInitial {
length += protocol .ByteCount (quicvarint .Len (uint64 (len (h .Token ))) + len (h .Token ))
}
return length
}
func (h *ExtendedHeader ) Log (logger utils .Logger ) {
var token string
if h .Type == protocol .PacketTypeInitial || h .Type == protocol .PacketTypeRetry {
if len (h .Token ) == 0 {
token = "Token: (empty), "
} else {
token = fmt .Sprintf ("Token: %#x, " , h .Token )
}
if h .Type == protocol .PacketTypeRetry {
logger .Debugf ("\tLong Header{Type: %s, DestConnectionID: %s, SrcConnectionID: %s, %sVersion: %s}" , h .Type , h .DestConnectionID , h .SrcConnectionID , token , h .Version )
return
}
}
logger .Debugf ("\tLong Header{Type: %s, DestConnectionID: %s, SrcConnectionID: %s, %sPacketNumber: %d, PacketNumberLen: %d, Length: %d, Version: %s}" , h .Type , h .DestConnectionID , h .SrcConnectionID , token , h .PacketNumber , h .PacketNumberLen , h .Length , h .Version )
}
func appendPacketNumber(b []byte , pn protocol .PacketNumber , pnLen protocol .PacketNumberLen ) ([]byte , error ) {
switch pnLen {
case protocol .PacketNumberLen1 :
b = append (b , uint8 (pn ))
case protocol .PacketNumberLen2 :
buf := make ([]byte , 2 )
binary .BigEndian .PutUint16 (buf , uint16 (pn ))
b = append (b , buf ...)
case protocol .PacketNumberLen3 :
buf := make ([]byte , 4 )
binary .BigEndian .PutUint32 (buf , uint32 (pn ))
b = append (b , buf [1 :]...)
case protocol .PacketNumberLen4 :
buf := make ([]byte , 4 )
binary .BigEndian .PutUint32 (buf , uint32 (pn ))
b = append (b , buf ...)
default :
return nil , fmt .Errorf ("invalid packet number length: %d" , pnLen )
}
return b , nil
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .