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  }