c++ - MySQL命令阶段没有来自服务器的响应
问题描述
我正在开发自己的 mysql 客户端。连接阶段运行良好。但是在随后的每个命令/数据包上,服务器都没有响应并在 30 秒后关闭连接。作为我的 mysql 服务器,我使用默认配置的 xampp。(我知道 C++ 有很好的 mysql 库,但我想创建自己的)。
这是我的代码(它只是用于测试,我知道它远非完美)
#include <string.h>
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <bitset>
#include <unistd.h>
#include <openssl/sha.h>
int main(int argc, char *argv[])
{
int socketDescriptor;
//server setup
{
bool preparation = true ;
//prepare socket address information
struct addrinfo hints = {0}, *addressInfo;
hints.ai_flags = AI_PASSIVE;
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
if (getaddrinfo(NULL, (const char *) "3306", &hints, &addressInfo))
preparation = false;
//initialize socket and prepare for accepting connections
socketDescriptor = socket(addressInfo->ai_family, addressInfo->ai_socktype, addressInfo->ai_protocol);
if (-1 == socketDescriptor)
preparation = false;
struct timeval timeout;
timeout.tv_sec = 1;
timeout.tv_usec = 0;
if (-1 == setsockopt(socketDescriptor, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)))
preparation = false;
if (-1 == connect(socketDescriptor, addressInfo->ai_addr, addressInfo->ai_addrlen))
preparation = false;
freeaddrinfo(addressInfo);
if (!preparation)
{
std::cerr << "Server initialization failed" << std::endl;
exit(1);
}
}
//get handshakev10
//fetch header
char header[4] = {0};
if(4 > recv(socketDescriptor, header, 4, 0))
exit(1);
uint32_t payloadLength = 0;
for(int i = 0; i < 3; i++)
payloadLength |= (header[i] << (8 * i)) & 0b11111111;
uint8_t sequenceID = header[3];
std::string serverVersion = "";
uint32_t threadID = 0;
char authData1[8] = {0};
uint32_t capabilityFlags = 0;
uint8_t characterSet = 0;
uint16_t statusFlags = 0;
std::string pluginName = "";
//fetch payload
char payload[payloadLength] = {0};
int offset = 0;
if(payloadLength > recv(socketDescriptor, payload, payloadLength, 0))
exit(1);
if(10 != payload[offset])
exit(1);
offset++;
//parse payload
while('\0' != payload[offset])
{
serverVersion += payload[offset];
offset++;
}
offset++;
for(int i = 0; i < 4; i++)
{
threadID |= (payload[offset] & 0b11111111) << (8 * i);
offset++;
}
for(int i = 0; i < 8; i++)
{
authData1[i] = payload[offset];
offset++;
}
offset++;
capabilityFlags |= payload[offset] & 0b11111111;
offset++;
capabilityFlags |= (payload[offset] & 0b11111111) << 8;
offset++;
characterSet = payload[offset];
offset++;
statusFlags |= payload[offset] & 0b11111111;
offset++;
statusFlags |= (payload[offset] & 0b11111111) << 8;
offset++;
capabilityFlags |= (payload[offset] & 0b11111111) << 16;
offset++;
capabilityFlags |= (payload[offset] & 0b11111111) << 24;
offset++;
uint8_t authData2Len = payload[offset];
offset++;
offset += 10;
if(!authData2Len) authData2Len = 13;
else authData2Len -= 9;
char authData2[authData2Len] = {0};
for(int i = 0; i < authData2Len; i++)
{
authData2[i] = payload[offset];
offset++;
}
offset++;
while('\0' != payload[offset])
{
pluginName += payload[offset];
offset++;
}
//generate authData with native password method
unsigned char *password = (unsigned char *)"test";
if("mysql_native_password" != pluginName)
exit(1);
unsigned char hashedPW[20] = {0};
unsigned char doubleHashedPW[20] = {0};
unsigned char hashable[40] = {0};
SHA1(password, 4, hashedPW);
SHA1(hashedPW, 20, doubleHashedPW);
for(int i = 0; i < 8; i++)
hashable[i] = authData1[i];
for(int i = 0; i < 12; i++)
hashable[i + 8] = authData2[i];
for(int i = 0; i < 20; i++)
hashable[i + 20] = doubleHashedPW[i];
SHA1(hashable, 40, doubleHashedPW);
for(int i = 0; i < 20; i++)
hashedPW[i] = hashedPW[i] ^ doubleHashedPW[i];
//prepare handhshakeResponse41
uint32_t maxPacketSize = 2048;
char* username = "MyCustomUser";
char *database = "accounts";
char *responsePluginName = "mysql_native_password";
capabilityFlags &= 0b11111011111011111111111111111111;
uint32_t responsePayloadLen = 4+4+4+1+23+strlen(username)+1+21+strlen(database)+1+strlen(responsePluginName)+1+1;
char responsePayload[responsePayloadLen] = {0};
for(int i = 0; i < 3; i++)
responsePayload[i] = (responsePayloadLen-4 >> (i * 8)) & 0b11111111;
responsePayload[3] = 1;
for(int i = 0; i < 4; i++)
responsePayload[i+4] = (capabilityFlags >> (i * 8)) & 0b11111111;
for(int i = 0; i < 4; i++)
responsePayload[i+8] = (maxPacketSize >> (i * 8)) & 0b11111111;
responsePayload[12] = characterSet;
for(int i = 0; i < strlen(username) + 1; i++)
responsePayload[36 + i] = username[i];
responsePayload[49] = 20;
for(int i = 0; i < 20; i++)
responsePayload[50 + i] = hashedPW[i];
for(int i = 0; i < strlen(database) + 1; i++)
responsePayload[70 + i] = database[i];
for(int i = 0; i < strlen(responsePluginName) + 1; i++)
responsePayload[79 + i] = responsePluginName[i];
responsePayload[101] = 0;
send(socketDescriptor, responsePayload, responsePayloadLen, 0);
//send COM_PING packet
char a = 1;
while(1 == recv(socketDescriptor, &a, 1, 0))
std::cout << std::bitset<8>(a) << " : " << a << std::endl;
char b[5] = {0};
b[0] = 1;
b[4] = 0x0E;
send(socketDescriptor, b, 5, 0);
std::cout << "send: " << std::endl;
for(int i = 0; i < 5; i++)
std::cout << std::bitset<8>(b[i]) << " : " << b[i] << std::endl;
std::cout << "recieved: " << std::endl;
while(0 != recv(socketDescriptor, &a, 1, 0))
std::cout << std::bitset<8>(a) << " : " << a << std::endl;
}
解决方案
我发现问题在于在我的 handshakeResponse41 中设置正确的功能标志。我忘记设置标志以指示不应使用压缩协议。
推荐阅读
- python - 我该如何解决这个错误。它看起来像一个类型错误,但我很确定这些数组属于同一类型
- java - 如何在 discrod4j 中为聊天机器人添加冷却时间?
- printing - 如何让 HP Color LaserJet 打印机驱动程序重新自动安装
- hyperledger-fabric - 我是否应该学习超级账本作曲家,即使它已经贬值
- python - 本地服务器上的 Flask 部署
- ffmpeg - FFMPEG ldash 1 低延迟选项,但 dash.js 不是低延迟和有滞后的错误并且总是从 0 开始无法控制
- javascript - 具有多种情况的 JavaScript Switch 语句
- r - 将字符串列表中的每个字符串元素编码为 R 数据框列中的数字列表
- r - R函数在webscraper中循环相同的数据
- node.js - 在 Firebase 身份验证 NodeJS 中使用电子邮件和密码进行重定向