mirror of
https://github.com/apernet/hysteria.git
synced 2025-04-03 04:27:39 +03:00
77 lines
1.9 KiB
Go
77 lines
1.9 KiB
Go
package frag
|
|
|
|
import (
|
|
"github.com/apernet/hysteria/core/internal/protocol"
|
|
)
|
|
|
|
func FragUDPMessage(m protocol.UDPMessage, maxSize int) []protocol.UDPMessage {
|
|
if m.Size() <= maxSize {
|
|
return []protocol.UDPMessage{m}
|
|
}
|
|
fullPayload := m.Data
|
|
maxPayloadSize := maxSize - m.HeaderSize()
|
|
off := 0
|
|
fragID := uint8(0)
|
|
fragCount := uint8((len(fullPayload) + maxPayloadSize - 1) / maxPayloadSize) // round up
|
|
frags := make([]protocol.UDPMessage, fragCount)
|
|
for off < len(fullPayload) {
|
|
payloadSize := len(fullPayload) - off
|
|
if payloadSize > maxPayloadSize {
|
|
payloadSize = maxPayloadSize
|
|
}
|
|
frag := m
|
|
frag.FragID = fragID
|
|
frag.FragCount = fragCount
|
|
frag.Data = fullPayload[off : off+payloadSize]
|
|
frags[fragID] = frag
|
|
off += payloadSize
|
|
fragID++
|
|
}
|
|
return frags
|
|
}
|
|
|
|
// Defragger handles the defragmentation of UDP messages.
|
|
// The current implementation can only handle one packet ID at a time.
|
|
// If another packet arrives before a packet has received all fragments
|
|
// in their entirety, any previous state is discarded.
|
|
type Defragger struct {
|
|
pktID uint16
|
|
frags []*protocol.UDPMessage
|
|
count uint8
|
|
size int // data size
|
|
}
|
|
|
|
func (d *Defragger) Feed(m *protocol.UDPMessage) *protocol.UDPMessage {
|
|
if m.FragCount <= 1 {
|
|
return m
|
|
}
|
|
if m.FragID >= m.FragCount {
|
|
// wtf is this?
|
|
return nil
|
|
}
|
|
if m.PacketID != d.pktID || m.FragCount != uint8(len(d.frags)) {
|
|
// new message, clear previous state
|
|
d.pktID = m.PacketID
|
|
d.frags = make([]*protocol.UDPMessage, m.FragCount)
|
|
d.frags[m.FragID] = m
|
|
d.count = 1
|
|
d.size = len(m.Data)
|
|
} else if d.frags[m.FragID] == nil {
|
|
d.frags[m.FragID] = m
|
|
d.count++
|
|
d.size += len(m.Data)
|
|
if int(d.count) == len(d.frags) {
|
|
// all fragments received, assemble
|
|
data := make([]byte, d.size)
|
|
off := 0
|
|
for _, frag := range d.frags {
|
|
off += copy(data[off:], frag.Data)
|
|
}
|
|
m.Data = data
|
|
m.FragID = 0
|
|
m.FragCount = 1
|
|
return m
|
|
}
|
|
}
|
|
return nil
|
|
}
|