preface
This RPC supports TCP KCP UNIX so we need to design the protocol
Github.com/dollarkille…
Defining a handshake protocol
Handshake logic:
- Establish a link to transmit aes key to the server via asymmetric encryption (with token)
- 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