From 40424da19f27ad8a1b39f05fb280af6fa6c9ef01 Mon Sep 17 00:00:00 2001 From: h7x4 Date: Fri, 12 Jun 2026 02:51:25 +0900 Subject: [PATCH] Run clang-format --- .clang-format | 296 +++++++++++++++++++++++++++++++++++++++ src/main.c | 110 +++++++-------- src/minecraft.c | 15 +- src/minecraft.h | 6 +- src/rcon.c | 319 +++++++++++++++++++++--------------------- src/rcon.h | 25 ++-- test/test_minecraft.c | 6 +- test/test_rcon.c | 9 +- 8 files changed, 536 insertions(+), 250 deletions(-) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..7ea9da5 --- /dev/null +++ b/.clang-format @@ -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 +... diff --git a/src/main.c b/src/main.c index 8aa7072..11aa4fd 100644 --- a/src/main.c +++ b/src/main.c @@ -6,72 +6,72 @@ #include #include -#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; } diff --git a/src/minecraft.c b/src/minecraft.c index e80bf5b..2e92901 100644 --- a/src/minecraft.c +++ b/src/minecraft.c @@ -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; diff --git a/src/minecraft.h b/src/minecraft.h index 238563d..dcc2424 100644 --- a/src/minecraft.h +++ b/src/minecraft.h @@ -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); diff --git a/src/rcon.c b/src/rcon.c index 28ce64a..c10ee6c 100644 --- a/src/rcon.c +++ b/src/rcon.c @@ -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 +#include #include #include #include -#include #include -#include -#include +#include #ifdef __FreeBSD__ #include @@ -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; } diff --git a/src/rcon.h b/src/rcon.h index ece946a..a90068a 100644 --- a/src/rcon.h +++ b/src/rcon.h @@ -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); diff --git a/test/test_minecraft.c b/test/test_minecraft.c index 3f1a47d..21cafc4 100644 --- a/test/test_minecraft.c +++ b/test/test_minecraft.c @@ -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); diff --git a/test/test_rcon.c b/test/test_rcon.c index fa74e88..064121e 100644 --- a/test/test_rcon.c +++ b/test/test_rcon.c @@ -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};