From ace6ce28fbd880483a68c88c9bb63f915cd6e5d4 Mon Sep 17 00:00:00 2001 From: Jonas Gunz Date: Sat, 3 Oct 2020 00:41:38 +0200 Subject: nice rcon interface via rcon_login/rcon_command --- src/main.c | 67 +++++++++++++++------------------ src/rcon.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- src/rcon.h | 31 +++++++++++++--- 3 files changed, 170 insertions(+), 51 deletions(-) (limited to 'src') diff --git a/src/main.c b/src/main.c index 1a3c46f..0a80bf6 100644 --- a/src/main.c +++ b/src/main.c @@ -26,20 +26,45 @@ typedef struct program_params_s { program_params_t parse_args ( int argc, char* argv[] ); +int connect_socket ( char* _host, char* _port ); + int main( int argc, char* argv[] ) { program_params_t args = parse_args( argc, argv ); + int sock = connect_socket ( args.host, args.port ); + + fprintf ( stderr, "Connection successful.\n" ); + + if ( rcon_login ( sock, args.password ) ) { + fprintf ( stderr, "Authentification failed.\n" ); + exit ( EXIT_FAILURE ); + } + + char* result = NULL; + rcon_command ( &result, sock, args.command ); + + printf("%s\n", result); + + close (sock); + + return 0; +} + +program_params_t parse_args ( int argc, char* argv[] ) { + program_params_t ret = { "127.0.0.1", "25575", "1234", "list" }; + return ret; +} + +int connect_socket ( char* _host, char* _port ) { int sock = -1; int ret = 0; struct addrinfo hints, *result, *iter; - char recvbuf [ RCON_RECV_PKGSIZE ]; - char sendbuf [ RCON_SEND_PKGSIZE ]; memset ( &hints, 0, sizeof( struct addrinfo ) ); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; - ret = getaddrinfo ( args.host, args.port, &hints, &result ); + ret = getaddrinfo ( _host, _port, &hints, &result ); if ( ret ) { fprintf ( stderr, "getaddrinfo: %s\n", gai_strerror(ret) ); exit ( EXIT_FAILURE ); @@ -47,7 +72,7 @@ int main( int argc, char* argv[] ) { for ( iter = result; iter != NULL; iter = iter->ai_next ) { sock = socket( result->ai_family, result->ai_socktype, result->ai_protocol ); - if ( socket < 0 ) + if ( sock < 0 ) continue; if ( connect ( sock, iter->ai_addr, iter->ai_addrlen ) != -1 ) @@ -61,38 +86,6 @@ int main( int argc, char* argv[] ) { exit ( EXIT_FAILURE ); } - fprintf ( stderr, "Connection successful.\n" ); - - rcon_packet_t pack = {0,1337,RCON_LOGIN,args.password, strlen(args.password)}, rcon_result; - ret = rcon_construct_packet ( sendbuf, RCON_SEND_PKGSIZE, &pack ); - - ret = send ( sock, sendbuf, ret, 0 ); - - ret = recv ( sock, recvbuf, RCON_RECV_PKGSIZE, 0); - rcon_parse_packet ( &rcon_result, recvbuf, ret ); - - if ( rcon_result.type != RCON_COMMAND ) { - fprintf ( stderr, "Authentification failed." ); - exit ( EXIT_FAILURE ); - } - - rcon_packet_t pack2 = {0,6969,RCON_COMMAND, args.command, strlen(args.command)}; - - ret = rcon_construct_packet ( sendbuf, RCON_SEND_PKGSIZE, &pack2 ); - - ret = send ( sock, sendbuf, ret, 0 ); - - ret = recv ( sock, recvbuf, RCON_RECV_PKGSIZE, 0); - rcon_parse_packet ( &rcon_result, recvbuf, ret ); - - printf("%s\n", rcon_result.payload); - - close (sock); - - return 0; + return sock; } -program_params_t parse_args ( int argc, char* argv[] ) { - program_params_t ret = { "127.0.0.1", "25575", "1234", "list" }; - return ret; -} diff --git a/src/rcon.c b/src/rcon.c index 7d5492e..2a79e64 100644 --- a/src/rcon.c +++ b/src/rcon.c @@ -22,12 +22,14 @@ #include "rcon.h" -static char* rcon_errors[] = { - "No Error.", - "Undefined Error.", - "Login Denied.", - "Buffer size incorrect.", - "Malformed packet recieved." +static const unsigned int rcon_errors_len = 6; +static const char* rcon_errors[] = { + "OK", + "Undefined error", + "Authentification failed", + "Inadequate buffer", + "Packet format error", + "Connection timed out" }; static int rcon_write_int ( char* _buffer, int _len, int32_t _data ) { @@ -92,6 +94,111 @@ int rcon_construct_packet ( char* _buffer, uint32_t _len, rcon_packet_t* _packet return bytecount; } -char* rcon_strerror ( int _errno ) { - return _errno > 4 ? rcon_errors[1] : rcon_errors[_errno]; +const char* rcon_strerror ( int _errno ) { + return _errno >= rcon_errors_len ? rcon_errors[1] : rcon_errors[_errno]; +} + +// For packets created by rcon_parse_packet() +void rcon_free_packet ( rcon_packet_t* _packet ) { + if ( ! _packet || ! _packet->payload ) + return; + + free ( _packet->payload ); + _packet->payload = NULL; + _packet->payload_len = 0; +} + +//returns 0 on success +int rcon_send_packet ( int _socket, rcon_packet_t* _packet ) { + char buff [ RCON_SEND_PKGSIZE ]; + int ret; + if ( _socket < 0 || !_packet ) + return RCON_ERR_GENERIC; + + if( ! ((ret = rcon_construct_packet ( buff, RCON_SEND_PKGSIZE, _packet )) > 0) ) + return RCON_ERR_PACKET; + if ( send ( _socket, buff, ret, 0 ) > 0 ) + return 0; + + return RCON_ERR_GENERIC; +} + +//returns 0 on success +int rcon_recv_packet ( int _socket, rcon_packet_t* _packet, int _timeout_msecs ) { + char buff [ RCON_SEND_PKGSIZE ]; + int ret; + struct pollfd fds; + + if ( _socket < 0 || !_packet ) + return RCON_ERR_GENERIC; + + fds.fd = _socket; + fds.events = POLLIN; + + ret = poll ( &fds, 1, _timeout_msecs ); + if ( ret > 0 && fds.revents & POLLIN) { + ret = recv ( _socket, buff, RCON_RECV_PKGSIZE, 0 ); + if ( ! (rcon_parse_packet ( _packet, buff, ret ) > 0) ) + return RCON_ERR_PACKET; + + return 0; + } + + return RCON_ERR_TIMEOUT; //timeout +} + +int rcon_login ( int _socket, const char* _password ) { + int ret; + rcon_packet_t result, request = { + 0, + 1337, // TODO remove hardcoded ID + RCON_LOGIN, + (char*) _password, + strlen(_password) + }; + + if ( _socket < 0 || !_password ) + return RCON_ERR_GENERIC; + + if ( (ret = rcon_send_packet ( _socket, &request )) ) + return ret; + + if ( (ret = rcon_recv_packet ( _socket, &result, 1000 )) ) + return ret; + + if ( result.type != RCON_COMMAND || result.id != 1337 ) + return RCON_ERR_AUTH; + + return 0; +} + +int rcon_command ( char** _output, int _socket, const char* _command ) { + int ret; + if ( _socket < 0 || !_command ) + return RCON_ERR_GENERIC; + + rcon_packet_t result, request = { + 0, + 1337, // TODO remove hardcoded ID + RCON_COMMAND, + (char*) _command, //NONONONONONONONONONONO + strlen(_command) + }; + + if ( (ret = rcon_send_packet ( _socket, &request )) ) + return ret; + + if ( (ret = rcon_recv_packet ( _socket, &result, 1000 )) ) + return ret; + + // TODO truncated response + *_output = malloc ( result.payload_len + 1 ); + *_output[result.payload_len] = 0; + memcpy ( *_output, result.payload, result.payload_len ); + rcon_free_packet ( &result ); + + if ( result.type != RCON_RESPONSE || result.id != 1337 ) + return RCON_ERR_PACKET; + + return 0; } diff --git a/src/rcon.h b/src/rcon.h index 0d518d0..8ca46c6 100644 --- a/src/rcon.h +++ b/src/rcon.h @@ -18,6 +18,9 @@ #include #include +#include +#include + #define RCON_LOGIN 3 #define RCON_LOLGINFAIL -1 #define RCON_COMMAND 2 @@ -26,16 +29,32 @@ #define RCON_RECV_PKGSIZE 4110 #define RCON_SEND_PKGSIZE 1460 +#define RCON_ERR_OK 0 +#define RCON_ERR_GENERIC 1 +#define RCON_ERR_AUTH 2 +#define RCON_ERR_BUFFER 3 +#define RCON_ERR_PACKET 4 +#define RCON_ERR_TIMEOUT 5 + typedef struct rcon_packet_s { - int32_t length; - int32_t id; - int32_t type; - char* payload; - uint32_t payload_len; + int32_t length; + int32_t id; + int32_t type; + char* payload; + uint32_t payload_len; } rcon_packet_t; int rcon_parse_packet ( rcon_packet_t* _packet, char* _buffer, uint32_t _len ); int rcon_construct_packet ( char* _buffer, uint32_t _len, rcon_packet_t* _packet ); -char* rcon_strerror ( int _errno ); +int rcon_login ( int _socket, const char* _password ); + +int rcon_command ( char** _output, int _socket, const char* _command ); + +int rcon_recv_packet ( int _socket, rcon_packet_t* _packet, int _timeout_msecs ); + +int rcon_send_packet ( int _socket, rcon_packet_t* _packet ); + +const char* rcon_strerror ( int _errno ); + -- cgit v1.2.3