preface

This RPC supports TCP KCP UNIX so we need to design the protocol

Github.com/dollarkille…

Defining a handshake protocol

Handshake logic:

  1. Establish a link to transmit aes key to the server via asymmetric encryption (with token)
  2. Symmetric encryption is used when the server authenticates the token and records the AES key to interact with the client
The starting character keySize tokenSize errorSize key token err
0x09 4 4 4 xxx xxx xxx

type Handshake struct {
	Key   []byte  // AES encryption KEY
	Token []byte  // AUTH check is used
	Error []byte  // Error padding
}
Copy the code

coding

func EncodeHandshake(key, token, err []byte) []byte {
	buf := make([]byte.13+len(key)+len(token)+len(err))

	buf[0] = LightHandshakeSt
	binary.LittleEndian.PutUint32(buf[1:5].uint32(len(key)))
	binary.LittleEndian.PutUint32(buf[5:9].uint32(len(token)))
	binary.LittleEndian.PutUint32(buf[9:13].uint32(len(err)))

	st := 13
	endI := st + len(key)
	copy(buf[st:endI], key)

	st = endI
	endI = st + len(token)
	copy(buf[st:endI], token)

	st = endI
	endI = st + len(err)
	copy(buf[st:endI], err)

	return buf
}
Copy the code

decoding

func (h *Handshake) Handshake(r io.Reader) error {
	headerByte := make([]byte.13)

	// Read the flag bit
	_, err := io.ReadFull(r, headerByte[:1])
	iferr ! =nil {
		return err
	}

	if headerByte[0] != LightHandshakeSt {
		return errors.New("NO Light Handshake")}// Read the rest
	_, err = io.ReadFull(r, headerByte[1:)iferr ! =nil {
		return err
	}

	/ / head
	keySize := binary.LittleEndian.Uint32(headerByte[1:5])
	tokenSize := binary.LittleEndian.Uint32(headerByte[5:9])
	errorSize := binary.LittleEndian.Uint32(headerByte[9:13])

	bodyData := make([]byte, keySize+tokenSize+errorSize)
	_, err = io.ReadFull(r, bodyData)
	iferr ! =nil {
		return err
	}

	var st uint32 = 0
	endIdx := keySize
	key := make([]byte, keySize)
	copy(key, bodyData[st:endIdx])
	h.Key = key

	st = endIdx
	endIdx = st + tokenSize
	token := make([]byte, tokenSize)
	copy(token, bodyData[st:endIdx])
	h.Token = token

	st = endIdx
	endIdx = st + errorSize
	errStr := make([]byte, errorSize)
	copy(errStr, bodyData[st:endIdx])
	h.Error = errStr

	return nil
}
Copy the code

Define transport protocol

/** Protocol design start: Version: crc32 Verification: magicNumberSize: serverNameSize: serverMethodSize: metaDataSize: payloadSize: respType : compressorType : serializationType : magicNumber : serverName : serverMethod : metaData : payload 0x05 : 0x01 : 4 : 4 : 4 : 4 : 4 : 4 : 1 : 1 : 1 : xxx : xxx : xxx : xxx : xxx */ type Message struct { Header *Header MagicNumber string ServiceName string ServiceMethod string MetaData []byte Payload []byte } type Header struct { St byte Version byte Crc32 uint32 MagicNumberSize uint32 ServerNameSize uint32 ServerMethodSize uint32 MetaDataSize uint32 PayloadSize uint32 RespType byte CompressorType byte SerializationType byte }Copy the code

coding

// EncodeMessage base code
func EncodeMessage(magicStr string, server, method, metaData []byte, respType, compressorType, serializationType byte, payload []byte) (magic string, data []byte, err error) {
	var magicNumber = []byte(magicStr)
	if magicStr == "" {
		magicNumber = []byte(xid.New().String())
	}

	bufSize := HeadSize + len(server) + len(method) + len(metaData) + len(payload) + len(magicNumber)
	buf := make([]byte, bufSize)

	buf[0] = LightSt
	buf[1] = byte(V1)
	binary.LittleEndian.PutUint32(buf[6:10].uint32(len(magicNumber)))
	binary.LittleEndian.PutUint32(buf[10:14].uint32(len(server)))
	binary.LittleEndian.PutUint32(buf[14:18].uint32(len(method)))
	binary.LittleEndian.PutUint32(buf[18:22].uint32(len(metaData)))
	binary.LittleEndian.PutUint32(buf[22:26].uint32(len(payload)))
	buf[26] = respType
	buf[27] = compressorType
	buf[28] = serializationType

	st := HeadSize
	endI := st + len(magicNumber)
	copy(buf[st:endI], magicNumber)

	st = endI
	endI = st + len(server)
	copy(buf[st:endI], server)

	st = endI
	endI = st + len(method)
	copy(buf[st:endI], method)

	st = endI
	endI = st + len(metaData)
	copy(buf[st:endI], metaData)

	st = endI
	endI = st + len(payload)
	copy(buf[st:endI], payload)

	if Crc32 {
		u := crc32.ChecksumIEEE(buf[6:])
		binary.LittleEndian.PutUint32(buf[2:6], u)
	}

	return string(magicNumber), buf, nil
}
Copy the code

decoding

func (m *Protocol) IODecode(r io.Reader) (*Message, error) {
	headerByte := make([]byte, HeadSize)
	// Read the flag bit
	_, err := io.ReadFull(r, headerByte[:1])
	iferr ! =nil {
		return nil, err
	}

	if headerByte[0] != LightSt {
		log.Println(headerByte)
		return nil, errors.New("NO Light")}// Read the rest
	_, err = io.ReadFull(r, headerByte[1:)iferr ! =nil {
		return nil, err
	}

	/ / parsing the headers
	header, err := DecodeHeader(headerByte)
	iferr ! =nil {
		return nil. err } bodyLen := header.MagicNumberSize + header.ServerNameSize + header.ServerMethodSize + header.MetaDataSize + header.PayloadSize bodyData :=make([]byte, bodyLen)
	_, err = io.ReadFull(r, bodyData)
	iferr ! =nil {
		return nil, err
	}

	msg, err := DecodeMessageV2(bodyData, header, 0)
	iferr ! =nil {
		return nil, err
	}

	return msg, nil
}

func DecodeHeader(data []byte) (*Header, error) {
	var header Header
	header.St = data[0]
	header.Version = data[1]
	header.Crc32 = binary.LittleEndian.Uint32(data[2:6])
	if Crc32 {
		u := crc32.ChecksumIEEE(data[6:)ifheader.Crc32 ! = u {return nil, errors.New("CRC Calibration")
		}
	}
	header.MagicNumberSize = binary.LittleEndian.Uint32(data[6:10])
	header.ServerNameSize = binary.LittleEndian.Uint32(data[10:14])
	header.ServerMethodSize = binary.LittleEndian.Uint32(data[14:18])
	header.MetaDataSize = binary.LittleEndian.Uint32(data[18:22])
	header.PayloadSize = binary.LittleEndian.Uint32(data[22:26])
	header.RespType = data[26]
	header.CompressorType = data[27]
	header.SerializationType = data[28]

	return &header, nil
}

// DecodeMessage DecodeMessage
func DecodeMessage(data []byte) (*Message, error) {
	header, err := DecodeHeader(data)
	iferr ! =nil {
		return nil, err
	}
	return DecodeMessageV2(data, header, HeadSize)
}

func DecodeMessageV2(data []byte, header *Header, headSize uint32) (*Message, error) {
	var result Message
	result.Header = header
	var st uint32 = headSize
	endI := st + header.MagicNumberSize
	les := endI - st
	magicNumber := make([]byte, les)
	copy(magicNumber, data[st:endI])
	result.MagicNumber = string(magicNumber)

	st = endI
	endI = st + header.ServerNameSize
	les = endI - st
	serverName := make([]byte, les)
	copy(serverName, data[st:endI])
	result.ServiceName = string(serverName)

	st = endI
	endI = st + header.ServerMethodSize
	les = endI - st
	serverMethodSize := make([]byte, les)
	copy(serverMethodSize, data[st:endI])
	result.ServiceMethod = string(serverMethodSize)

	st = endI
	endI = st + header.MetaDataSize
	les = endI - st
	metaDataSize := make([]byte, les)
	copy(metaDataSize, data[st:endI])
	result.MetaData = metaDataSize

	st = endI
	endI = st + header.PayloadSize
	les = endI - st
	payloadSize := make([]byte, les)
	copy(payloadSize, data[st:endI])
	result.Payload = payloadSize

	return &result, nil
}
Copy the code

columnJuejin. Cn/column / 6986…