Skip to content

Commit

Permalink
Add FrameBuilder for building frames with target packet length
Browse files Browse the repository at this point in the history
  • Loading branch information
sippejw committed May 7, 2024
1 parent cb2c7f1 commit e295477
Showing 1 changed file with 53 additions and 0 deletions.
53 changes: 53 additions & 0 deletions u_quic_frames.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,59 @@ type QUICFrameBuilder interface {
// It could be used to deterministically build QUIC Frames from crypto data.
type QUICFrames []QUICFrame

// QUICPacket is a struct that contains a slice of QUICFrame and the total length
// of all frames including PADDING frames. It can be used to deterministically
// build QUIC Packets with a target length.
type QUICPacket struct {
Frames QUICFrames

Length uint16
}

// Build ingests data from crypto frames without the crypto frame header
// and returns the byte representation of all frames as specified in
// the Frames slice. It then calculates the padding sizes needed to
// reach the specified Length and updates the PADDING frames accordingly.
func (qp QUICPacket) Build(cryptoData []byte) (payload []byte, err error) {
// dry-run to determine the total length of all frames so far
dryrunPayload, err := qp.Frames.Build(cryptoData)
if err != nil {
return nil, err
}

// determine length of PADDING frames to append
lenPADDINGsigned := int64(qp.Length) - int64(len(dryrunPayload))
if lenPADDINGsigned > 0 {
lenPADDING := uint64(lenPADDINGsigned)
// determine number of PADDING frames to append
numPADDING := 0
for _, frame := range qp.Frames {
if _, ok := frame.(QUICFramePadding); ok {
numPADDING++
}
}

// create a list of values made from dividing lenPADDING into equal sizes of length numPADDING
paddingSizes := make([]uint64, numPADDING)
paddingSize := lenPADDING / uint64(numPADDING)
for i := 0; i < numPADDING; i++ {
paddingSizes[i] = paddingSize
}
// distribute the remaining lenPADDING into the list of values
remaining := lenPADDING % uint64(numPADDING)
paddingSizes[len(paddingSizes)-1] += remaining

// update the padding frames with the calculated sizes
for i, frame := range qp.Frames {
if _, ok := frame.(QUICFramePadding); ok {
qp.Frames[i] = QUICFramePadding{Length: int(paddingSizes[0])}
paddingSizes = paddingSizes[1:]
}
}
}
return qp.Frames.Build(cryptoData)
}

// Build ingests data from crypto frames without the crypto frame header
// and returns the byte representation of all frames as specified in
// the slice.
Expand Down

0 comments on commit e295477

Please sign in to comment.