rcon protocol helpers
This commit is contained in:
100
src/main.c
100
src/main.c
@@ -58,9 +58,107 @@ int rcon_connect(int port) {
|
||||
return sockfd;
|
||||
}
|
||||
|
||||
|
||||
void send_packet(int sockfd, int32_t id, int32_t type, const char *body) {
|
||||
int body_len = strlen(body);
|
||||
int32_t size = 10 + body_len; // 4 (id) + 4 (type) + body + 2 (null terminators)
|
||||
|
||||
send(sockfd, &size, sizeof(int32_t), 0);
|
||||
send(sockfd, &id, sizeof(int32_t), 0);
|
||||
send(sockfd, &type, sizeof(int32_t), 0);
|
||||
send(sockfd, body, body_len + 1, 0);
|
||||
const char null = '\0';
|
||||
send(sockfd, &null, 1, 0);
|
||||
}
|
||||
|
||||
int recv_packet(int sockfd, rcon_packet_t *packet) {
|
||||
if (recv(sockfd, &packet->size, sizeof(int32_t), 0) <= 0) { return -1; }
|
||||
if (recv(sockfd, &packet->id, sizeof(int32_t), 0) <= 0) { return -1; }
|
||||
if (recv(sockfd, &packet->type, sizeof(int32_t), 0) <= 0) { return -1; }
|
||||
|
||||
// read body (size - 10 bytes for id, type, and two null terminators)
|
||||
int body_size = packet->size - 10;
|
||||
if (body_size > 0 && body_size < sizeof(packet->body)) {
|
||||
if (recv(sockfd, packet->body, body_size + 2, 0) <= 0) {
|
||||
return -1;
|
||||
}
|
||||
packet->body[body_size] = '\0';
|
||||
} else {
|
||||
packet->body[0] = '\0';
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rcon_authenticate(int sockfd, const char *password) {
|
||||
send_packet(sockfd, 1, SERVERDATA_AUTH, password);
|
||||
|
||||
rcon_packet_t response;
|
||||
if (recv_packet(sockfd, &response) < 0) {
|
||||
perror("failed to receive auth response\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (response.id == -1) {
|
||||
perror("authentication failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("authenticated successfully\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
char* rcon_command(int sockfd, const char *command) {
|
||||
static char result[8192];
|
||||
result[0] = '\0';
|
||||
|
||||
send_packet(sockfd, 2, SERVERDATA_EXECCOMMAND, command);
|
||||
|
||||
// Handle multi-packet responses
|
||||
while (1) {
|
||||
rcon_packet_t response;
|
||||
if (recv_packet(sockfd, &response) < 0) {
|
||||
perror("failed to receive command response\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (response.type == SERVERDATA_RESPONSE_VALUE) {
|
||||
strncat(result, response.body, sizeof(result) - strlen(result) - 1);
|
||||
|
||||
// Check if response is complete (body length < 4096)
|
||||
if (strlen(response.body) < 4096) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
const int PORT_NUM = read_env_int("RCON_PORT_NUMBER");
|
||||
const char *password = getenv("RCON_PASSWORD");
|
||||
|
||||
if (password == NULL) {
|
||||
perror("error: RCON_PASSWORD environment variable not set.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
printf("port: %d\n", PORT_NUM);
|
||||
|
||||
rcon_connect(PORT_NUM);
|
||||
int sockfd = rcon_connect(PORT_NUM);
|
||||
|
||||
if (rcon_authenticate(sockfd, password) < 0) {
|
||||
close(sockfd);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// example
|
||||
char *response = rcon_command(sockfd, "help");
|
||||
if (response) {
|
||||
printf("Response:\n%s\n", response);
|
||||
}
|
||||
|
||||
close(sockfd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user