fix: splitSeq, map struct{}, unlock before WriteToUDP

fix: splitSeq, map struct{}, unlock before WriteToUDP
This commit is contained in:
cubexteam
2026-03-04 18:16:16 +03:00
committed by GitHub
parent 0f42c90ac0
commit b16628dd5d

View File

@@ -26,17 +26,17 @@ type Session struct {
sendSeq uint32 sendSeq uint32
recvSeq uint32 recvSeq uint32
msgIndex uint32 msgIndex uint32
splitSeq uint16
orderIndex [MaxChannels]uint32 orderIndex [MaxChannels]uint32
orderNext [MaxChannels]uint32 orderNext [MaxChannels]uint32
orderQueues [MaxChannels]map[uint32][]byte orderQueues [MaxChannels]map[uint32][]byte
recvSeqs map[uint32]bool recvSeqs map[uint32]struct{}
pendingACK []uint32 pendingACK []uint32
pendingNACK []uint32 pendingNACK []uint32
splitMap map[uint16]*splitBuf splitMap map[uint16]*splitBuf
recoveryMap map[uint32]*Datagram recoveryMap map[uint32]*Datagram
lastRecv time.Time lastRecv time.Time
@@ -55,12 +55,12 @@ func NewSession(conn *net.UDPConn, addr *net.UDPAddr, guid int64, mtu uint16) *S
GUID: guid, GUID: guid,
MTU: mtu, MTU: mtu,
state: StateHandshaking, state: StateHandshaking,
recvSeqs: make(map[uint32]bool), recvSeqs: make(map[uint32]struct{}),
splitMap: make(map[uint16]*splitBuf), splitMap: make(map[uint16]*splitBuf),
recoveryMap: make(map[uint32]*Datagram), recoveryMap: make(map[uint32]*Datagram),
lastRecv: time.Now(), lastRecv: time.Now(),
} }
for i := 0; i < MaxChannels; i++ { for i := range s.orderQueues {
s.orderQueues[i] = make(map[uint32][]byte) s.orderQueues[i] = make(map[uint32][]byte)
} }
return s return s
@@ -110,13 +110,16 @@ func (s *Session) HandleNACK(data []byte) {
return return
} }
s.mu.Lock() s.mu.Lock()
defer s.mu.Unlock() toResend := make([]*Datagram, 0, len(nums))
for _, n := range nums { for _, n := range nums {
dg, ok := s.recoveryMap[n] if dg, ok := s.recoveryMap[n]; ok {
if ok { toResend = append(toResend, dg)
s.conn.WriteToUDP(dg.Encode(), s.Addr)
} }
} }
s.mu.Unlock()
for _, dg := range toResend {
_, _ = s.conn.WriteToUDP(dg.Encode(), s.Addr)
}
} }
func (s *Session) FlushACKs() { func (s *Session) FlushACKs() {
@@ -128,10 +131,10 @@ func (s *Session) FlushACKs() {
s.mu.Unlock() s.mu.Unlock()
if len(acks) > 0 { if len(acks) > 0 {
s.conn.WriteToUDP(EncodeACK(acks), s.Addr) _, _ = s.conn.WriteToUDP(EncodeACK(acks), s.Addr)
} }
if len(nacks) > 0 { if len(nacks) > 0 {
s.conn.WriteToUDP(EncodeNACK(nacks), s.Addr) _, _ = s.conn.WriteToUDP(EncodeNACK(nacks), s.Addr)
} }
} }
@@ -165,7 +168,8 @@ func (s *Session) Send(payload []byte, reliability Reliability, orderChannel byt
return return
} }
splitID := s.splitID() splitID := s.splitSeq
s.splitSeq++
count := (len(payload) + maxPayload - 1) / maxPayload count := (len(payload) + maxPayload - 1) / maxPayload
orderIdx := s.orderIndex[orderChannel] orderIdx := s.orderIndex[orderChannel]
if reliability.IsOrdered() { if reliability.IsOrdered() {
@@ -177,15 +181,16 @@ func (s *Session) Send(payload []byte, reliability Reliability, orderChannel byt
if end > len(payload) { if end > len(payload) {
end = len(payload) end = len(payload)
} }
chunk := make([]byte, end-start)
copy(chunk, payload[start:end])
f := &Frame{ f := &Frame{
Reliability: reliability, Reliability: reliability,
Split: true, Split: true,
SplitCount: uint32(count), SplitCount: uint32(count),
SplitID: splitID, SplitID: splitID,
SplitIndex: uint32(i), SplitIndex: uint32(i),
Payload: make([]byte, end-start), Payload: chunk,
} }
copy(f.Payload, payload[start:end])
if reliability.IsReliable() { if reliability.IsReliable() {
f.MessageIndex = s.msgIndex f.MessageIndex = s.msgIndex
s.msgIndex++ s.msgIndex++
@@ -198,32 +203,22 @@ func (s *Session) Send(payload []byte, reliability Reliability, orderChannel byt
} }
} }
func (s *Session) splitID() uint16 {
id := uint16(s.msgIndex & 0xffff)
return id
}
func (s *Session) sendDatagram(frames []*Frame) { func (s *Session) sendDatagram(frames []*Frame) {
seq := s.sendSeq seq := s.sendSeq
s.sendSeq++ s.sendSeq++
dg := &Datagram{SeqNum: seq, Frames: frames} dg := &Datagram{SeqNum: seq, Frames: frames}
pkt := dg.Encode() _, _ = s.conn.WriteToUDP(dg.Encode(), s.Addr)
s.conn.WriteToUDP(pkt, s.Addr)
hasReliable := false
for _, f := range frames { for _, f := range frames {
if f.Reliability.IsReliable() { if f.Reliability.IsReliable() {
hasReliable = true s.recoveryMap[seq] = dg
break break
} }
} }
if hasReliable {
s.recoveryMap[seq] = dg
}
} }
func (s *Session) SendRaw(data []byte) { func (s *Session) SendRaw(data []byte) {
s.conn.WriteToUDP(data, s.Addr) _, _ = s.conn.WriteToUDP(data, s.Addr)
} }
func (s *Session) TimedOut() bool { func (s *Session) TimedOut() bool {
@@ -240,5 +235,5 @@ func (s *Session) Disconnect() {
s.mu.Unlock() s.mu.Unlock()
f := &Frame{Reliability: Unreliable, Payload: []byte{0x15}} f := &Frame{Reliability: Unreliable, Payload: []byte{0x15}}
dg := &Datagram{SeqNum: seq, Frames: []*Frame{f}} dg := &Datagram{SeqNum: seq, Frames: []*Frame{f}}
s.conn.WriteToUDP(dg.Encode(), s.Addr) _, _ = s.conn.WriteToUDP(dg.Encode(), s.Addr)
} }