* Lower SetMtu minimum from 50 to IKCP_OVERHEAD+1 (25)
The hardcoded minimum of 50 bytes is an arbitrary safety margin.
The real minimum is IKCP_OVERHEAD (24 bytes for the KCP header)
plus at least 1 byte of payload data. This allows use of smaller
MTUs in transport scenarios where capacity is constrained.
* Address review: use mtu <= IKCP_OVERHEAD and update boundary tests
- Changed condition from mtu < IKCP_OVERHEAD+1 to mtu <= IKCP_OVERHEAD
for readability.
- Updated TestSetMTU to verify the new boundary: MTU at or below
IKCP_OVERHEAD is rejected, MTU just above total overhead is accepted.
RingBuffer.Discard() used `end <= cap` to decide whether the discard
range is contiguous. When head + n equals exactly len(elements), this
incorrectly set head to len(elements) instead of wrapping it to 0.
A subsequent Peek() or Push() would then access elements[len(elements)],
triggering a runtime panic: "index out of range [64] with length 64".
The crash path in production:
KCP.Input -> parse_una -> snd_buf.Discard(count) -> shrink_buf ->
snd_buf.Peek() -> panic
Fix: change the boundary condition from `end <= cap` to `end < cap`,
so the exact-boundary case falls through to the wrap-around branch
which correctly computes head = end - cap = 0.
Add TestRingBufferDiscardBoundary to cover this edge case.
- Remove unused Listener.chSessionClosed field and its allocation;
the channel was never read from or written to anywhere in the codebase.
- Optimize RingBuffer.Discard: replace per-element modulo loop with
at most 2 clear() calls on contiguous ranges, eliminating N modulo
operations for bulk discard.
- Replace if-else if chain with switch statement for cmd dispatch
in Input(), enabling potential jump table optimization by the compiler.
- Use struct literal to construct segment in IKCP_CMD_PUSH case,
replacing 8 individual field assignments with a single expression.
- Move segmentHeader type definition from kcp.go to kcp_encoding.go,
co-locating it with the encode/decode functions that use it.
Remove the custom uint32 helper functions _imin_, _imax_, and _ibound_
in favor of Go's built-in min() and max() generics (available since
Go 1.21). The codebase already uses built-in min/max elsewhere.
- _imin_(a, b) -> min(a, b)
- _imax_(a, b) -> max(a, b)
- _ibound_(lo, mid, hi) -> min(max(lo, mid), hi)
Benchmarks show that Go's encoding/binary PutUintXX/UintXX functions
(which compile down to bare MOV instructions on amd64/arm64) are 3-6%
faster than the encodeSegHeader/decodeSegHeader wrapper functions,
especially in multi-segment scenarios.
Replace the wrapper calls in segment.encode() and KCP.Input() with
direct binary.LittleEndian.PutUint32/PutUint16/Uint32/Uint16 calls,
using a single BCE (Bounds Check Elimination) hint per call site.
This eliminates the intermediate segmentHeader struct allocation in
encode and the pointer-receiver copy overhead in decode, letting the
compiler fully inline all field reads/writes.
Add bench_encode_test.go with BenchmarkSegmentEncode and
BenchmarkKCPInput for focused encode/decode benchmarking.
Replace chained ikcp_encode*/ikcp_decode* function calls with direct
binary.LittleEndian operations at fixed offsets in segment.encode()
and KCP.Input().
The original implementation used 6-7 sequential function calls that
each returned intermediate slices, adding unnecessary call overhead
and preventing compiler optimizations on the hot path.
Benchmark results (Apple M4 Pro, 6 samples, p=0.002):
SegmentEncode: 3.192ns -> 2.895ns (-9.32%)
KCPInput: 12.11ns -> 10.92ns (-9.79%)
Zero change in allocations. All existing tests pass including race
detector.
This commit addresses several potential issues found through code review:
kcp.go:
- Fix potential memory leak in segmentHeap.Pop() by clearing the last
element reference before slice truncation, allowing GC to collect it
crypt.go:
- Add bounds check in salsa20BlockCrypt.Encrypt/Decrypt to prevent
panic when input slice is shorter than 8 bytes (nonce size)
- Add empty slice check in simpleXORBlockCrypt.Encrypt/Decrypt to
prevent index out of range panic
- Add empty slice check in noneBlockCrypt.Encrypt/Decrypt to prevent
index out of range panic on dst[0] access
sess.go:
- Remove panic in postProcess rate limiter error handling; WaitN only
returns errors for context cancellation or invalid burst size, both
of which are non-critical in this context
Optimizations:
- ringbuffer: optimize Len(), IsEmpty(), Discard(), Clear() methods with
branchless arithmetic and simplified logic
- fec: fix memory leak in shardHeap.Pop() by setting element to nil before
truncating slice, preventing GC from holding stale references
- timedsched: fix memory leak in timedFuncHeap.Pop() with same nil-before-truncate
pattern; optimize prepend() using slice swap instead of append
- autotune: add sortCache field to Autotuner to reuse slice allocation in
FindPeriod(), avoiding repeated allocations during period detection
- snmp: replace fmt.Sprint with strconv.FormatUint for better performance
in Copy() and Reset() methods
- entropy: remove defer overhead in rngAES.Read() and rngChacha8.Read()
hot paths for reduced function call cost
- bufferpool: pre-allocate ErrBufferPoolSizeExceeded error; reset slice
length on Put() to allow proper reuse
- sess: remove defer overhead in 6 setter methods (SetWriteDelay,
SetWindowSize, SetStreamMode, SetACKNoDelay, SetDUP, SetNoDelay)
These changes reduce memory allocations, fix potential memory leaks in
heap-based data structures, and eliminate defer overhead in frequently
called methods.
- Reuse buffers and use rng.Read to cut per-iteration allocations in random echo test
- Separate RNG for payload length to keep data stream deterministic
- Optimize UDP source validation by comparing UDPAddr directly to avoid per-packet String allocation
Fix shouldTune flag not being reset when auto-detected FEC parameters
match current parameters. This could cause the decoder to permanently
discard all incoming packets if a corrupted packet triggered shouldTune
but the actual FEC configuration hadn't changed.
Move `dec.shouldTune = false` outside the parameter-change check to
ensure the flag is always reset when valid parameters are detected.
Replace the heap-based pulseHeap implementation with a fixed-size ring
buffer array to avoid interface{} allocations from container/heap
Push/Pop operations.
Changes:
- Use fixed-size array [maxAutoTuneSamples]pulse instead of slice
- Track elements with head/tail/count instead of heap operations
- Copy elements from ring buffer in FindPeriod() for sorting
- Remove container/heap import dependency
Benchmark results (BenchmarkEchoSpeed4K):
- Before: 185 allocs/op
- After: 163 allocs/op (~12% reduction)
All existing tests pass with identical behavior.
- Replace division and modulo operations with bitwise equivalents:
- len(src) / 8 -> len(src) >> 3
- len(src) / 16 -> len(src) >> 4
- n / 8 -> n >> 3
- n % 8 -> n & 7
- Improve lock handling in blockCrypt:
- Split single mutex into separate encMu/decMu for encrypt/decrypt
- Remove defer for Lock/Unlock to reduce overhead
- Cache blockSize in struct to avoid repeated method calls
- Optimize Salsa20 and None ciphers:
- Skip unnecessary copy when dst and src point to same memory
- Add //go:nosplit directive to hot path functions
All encryption tests pass. Benchmark results show no regression with
zero memory allocations maintained (0 B/op, 0 allocs/op).
commit e51740f7e6
Author: xtaci <imap@live.com>
Date: Sat Jan 24 22:11:58 2026 +0800
optimize crypto using subtle/XORBytes
commit 071dc4a69d
Author: xtaci <imap@live.com>
Date: Sat Jan 24 21:55:49 2026 +0800
1. Fix incorrect RepeatSegs counter in parse_data() function
- Previously, the repeat flag was never set to true when duplicate packets
were detected, causing incorrect statistics reporting
- Added missing else branch to properly mark duplicate segments
- Impact: Correct tracking of repeated packet statistics
2. Fix memory leak in FEC decoder auto-tune functionality
- When FEC parameters were adjusted dynamically, the old shardSet map
was discarded without recycling its buffer pool entries
- Added proper cleanup loop to return old shard packets to buffer pool
before creating new shardSet
- Impact: Prevents memory growth during long-lived connections with
dynamic FEC parameter adjustments
Files modified:
- kcp.go: Added else branch in parse_data() to set repeat=true for duplicates
- fec.go: Added buffer cleanup loop before shardSet recreation in decode()
All existing tests pass, including FEC encoding/decoding and lossy connection tests.
- Previously, the repeat flag was never set to true when duplicate packets
were detected, causing incorrect statistics reporting
- Added missing else branch to properly mark duplicate segments
- Impact: Correct tracking of repeated packet statistics
2. Fix memory leak in FEC decoder auto-tune functionality
- When FEC parameters were adjusted dynamically, the old shardSet map
was discarded without recycling its buffer pool entries
- Added proper cleanup loop to return old shard packets to buffer pool
before creating new shardSet
- Impact: Prevents memory growth during long-lived connections with
dynamic FEC parameter adjustments
Files modified:
- kcp.go: Added else branch in parse_data() to set repeat=true for duplicates
- fec.go: Added buffer cleanup loop before shardSet recreation in decode()
All existing tests pass, including FEC encoding/decoding and lossy connection tests.
- Replace atomic.Pointer[func([]byte)] with atomic.Value for OOB callback storage to improve compatibility.
- Rename SetCallbackForOOB to SetOOBHandler and GetMaxSizeForOOB to GetOOBMaxSize for clearer, consistent API naming.
- Add locking in SendOOB to ensure thread safety during OOB packet construction.
- Update related test cases in sess_test.go to use the new interface names.
- Revise comments and documentation for better clarity and maintainability.
user takes care of the nil handler
use 0xffffffff as the seqid of OOB
return error on nil handler
fix race in test
shorten test data size
add more test on OOB
enhance Error test
allow nil from sender side
add OOBPackets in snmp
use dummy handler instead of resetting the atomic.Value
add test for dummy handler
remove a comment
formalize callback function prototype
use const
rename to expose
Add comments to clarify KCP input and FEC decoding order for FEC packets.
fix test
comments
add TestOOB_OneSideHandler