proxymysql/app/mysqlserver/helper.go

228 lines
4.6 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package mysqlserver
import (
"encoding/binary"
"math/rand"
)
func WithHeaderPacket(data []byte, sequenceId uint8) []byte {
payloadLength := len(data)
header := make([]byte, 4)
header[0] = byte(payloadLength)
header[1] = byte(payloadLength >> 8)
header[2] = byte(payloadLength >> 16)
header[3] = sequenceId // 序列号 Sequence ID
return append(header, data...)
}
func WriteByte(value byte) []byte {
return []byte{value}
}
func WriteUint16(value uint16) []byte {
data := make([]byte, 2)
binary.LittleEndian.PutUint16(data, value)
return data
}
func WriteUint24(value uint32) []byte {
data := make([]byte, 3)
_ = data[2] // early bounds check to guarantee safety of writes below
data[0] = byte(value)
data[1] = byte(value >> 8)
data[2] = byte(value >> 16)
return data
}
func WriteUint32(value uint32) []byte {
data := make([]byte, 4)
binary.LittleEndian.PutUint32(data, value)
return data
}
func WriteUint64(value uint64) []byte {
data := make([]byte, 8)
binary.LittleEndian.PutUint64(data, value)
return data
}
func WriteString(value string) []byte {
return []byte(value)
}
func WriteStringNull(value string) []byte {
data := make([]byte, 0, len(value)+1)
data = append(data, []byte(value)...)
data = append(data, 0x00)
return data
}
func ReadString(value []byte) string {
return string(value)
}
func ReadHexString(value []byte) string {
return string(value)
}
func ReadStringNull(value []byte) string {
ln := len(value)
if ln == 0 {
return ""
}
// 剔除最后一位0x00
return string(value[:ln-1])
}
func ReadByte(value []byte) uint8 {
return value[0]
}
func ReadUint16(value []byte) uint16 {
return binary.LittleEndian.Uint16(value)
}
func ReadUint24(value []byte) uint32 {
_ = value[2]
return uint32(value[0]) | uint32(value[1])<<8 | uint32(value[2])<<16
}
func ReadUint32(value []byte) uint32 {
return binary.LittleEndian.Uint32(value)
}
func ReadUint64(value []byte) uint64 {
return binary.LittleEndian.Uint64(value)
}
// mysql 二进制数据长度编码Length Coded Binary
// 第一个字节值 后续字节数 长度值说明
// 0-250 0 第一个字节值即为数据的真实长度
// 251 0 空数据,数据的真实长度为零
// 252 2 后续额外2个字节标识了数据的真实长度
// 253 3 后续额外3个字节标识了数据的真实长度
// 254 8 后续额外8个字节标识了数据的真实长度
func ReadLengthEncodedInt(data []byte) (dataLength uint64, pos int, ok bool) {
if len(data) == 0 {
return 0, 0, false
}
pos = 0
switch data[pos] {
case 0xfb:
// 251: NULL
return 0, 1, true
case 0xfc:
// 252
// Encoded in the next 2 bytes.
if pos+2 >= len(data) {
return 0, 0, false
}
return uint64(data[pos+1]) |
uint64(data[pos+2])<<8, pos + 3, true
case 0xfd:
// 253
// Encoded in the next 3 bytes.
if pos+3 >= len(data) {
return 0, 0, false
}
return uint64(data[pos+1]) |
uint64(data[pos+2])<<8 |
uint64(data[pos+3])<<16, pos + 4, true
case 0xfe:
// 254
// Encoded in the next 8 bytes.
if pos+8 >= len(data) {
return 0, 0, false
}
return uint64(data[pos+1]) |
uint64(data[pos+2])<<8 |
uint64(data[pos+3])<<16 |
uint64(data[pos+4])<<24 |
uint64(data[pos+5])<<32 |
uint64(data[pos+6])<<40 |
uint64(data[pos+7])<<48 |
uint64(data[pos+8])<<56, pos + 9, true
}
return uint64(data[pos]), pos + 1, true
}
func GetLengthEncodedIntSize(value uint64) int {
switch {
case value < 251:
return 1
case value < 1<<16:
return 3
case value < 1<<24:
return 4
default:
return 9
}
}
func WriteLengthEncodedInt(value uint64) []byte {
data := make([]byte, GetLengthEncodedIntSize(value))
switch {
case value < 251:
data[0] = byte(value)
case value < 1<<16:
data[0] = 0xfc
data[1] = byte(value)
data[2] = byte(value >> 8)
case value < 1<<24:
data[0] = 0xfd
data[1] = byte(value)
data[2] = byte(value >> 8)
data[3] = byte(value >> 16)
default:
data[0] = 0xfe
data[1] = byte(value)
data[2] = byte(value >> 8)
data[3] = byte(value >> 16)
data[4] = byte(value >> 24)
data[5] = byte(value >> 32)
data[6] = byte(value >> 40)
data[7] = byte(value >> 48)
data[8] = byte(value >> 56)
}
return data
}
func WriteLengthEncodedString(strByte []byte) []byte {
strLen := len(strByte)
encodedInt := WriteLengthEncodedInt(uint64(strLen))
data := make([]byte, 0, strLen+len(encodedInt))
data = append(data, encodedInt...)
data = append(data, strByte...)
return data
}
func GetAuthPluginData() []byte {
minChar := 30
maxChar := 127
res := make([]byte, 21)
for k := range res {
if k == 20 {
k = 0x00 // 认证字符串以0x00结尾
break
}
res[k] = byte(rand.Intn(maxChar-minChar) + minChar)
}
return res
}