Run clang-format
Build and test / build (push) Successful in 1m2s
Build and test / test (push) Successful in 1m7s
Build and test / build-freebsd-cross (push) Successful in 1m54s

This commit is contained in:
2026-06-12 02:51:25 +09:00
parent 3c2c462710
commit 40424da19f
8 changed files with 536 additions and 250 deletions
+296
View File
@@ -0,0 +1,296 @@
---
Language: Cpp
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignArrayOfStructures: None
AlignConsecutiveAssignments:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: true
AlignConsecutiveBitFields:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveDeclarations:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: true
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveMacros:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveShortCaseStatements:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCaseArrows: false
AlignCaseColons: false
AlignConsecutiveTableGenBreakingDAGArgColons:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveTableGenCondOperatorColons:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveTableGenDefinitionColons:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: false
AlignEscapedNewlines: Right
AlignOperands: Align
AlignTrailingComments:
Kind: Always
OverEmptyLines: 0
AllowAllArgumentsOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowBreakBeforeNoexceptSpecifier: Never
AllowShortBlocksOnASingleLine: Never
AllowShortCaseExpressionOnASingleLine: true
AllowShortCaseLabelsOnASingleLine: false
AllowShortCompoundRequirementOnASingleLine: true
AllowShortEnumsOnASingleLine: true
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Never
AllowShortLambdasOnASingleLine: All
AllowShortLoopsOnASingleLine: false
AllowShortNamespacesOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AttributeMacros:
- __capability
BinPackArguments: true
BinPackLongBracedList: true
BinPackParameters: BinPack
BitFieldColonSpacing: Both
BracedInitializerIndentWidth: -1
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: Never
AfterEnum: false
AfterExternBlock: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
BeforeCatch: false
BeforeElse: false
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakAdjacentStringLiterals: true
BreakAfterAttributes: Leave
BreakAfterJavaFieldAnnotations: false
BreakAfterReturnType: None
BreakArrays: true
BreakBeforeBinaryOperators: None
BreakBeforeConceptDeclarations: Always
BreakBeforeBraces: Attach
BreakBeforeInlineASMColon: OnlyMultiline
BreakBeforeTemplateCloser: false
BreakBeforeTernaryOperators: true
BreakBinaryOperations: Never
BreakConstructorInitializers: BeforeColon
BreakFunctionDefinitionParameters: false
BreakInheritanceList: BeforeColon
BreakStringLiterals: true
BreakTemplateDeclarations: MultiLine
ColumnLimit: 120
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: LogicalBlock
EnumTrailingComma: Leave
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IfMacros:
- KJ_IF_MAYBE
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
SortPriority: 0
CaseSensitive: false
- Regex: '.*'
Priority: 1
SortPriority: 0
CaseSensitive: false
IncludeIsMainRegex: '(Test)?$'
IncludeIsMainSourceRegex: ''
IndentAccessModifiers: false
IndentCaseBlocks: false
IndentCaseLabels: false
IndentExportBlock: true
IndentExternBlock: AfterExternBlock
IndentGotoLabels: true
IndentPPDirectives: None
IndentRequiresClause: true
IndentWidth: 2
IndentWrappedFunctionNames: false
InsertBraces: false
InsertNewlineAtEOF: false
InsertTrailingCommas: None
IntegerLiteralSeparator:
Binary: 0
BinaryMinDigits: 0
Decimal: 0
DecimalMinDigits: 0
Hex: 0
HexMinDigits: 0
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLines:
AtEndOfFile: false
AtStartOfBlock: true
AtStartOfFile: true
KeepFormFeed: false
LambdaBodyIndentation: Signature
LineEnding: DeriveLF
MacroBlockBegin: ''
MacroBlockEnd: ''
MainIncludeChar: Quote
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
OneLineFormatOffRegex: ''
PackConstructorInitializers: BinPack
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakBeforeMemberAccess: 150
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakOpenParenthesis: 0
PenaltyBreakScopeResolution: 500
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyIndentedWhitespace: 0
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
PPIndentWidth: -1
QualifierAlignment: Leave
ReferenceAlignment: Pointer
ReflowComments: Always
RemoveBracesLLVM: false
RemoveEmptyLinesInUnwrappedLines: false
RemoveParentheses: Leave
RemoveSemicolon: false
RequiresClausePosition: OwnLine
RequiresExpressionIndentation: OuterScope
SeparateDefinitionBlocks: Leave
ShortNamespaceLines: 1
SkipMacroDefinitionBody: false
SortIncludes:
Enabled: true
IgnoreCase: false
SortJavaStaticImport: Before
SortUsingDeclarations: LexicographicNumeric
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterOperatorKeyword: false
SpaceAfterTemplateKeyword: true
SpaceAroundPointerQualifiers: Default
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeJsonColon: false
SpaceBeforeParens: ControlStatements
SpaceBeforeParensOptions:
AfterControlStatements: true
AfterForeachMacros: true
AfterFunctionDefinitionName: false
AfterFunctionDeclarationName: false
AfterIfMacros: true
AfterNot: false
AfterOverloadedOperator: false
AfterPlacementOperator: true
AfterRequiresInClause: false
AfterRequiresInExpression: false
BeforeNonEmptyParentheses: false
SpaceBeforeRangeBasedForLoopColon: true
SpaceBeforeSquareBrackets: false
SpaceInEmptyBlock: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: Never
SpacesInContainerLiterals: true
SpacesInLineCommentPrefix:
Minimum: 1
Maximum: -1
SpacesInParens: Never
SpacesInParensOptions:
ExceptDoubleParentheses: false
InCStyleCasts: false
InConditionalStatements: false
InEmptyParentheses: false
Other: false
SpacesInSquareBrackets: false
Standard: Latest
StatementAttributeLikeMacros:
- Q_EMIT
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TableGenBreakInsideDAGArg: DontBreak
TabWidth: 8
UseTab: Never
VerilogBreakBetweenInstancePorts: true
WhitespaceSensitiveMacros:
- BOOST_PP_STRINGIZE
- CF_SWIFT_NAME
- NS_SWIFT_NAME
- PP_STRINGIZE
- STRINGIZE
WrapNamespaceBodyWithEmptyLines: Leave
...
+55 -55
View File
@@ -6,72 +6,72 @@
#include <stdlib.h>
#include <unistd.h>
#include "rcon.h"
#include "minecraft.h"
#include "rcon.h"
const char *LOCALHOST = "127.0.0.1";
int read_env_int(const char *var) {
const char* port_str = getenv(var);
if (port_str == NULL) {
fprintf(stderr, "error: %s environment variable not set.\n", var);
exit(EXIT_FAILURE);
}
char* endptr;
long val = strtol(port_str, &endptr, 10);
if (endptr == port_str || *endptr != '\0') {
fprintf(stderr, "error: invalid number format for %s.\n", var);
exit(EXIT_FAILURE);
}
return (int)val;
const char *port_str = getenv(var);
if (port_str == NULL) {
fprintf(stderr, "error: %s environment variable not set.\n", var);
exit(EXIT_FAILURE);
}
char *endptr;
long val = strtol(port_str, &endptr, 10);
if (endptr == port_str || *endptr != '\0') {
fprintf(stderr, "error: invalid number format for %s.\n", var);
exit(EXIT_FAILURE);
}
return (int)val;
}
int main(void) {
const int PORT_NUM = read_env_int("RCON_PORT_NUMBER");
const char *password = getenv("RCON_PASSWORD");
const int PORT_NUM = read_env_int("RCON_PORT_NUMBER");
const char *password = getenv("RCON_PASSWORD");
if (password == NULL) {
fprintf(stderr, "error: RCON_PASSWORD environment variable not set.\n");
exit(EXIT_FAILURE);
}
if (password == NULL) {
fprintf(stderr, "error: RCON_PASSWORD environment variable not set.\n");
exit(EXIT_FAILURE);
}
printf("=== RCON Configuration ===\n");
printf("port: %d\n", PORT_NUM);
printf("password: '%s'\n", password);
printf("==========================\n\n");
printf("=== RCON Configuration ===\n");
printf("port: %d\n", PORT_NUM);
printf("password: '%s'\n", password);
printf("==========================\n\n");
int sockfd = rcon_connect(LOCALHOST, PORT_NUM);
if (rcon_authenticate(sockfd, password) < 0) {
close(sockfd);
exit(EXIT_FAILURE);
}
player_entity_t* entities = malloc(sizeof(player_entity_t) * 20);
if (!entities) {
perror("malloc failed");
close(sockfd);
exit(EXIT_FAILURE);
}
if (query_player_entities(sockfd, 20, entities) < 0) {
fprintf(stderr, "failed to query player entities\n");
free(entities);
close(sockfd);
exit(EXIT_FAILURE);
}
printf("\n=== player positions ===\n");
for (size_t i = 0; i < 20 && entities[i].name != NULL; i++) {
printf("%s: (%.2f, %.2f, %.2f)\n", entities[i].name, entities[i].x, entities[i].y, entities[i].z);
}
for (size_t i = 0; i < 20; i++) {
free_player_entity(&entities[i]);
}
free(entities);
int sockfd = rcon_connect(LOCALHOST, PORT_NUM);
if (rcon_authenticate(sockfd, password) < 0) {
close(sockfd);
return 0;
exit(EXIT_FAILURE);
}
player_entity_t *entities = malloc(sizeof(player_entity_t) * 20);
if (!entities) {
perror("malloc failed");
close(sockfd);
exit(EXIT_FAILURE);
}
if (query_player_entities(sockfd, 20, entities) < 0) {
fprintf(stderr, "failed to query player entities\n");
free(entities);
close(sockfd);
exit(EXIT_FAILURE);
}
printf("\n=== player positions ===\n");
for (size_t i = 0; i < 20 && entities[i].name != NULL; i++) {
printf("%s: (%.2f, %.2f, %.2f)\n", entities[i].name, entities[i].x, entities[i].y, entities[i].z);
}
for (size_t i = 0; i < 20; i++) {
free_player_entity(&entities[i]);
}
free(entities);
close(sockfd);
return 0;
}
+5 -10
View File
@@ -57,8 +57,7 @@ int parse_player_entity(const char *response, player_entity_t *entity) {
strncpy(coords_str, coords_start, coords_len);
coords_str[coords_len] = '\0';
if (sscanf(coords_str, "%lfd, %lfd, %lfd", &entity->x, &entity->y,
&entity->z) != 3) {
if (sscanf(coords_str, "%lfd, %lfd, %lfd", &entity->x, &entity->y, &entity->z) != 3) {
fprintf(stderr, "invalid coordinates format\n");
free(entity->name);
return -1;
@@ -67,8 +66,7 @@ int parse_player_entity(const char *response, player_entity_t *entity) {
return 0;
}
int parse_multiple_player_entities(char *response, size_t max_entities,
player_entity_t *entities) {
int parse_multiple_player_entities(char *response, size_t max_entities, player_entity_t *entities) {
size_t entity_count = 0;
char *line = strtok(response, "\n");
@@ -80,8 +78,7 @@ int parse_multiple_player_entities(char *response, size_t max_entities,
fprintf(stderr, "failed to parse player entity from line: %s\n", line);
}
} else {
fprintf(stderr,
"warning: more player entities in response than provided space for\n");
fprintf(stderr, "warning: more player entities in response than provided space for\n");
break;
}
@@ -91,10 +88,8 @@ int parse_multiple_player_entities(char *response, size_t max_entities,
return 0;
}
int query_player_entities(int sockfd, size_t max_entities,
player_entity_t *entities) {
char *response = rcon_command_multipacket(
sockfd, "execute as @a run data get entity @s Pos");
int query_player_entities(int sockfd, size_t max_entities, player_entity_t *entities) {
char *response = rcon_command_multipacket(sockfd, "execute as @a run data get entity @s Pos");
if (!response) {
fprintf(stderr, "failed to execute command\n");
return -1;
+2 -4
View File
@@ -11,8 +11,6 @@ void free_player_entity(player_entity_t *entity);
int parse_player_entity(const char *response, player_entity_t *entity);
int parse_multiple_player_entities(char *response, size_t entities_size,
player_entity_t *entities);
int parse_multiple_player_entities(char *response, size_t entities_size, player_entity_t *entities);
int query_player_entities(int sockfd, size_t entities_size,
player_entity_t *entities);
int query_player_entities(int sockfd, size_t entities_size, player_entity_t *entities);
+160 -159
View File
@@ -1,16 +1,17 @@
/*
* rcon.c - RCON client implementation
*
* This file implements some basic functions for communicating with arbitrary RCON servers.
* This file implements some basic functions for communicating with arbitrary
* RCON servers.
*/
#include <arpa/inet.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <errno.h>
#include <unistd.h>
#ifdef __FreeBSD__
#include <netinet/in.h>
@@ -18,197 +19,197 @@
#include "rcon.h"
int rcon_connect(const char* address, int port) {
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
int rcon_connect(const char *address, int port) {
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
struct timeval tv;
tv.tv_sec = 2;
tv.tv_usec = 0;
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
struct timeval tv;
tv.tv_sec = 2;
tv.tv_usec = 0;
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
if (inet_pton(AF_INET, address, &server_addr.sin_addr) <= 0) {
perror("invalid address");
close(sockfd);
exit(EXIT_FAILURE);
}
if (inet_pton(AF_INET, address, &server_addr.sin_addr) <= 0) {
perror("invalid address");
close(sockfd);
exit(EXIT_FAILURE);
}
if (connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("connection failed");
close(sockfd);
exit(EXIT_FAILURE);
}
if (connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("connection failed");
close(sockfd);
exit(EXIT_FAILURE);
}
printf("connected to rcon server\n");
return sockfd;
printf("connected to rcon server\n");
return sockfd;
}
void send_packet(int sockfd, int32_t id, int32_t type, const char *body) {
size_t body_len = strlen(body);
size_t body_len = strlen(body);
size_t packet_size = sizeof(int32_t) * 3 + body_len + 2;
unsigned char *packet = malloc(packet_size);
if (!packet) {
perror("malloc failed");
return;
}
size_t packet_size = sizeof(int32_t) * 3 + body_len + 2;
unsigned char *packet = malloc(packet_size);
if (!packet) {
perror("malloc failed");
return;
}
int32_t size = htole32(packet_size - sizeof(int32_t));
memcpy(packet, &size, sizeof(int32_t));
int32_t size = htole32(packet_size - sizeof(int32_t));
memcpy(packet, &size, sizeof(int32_t));
int32_t id_ = htole32(id);
memcpy(packet + 4, &id_, sizeof(int32_t));
int32_t id_ = htole32(id);
memcpy(packet + 4, &id_, sizeof(int32_t));
int32_t type_ = htole32(type);
memcpy(packet + 8, &type_, sizeof(int32_t));
int32_t type_ = htole32(type);
memcpy(packet + 8, &type_, sizeof(int32_t));
memcpy(packet + 12, body, body_len);
packet[3 * sizeof(int32_t) + body_len] = 0;
packet[3 * sizeof(int32_t) + body_len + 1] = 0;
memcpy(packet + 12, body, body_len);
packet[3 * sizeof(int32_t) + body_len] = 0;
packet[3 * sizeof(int32_t) + body_len + 1] = 0;
ssize_t sent = send(sockfd, packet, packet_size, 0);
if (sent < 0) {
perror("send failed");
}
ssize_t sent = send(sockfd, packet, packet_size, 0);
if (sent < 0) {
perror("send failed");
}
free(packet);
free(packet);
}
int recv_packet(int sockfd, rcon_packet_t *packet) {
ssize_t bytes;
ssize_t bytes;
bytes = recv(sockfd, &packet->size, sizeof(int32_t), MSG_WAITALL);
bytes = recv(sockfd, &packet->size, sizeof(int32_t), MSG_WAITALL);
if (bytes <= 0) {
if (bytes == 0) {
fprintf(stderr, "connection closed by server\n");
} else if (errno == EAGAIN || errno == EWOULDBLOCK) {
return -2; // Timeout
} else {
perror("recv size failed");
}
return -1;
}
packet->size = le32toh(packet->size);
if (packet->size < (int32_t)RCON_PACKET_MIN_SIZE || packet->size > (int32_t)RCON_PACKET_MAX_SIZE) {
fprintf(stderr, "invalid packet size: %d\n", packet->size);
return -1;
}
bytes = recv(sockfd, &packet->id, sizeof(int32_t), MSG_WAITALL);
if (bytes <= 0) {
perror("recv id failed");
return -1;
}
packet->id = le32toh(packet->id);
bytes = recv(sockfd, &packet->type, sizeof(int32_t), MSG_WAITALL);
if (bytes <= 0) {
perror("recv type failed");
return -1;
}
packet->type = le32toh(packet->type);
int expected_body_size = packet->size - sizeof(int32_t) * 2 - 2;
if (expected_body_size < 0 || expected_body_size >= (int)sizeof(packet->body)) {
fprintf(stderr, "invalid packet body size: %d\n", expected_body_size);
return -1;
}
if (expected_body_size > 0) {
bytes = recv(sockfd, packet->body, expected_body_size, MSG_WAITALL);
if (bytes <= 0) {
if (bytes == 0) {
fprintf(stderr, "connection closed by server\n");
} else if (errno == EAGAIN || errno == EWOULDBLOCK) {
return -2; // Timeout
} else {
perror("recv size failed");
}
return -1;
perror("recv body failed");
return -1;
}
packet->size = le32toh(packet->size);
}
packet->body[expected_body_size] = '\0';
if (packet->size < (int32_t)RCON_PACKET_MIN_SIZE || packet->size > (int32_t)RCON_PACKET_MAX_SIZE) {
fprintf(stderr, "invalid packet size: %d\n", packet->size);
return -1;
}
uint8_t padding[2];
bytes = recv(sockfd, padding, sizeof(padding), MSG_WAITALL);
if (bytes <= 0) {
perror("recv padding failed");
return -1;
}
bytes = recv(sockfd, &packet->id, sizeof(int32_t), MSG_WAITALL);
if (bytes <= 0) {
perror("recv id failed");
return -1;
}
packet->id = le32toh(packet->id);
if (padding[0] != 0 || padding[1] != 0) {
fprintf(stderr, "invalid packet padding\n");
return -1;
}
bytes = recv(sockfd, &packet->type, sizeof(int32_t), MSG_WAITALL);
if (bytes <= 0) {
perror("recv type failed");
return -1;
}
packet->type = le32toh(packet->type);
packet->_padding = padding[1];
int expected_body_size = packet->size - sizeof(int32_t) * 2 - 2;
if (expected_body_size < 0 || expected_body_size >= (int)sizeof(packet->body)) {
fprintf(stderr, "invalid packet body size: %d\n", expected_body_size);
return -1;
}
if (expected_body_size > 0) {
bytes = recv(sockfd, packet->body, expected_body_size, MSG_WAITALL);
if (bytes <= 0) {
perror("recv body failed");
return -1;
}
}
packet->body[expected_body_size] = '\0';
uint8_t padding[2];
bytes = recv(sockfd, padding, sizeof(padding), MSG_WAITALL);
if (bytes <= 0) {
perror("recv padding failed");
return -1;
}
if (padding[0] != 0 || padding[1] != 0) {
fprintf(stderr, "invalid packet padding\n");
return -1;
}
packet->_padding = padding[1];
return 0;
return 0;
}
int rcon_authenticate(int sockfd, const char *password) {
printf("authenticating with password: '%s'\n", password);
printf("authenticating with password: '%s'\n", password);
const int32_t auth_packet_id = 1;
const int32_t auth_packet_id = 1;
send_packet(sockfd, auth_packet_id, RCON_SERVERDATA_AUTH, password);
send_packet(sockfd, auth_packet_id, RCON_SERVERDATA_AUTH, password);
printf("waiting for auth response...\n");
printf("waiting for auth response...\n");
rcon_packet_t response;
if (recv_packet(sockfd, &response) < 0) {
fprintf(stderr, "failed to receive auth response\n");
return -1;
}
printf("received auth packet: id=%d, type=%d\n", response.id, response.type);
if (response.type != RCON_SERVERDATA_AUTH_RESPONSE) {
fprintf(stderr, "authentication failed - unexpected initial packet type: %d\n", response.type);
return -1;
}
// Check if authentication failed (id == -1)
if (response.id == -1) {
fprintf(stderr, "authentication failed - invalid password\n");
return -1;
}
if (response.id != auth_packet_id) {
fprintf(stderr, "authentication failed - unexpected response id: %d\n", response.id);
return -1;
}
printf("authenticated successfully\n");
return 0;
}
char *rcon_command_multipacket(int sockfd, const char *command) {
static char result[65536];
result[0] = '\0';
int cmd_id = 100;
int dummy_id = 101;
send_packet(sockfd, cmd_id, RCON_SERVERDATA_EXECCOMMAND, command);
send_packet(sockfd, dummy_id, RCON_SERVERDATA_EXECCOMMAND, "");
while (1) {
rcon_packet_t response;
if (recv_packet(sockfd, &response) < 0) {
fprintf(stderr, "failed to receive auth response\n");
return -1;
fprintf(stderr, "failed to receive command response\n");
return NULL;
}
printf("received auth packet: id=%d, type=%d\n", response.id, response.type);
if (response.type != RCON_SERVERDATA_AUTH_RESPONSE) {
fprintf(stderr, "authentication failed - unexpected initial packet type: %d\n", response.type);
return -1;
if (response.id == dummy_id) {
break;
}
// Check if authentication failed (id == -1)
if (response.id == -1) {
fprintf(stderr, "authentication failed - invalid password\n");
return -1;
if (response.type == RCON_SERVERDATA_RESPONSE_VALUE && response.id == cmd_id) {
strncat(result, response.body, sizeof(result) - strlen(result) - 1);
}
}
if (response.id != auth_packet_id) {
fprintf(stderr, "authentication failed - unexpected response id: %d\n", response.id);
return -1;
}
printf("authenticated successfully\n");
return 0;
}
char* rcon_command_multipacket(int sockfd, const char *command) {
static char result[65536];
result[0] = '\0';
int cmd_id = 100;
int dummy_id = 101;
send_packet(sockfd, cmd_id, RCON_SERVERDATA_EXECCOMMAND, command);
send_packet(sockfd, dummy_id, RCON_SERVERDATA_EXECCOMMAND, "");
while (1) {
rcon_packet_t response;
if (recv_packet(sockfd, &response) < 0) {
fprintf(stderr, "failed to receive command response\n");
return NULL;
}
if (response.id == dummy_id) {
break;
}
if (response.type == RCON_SERVERDATA_RESPONSE_VALUE && response.id == cmd_id) {
strncat(result, response.body, sizeof(result) - strlen(result) - 1);
}
}
return result;
return result;
}
+13 -12
View File
@@ -7,23 +7,24 @@
#define RCON_SERVERDATA_AUTH_RESPONSE 2
typedef struct {
// size of the remainder of the packet
int32_t size;
// packet id (client sets, server echoes, -1 on auth failure)
int32_t id;
// packet type (see the SERVERDATA_* constants)
int32_t type;
// null-terminated command string (for auth and exec) or response string (from server)
char body[4096];
// yet another null byte after the body (required by protocol)
uint8_t _padding;
// size of the remainder of the packet
int32_t size;
// packet id (client sets, server echoes, -1 on auth failure)
int32_t id;
// packet type (see the SERVERDATA_* constants)
int32_t type;
// null-terminated command string (for auth and exec) or response string (from
// server)
char body[4096];
// yet another null byte after the body (required by protocol)
uint8_t _padding;
} rcon_packet_t;
// Minimum and maximum values for the `size` field of a valid packet.
#define RCON_PACKET_MIN_SIZE (sizeof(int32_t) * 2 + 2)
#define RCON_PACKET_MAX_SIZE (sizeof(rcon_packet_t) - sizeof(int32_t))
int rcon_connect(const char* address, int port);
int rcon_connect(const char *address, int port);
void send_packet(int sockfd, int32_t id, int32_t type, const char *body);
@@ -31,4 +32,4 @@ int recv_packet(int sockfd, rcon_packet_t *packet);
int rcon_authenticate(int sockfd, const char *password);
char* rcon_command_multipacket(int sockfd, const char *command);
char *rcon_command_multipacket(int sockfd, const char *command);
+2 -4
View File
@@ -24,10 +24,8 @@ static void test_parse_multiple_player_entities(void **state) {
(void)state;
player_entity_t entities[2] = {0};
char response[] =
"Steve has the following entity data: [-1234.1234567891234d, 71.0d, "
"113.0000000000001d]\n"
"Alex has the following entity data: [100.0d, 64.0d, -50.5d]";
char response[] = "Steve has the following entity data: [-1234.1234567891234d, 71.0d, 113.0000000000001d]\n"
"Alex has the following entity data: [100.0d, 64.0d, -50.5d]";
assert_int_equal(parse_multiple_player_entities(response, 2, entities), 0);
+3 -6
View File
@@ -5,19 +5,16 @@
#include "../src/rcon.h"
static void assert_packet_equals(const rcon_packet_t *packet,
int32_t expected_id, int32_t expected_type,
static void assert_packet_equals(const rcon_packet_t *packet, int32_t expected_id, int32_t expected_type,
const char *expected_body) {
assert_int_equal(packet->id, expected_id);
assert_int_equal(packet->type, expected_type);
assert_string_equal(packet->body, expected_body);
assert_int_equal(packet->_padding, 0);
assert_int_equal(packet->size,
(int32_t)(sizeof(int32_t) * 2 + strlen(expected_body) + 2));
assert_int_equal(packet->size, (int32_t)(sizeof(int32_t) * 2 + strlen(expected_body) + 2));
}
static void send_raw_packet(int sockfd, int32_t id, int32_t type,
const char *body) {
static void send_raw_packet(int sockfd, int32_t id, int32_t type, const char *body) {
size_t body_len = strlen(body);
size_t packet_size = sizeof(int32_t) * 3 + body_len + 2;
uint8_t packet[sizeof(int32_t) * 3 + 4096 + 2] = {0};