Run clang-format
This commit is contained in:
+296
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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
@@ -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};
|
||||
|
||||
Reference in New Issue
Block a user