github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/dm/debug-tools/binlog-event-blackhole/packet.go (about) 1 // Copyright 2019 PingCAP, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package main 15 16 import ( 17 "encoding/binary" 18 "io" 19 "os" 20 ) 21 22 // registerSlaveCommand generates a COM_REGISTER_SLAVE command (with uninitialized header). 23 // ref https://dev.mysql.com/doc/internals/en/com-register-slave.html. 24 func registerSlaveCommand(username, password string, serverID uint32) []byte { 25 hn, _ := os.Hostname() 26 27 packet := make([]byte, 4+1+4+1+len(hn)+1+len(username)+1+len(password)+2+4+4) 28 offset := 4 // 4 bytes header 29 30 packet[offset] = 0x15 // COM_REGISTER_SLAVE 31 offset++ 32 33 binary.LittleEndian.PutUint32(packet[offset:], serverID) 34 offset += 4 35 36 packet[offset] = uint8(len(hn)) 37 offset++ 38 n := copy(packet[offset:], hn) 39 offset += n 40 41 packet[offset] = uint8(len(username)) 42 offset++ 43 n = copy(packet[offset:], username) 44 offset += n 45 46 packet[offset] = uint8(len(password)) 47 offset++ 48 n = copy(packet[offset:], password) 49 offset += n 50 51 binary.LittleEndian.PutUint16(packet[offset:], 0) 52 offset += 2 53 54 binary.LittleEndian.PutUint32(packet[offset:], 0) 55 offset += 4 56 57 binary.LittleEndian.PutUint32(packet[offset:], 0) 58 59 setCommandHeader(packet, 0) 60 61 return packet 62 } 63 64 // dumpCommand generates a COM_BINLOG_DUMP command. 65 // ref https://dev.mysql.com/doc/internals/en/com-binlog-dump.html. 66 func dumpCommand(serverID uint32, name string, pos uint32) []byte { 67 packet := make([]byte, 4+1+4+2+4+len(name)) 68 offset := 4 // 4 bytes header 69 70 packet[offset] = 0x12 // COM_BINLOG_DUMP 71 offset++ 72 73 binary.LittleEndian.PutUint32(packet[offset:], pos) 74 offset += 4 75 76 binary.LittleEndian.PutUint16(packet[offset:], 0x00) // BINLOG_DUMP_NEVER_STOP 77 offset += 2 78 79 binary.LittleEndian.PutUint32(packet[offset:], serverID) 80 offset += 4 81 82 copy(packet[offset:], name) 83 84 setCommandHeader(packet, 0) 85 86 return packet 87 } 88 89 // setCommandHeader set the header of the command inplace. 90 // ref https://dev.mysql.com/doc/internals/en/mysql-packet.html. 91 func setCommandHeader(packet []byte, seqID uint8) { 92 // do not handle a payload which is larger than or equal to 2^24−1 bytes (16 MB) now. 93 length := len(packet) - 4 94 packet[0] = byte(length) 95 packet[1] = byte(length >> 8) 96 packet[2] = byte(length >> 16) 97 98 packet[3] = seqID 99 } 100 101 // readPacket tries to read a MySQL packet (header & payload) from the Reader. 102 func readPacket(r io.Reader) ([]byte, []byte, error) { 103 header := []byte{0, 0, 0, 0} 104 _, err := io.ReadFull(r, header) 105 if err != nil { 106 return nil, nil, err 107 } 108 109 length := int(uint32(header[0]) | uint32(header[1])<<8 | uint32(header[2])<<16) 110 payload := make([]byte, length) 111 _, err = io.ReadFull(r, payload) 112 if err != nil { 113 return nil, nil, err 114 } 115 116 return header, payload, nil 117 }