aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Jonas Gunz <himself@jonasgunz.de> 2020-10-03 00:41:38 +0200
committerGravatar Jonas Gunz <himself@jonasgunz.de> 2020-10-03 00:41:38 +0200
commitace6ce28fbd880483a68c88c9bb63f915cd6e5d4 (patch)
tree199cc740344d4de49da903a6e63189b49781cbc9
parentdbaefe4e1e6280f74706c3bb5d19434ef22c4f3a (diff)
downloadminecraft-rcon-ace6ce28fbd880483a68c88c9bb63f915cd6e5d4.tar.gz
nice rcon interface via rcon_login/rcon_command
-rw-r--r--src/main.c67
-rw-r--r--src/rcon.c123
-rw-r--r--src/rcon.h31
3 files changed, 170 insertions, 51 deletions
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 <stdlib.h>
#include <string.h>
+#include <poll.h>
+#include <sys/socket.h>
+
#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 );
+