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