github.com/xmplusdev/xmcore@v1.8.11-0.20240412132628-5518b55526af/transport/internet/kcp/segment.go (about) 1 package kcp 2 3 import ( 4 "encoding/binary" 5 6 "github.com/xmplusdev/xmcore/common/buf" 7 ) 8 9 // Command is a KCP command that indicate the purpose of a Segment. 10 type Command byte 11 12 const ( 13 // CommandACK indicates an AckSegment. 14 CommandACK Command = 0 15 // CommandData indicates a DataSegment. 16 CommandData Command = 1 17 // CommandTerminate indicates that peer terminates the connection. 18 CommandTerminate Command = 2 19 // CommandPing indicates a ping. 20 CommandPing Command = 3 21 ) 22 23 type SegmentOption byte 24 25 const ( 26 SegmentOptionClose SegmentOption = 1 27 ) 28 29 type Segment interface { 30 Release() 31 Conversation() uint16 32 Command() Command 33 ByteSize() int32 34 Serialize([]byte) 35 parse(conv uint16, cmd Command, opt SegmentOption, buf []byte) (bool, []byte) 36 } 37 38 const ( 39 DataSegmentOverhead = 18 40 ) 41 42 type DataSegment struct { 43 Conv uint16 44 Option SegmentOption 45 Timestamp uint32 46 Number uint32 47 SendingNext uint32 48 49 payload *buf.Buffer 50 timeout uint32 51 transmit uint32 52 } 53 54 func NewDataSegment() *DataSegment { 55 return new(DataSegment) 56 } 57 58 func (s *DataSegment) parse(conv uint16, cmd Command, opt SegmentOption, buf []byte) (bool, []byte) { 59 s.Conv = conv 60 s.Option = opt 61 if len(buf) < 15 { 62 return false, nil 63 } 64 s.Timestamp = binary.BigEndian.Uint32(buf) 65 buf = buf[4:] 66 67 s.Number = binary.BigEndian.Uint32(buf) 68 buf = buf[4:] 69 70 s.SendingNext = binary.BigEndian.Uint32(buf) 71 buf = buf[4:] 72 73 dataLen := int(binary.BigEndian.Uint16(buf)) 74 buf = buf[2:] 75 76 if len(buf) < dataLen { 77 return false, nil 78 } 79 s.Data().Clear() 80 s.Data().Write(buf[:dataLen]) 81 buf = buf[dataLen:] 82 83 return true, buf 84 } 85 86 func (s *DataSegment) Conversation() uint16 { 87 return s.Conv 88 } 89 90 func (*DataSegment) Command() Command { 91 return CommandData 92 } 93 94 func (s *DataSegment) Detach() *buf.Buffer { 95 r := s.payload 96 s.payload = nil 97 return r 98 } 99 100 func (s *DataSegment) Data() *buf.Buffer { 101 if s.payload == nil { 102 s.payload = buf.New() 103 } 104 return s.payload 105 } 106 107 func (s *DataSegment) Serialize(b []byte) { 108 binary.BigEndian.PutUint16(b, s.Conv) 109 b[2] = byte(CommandData) 110 b[3] = byte(s.Option) 111 binary.BigEndian.PutUint32(b[4:], s.Timestamp) 112 binary.BigEndian.PutUint32(b[8:], s.Number) 113 binary.BigEndian.PutUint32(b[12:], s.SendingNext) 114 binary.BigEndian.PutUint16(b[16:], uint16(s.payload.Len())) 115 copy(b[18:], s.payload.Bytes()) 116 } 117 118 func (s *DataSegment) ByteSize() int32 { 119 return 2 + 1 + 1 + 4 + 4 + 4 + 2 + s.payload.Len() 120 } 121 122 func (s *DataSegment) Release() { 123 s.payload.Release() 124 s.payload = nil 125 } 126 127 type AckSegment struct { 128 Conv uint16 129 Option SegmentOption 130 ReceivingWindow uint32 131 ReceivingNext uint32 132 Timestamp uint32 133 NumberList []uint32 134 } 135 136 const ackNumberLimit = 128 137 138 func NewAckSegment() *AckSegment { 139 return new(AckSegment) 140 } 141 142 func (s *AckSegment) parse(conv uint16, cmd Command, opt SegmentOption, buf []byte) (bool, []byte) { 143 s.Conv = conv 144 s.Option = opt 145 if len(buf) < 13 { 146 return false, nil 147 } 148 149 s.ReceivingWindow = binary.BigEndian.Uint32(buf) 150 buf = buf[4:] 151 152 s.ReceivingNext = binary.BigEndian.Uint32(buf) 153 buf = buf[4:] 154 155 s.Timestamp = binary.BigEndian.Uint32(buf) 156 buf = buf[4:] 157 158 count := int(buf[0]) 159 buf = buf[1:] 160 161 if len(buf) < count*4 { 162 return false, nil 163 } 164 for i := 0; i < count; i++ { 165 s.PutNumber(binary.BigEndian.Uint32(buf)) 166 buf = buf[4:] 167 } 168 169 return true, buf 170 } 171 172 func (s *AckSegment) Conversation() uint16 { 173 return s.Conv 174 } 175 176 func (*AckSegment) Command() Command { 177 return CommandACK 178 } 179 180 func (s *AckSegment) PutTimestamp(timestamp uint32) { 181 if timestamp-s.Timestamp < 0x7FFFFFFF { 182 s.Timestamp = timestamp 183 } 184 } 185 186 func (s *AckSegment) PutNumber(number uint32) { 187 s.NumberList = append(s.NumberList, number) 188 } 189 190 func (s *AckSegment) IsFull() bool { 191 return len(s.NumberList) == ackNumberLimit 192 } 193 194 func (s *AckSegment) IsEmpty() bool { 195 return len(s.NumberList) == 0 196 } 197 198 func (s *AckSegment) ByteSize() int32 { 199 return 2 + 1 + 1 + 4 + 4 + 4 + 1 + int32(len(s.NumberList)*4) 200 } 201 202 func (s *AckSegment) Serialize(b []byte) { 203 binary.BigEndian.PutUint16(b, s.Conv) 204 b[2] = byte(CommandACK) 205 b[3] = byte(s.Option) 206 binary.BigEndian.PutUint32(b[4:], s.ReceivingWindow) 207 binary.BigEndian.PutUint32(b[8:], s.ReceivingNext) 208 binary.BigEndian.PutUint32(b[12:], s.Timestamp) 209 b[16] = byte(len(s.NumberList)) 210 n := 17 211 for _, number := range s.NumberList { 212 binary.BigEndian.PutUint32(b[n:], number) 213 n += 4 214 } 215 } 216 217 func (s *AckSegment) Release() {} 218 219 type CmdOnlySegment struct { 220 Conv uint16 221 Cmd Command 222 Option SegmentOption 223 SendingNext uint32 224 ReceivingNext uint32 225 PeerRTO uint32 226 } 227 228 func NewCmdOnlySegment() *CmdOnlySegment { 229 return new(CmdOnlySegment) 230 } 231 232 func (s *CmdOnlySegment) parse(conv uint16, cmd Command, opt SegmentOption, buf []byte) (bool, []byte) { 233 s.Conv = conv 234 s.Cmd = cmd 235 s.Option = opt 236 237 if len(buf) < 12 { 238 return false, nil 239 } 240 241 s.SendingNext = binary.BigEndian.Uint32(buf) 242 buf = buf[4:] 243 244 s.ReceivingNext = binary.BigEndian.Uint32(buf) 245 buf = buf[4:] 246 247 s.PeerRTO = binary.BigEndian.Uint32(buf) 248 buf = buf[4:] 249 250 return true, buf 251 } 252 253 func (s *CmdOnlySegment) Conversation() uint16 { 254 return s.Conv 255 } 256 257 func (s *CmdOnlySegment) Command() Command { 258 return s.Cmd 259 } 260 261 func (*CmdOnlySegment) ByteSize() int32 { 262 return 2 + 1 + 1 + 4 + 4 + 4 263 } 264 265 func (s *CmdOnlySegment) Serialize(b []byte) { 266 binary.BigEndian.PutUint16(b, s.Conv) 267 b[2] = byte(s.Cmd) 268 b[3] = byte(s.Option) 269 binary.BigEndian.PutUint32(b[4:], s.SendingNext) 270 binary.BigEndian.PutUint32(b[8:], s.ReceivingNext) 271 binary.BigEndian.PutUint32(b[12:], s.PeerRTO) 272 } 273 274 func (*CmdOnlySegment) Release() {} 275 276 func ReadSegment(buf []byte) (Segment, []byte) { 277 if len(buf) < 4 { 278 return nil, nil 279 } 280 281 conv := binary.BigEndian.Uint16(buf) 282 buf = buf[2:] 283 284 cmd := Command(buf[0]) 285 opt := SegmentOption(buf[1]) 286 buf = buf[2:] 287 288 var seg Segment 289 switch cmd { 290 case CommandData: 291 seg = NewDataSegment() 292 case CommandACK: 293 seg = NewAckSegment() 294 default: 295 seg = NewCmdOnlySegment() 296 } 297 298 valid, extra := seg.parse(conv, cmd, opt, buf) 299 if !valid { 300 return nil, nil 301 } 302 return seg, extra 303 }