Increase KCP fragment limit from u8 to u16
- Change frg field from u8 to u16 in packet header (25 bytes total) - Update encode/decode to use get_u16_le/put_u16_le - Update Segment struct frg field to u16 - Remove truncating cast in session.rs - Max message size now ~91MB (65,535 fragments × MTU) - Internal protocol only, no interop concerns Nym uses KCP for reliability and multiplexing, not standard real-time use cases. The u8 limit (255 fragments, ~355KB) was insufficient. Addresses: nym-yih9
This commit is contained in:
committed by
Jędrzej Stuczyński
parent
65bd47f342
commit
9bcae469fc
@@ -68,3 +68,5 @@ nym-api/redocly/formatted-openapi.json
|
||||
.beads
|
||||
CLAUDE.md
|
||||
docs
|
||||
.claude
|
||||
.superego
|
||||
@@ -3,7 +3,11 @@ use log::{debug, trace};
|
||||
|
||||
use super::error::KcpError;
|
||||
|
||||
pub const KCP_HEADER: usize = 24;
|
||||
// Nym-KCP uses a modified header format with u16 for frg field (25 bytes total).
|
||||
// Standard KCP uses u8 for frg (24 bytes). This deviation from skywind3000/kcp protocol
|
||||
// supports messages up to ~91MB (65535 fragments × MTU) vs standard 355KB limit.
|
||||
// This is intentional - Nym uses KCP internally for reliability/multiplexing, not interop.
|
||||
pub const KCP_HEADER: usize = 25;
|
||||
|
||||
/// Typed enumeration for KCP commands.
|
||||
#[repr(u8)]
|
||||
@@ -48,11 +52,12 @@ impl Into<u8> for KcpCommand {
|
||||
}
|
||||
|
||||
/// A single KCP packet (on-wire format).
|
||||
/// Note: Nym-KCP uses u16 for frg (fragment count) instead of standard u8.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct KcpPacket {
|
||||
conv: u32,
|
||||
cmd: KcpCommand,
|
||||
frg: u8,
|
||||
frg: u16,
|
||||
wnd: u16,
|
||||
ts: u32,
|
||||
sn: u32,
|
||||
@@ -65,7 +70,7 @@ impl KcpPacket {
|
||||
pub fn new(
|
||||
conv: u32,
|
||||
cmd: KcpCommand,
|
||||
frg: u8,
|
||||
frg: u16,
|
||||
wnd: u16,
|
||||
ts: u32,
|
||||
sn: u32,
|
||||
@@ -104,7 +109,7 @@ impl KcpPacket {
|
||||
self.cmd
|
||||
}
|
||||
|
||||
pub fn frg(&self) -> u8 {
|
||||
pub fn frg(&self) -> u16 {
|
||||
self.frg
|
||||
}
|
||||
|
||||
@@ -154,12 +159,12 @@ impl KcpPacket {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
// Peek into the first 28 bytes
|
||||
// Peek into the header (25 bytes for Nym-KCP)
|
||||
let mut header = &src[..KCP_HEADER];
|
||||
|
||||
let conv = header.get_u32_le();
|
||||
let cmd_byte = header.get_u8();
|
||||
let frg = header.get_u8();
|
||||
let frg = header.get_u16_le();
|
||||
let wnd = header.get_u16_le();
|
||||
let ts = header.get_u32_le();
|
||||
let sn = header.get_u32_le();
|
||||
@@ -206,7 +211,7 @@ impl KcpPacket {
|
||||
|
||||
dst.put_u32_le(self.conv);
|
||||
dst.put_u8(self.cmd.into()); // Convert enum -> u8
|
||||
dst.put_u8(self.frg);
|
||||
dst.put_u16_le(self.frg);
|
||||
dst.put_u16_le(self.wnd);
|
||||
dst.put_u32_le(self.ts);
|
||||
dst.put_u32_le(self.sn);
|
||||
|
||||
@@ -50,7 +50,7 @@ pub struct KcpSession {
|
||||
#[derive(Debug, Clone)]
|
||||
struct Segment {
|
||||
sn: u32,
|
||||
frg: u8,
|
||||
frg: u16,
|
||||
ts: u32,
|
||||
resendts: u32,
|
||||
rto: u32,
|
||||
@@ -60,7 +60,7 @@ struct Segment {
|
||||
|
||||
impl Segment {
|
||||
#[allow(dead_code)]
|
||||
fn new(sn: u32, frg: u8, data: Vec<u8>) -> Self {
|
||||
fn new(sn: u32, frg: u16, data: Vec<u8>) -> Self {
|
||||
Segment {
|
||||
sn,
|
||||
frg,
|
||||
@@ -173,7 +173,7 @@ impl KcpSession {
|
||||
// first has frg=count-1. This allows receiver to know total count from first packet.
|
||||
// In KCP, `frg` is set to the remaining fragments in reverse order.
|
||||
// i.e., the last fragment has frg=0, the first has frg=count-1.
|
||||
let frg = (count - i - 1) as u8;
|
||||
let frg = (count - i - 1) as u16;
|
||||
|
||||
let seg = Segment {
|
||||
sn: self.snd_nxt,
|
||||
|
||||
Reference in New Issue
Block a user