mcpinger/network_utils.cpp

119 lines
4.1 KiB
C++
Raw Normal View History

2024-05-08 13:27:23 +02:00
//network_utils.cpp
2024-05-08 10:24:32 +02:00
#include "network_utils.h"
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <iostream>
#include <cstring>
#include <algorithm>
#include "protocol_utils.h"
2024-05-08 13:27:23 +02:00
int sendData(int sockfd, const std::vector<unsigned char> &data) {
2024-05-08 10:24:32 +02:00
ssize_t sent = send(sockfd, data.data(), data.size(), 0);
if (sent < 0) {
perror("Error sending data");
return ERROR_SENDING_DATA;
}
return SUCCESS;
}
2024-05-08 13:27:23 +02:00
int receiveData(int sockfd, std::vector<unsigned char> &buffer) {
2024-05-08 10:24:32 +02:00
buffer.resize(1024);
ssize_t bytesReceived = recv(sockfd, buffer.data(), buffer.size(), 0);
if (bytesReceived < 0) {
perror("Error receiving data");
return ERROR_RECEIVING_DATA;
}
buffer.resize(bytesReceived);
return SUCCESS;
}
2024-05-08 13:27:23 +02:00
std::string
pingMinecraftServer(const std::string &hostname, int port, const std::string &virtualHostname, int virtualPort,
int protocolVersionIn, int nextStateIn) {
2024-05-08 10:24:32 +02:00
struct addrinfo hints{}, *res, *result;
int sockfd, err;
2024-05-08 13:27:23 +02:00
(void) memset(&hints, 0, sizeof(hints));
2024-05-08 10:24:32 +02:00
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
err = getaddrinfo(hostname.c_str(), std::to_string(port).c_str(), &hints, &result);
if (err != 0) {
std::cerr << "Error resolving hostname: " << gai_strerror(err) << std::endl;
2024-05-08 13:27:23 +02:00
return "ERROR_RESOLVING_HOSTNAME";
2024-05-08 10:24:32 +02:00
}
for (res = result; res != nullptr; res = res->ai_next) {
sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (sockfd == -1) continue;
2024-05-08 13:27:23 +02:00
// Set timeouts
struct timeval timeout;
timeout.tv_sec = 5; // 5 seconds timeout
timeout.tv_usec = 0;
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char *) &timeout, sizeof(timeout));
setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, (const char *) &timeout, sizeof(timeout));
2024-05-08 10:24:32 +02:00
if (connect(sockfd, res->ai_addr, res->ai_addrlen) != -1) break;
2024-05-08 13:27:23 +02:00
(void) close(sockfd);
2024-05-08 10:24:32 +02:00
}
if (res == nullptr) {
freeaddrinfo(result);
2024-05-08 13:27:23 +02:00
return "ERROR_CONNECTION_FAILED";
2024-05-08 10:24:32 +02:00
}
freeaddrinfo(result);
// Handshake
std::vector<unsigned char> packet;
packet.push_back(0x00U); // Packet ID for handshake
std::vector<unsigned char> protocolVersion = encodeVarint(protocolVersionIn);
std::vector<unsigned char> serverAddress = encodeString(virtualHostname);
2024-05-08 13:27:23 +02:00
std::vector<unsigned char> serverPort = {static_cast<unsigned char>((virtualPort >> 8) & 0xFF),
static_cast<unsigned char>(virtualPort & 0xFFU)};
2024-05-08 10:24:32 +02:00
std::vector<unsigned char> nextState = encodeVarint(nextStateIn);
2024-05-08 13:27:23 +02:00
(void) packet.insert(packet.end(), protocolVersion.begin(), protocolVersion.end());
(void) packet.insert(packet.end(), serverAddress.begin(), serverAddress.end());
(void) packet.insert(packet.end(), serverPort.begin(), serverPort.end());
(void) packet.insert(packet.end(), nextState.begin(), nextState.end());
2024-05-08 10:24:32 +02:00
std::vector<unsigned char> handshakeLength = encodeVarint(packet.size());
2024-05-08 13:27:23 +02:00
(void) packet.insert(packet.begin(), handshakeLength.begin(), handshakeLength.end());
2024-05-08 10:24:32 +02:00
if (sendData(sockfd, packet) != SUCCESS) {
2024-05-08 13:27:23 +02:00
(void) close(sockfd);
return "ERROR_SENDING_DATA";
2024-05-08 10:24:32 +02:00
}
// Status request
std::vector<unsigned char> statusRequest = {0x01U, 0x00U}; // Packet length and Packet ID for status request
if (sendData(sockfd, statusRequest) != SUCCESS) {
2024-05-08 13:27:23 +02:00
(void) close(sockfd);
return "ERROR_SENDING_DATA";
2024-05-08 10:24:32 +02:00
}
// Read status response
std::vector<unsigned char> response;
if (receiveData(sockfd, response) != SUCCESS) {
2024-05-08 13:27:23 +02:00
(void) close(sockfd);
return "ERROR_RECEIVING_DATA";
2024-05-08 10:24:32 +02:00
}
// Extract JSON string (assuming it starts from the position of the first '{' found in the response)
auto pos = std::find(response.begin(), response.end(), '{');
if (pos != response.end()) {
std::string json(pos, response.end());
std::cout << json << std::endl;
2024-05-08 13:27:23 +02:00
(void) close(sockfd);
return json;
2024-05-08 10:24:32 +02:00
} else {
2024-05-08 13:27:23 +02:00
(void) close(sockfd);
return "ERROR_JSON";
2024-05-08 10:24:32 +02:00
}
}