package ackhandler
import (
"fmt"
"github.com/tmc/go-iroh/internal/qng/internal/monotime"
"github.com/tmc/go-iroh/internal/qng/internal/protocol"
"github.com/tmc/go-iroh/internal/qng/internal/utils"
"github.com/tmc/go-iroh/internal/qng/internal/wire"
)
type ReceivedPacketHandler struct {
initialPackets *receivedPacketTracker
handshakePackets *receivedPacketTracker
appDataPaths map [protocol .PathID ]*appDataReceivedPacketTracker
lowest1RTTPacket protocol .PacketNumber
}
func NewReceivedPacketHandler (logger utils .Logger ) *ReceivedPacketHandler {
return &ReceivedPacketHandler {
initialPackets : newReceivedPacketTracker (),
handshakePackets : newReceivedPacketTracker (),
appDataPaths : map [protocol .PathID ]*appDataReceivedPacketTracker {
protocol .PathIDZero : newAppDataReceivedPacketTracker (logger ),
},
lowest1RTTPacket : protocol .InvalidPacketNumber ,
}
}
func (h *ReceivedPacketHandler ) getAppDataPath (pid protocol .PathID ) *appDataReceivedPacketTracker {
return h .appDataPaths [pid ]
}
func (h *ReceivedPacketHandler ) AddPath (pid protocol .PathID , logger utils .Logger ) error {
if pid == protocol .PathIDZero {
return fmt .Errorf ("cannot add received path with reserved id %d" , protocol .PathIDZero )
}
if _ , ok := h .appDataPaths [pid ]; ok {
return fmt .Errorf ("received path %d already exists" , pid )
}
h .appDataPaths [pid ] = newAppDataReceivedPacketTracker (logger )
return nil
}
func (h *ReceivedPacketHandler ) RemovePath (pid protocol .PathID ) {
if pid == protocol .PathIDZero {
return
}
delete (h .appDataPaths , pid )
}
func (h *ReceivedPacketHandler ) ReceivedPacketForPath (
pn protocol .PacketNumber ,
ecn protocol .ECN ,
pid protocol .PathID ,
rcvTime monotime .Time ,
ackEliciting bool ,
) error {
if h .lowest1RTTPacket == protocol .InvalidPacketNumber || pn < h .lowest1RTTPacket {
h .lowest1RTTPacket = pn
}
path := h .getAppDataPath (pid )
if path == nil {
panic (fmt .Sprintf ("ReceivedPacketForPath: unknown path %d" , pid ))
}
return path .ReceivedPacket (pn , ecn , rcvTime , ackEliciting )
}
func (h *ReceivedPacketHandler ) GetAckFrameForPath (pid protocol .PathID , now monotime .Time , onlyIfQueued bool ) *wire .AckFrame {
path := h .getAppDataPath (pid )
if path == nil {
return nil
}
return path .GetAckFrame (now , onlyIfQueued )
}
func (h *ReceivedPacketHandler ) GetAlarmTimeoutForPath (pid protocol .PathID ) monotime .Time {
path := h .getAppDataPath (pid )
if path == nil {
return 0
}
return path .GetAlarmTimeout ()
}
func (h *ReceivedPacketHandler ) IsPotentiallyDuplicateForPath (pn protocol .PacketNumber , pid protocol .PathID ) bool {
path := h .getAppDataPath (pid )
if path == nil {
return false
}
return path .IsPotentiallyDuplicate (pn )
}
func (h *ReceivedPacketHandler ) ReceivedPacket (
pn protocol .PacketNumber ,
ecn protocol .ECN ,
encLevel protocol .EncryptionLevel ,
rcvTime monotime .Time ,
ackEliciting bool ,
) error {
switch encLevel {
case protocol .EncryptionInitial :
return h .initialPackets .ReceivedPacket (pn , ecn , ackEliciting )
case protocol .EncryptionHandshake :
if h .handshakePackets == nil {
return nil
}
return h .handshakePackets .ReceivedPacket (pn , ecn , ackEliciting )
case protocol .Encryption0RTT :
if h .lowest1RTTPacket != protocol .InvalidPacketNumber && pn > h .lowest1RTTPacket {
return fmt .Errorf ("received packet number %d on a 0-RTT packet after receiving %d on a 1-RTT packet" , pn , h .lowest1RTTPacket )
}
return h .getAppDataPath (protocol .PathIDZero ).ReceivedPacket (pn , ecn , rcvTime , ackEliciting )
case protocol .Encryption1RTT :
if h .lowest1RTTPacket == protocol .InvalidPacketNumber || pn < h .lowest1RTTPacket {
h .lowest1RTTPacket = pn
}
return h .getAppDataPath (protocol .PathIDZero ).ReceivedPacket (pn , ecn , rcvTime , ackEliciting )
default :
panic (fmt .Sprintf ("received packet with unknown encryption level: %s" , encLevel ))
}
}
func (h *ReceivedPacketHandler ) IgnorePacketsBelow (pn protocol .PacketNumber ) {
h .getAppDataPath (protocol .PathIDZero ).IgnoreBelow (pn )
}
func (h *ReceivedPacketHandler ) DropPackets (encLevel protocol .EncryptionLevel ) {
switch encLevel {
case protocol .EncryptionInitial :
h .initialPackets = nil
case protocol .EncryptionHandshake :
h .handshakePackets = nil
case protocol .Encryption0RTT :
default :
panic (fmt .Sprintf ("Cannot drop keys for encryption level %s" , encLevel ))
}
}
func (h *ReceivedPacketHandler ) GetAlarmTimeout () monotime .Time {
return h .getAppDataPath (protocol .PathIDZero ).GetAlarmTimeout ()
}
func (h *ReceivedPacketHandler ) GetAckFrame (encLevel protocol .EncryptionLevel , now monotime .Time , onlyIfQueued bool ) *wire .AckFrame {
switch encLevel {
case protocol .EncryptionInitial :
if h .initialPackets != nil {
return h .initialPackets .GetAckFrame ()
}
return nil
case protocol .EncryptionHandshake :
if h .handshakePackets != nil {
return h .handshakePackets .GetAckFrame ()
}
return nil
case protocol .Encryption1RTT :
return h .getAppDataPath (protocol .PathIDZero ).GetAckFrame (now , onlyIfQueued )
default :
return nil
}
}
func (h *ReceivedPacketHandler ) IsPotentiallyDuplicate (pn protocol .PacketNumber , encLevel protocol .EncryptionLevel ) bool {
switch encLevel {
case protocol .EncryptionInitial :
if h .initialPackets != nil {
return h .initialPackets .IsPotentiallyDuplicate (pn )
}
case protocol .EncryptionHandshake :
if h .handshakePackets != nil {
return h .handshakePackets .IsPotentiallyDuplicate (pn )
}
case protocol .Encryption0RTT , protocol .Encryption1RTT :
return h .getAppDataPath (protocol .PathIDZero ).IsPotentiallyDuplicate (pn )
}
panic ("unexpected encryption level" )
}
The pages are generated with Golds v0.8.4 . (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 .