From 0a803aab558352c9e78fc2661de766dda4cc91ba Mon Sep 17 00:00:00 2001 From: Tiiffi Date: Wed, 4 Nov 2015 22:07:53 +0200 Subject: [PATCH 01/29] .gitignore update. --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 0a05717..190da4c 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,8 @@ *.o *.dev *.win +*.txt *.layout *.project mcrcon +todo From e8f685ff0a924a7c60ec935896d87348017e8406 Mon Sep 17 00:00:00 2001 From: Tiiffi Date: Wed, 4 Nov 2015 22:08:44 +0200 Subject: [PATCH 02/29] README and help tweaks. --- README.md | 20 ++++++++++---------- mcrcon.c | 10 +++++----- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index dcacfc9..93e5cb4 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ ####Compiling: -Raw command: -```gcc -std=gnu11 -pedantic -Wall -Wextra -O2 -s -o mcrcon mcrcon.c``` +Compile with GCC or CLANG: +```cc -std=gnu99 -Wpedantic -Wall -Wextra -O2 -s -o mcrcon mcrcon.c``` or just run **make**. @@ -16,27 +16,27 @@ Sends rcon commands to minecraft server. ``` Option: - -h Prints usage. + -h Print usage. -s Silent mode. Do not print data received from rcon. -t Terminal mode. Acts as interactive terminal. -p Rcon password. Default: "". -H Host address or ip. -P Port. Default: 25575. - -c Do not print colors. Disables bukkit color printing. - -r Print everything in raw mode. + -c Disable colors. + -r Output raw packets. Good for debugging and custom handling of the output. ``` -Invidual commands must be separated with spaces. +Commands must be separated with spaces. Example: - ```mcrcon -c -H 192.168.1.42 -P 9999 -p password cmd1 "cmd2 with spaces"``` + ```mcrcon -c -H 192.168.1.42 -P 25575 -p password cmd1 "cmd2 arg1 arg2"``` -#####Enable rcon -Remember to enable rcon by changing/adding these lines to ```server.properties``` file. +#####Enable server rcon +Remember to enable rcon by changing / adding following lines in ```server.properties``` file. ``` enable-rcon=true +rcon.port=25575 rcon.password=your_rcon_pasword -rcon.port=9999 ``` --- diff --git a/mcrcon.c b/mcrcon.c index a105297..2996a54 100644 --- a/mcrcon.c +++ b/mcrcon.c @@ -217,18 +217,18 @@ void usage(void) "Usage: "IN_NAME" [OPTIONS]... [COMMANDS]...\n" "Sends rcon commands to minecraft server.\n\n" "Option:\n" - " -h\t\tPrints usage.\n" + " -h\t\tPrint usage.\n" " -s\t\tSilent mode. Do not print data received from rcon.\n" " -t\t\tTerminal mode. Acts as interactive terminal.\n" " -p\t\tRcon password. Default: \"\".\n" " -H\t\tHost address or ip.\n" " -P\t\tPort. Default: 25575.\n" - " -c\t\tDo not print colors. Disables bukkit color printing.\n" - " -r\t\tPrint everything in raw mode.\n\t\tGood for debugging and custom handling of the output.\n" + " -c\t\tDisable colors.\n" + " -r\t\tOutput raw packets.\n\t\tGood for debugging and custom handling of the output.\n" ,stdout); - puts("\nInvidual commands must be separated with spaces.\n"); - puts("Example:\n "IN_NAME" -c -H 192.168.1.42 -P 9999 -p password cmd1 \"cmd2 with spaces\"\n"); + puts("\nCommands must be separated with spaces.\n"); + puts("Example:\n "IN_NAME" -c -H 192.168.1.42 -P 9999 -p password cmd1 \"cmd2 arg1 arg2\"\n"); puts("minecraft rcon ("IN_NAME") "VERSION".\nReport bugs to tiiffi_at_gmail_dot_com.\n"); #ifdef _WIN32 From 7605586324ac5e2fa74d2d0fd4bb3793b0bc2005 Mon Sep 17 00:00:00 2001 From: Tiiffi Date: Wed, 4 Nov 2015 22:31:09 +0200 Subject: [PATCH 03/29] Changed port in example command. --- mcrcon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mcrcon.c b/mcrcon.c index 2996a54..6e7a7cc 100644 --- a/mcrcon.c +++ b/mcrcon.c @@ -228,7 +228,7 @@ void usage(void) ,stdout); puts("\nCommands must be separated with spaces.\n"); - puts("Example:\n "IN_NAME" -c -H 192.168.1.42 -P 9999 -p password cmd1 \"cmd2 arg1 arg2\"\n"); + puts("Example:\n "IN_NAME" -c -H 192.168.1.42 -P 25575 -p password cmd1 \"cmd2 arg1 arg2\"\n"); puts("minecraft rcon ("IN_NAME") "VERSION".\nReport bugs to tiiffi_at_gmail_dot_com.\n"); #ifdef _WIN32 From 9c6c8e3069444d8735b7ec101bb90b2e77f20fbd Mon Sep 17 00:00:00 2001 From: Tiiffi Date: Thu, 19 Nov 2015 07:16:00 +0200 Subject: [PATCH 04/29] Replaced some networking functions with new ones. --- README.md | 2 +- mcrcon.c | 172 ++++++++++++++++++++++++++++++------------------------ 2 files changed, 98 insertions(+), 76 deletions(-) diff --git a/README.md b/README.md index 93e5cb4..77ee6dd 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ ####Compiling: Compile with GCC or CLANG: -```cc -std=gnu99 -Wpedantic -Wall -Wextra -O2 -s -o mcrcon mcrcon.c``` +```cc -std=gnu99 -pedantic -Wall -Wextra -O2 -s -o mcrcon mcrcon.c``` or just run **make**. diff --git a/mcrcon.c b/mcrcon.c index 6e7a7cc..99a266e 100644 --- a/mcrcon.c +++ b/mcrcon.c @@ -50,7 +50,7 @@ #define RCON_AUTHENTICATE 3 #define RCON_RESPONSEVALUE 0 #define RCON_AUTH_RESPONSE 2 -#define RCON_PID 42 +#define RCON_PID 0xBADC0DE /* Safe value I think. This should me made dynamic for more stable performance! */ #define DATA_BUFFSIZE 10240 @@ -68,23 +68,32 @@ typedef struct _rc_packet { /* ignoring string2 atm.. */ } rc_packet; -/* functions */ + +// ============================================= +// FUNCTIONS +// ============================================= + +// Networking +#ifdef _WIN32 +void net_init_WSA(void); +#endif + +void net_close(int sd); +int net_connect(const char *host, const char *port); +int net_send(int sd, const char *buffer, size_t size); + +int net_send_packet(int sd, rc_packet *packet); +rc_packet* net_recv_packet(int sd); + +int net_clean_incoming(int sd, int size); + +// Other stuff void usage(void); void error(char *errstring); #ifndef _WIN32 void print_color(int color); #endif -struct addrinfo *net_resolve(char *host, char *port); -void net_close_socket(int sd); -int net_open_socket(char *host, char *port); -int net_send_packet(int sd, rc_packet *packet); -rc_packet* net_recv_packet(int sd); -#ifdef _WIN32 -void net_init_WSA(void); -#endif -int net_clean_incoming(int sd, int size); - rc_packet* packet_build(int id, int cmd, char *s1); void packet_print(rc_packet *packet); @@ -96,7 +105,9 @@ int run_terminal_mode(int rsock); int run_commands(int argc, char *argv[]); -/* some globals */ +// ============================================= +// GLOBAL VARIABLES +// ============================================= int raw_output = 0; int silent_mode = 0; int print_colors = 1; @@ -110,7 +121,7 @@ int rsock; /* rcon socket */ /* safety stuff (windows is still misbehaving) */ void exit_proc(void) { - if(rsock != -1) net_close_socket(rsock); + if(rsock != -1) net_close(rsock); } /* Check windows & linux behaviour !!! */ @@ -188,7 +199,7 @@ int main(int argc, char *argv[]) #endif /* open socket */ - rsock = net_open_socket(host, port); + rsock = net_connect(host, port); /* auth & commands */ if(rcon_auth(rsock, pass)) @@ -205,7 +216,7 @@ int main(int argc, char *argv[]) } /* cleanup */ - net_close_socket(rsock); + net_close(rsock); rsock = -1; return ret; @@ -244,48 +255,8 @@ void error(char *errstring) exit(-1); } -#ifdef _WIN32 -void net_init_WSA(void) -{ - WSADATA wsadata; - int err; - - err = WSAStartup(MAKEWORD(1, 1), &wsadata); - if(err != 0) - { - fprintf(stderr, "WSAStartup failed. Errno: %d.\n", err); - exit(-1); - } -} -#endif - -struct addrinfo *net_resolve(char *host, char *port) -{ - /* !!! This function should be integrated to open_socket function for cleaner code !!! */ - - //struct in_addr6 serveraddr; - struct addrinfo hints, *result; - int ret; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; - /* hints.ai_flags = AI_NUMERICSERV; // Windows retardism */ - - ret = getaddrinfo(host, port, &hints, &result); - if(ret != 0) - { - if(ret == EAI_SERVICE) fprintf(stderr, "Invalid port (%s).\n", port); - fprintf(stderr, "Error: Unable to resolve hostname (%s).\n", host); - exit(-1); - } - - return result; -} - /* socket close and cleanup */ -void net_close_socket(int sd) +void net_close(int sd) { #ifdef _WIN32 closesocket(sd); @@ -296,36 +267,87 @@ void net_close_socket(int sd) } /* Opens and connects socket */ -int net_open_socket(char *host, char *port) +int net_connect(const char *host, const char *port) { int sd; - struct addrinfo *serverinfo; + struct addrinfo hints = {0}; + struct addrinfo *server_info, *p; - serverinfo = net_resolve(host, port); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; - sd = socket(serverinfo->ai_family, serverinfo->ai_socktype, serverinfo->ai_protocol); - if(sd < 0) - { - #ifdef _WIN32 - WSACleanup(); - #endif - freeaddrinfo(serverinfo); - error("Error: cannot create socket.\n"); - } + #ifdef _WIN32 + net_init_WSA(); + #endif - if(connect(sd, serverinfo->ai_addr, serverinfo->ai_addrlen) != 0) + // Get host address info + int result = getaddrinfo(host, port, &hints, &server_info); + if (result != 0) { - net_close_socket(sd); - fprintf(stderr, "Error: connection failed (%s).\n", host); - freeaddrinfo(serverinfo); - exit(-1); + if (result == EAI_SERVICE) + { + fprintf(stderr, "Invalid port %s.\n", port); + } + if (result == EAI_NONAME) + { + fprintf(stderr, "Unable to resolve hostname %s.\n", host); + } + else + { + fprintf(stderr, "getaddrinfo() error %d.\n", result); + } + exit(EXIT_FAILURE); } - freeaddrinfo(serverinfo); + // Go through the hosts and try to connect + for (p = server_info; p != NULL; p = p->ai_next) + { + sd = socket(p->ai_family, p->ai_socktype, p->ai_protocol); + if (sd == -1) continue; + + result = connect(sd, p->ai_addr, p->ai_addrlen); + if (result == -1) + { + net_close(sd); + continue; + } + + break; + } + + if (p == NULL) { + fprintf(stderr, "Failed to connect.\n"); + exit(EXIT_FAILURE); + } + + // Cheating because Windows is retarded (inet_ntop function missing) + fprintf(stdout, "Connected to %s:%s.\n", host, port); + + freeaddrinfo(server_info); + return sd; } +int net_send(int sd, const char *buffer, size_t size) +{ + size_t sent = 0; + size_t left = size; + + while (sent < size) + { + int result = send(sd, buffer + sent, left, 0); + + if (result == -1) return -1; + + sent += result; + left -= sent; + } + + return 0; +} + int net_send_packet(int sd, rc_packet *packet) { int len; From c5731c1109c43a7c68f8138295f3ce494839e6a9 Mon Sep 17 00:00:00 2001 From: Tiiffi Date: Wed, 26 Oct 2016 21:08:09 +0300 Subject: [PATCH 05/29] New indentation and changes in net_connect error reporting. --- mcrcon.c | 866 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 487 insertions(+), 379 deletions(-) diff --git a/mcrcon.c b/mcrcon.c index 99a266e..629fcfa 100644 --- a/mcrcon.c +++ b/mcrcon.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015, Tiiffi gmail_dot_com> + * Copyright (c) 2012-2016, Tiiffi gmail_dot_com> * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -23,8 +23,9 @@ #include #include +#include +#include #include -#include #include #ifdef _WIN32 @@ -35,6 +36,7 @@ #include #include #else + #include #include #include #include @@ -68,19 +70,21 @@ typedef struct _rc_packet { /* ignoring string2 atm.. */ } rc_packet; +/* =================================== */ +/* FUNCTION DEFINITIONS */ +/* =================================== */ -// ============================================= -// FUNCTIONS -// ============================================= +// endianness related functions +bool is_bigendian(void); +int32_t reverse_int32(int32_t n); -// Networking #ifdef _WIN32 void net_init_WSA(void); #endif -void net_close(int sd); -int net_connect(const char *host, const char *port); -int net_send(int sd, const char *buffer, size_t size); +void net_close(int sd); +int net_connect(const char *host, const char *port); +int net_send(int sd, const uint8_t *buffer, size_t size); int net_send_packet(int sd, rc_packet *packet); rc_packet* net_recv_packet(int sd); @@ -120,526 +124,630 @@ int rsock; /* rcon socket */ #endif /* safety stuff (windows is still misbehaving) */ -void exit_proc(void) { - if(rsock != -1) net_close(rsock); +void exit_proc(void) +{ + if (rsock != -1) net_close(rsock); } /* Check windows & linux behaviour !!! */ -void sighandler(/*int sig*/) { - connection_alive = 0; - #ifndef _WIN32 - exit(-1); - #endif +void sighandler(/*int sig*/) +{ + connection_alive = 0; + #ifndef _WIN32 + exit(-1); + #endif } int main(int argc, char *argv[]) { - int opt, ret = 0; - int terminal_mode = 0; + int opt, ret = 0; + int terminal_mode = 0; - char *host = NULL; - char *pass = ""; - char *port = "25575"; + char *host = NULL; + char *pass = ""; + char *port = "25575"; - if(argc < 2) usage(); + if(argc < 2) usage(); - opterr = 1; /* default error handler enabled */ - while((opt = getopt(argc, argv, "rtcshH:p:P:i")) != -1) - { - switch(opt) - { - case 'H': host = optarg; break; - case 'P': port = optarg; break; - case 'p': pass = optarg; break; - case 'C': - case 'c': print_colors = 0; break; - case 'S': - case 's': silent_mode = 1; break; - case 'T': - case 't': - case 'I': - case 'i': terminal_mode = 1; break; - case 'r': raw_output = 1; break; - case 'h': - case '?': - /* - if(optopt == 'P' || optopt == 'H' || optopt == 'p') - fprintf (stderr, "Option -%c requires an argument.\n\n", optopt); - */ + opterr = 1; /* default error handler enabled */ - /* else fprintf (stderr, "Unknown option -%c\n\n", optopt); */ + while ((opt = getopt(argc, argv, "rtcshH:p:P:i")) != -1) + { + switch (opt) + { + case 'H': host = optarg; break; + case 'P': port = optarg; break; + case 'p': pass = optarg; break; + case 'C': + case 'c': print_colors = 0; break; + case 'S': + case 's': silent_mode = 1; break; + case 'T': + case 't': + case 'I': + case 'i': terminal_mode = 1; break; + case 'r': raw_output = 1; break; + case 'h': + case '?': + /* + if(optopt == 'P' || optopt == 'H' || optopt == 'p') + fprintf (stderr, "Option -%c requires an argument.\n\n", optopt); + */ - usage(); - break; + /* else fprintf (stderr, "Unknown option -%c\n\n", optopt); */ - default: abort(); - } - } + usage(); + break; - if(host == NULL) { - fputs("Host not defined. Check -H flag.\n\n", stdout); - usage(); - } + default: abort(); + } +} - if(optind == argc && terminal_mode == 0) { - fputs("No commands specified.\n\n", stdout); - usage(); - } + if (host == NULL) + { + fputs("Host not defined. Check -H flag.\n\n", stdout); + usage(); + } - /* safety features to prevent "IO: Connection reset" bug on the server side */ - atexit(&exit_proc); - signal(SIGABRT, &sighandler); - signal(SIGTERM, &sighandler); - signal(SIGINT, &sighandler); + if(optind == argc && terminal_mode == 0) + { + fputs("No commands specified.\n\n", stdout); + usage(); + } - #ifdef _WIN32 - net_init_WSA(); - console_handle = GetStdHandle(STD_OUTPUT_HANDLE); - if(console_handle == INVALID_HANDLE_VALUE) console_handle = NULL; - #endif + /* safety features to prevent "IO: Connection reset" bug on the server side */ + atexit(&exit_proc); + signal(SIGABRT, &sighandler); + signal(SIGTERM, &sighandler); + signal(SIGINT, &sighandler); - /* open socket */ - rsock = net_connect(host, port); + #ifdef _WIN32 + net_init_WSA(); + console_handle = GetStdHandle(STD_OUTPUT_HANDLE); + if(console_handle == INVALID_HANDLE_VALUE) console_handle = NULL; + #endif - /* auth & commands */ - if(rcon_auth(rsock, pass)) - { - if(terminal_mode) - ret = run_terminal_mode(rsock); - else - ret = run_commands(argc, argv); - } - else /* auth failed */ - { - ret = -1; - fprintf(stdout, "Authentication failed!\n"); - } + /* open socket */ + rsock = net_connect(host, port); - /* cleanup */ - net_close(rsock); - rsock = -1; + /* auth & commands */ + if(rcon_auth(rsock, pass)) + { + if(terminal_mode) + ret = run_terminal_mode(rsock); + else + ret = run_commands(argc, argv); + } + else /* auth failed */ + { + ret = -1; + fprintf(stdout, "Authentication failed!\n"); + } - return ret; + /* cleanup */ + net_close(rsock); + rsock = -1; + + return ret; } void usage(void) { - fputs( - "Usage: "IN_NAME" [OPTIONS]... [COMMANDS]...\n" - "Sends rcon commands to minecraft server.\n\n" - "Option:\n" - " -h\t\tPrint usage.\n" - " -s\t\tSilent mode. Do not print data received from rcon.\n" - " -t\t\tTerminal mode. Acts as interactive terminal.\n" - " -p\t\tRcon password. Default: \"\".\n" - " -H\t\tHost address or ip.\n" - " -P\t\tPort. Default: 25575.\n" - " -c\t\tDisable colors.\n" - " -r\t\tOutput raw packets.\n\t\tGood for debugging and custom handling of the output.\n" - ,stdout); + fputs( + "Usage: "IN_NAME" [OPTIONS]... [COMMANDS]...\n" + "Sends rcon commands to minecraft server.\n\n" + "Option:\n" + " -h\t\tPrint usage.\n" + " -s\t\tSilent mode. Do not print data received from rcon.\n" + " -t\t\tTerminal mode. Acts as interactive terminal.\n" + " -p\t\tRcon password. Default: \"\".\n" + " -H\t\tHost address or ip.\n" + " -P\t\tPort. Default: 25575.\n" + " -c\t\tDisable colors.\n" + " -r\t\tOutput raw packets.\n\t\tGood for debugging and custom handling of the output.\n" + ,stdout + ); - puts("\nCommands must be separated with spaces.\n"); - puts("Example:\n "IN_NAME" -c -H 192.168.1.42 -P 25575 -p password cmd1 \"cmd2 arg1 arg2\"\n"); - puts("minecraft rcon ("IN_NAME") "VERSION".\nReport bugs to tiiffi_at_gmail_dot_com.\n"); + puts("\nCommands must be separated with spaces.\n"); + puts("Example:\n "IN_NAME" -c -H 192.168.1.42 -P 25575 -p password cmd1 \"cmd2 arg1 arg2\"\n"); + puts("minecraft rcon ("IN_NAME") "VERSION".\nReport bugs to tiiffi_at_gmail_dot_com.\n"); - #ifdef _WIN32 - puts("Press enter to exit."); - getchar(); - #endif - exit(0); + #ifdef _WIN32 + puts("Press enter to exit."); + getchar(); + #endif + + exit(0); } void error(char *errstring) { - fputs(errstring, stderr); - exit(-1); + fputs(errstring, stderr); + exit(-1); } /* socket close and cleanup */ void net_close(int sd) { - #ifdef _WIN32 - closesocket(sd); - WSACleanup(); - #else - close(sd); - #endif + #ifdef _WIN32 + closesocket(sd); + WSACleanup(); + #else + close(sd); + #endif } /* Opens and connects socket */ int net_connect(const char *host, const char *port) { - int sd; + int sd; - struct addrinfo hints = {0}; - struct addrinfo *server_info, *p; + struct addrinfo hints = {0}; + struct addrinfo *server_info, *p; - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; - #ifdef _WIN32 - net_init_WSA(); - #endif + #ifdef _WIN32 + net_init_WSA(); + #endif - // Get host address info - int result = getaddrinfo(host, port, &hints, &server_info); - if (result != 0) - { - if (result == EAI_SERVICE) - { - fprintf(stderr, "Invalid port %s.\n", port); - } - if (result == EAI_NONAME) - { - fprintf(stderr, "Unable to resolve hostname %s.\n", host); - } - else - { - fprintf(stderr, "getaddrinfo() error %d.\n", result); - } - exit(EXIT_FAILURE); - } + // Get host address info + int ret = getaddrinfo(host, port, &hints, &server_info); + if (ret != 0) + { + fprintf("getaddrinfo(): %s\n", gai_strerror(ret)); + exit(EXIT_FAILURE); + } - // Go through the hosts and try to connect - for (p = server_info; p != NULL; p = p->ai_next) - { - sd = socket(p->ai_family, p->ai_socktype, p->ai_protocol); - if (sd == -1) continue; + // Go through the hosts and try to connect + for (p = server_info; p != NULL; p = p->ai_next) + { + sd = socket(p->ai_family, p->ai_socktype, p->ai_protocol); + if (sd == -1) + continue; - result = connect(sd, p->ai_addr, p->ai_addrlen); - if (result == -1) - { - net_close(sd); - continue; - } + ret = connect(sd, p->ai_addr, p->ai_addrlen); + if (ret == -1) + { + net_close(sd); + continue; + } + // Get out of the loop when connect is successful + break; + } - break; - } + freeaddrinfo(server_info); - if (p == NULL) { - fprintf(stderr, "Failed to connect.\n"); - exit(EXIT_FAILURE); - } + if (p == NULL) + { + fprintf(stderr, "Failed to connect.\n"); + exit(EXIT_FAILURE); + } - // Cheating because Windows is retarded (inet_ntop function missing) - fprintf(stdout, "Connected to %s:%s.\n", host, port); + fprintf(stdout, "Connected to %s:%s\n", host, port); - freeaddrinfo(server_info); - - return sd; + return sd; } -int net_send(int sd, const char *buffer, size_t size) +int net_send(int sd, const uint8_t *buffer, size_t size) { - size_t sent = 0; - size_t left = size; + size_t sent = 0; + size_t left = size; - while (sent < size) - { - int result = send(sd, buffer + sent, left, 0); + while (sent < size) + { + int result = send(sd, buffer + sent, left, 0); - if (result == -1) return -1; + if (result == -1) return -1; - sent += result; - left -= sent; - } + sent += result; + left -= sent; + } - return 0; + return 0; } int net_send_packet(int sd, rc_packet *packet) { - int len; - int total = 0; /* how many bytes we've sent */ - int bytesleft; /* how many we have left to send */ - int ret = -1; + int len; + int total = 0; /* how many bytes we've sent */ + int bytesleft; /* how many we have left to send */ + int ret = -1; - bytesleft = len = packet->size + sizeof(int); + bytesleft = len = packet->size + sizeof(int); - while(total < len) - { - ret = send(sd, (char *) packet + total, bytesleft, 0); - if(ret == -1) { break; } - total += ret; - bytesleft -= ret; - } + while(total < len) + { + ret = send(sd, (char *) packet + total, bytesleft, 0); + if(ret == -1) { break; } + total += ret; + bytesleft -= ret; + } - /* return -1 on failure, 0 on success */ - return ret == -1 ? -1 : 1; + /* return -1 on failure, 0 on success */ + return ret == -1 ? -1 : 1; } rc_packet *net_recv_packet(int sd) { - int psize; - static rc_packet packet = {0, 0, 0, { 0x00 }}; + int psize; + static rc_packet packet = {0, 0, 0, { 0x00 }}; - /* packet.size = packet.id = packet.cmd = 0; */ + /* packet.size = packet.id = packet.cmd = 0; */ - int ret = recv(sd, (char *) &psize, sizeof(int), 0); + int ret = recv(sd, (char *) &psize, sizeof(int), 0); - if(ret == 0) { - fprintf(stderr, "Connection lost.\n"); - connection_alive = 0; - return NULL; - } + if (ret == 0) + { + fprintf(stderr, "Connection lost.\n"); + connection_alive = 0; + return NULL; + } - if(ret != sizeof(int)) { - fprintf(stderr, "Error: recv() failed. Invalid packet size (%d).\n", ret); - connection_alive = 0; - return NULL; - } + if (ret != sizeof(int)) + { + fprintf(stderr, "Error: recv() failed. Invalid packet size (%d).\n", ret); + connection_alive = 0; + return NULL; + } - if(psize < 10 || psize > DATA_BUFFSIZE) { - fprintf(stderr, "Warning: invalid packet size (%d). Must over 10 and less than %d.\n", psize, DATA_BUFFSIZE); - if(psize > DATA_BUFFSIZE || psize < 0) psize = DATA_BUFFSIZE; - net_clean_incoming(sd, psize); - return NULL; - } + if (psize < 10 || psize > DATA_BUFFSIZE) + { + fprintf(stderr, "Warning: invalid packet size (%d). Must over 10 and less than %d.\n", psize, DATA_BUFFSIZE); - packet.size = psize; + if(psize > DATA_BUFFSIZE || psize < 0) psize = DATA_BUFFSIZE; + net_clean_incoming(sd, psize); + + return NULL; + } - ret = recv(sd, (char *) &packet + sizeof(int), psize, 0); - if(ret == 0) { - fprintf(stderr, "Connection lost.\n"); - connection_alive = 0; - return NULL; - } - if(ret != psize) { - fprintf(stderr, "Warning: recv() return value (%d) does not match expected packet size (%d).\n", ret, psize); - net_clean_incoming(sd, DATA_BUFFSIZE); /* Should be enough. Needs some checking */ - return NULL; - } + packet.size = psize; - return &packet; + ret = recv(sd, (char *) &packet + sizeof(int), psize, 0); + if (ret == 0) + { + fprintf(stderr, "Connection lost.\n"); + connection_alive = 0; + return NULL; + } + + if(ret != psize) + { + fprintf(stderr, "Warning: recv() return value (%d) does not match expected packet size (%d).\n", ret, psize); + net_clean_incoming(sd, DATA_BUFFSIZE); /* Should be enough. Needs some checking */ + return NULL; + } + + return &packet; } int net_clean_incoming(int sd, int size) { - char tmp[size]; + char tmp[size]; - int ret = recv(sd, tmp, size, 0); + int ret = recv(sd, tmp, size, 0); - if(ret == 0) { - fprintf(stderr, "Connection lost.\n"); - connection_alive = 0; - } + if(ret == 0) + { + fprintf(stderr, "Connection lost.\n"); + connection_alive = 0; + } - return ret; + return ret; } void print_color(int color) { - /* sh compatible color array */ - #ifndef _WIN32 - char *colors[] = { - "\033[0;30m", /* 00 BLACK 0x30 */ - "\033[0;34m", /* 01 BLUE 0x31 */ - "\033[0;32m", /* 02 GREEN 0x32 */ - "\033[0;36m", /* 03 CYAN 0x33 */ - "\033[0;31m", /* 04 RED 0x34 */ - "\033[0;35m", /* 05 PURPLE 0x35 */ - "\033[0;33m", /* 06 GOLD 0x36 */ - "\033[0;37m", /* 07 GREY 0x37 */ - "\033[1;30m", /* 08 DGREY 0x38 */ - "\033[1;34m", /* 09 LBLUE 0x39 */ - "\033[1;32m", /* 10 LGREEN 0x61 */ - "\033[1;36m", /* 11 LCYAN 0x62 */ - "\033[1;31m", /* 12 LRED 0x63 */ - "\033[1;35m", /* 13 LPURPLE 0x64 */ - "\033[1;33m", /* 14 YELLOW 0x65 */ - "\033[1;37m", /* 15 WHITE 0x66 */ - }; + /* sh compatible color array */ + #ifndef _WIN32 + char *colors[] = + { + "\033[0;30m", /* 00 BLACK 0x30 */ + "\033[0;34m", /* 01 BLUE 0x31 */ + "\033[0;32m", /* 02 GREEN 0x32 */ + "\033[0;36m", /* 03 CYAN 0x33 */ + "\033[0;31m", /* 04 RED 0x34 */ + "\033[0;35m", /* 05 PURPLE 0x35 */ + "\033[0;33m", /* 06 GOLD 0x36 */ + "\033[0;37m", /* 07 GREY 0x37 */ + "\033[1;30m", /* 08 DGREY 0x38 */ + "\033[1;34m", /* 09 LBLUE 0x39 */ + "\033[1;32m", /* 10 LGREEN 0x61 */ + "\033[1;36m", /* 11 LCYAN 0x62 */ + "\033[1;31m", /* 12 LRED 0x63 */ + "\033[1;35m", /* 13 LPURPLE 0x64 */ + "\033[1;33m", /* 14 YELLOW 0x65 */ + "\033[1;37m", /* 15 WHITE 0x66 */ + }; - if(color == 0) { - fputs("\033[0m", stdout); /* CANCEL COLOR */ - } - else - #endif - { - if(color >= 0x61 && color <= 0x66) color -= 0x57; - else if(color >= 0x30 && color <= 0x39) color -= 0x30; - else return; + if(color == 0) + { + fputs("\033[0m", stdout); /* CANCEL COLOR */ + } + else + #endif + { + if(color >= 0x61 && color <= 0x66) color -= 0x57; + else if(color >= 0x30 && color <= 0x39) color -= 0x30; + else return; - #ifndef _WIN32 - fputs(colors[color], stdout); - #else - SetConsoleTextAttribute(console_handle, color); - #endif - } + #ifndef _WIN32 + fputs(colors[color], stdout); + #else + SetConsoleTextAttribute(console_handle, color); + #endif + } } /* this hacky mess might use some optimizing */ void packet_print(rc_packet *packet) { - if (raw_output == 1) { - for(int i = 0; packet->data[i] != 0; ++i) putchar(packet->data[i]); - return; - } + if (raw_output == 1) + { + for(int i = 0; packet->data[i] != 0; ++i) putchar(packet->data[i]); + return; + } - int i; - int def_color = 0; + int i; + int def_color = 0; - #ifdef _WIN32 - CONSOLE_SCREEN_BUFFER_INFO console_info; - if(GetConsoleScreenBufferInfo(console_handle, &console_info) != 0) - def_color = console_info.wAttributes + 0x30; - else def_color = 0x37; - #endif + #ifdef _WIN32 + CONSOLE_SCREEN_BUFFER_INFO console_info; + if(GetConsoleScreenBufferInfo(console_handle, &console_info) != 0) + def_color = console_info.wAttributes + 0x30; + else def_color = 0x37; + #endif - /* colors enabled so try to handle the bukkit colors for terminal */ - if(print_colors == 1) { + /* colors enabled so try to handle the bukkit colors for terminal */ + if(print_colors == 1) { - for(i = 0; (unsigned char) packet->data[i] != 0; ++i) { - if((unsigned char) packet->data[i] == 0xa7) { - ++i; - print_color(packet->data[i]); - continue; - } - if(packet->data[i] == 0x0A) print_color(def_color); + for(i = 0; (unsigned char) packet->data[i] != 0; ++i) + { + if((unsigned char) packet->data[i] == 0xa7) + { + ++i; + print_color(packet->data[i]); + continue; + } + if(packet->data[i] == 0x0A) print_color(def_color); + putchar(packet->data[i]); + } + print_color(def_color); /* cancel coloring */ - putchar(packet->data[i]); - } - print_color(def_color); /* cancel coloring */ + } + /* strip colors */ + else + { + for(i = 0; (unsigned char) packet->data[i] != 0; ++i) + { + if((unsigned char) packet->data[i] == 0xa7) + { + ++i; + continue; + } + putchar(packet->data[i]); + } + } - } - /* strip colors */ - else - { - for(i = 0; (unsigned char) packet->data[i] != 0; ++i) { - if((unsigned char) packet->data[i] == 0xa7) { - ++i; - continue; - } - putchar(packet->data[i]); - } - } - - /* print newline if string has no newline */ - if(packet->data[i-1] != 10 && packet->data[i-1] != 13) - putchar('\n'); + /* print newline if string has no newline */ + if(packet->data[i-1] != 10 && packet->data[i-1] != 13) + putchar('\n'); } rc_packet *packet_build(int id, int cmd, char *s1) -{ /* hacky function */ - static rc_packet packet = {0, 0, 0, { 0x00 }}; +{ /* hacky function */ + static rc_packet packet = {0, 0, 0, { 0x00 }}; - /* size + id + cmd + s1 + s2 NULL terminator */ - int s1_len = strlen(s1); - if(s1_len > DATA_BUFFSIZE) { - fprintf(stderr, "Warning: Command string too long (%d). Maximum allowed: %d.\n", s1_len, DATA_BUFFSIZE); - return NULL; - } + /* size + id + cmd + s1 + s2 NULL terminator */ + int s1_len = strlen(s1); + if(s1_len > DATA_BUFFSIZE) + { + fprintf(stderr, "Warning: Command string too long (%d). Maximum allowed: %d.\n", s1_len, DATA_BUFFSIZE); + return NULL; + } - packet.size = sizeof(int) * 2 + s1_len + 2; - packet.id = id; - packet.cmd = cmd; - strncpy(packet.data, s1, DATA_BUFFSIZE); + packet.size = sizeof(int) * 2 + s1_len + 2; + packet.id = id; + packet.cmd = cmd; + strncpy(packet.data, s1, DATA_BUFFSIZE); - return &packet; + return &packet; +} + +// TODO(Tiiffi): String length limit? +uint8_t *packet_build_malloc(size_t *size, int32_t id, int32_t cmd, char *string) +{ + size_t string_length = strlen(string); + + *size = 3 * sizeof(int32_t) + string_length + 2; + uint8_t *packet = malloc(*size); + if (packet == NULL) return NULL; + + int32_t *p = (int32_t *) packet; + p[0] = (int32_t) *size - sizeof(int32_t); + p[1] = id; + p[2] = cmd; + + memcpy(&p[3], string, string_length); + + packet[12 + string_length] = 0; + packet[13 + string_length] = 0; + + return packet; +} + +/* rcon packet structure */ +#define MAX_PACKET_SIZE (size_t) 1460 // including size member +#define MIN_PACKET_SIZE (size_t) 10 +#define MAX_STRING_SIZE (size_t) (MAX_PACKET_SIZE - 2 - 3 * sizeof(int32_t)) +#define SIZEOF_PACKET(x) (size_t) (x.size + sizeof(int32_t)) + +struct rcon_packet +{ + int32_t size; + int32_t id; + int32_t cmd; + uint8_t data[MAX_STRING_SIZE]; +}; + +struct rcon_packet packet_build_new(int32_t id, int32_t cmd, char *string) +{ + struct rcon_packet packet; + size_t string_length = strlen(string); + + if (string_length > MAX_STRING_SIZE) + { + string_length = MAX_STRING_SIZE; + fprintf(stderr, + "Warning: command string is too long. Truncating to " + "%d characters.\n", MAX_STRING_SIZE + ); + } + + packet.size = 2 * sizeof(int32_t) + string_length + 2; + packet.id = id; + packet.cmd = cmd; + memcpy(packet.data, string, string_length); + packet.data[string_length] = 0; + packet.data[string_length + 1] = 0; + + return packet; } int rcon_auth(int rsock, char *passwd) { - int ret; + int ret; - rc_packet *packet = packet_build(RCON_PID, RCON_AUTHENTICATE, passwd); - if(packet == NULL) return 0; + rc_packet *packet = packet_build(RCON_PID, RCON_AUTHENTICATE, passwd); + if(packet == NULL) return 0; - ret = net_send_packet(rsock, packet); - if(!ret) return 0; /* send failed */ + ret = net_send_packet(rsock, packet); + if(!ret) return 0; /* send failed */ - packet = net_recv_packet(rsock); - if(packet == NULL) return 0; + packet = net_recv_packet(rsock); + if(packet == NULL) return 0; - /* return 1 if authentication OK */ - return packet->id == -1 ? 0 : 1; + /* return 1 if authentication OK */ + return packet->id == -1 ? 0 : 1; } int rcon_command(int rsock, char *command) { - int ret; + int ret; - rc_packet *packet = packet_build(RCON_PID, RCON_EXEC_COMMAND, command); - if(packet == NULL) { - connection_alive = 0; - return 0; - } + size_t size; + uint8_t *p = packet_build_malloc(&size, RCON_PID, RCON_EXEC_COMMAND, command); + if (p == NULL) + { + connection_alive = 0; + return 0; + } - ret = net_send_packet(rsock, packet); - if(!ret) return 0; /* send failed */ + net_send(rsock, p, size); - packet = net_recv_packet(rsock); - if(packet == NULL) return 0; + free(p); - if(packet->id != RCON_PID) return 0; /* wrong packet id */ + //ret = net_send_packet(rsock, packet); + //if(!ret) return 0; /* send failed */ - if(!silent_mode) { - /* - if(packet->size == 10) { - printf("Unknown command \"%s\". Type \"help\" or \"?\" for help.\n", command); - } - else - */ - if(packet->size > 10) - packet_print(packet); - } + rc_packet *packet; + packet = net_recv_packet(rsock); + if(packet == NULL) return 0; - /* return 1 if world was saved */ - return 1; + if(packet->id != RCON_PID) return 0; /* wrong packet id */ + + if(!silent_mode) + { + /* + if(packet->size == 10) { + printf("Unknown command \"%s\". Type \"help\" or \"?\" for help.\n", command); + } + else + */ + if(packet->size > 10) + packet_print(packet); + } + + /* return 1 if world was saved */ + return 1; } int run_commands(int argc, char *argv[]) { - int i, ok = 1, ret = 0; + int i, ok = 1, ret = 0; - for(i = optind; i < argc && ok; i++) { - ok = rcon_command(rsock, argv[i]); - ret += ok; - } + for(i = optind; i < argc && ok; i++) + { + ok = rcon_command(rsock, argv[i]); + ret += ok; + } - return ret; + return ret; } /* interactive terminal mode */ int run_terminal_mode(int rsock) { - int ret = 0; - char command[DATA_BUFFSIZE] = {0x00}; + int ret = 0; + char command[DATA_BUFFSIZE] = {0x00}; - puts("Logged in. Type \"Q\" to quit!"); + puts("Logged in. Type \"Q\" to quit!"); - while(connection_alive) { + while(connection_alive) + { + int len = get_line(command, DATA_BUFFSIZE); + if(command[0] == 'Q' && command[1] == 0) break; - int len = get_line(command, DATA_BUFFSIZE); - if(command[0] == 'Q' && command[1] == 0) break; + if(len > 0 && connection_alive) ret += rcon_command(rsock, command); - if(len > 0 && connection_alive) ret += rcon_command(rsock, command); + command[0] = len = 0; + } - command[0] = len = 0; - } - - return ret; + return ret; } /* gets line from stdin and deals with rubbish left in input buffer */ int get_line(char *buffer, int bsize) { - int ch, len; + int ch, len; - fputs("> ", stdout); - fgets(buffer, bsize, stdin); + fputs("> ", stdout); + fgets(buffer, bsize, stdin); - if(buffer[0] == 0) connection_alive = 0; + if(buffer[0] == 0) connection_alive = 0; - /* remove unwanted characters from the buffer */ - buffer[strcspn(buffer, "\r\n")] = '\0'; + /* remove unwanted characters from the buffer */ + buffer[strcspn(buffer, "\r\n")] = '\0'; - len = strlen(buffer); + len = strlen(buffer); - /* clean input buffer if needed */ - if(len == bsize - 1) - while ((ch = getchar()) != '\n' && ch != EOF); + /* clean input buffer if needed */ + if(len == bsize - 1) + while ((ch = getchar()) != '\n' && ch != EOF); - return len; + return len; +} + +// http://www.ibm.com/developerworks/aix/library/au-endianc/ +bool is_bigendian(void) +{ + const int32_t n = 1; + if (*(uint8_t *) &n == 0 ) return true; + return false; +} + +int32_t reverse_int32(int32_t n) +{ + int32_t tmp; + uint8_t *t = (uint8_t *) &tmp; + uint8_t *p = (uint8_t *) &n; + + t[0] = p[3]; + t[1] = p[2]; + t[2] = p[1]; + t[3] = p[0]; + + return tmp; } From c9e3f86a8913523fb1ca366ecb724e0fea2bd4dd Mon Sep 17 00:00:00 2001 From: Tiiffi Date: Thu, 27 Oct 2016 03:23:32 +0300 Subject: [PATCH 06/29] Makefile improvements. --- Makefile | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 1c3e5da..ee829ac 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,15 @@ -# Cross comple, eg. +# if you want to cross compile # export PATH=$PATH:/path/to/compiler/bin # export CROSS_COMPILE=arm-none-linux-gnueabi- # make -all: - $(CROSS_COMPILE)gcc -std=gnu99 -pedantic -Wall -Wextra -O2 -s -o mcrcon mcrcon.c +CC = gcc +CFLAGS = -std=gnu11 -Wall -Wextra -Wpedantic -O2 + +all: + $(CROSS_COMPILE)$(CC) $(CFLAGS) -o mcrcon mcrcon.c + +clean: + rm -f mcrcon + From cbbdbcca93c83bfef2d20191b211deda19a6b71c Mon Sep 17 00:00:00 2001 From: Tiiffi Date: Thu, 27 Oct 2016 03:25:28 +0300 Subject: [PATCH 07/29] net_init_WSA() function and error reporting improvements. --- mcrcon.c | 88 ++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 60 insertions(+), 28 deletions(-) diff --git a/mcrcon.c b/mcrcon.c index 629fcfa..fe49ffa 100644 --- a/mcrcon.c +++ b/mcrcon.c @@ -27,6 +27,8 @@ #include #include #include +#include +#include #ifdef _WIN32 /* for name resolving on windows */ @@ -36,7 +38,6 @@ #include #include #else - #include #include #include #include @@ -78,36 +79,35 @@ typedef struct _rc_packet { bool is_bigendian(void); int32_t reverse_int32(int32_t n); +// Network related functions #ifdef _WIN32 -void net_init_WSA(void); +void net_init_WSA(void); #endif +void net_close(int sd); +int net_connect(const char *host, const char *port); +int net_send(int sd, const uint8_t *buffer, size_t size); -void net_close(int sd); -int net_connect(const char *host, const char *port); -int net_send(int sd, const uint8_t *buffer, size_t size); +int net_send_packet(int sd, rc_packet *packet); +rc_packet* net_recv_packet(int sd); -int net_send_packet(int sd, rc_packet *packet); -rc_packet* net_recv_packet(int sd); - -int net_clean_incoming(int sd, int size); +int net_clean_incoming(int sd, int size); // Other stuff -void usage(void); -void error(char *errstring); +void usage(void); +void error(char *errstring); #ifndef _WIN32 -void print_color(int color); +void print_color(int color); #endif -rc_packet* packet_build(int id, int cmd, char *s1); -void packet_print(rc_packet *packet); +rc_packet* packet_build(int id, int cmd, char *s1); +void packet_print(rc_packet *packet); -int rcon_auth(int rsock, char *passwd); -int rcon_command(int rsock, char *command); - -int get_line(char *buffer, int len); -int run_terminal_mode(int rsock); -int run_commands(int argc, char *argv[]); +int rcon_auth(int rsock, char *passwd); +int rcon_command(int rsock, char *command); +int get_line(char *buffer, int len); +int run_terminal_mode(int rsock); +int run_commands(int argc, char *argv[]); // ============================================= // GLOBAL VARIABLES @@ -266,6 +266,26 @@ void error(char *errstring) exit(-1); } +#ifdef _WIN32 +void net_init_WSA(void) +{ + WSADATA wsadata; + int err; + + err = WSAStartup(MAKEWORD(1, 1), &wsadata); + if(err != 0) + { + fprintf(stderr, "WSAStartup failed. Errno: %d.\n", err); + exit(-1); + } +} +#endif +/* +void net_get_last_error(int ret) +{ + +} +*/ /* socket close and cleanup */ void net_close(int sd) { @@ -278,6 +298,8 @@ void net_close(int sd) } /* Opens and connects socket */ +/* http://man7.org/linux/man-pages/man3/getaddrinfo.3.html */ +/* https://bugs.chromium.org/p/chromium/issues/detail?id=44489 */ int net_connect(const char *host, const char *port) { int sd; @@ -297,7 +319,12 @@ int net_connect(const char *host, const char *port) int ret = getaddrinfo(host, port, &hints, &server_info); if (ret != 0) { - fprintf("getaddrinfo(): %s\n", gai_strerror(ret)); + fprintf(stderr, "Name resolution failed.\n"); + #ifdef _WIN32 + fprintf(stderr, "Error %d: %s", ret, gai_strerror(ret)); + #else + fprintf(stderr, "Error %d: %s\n", ret, gai_strerror(ret)); + #endif exit(EXIT_FAILURE); } @@ -318,14 +345,19 @@ int net_connect(const char *host, const char *port) break; } - freeaddrinfo(server_info); - if (p == NULL) { - fprintf(stderr, "Failed to connect.\n"); + /* TODO (Tiiffi): Check why windows does not report errors */ + fprintf(stderr, "Connection failed.\n"); + #ifndef _WIN32 + fprintf(stderr, "Error %d: %s\n", errno, strerror(errno)); + #endif + freeaddrinfo(server_info); exit(EXIT_FAILURE); } + freeaddrinfo(server_info); + fprintf(stdout, "Connected to %s:%s\n", host, port); return sd; @@ -399,7 +431,7 @@ rc_packet *net_recv_packet(int sd) if(psize > DATA_BUFFSIZE || psize < 0) psize = DATA_BUFFSIZE; net_clean_incoming(sd, psize); - + return NULL; } @@ -489,7 +521,7 @@ void packet_print(rc_packet *packet) for(int i = 0; packet->data[i] != 0; ++i) putchar(packet->data[i]); return; } - + int i; int def_color = 0; @@ -583,7 +615,7 @@ uint8_t *packet_build_malloc(size_t *size, int32_t id, int32_t cmd, char *string #define MIN_PACKET_SIZE (size_t) 10 #define MAX_STRING_SIZE (size_t) (MAX_PACKET_SIZE - 2 - 3 * sizeof(int32_t)) #define SIZEOF_PACKET(x) (size_t) (x.size + sizeof(int32_t)) - + struct rcon_packet { int32_t size; @@ -635,7 +667,7 @@ int rcon_auth(int rsock, char *passwd) int rcon_command(int rsock, char *command) { - int ret; + int ret; (void) ret; size_t size; uint8_t *p = packet_build_malloc(&size, RCON_PID, RCON_EXEC_COMMAND, command); From 4b663958aaaf0f8d0e377a1d018105dcac87c3fa Mon Sep 17 00:00:00 2001 From: Tiiffi Date: Thu, 27 Oct 2016 03:33:04 +0300 Subject: [PATCH 08/29] README.md update. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 77ee6dd..3d4e4db 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ ####Compiling: Compile with GCC or CLANG: -```cc -std=gnu99 -pedantic -Wall -Wextra -O2 -s -o mcrcon mcrcon.c``` +```cc -std=gnu11 -Wpedantic -Wall -Wextra -O2 -s -o mcrcon mcrcon.c``` or just run **make**. From a0d3d7f52e15d994d94180cf0aa4c6199e922079 Mon Sep 17 00:00:00 2001 From: Tiiffi Date: Fri, 28 Oct 2016 01:40:38 +0300 Subject: [PATCH 09/29] Commented windows version define and changed net_init_WSA() to request Winsock version 2.2 instead of old 1.1. --- mcrcon.c | 46 ++++++++++++++++++++++------------------------ 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/mcrcon.c b/mcrcon.c index fe49ffa..dfd7966 100644 --- a/mcrcon.c +++ b/mcrcon.c @@ -32,7 +32,7 @@ #ifdef _WIN32 /* for name resolving on windows */ - #define _WIN32_WINNT 0x0501 + //#define _WIN32_WINNT 0x0501 #include #include @@ -176,12 +176,12 @@ int main(int argc, char *argv[]) /* else fprintf (stderr, "Unknown option -%c\n\n", optopt); */ - usage(); - break; + usage(); + break; - default: abort(); + default: exit(-1); + } } -} if (host == NULL) { @@ -269,32 +269,30 @@ void error(char *errstring) #ifdef _WIN32 void net_init_WSA(void) { - WSADATA wsadata; - int err; + WSADATA wsadata; - err = WSAStartup(MAKEWORD(1, 1), &wsadata); - if(err != 0) - { - fprintf(stderr, "WSAStartup failed. Errno: %d.\n", err); - exit(-1); - } + // Request winsock 2.2 for now. + // Should be compatible down to Win XP. + WORD version = MAKEWORD(2, 2); + + int err = WSAStartup(version, &wsadata); + if (err != 0) + { + fprintf(stderr, "WSAStartup failed. Error: %d.\n", err); + exit(-1); + } } #endif -/* -void net_get_last_error(int ret) -{ -} -*/ /* socket close and cleanup */ void net_close(int sd) { - #ifdef _WIN32 - closesocket(sd); - WSACleanup(); - #else - close(sd); - #endif +#ifdef _WIN32 + closesocket(sd); + WSACleanup(); +#else + close(sd); +#endif } /* Opens and connects socket */ From 3e60b0d28fc3f8710fa71500793c34a6e74a923e Mon Sep 17 00:00:00 2001 From: Tiiffi Date: Fri, 28 Oct 2016 01:41:38 +0300 Subject: [PATCH 10/29] Added Windows support to Makefile. --- Makefile | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index ee829ac..35d6cdd 100644 --- a/Makefile +++ b/Makefile @@ -3,13 +3,22 @@ # export CROSS_COMPILE=arm-none-linux-gnueabi- # make +ifeq ($(OS), Windows_NT) + LINKER = -lws2_32 + EXENAME = mcrcon.exe + RM = cmd /C del /F +else + LINKER = + EXENAME = mcrcon + RM = rm -f +endif + CC = gcc CFLAGS = -std=gnu11 -Wall -Wextra -Wpedantic -O2 all: - $(CROSS_COMPILE)$(CC) $(CFLAGS) -o mcrcon mcrcon.c + $(CROSS_COMPILE)$(CC) $(CFLAGS) -o $(EXENAME) mcrcon.c $(LINKER) clean: - rm -f mcrcon - + $(RM) $(EXENAME) From edc750ccef79a06be4083d23cf023253bb5994b8 Mon Sep 17 00:00:00 2001 From: Tiiffi Date: Fri, 28 Oct 2016 03:21:16 +0300 Subject: [PATCH 11/29] Added packet_build_malloc() forward declaration and type cast to 2nd argument of send() function to silence windows compiler warnings. --- mcrcon.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/mcrcon.c b/mcrcon.c index dfd7966..fba0cba 100644 --- a/mcrcon.c +++ b/mcrcon.c @@ -86,10 +86,8 @@ void net_init_WSA(void); void net_close(int sd); int net_connect(const char *host, const char *port); int net_send(int sd, const uint8_t *buffer, size_t size); - int net_send_packet(int sd, rc_packet *packet); rc_packet* net_recv_packet(int sd); - int net_clean_incoming(int sd, int size); // Other stuff @@ -100,6 +98,7 @@ void print_color(int color); #endif rc_packet* packet_build(int id, int cmd, char *s1); +uint8_t *packet_build_malloc(size_t *size, int32_t id, int32_t cmd, char *string); void packet_print(rc_packet *packet); int rcon_auth(int rsock, char *passwd); @@ -361,14 +360,14 @@ int net_connect(const char *host, const char *port) return sd; } -int net_send(int sd, const uint8_t *buffer, size_t size) +int net_send(int sd, const uint8_t *buff, size_t size) { size_t sent = 0; size_t left = size; while (sent < size) { - int result = send(sd, buffer + sent, left, 0); + int result = send(sd, (const char *) buff + sent, left, 0); if (result == -1) return -1; @@ -632,7 +631,7 @@ struct rcon_packet packet_build_new(int32_t id, int32_t cmd, char *string) string_length = MAX_STRING_SIZE; fprintf(stderr, "Warning: command string is too long. Truncating to " - "%d characters.\n", MAX_STRING_SIZE + "%u characters.\n", MAX_STRING_SIZE ); } From 786767e9f18d998532c9e3861a56a081ac36c735 Mon Sep 17 00:00:00 2001 From: Tiiffi Date: Sun, 13 Nov 2016 14:12:30 +0200 Subject: [PATCH 12/29] License update. --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 2dc77ad..a3e4a6e 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2012-2015, Tiiffi gmail_dot_com> +Copyright (c) 2012-2016, Tiiffi This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages From 88c91d4096b194d54986d06eb1b76f6d3787882a Mon Sep 17 00:00:00 2001 From: Tiiffi Date: Sun, 13 Nov 2016 14:15:29 +0200 Subject: [PATCH 13/29] Updated compiler flags. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 35d6cdd..3c8d242 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ else endif CC = gcc -CFLAGS = -std=gnu11 -Wall -Wextra -Wpedantic -O2 +CFLAGS = -std=gnu99 -Wall -Wextra -Wpedantic -Os -s all: $(CROSS_COMPILE)$(CC) $(CFLAGS) -o $(EXENAME) mcrcon.c $(LINKER) From 449eac6358b9f907975f4583772f5c552aed45b7 Mon Sep 17 00:00:00 2001 From: Tiiffi Date: Sun, 13 Nov 2016 14:16:14 +0200 Subject: [PATCH 14/29] Added manpage to the project. --- mcrcon.1 | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 mcrcon.1 diff --git a/mcrcon.1 b/mcrcon.1 new file mode 100644 index 0000000..7c16312 --- /dev/null +++ b/mcrcon.1 @@ -0,0 +1,33 @@ +.\" Process this file with +.\" groff -man -Tascii mcrcon.1 +.\" +.TH MCRCON 1 "November 2016" "Version 0.0.5" +.SH NAME +mcrcon \- sends rcon commands to a Minecraft server +.SH SYNOPSIS +.B mcrcon [ +options +.B ] [ +commands +.B ] +.SH DESCRIPTION +.B mcrcon +Mcrcon is Minecraft rcon client / terminal with bukkit coloring support. +It is well suited for remote administration and to be used as part of automated server maintenance scripts. +.SH OPTIONS +.IP -h +Print usage instructions. +.IP -s +Silent mode. Do not print data received from rcon. +.IP -t +Terminal mode. Act as an interactive terminal. +.IP -p +Rcon password. Default is "". +.IP -H +Hostname or IP address to connect to. +.IP -P +Port to connect to. Default is 25575. +.IP -C +Color off. Disables bukkit color printing. +.SH BUGS +Bugs can be reported to tiiffi@gmail.com or https://github.com/Tiiffi/mcrcon/issues/ From d92a60bed4ec47d52cdd13dbdaaa9e03186d7015 Mon Sep 17 00:00:00 2001 From: Tiiffi Date: Sun, 13 Nov 2016 18:12:03 +0200 Subject: [PATCH 15/29] Added Install / uninstall rules to Makefile and made changes to error printing. Also now password is not set by default and terminal mode is activated automatically if there are no commands to execute. --- Makefile | 14 +++++++++- mcrcon.c | 78 +++++++++++++++++++++++++++++++------------------------- 2 files changed, 56 insertions(+), 36 deletions(-) diff --git a/Makefile b/Makefile index 3c8d242..b17c7f8 100644 --- a/Makefile +++ b/Makefile @@ -19,6 +19,18 @@ CFLAGS = -std=gnu99 -Wall -Wextra -Wpedantic -Os -s all: $(CROSS_COMPILE)$(CC) $(CFLAGS) -o $(EXENAME) mcrcon.c $(LINKER) +ifneq ($(OS), Windows_NT) +install: + cp $(EXENAME) /usr/local/bin/$(EXENAME) + chmod 0755 /usr/local/bin/$(EXENAME) + cp mcrcon.1 /usr/local/share/man/man1/mcrcon.1 + chmod 0644 /usr/local/share/man/man1/mcrcon.1 + @echo "\nmcrcon installed. Run 'make uninstall' if you want to uninstall.\n" +uninstall: + rm -f /usr/local/bin/$(EXENAME) + rm -f /usr/local/share/man/man1/mcrcon.1 + @echo "\nmcrcon uninstalled.\n" +endif + clean: $(RM) $(EXENAME) - diff --git a/mcrcon.c b/mcrcon.c index fba0cba..d47d044 100644 --- a/mcrcon.c +++ b/mcrcon.c @@ -58,17 +58,17 @@ /* Safe value I think. This should me made dynamic for more stable performance! */ #define DATA_BUFFSIZE 10240 -#define VERSION "0.0.5" +#define VERSION "0.0.6" #define IN_NAME "mcrcon" #define VER_STR IN_NAME" "VERSION -/* rcon packet structure */ +// rcon packet structure typedef struct _rc_packet { int size; int id; int cmd; char data[DATA_BUFFSIZE]; - /* ignoring string2 atm.. */ + // ignoring string2 atm. } rc_packet; /* =================================== */ @@ -76,7 +76,7 @@ typedef struct _rc_packet { /* =================================== */ // endianness related functions -bool is_bigendian(void); +bool is_bigendian(void); int32_t reverse_int32(int32_t n); // Network related functions @@ -90,13 +90,17 @@ int net_send_packet(int sd, rc_packet *packet); rc_packet* net_recv_packet(int sd); int net_clean_incoming(int sd, int size); -// Other stuff +// Misc stuff void usage(void); void error(char *errstring); #ifndef _WIN32 void print_color(int color); #endif +int get_line(char *buffer, int len); +int run_terminal_mode(int rsock); +int run_commands(int argc, char *argv[]); +// Rcon protocol related functions rc_packet* packet_build(int id, int cmd, char *s1); uint8_t *packet_build_malloc(size_t *size, int32_t id, int32_t cmd, char *string); void packet_print(rc_packet *packet); @@ -104,31 +108,29 @@ void packet_print(rc_packet *packet); int rcon_auth(int rsock, char *passwd); int rcon_command(int rsock, char *command); -int get_line(char *buffer, int len); -int run_terminal_mode(int rsock); -int run_commands(int argc, char *argv[]); // ============================================= // GLOBAL VARIABLES // ============================================= -int raw_output = 0; -int silent_mode = 0; -int print_colors = 1; -int connection_alive = 1; -int rsock; /* rcon socket */ +static int raw_output = 0; +static int silent_mode = 0; +static int print_colors = 1; +static int connection_alive = 1; +static int rsock; #ifdef _WIN32 - /* console coloring on windows */ + // console coloring on windows HANDLE console_handle; #endif -/* safety stuff (windows is still misbehaving) */ +// safety stuff (windows is still misbehaving) void exit_proc(void) { - if (rsock != -1) net_close(rsock); + if (rsock != -1) + net_close(rsock); } -/* Check windows & linux behaviour !!! */ +// Check windows & linux behaviour !!! void sighandler(/*int sig*/) { connection_alive = 0; @@ -143,12 +145,14 @@ int main(int argc, char *argv[]) int terminal_mode = 0; char *host = NULL; - char *pass = ""; + char *pass = NULL; // this should be null by default! char *port = "25575"; - if(argc < 2) usage(); + if(argc < 2) + usage(); - opterr = 1; /* default error handler enabled */ + // default getopt error handler enabled + opterr = 1; while ((opt = getopt(argc, argv, "rtcshH:p:P:i")) != -1) { @@ -184,15 +188,19 @@ int main(int argc, char *argv[]) if (host == NULL) { - fputs("Host not defined. Check -H flag.\n\n", stdout); - usage(); + fputs("Host not defined (-H flag). Try 'mcrcon -h' for more information.\n\n", stdout); + return 0; + } + + if (pass == NULL) + { + fputs("Password not defined (-p flag). Try 'mcrcon -h' for more information.\n\n", stdout); + return 0; } if(optind == argc && terminal_mode == 0) - { - fputs("No commands specified.\n\n", stdout); - usage(); - } + terminal_mode = 1; + /* safety features to prevent "IO: Connection reset" bug on the server side */ atexit(&exit_proc); @@ -233,23 +241,23 @@ int main(int argc, char *argv[]) void usage(void) { fputs( - "Usage: "IN_NAME" [OPTIONS]... [COMMANDS]...\n" - "Sends rcon commands to minecraft server.\n\n" + "Usage: "IN_NAME" [OPTIONS]... [COMMANDS]...\n\n" + "Sends rcon commands to Minecraft server.\n\n" "Option:\n" " -h\t\tPrint usage.\n" - " -s\t\tSilent mode. Do not print data received from rcon.\n" + " -H\t\tServer address.\n" + " -P\t\tPort. Default is 25575.\n" + " -p\t\tRcon password.\"\".\n" " -t\t\tTerminal mode. Acts as interactive terminal.\n" - " -p\t\tRcon password. Default: \"\".\n" - " -H\t\tHost address or ip.\n" - " -P\t\tPort. Default: 25575.\n" + " -s\t\tSilent mode. Do not print data received from rcon.\n" " -c\t\tDisable colors.\n" " -r\t\tOutput raw packets.\n\t\tGood for debugging and custom handling of the output.\n" ,stdout ); puts("\nCommands must be separated with spaces.\n"); - puts("Example:\n "IN_NAME" -c -H 192.168.1.42 -P 25575 -p password cmd1 \"cmd2 arg1 arg2\"\n"); - puts("minecraft rcon ("IN_NAME") "VERSION".\nReport bugs to tiiffi_at_gmail_dot_com.\n"); + puts("Example:\n "IN_NAME" -c -H my.minecraft.server -P 25575 -p password cmd1 \"cmd2 arg1 arg2\"\n"); + puts(VER_STR"\nReport bugs to tiiffi_at_gmail_dot_com or http://github.com/tiiffi/mcrcon/issues/\n"); #ifdef _WIN32 puts("Press enter to exit."); @@ -631,7 +639,7 @@ struct rcon_packet packet_build_new(int32_t id, int32_t cmd, char *string) string_length = MAX_STRING_SIZE; fprintf(stderr, "Warning: command string is too long. Truncating to " - "%u characters.\n", MAX_STRING_SIZE + "%u characters.\n", (unsigned) MAX_STRING_SIZE ); } From c1bfcbb6115d7e02f934667fe94f8081fa68a8b2 Mon Sep 17 00:00:00 2001 From: Tiiffi Date: Tue, 15 Nov 2016 19:48:10 +0200 Subject: [PATCH 16/29] Improved error messages and version flag info added to usage helper. --- mcrcon.c | 47 ++++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/mcrcon.c b/mcrcon.c index d47d044..20a16fd 100644 --- a/mcrcon.c +++ b/mcrcon.c @@ -60,7 +60,7 @@ #define VERSION "0.0.6" #define IN_NAME "mcrcon" -#define VER_STR IN_NAME" "VERSION +#define VER_STR IN_NAME" "VERSION" (built: "__DATE__" "__TIME__")" // rcon packet structure typedef struct _rc_packet { @@ -145,7 +145,7 @@ int main(int argc, char *argv[]) int terminal_mode = 0; char *host = NULL; - char *pass = NULL; // this should be null by default! + char *pass = NULL; char *port = "25575"; if(argc < 2) @@ -154,7 +154,7 @@ int main(int argc, char *argv[]) // default getopt error handler enabled opterr = 1; - while ((opt = getopt(argc, argv, "rtcshH:p:P:i")) != -1) + while ((opt = getopt(argc, argv, "vrtcshH:p:P:i")) != -1) { switch (opt) { @@ -170,17 +170,17 @@ int main(int argc, char *argv[]) case 'I': case 'i': terminal_mode = 1; break; case 'r': raw_output = 1; break; + case 'v': + puts(VER_STR"\nhttps://github.com/Tiiffi/mcrcon"); + exit(0); + break; case 'h': - case '?': + case '?': usage(); break; /* if(optopt == 'P' || optopt == 'H' || optopt == 'p') fprintf (stderr, "Option -%c requires an argument.\n\n", optopt); - */ - - /* else fprintf (stderr, "Unknown option -%c\n\n", optopt); */ - - usage(); - break; + + else fprintf (stderr, "Unknown option -%c\n\n", optopt); */ default: exit(-1); } @@ -188,13 +188,13 @@ int main(int argc, char *argv[]) if (host == NULL) { - fputs("Host not defined (-H flag). Try 'mcrcon -h' for more information.\n\n", stdout); + fputs("Host not defined (-H flag). Try 'mcrcon -h' or 'man mcrcon' for more information.\n\n", stdout); return 0; } if (pass == NULL) { - fputs("Password not defined (-p flag). Try 'mcrcon -h' for more information.\n\n", stdout); + fputs("Password not defined (-p flag). Try 'mcrcon -h' 'man mcrcon' for more information.\n\n", stdout); return 0; } @@ -244,20 +244,21 @@ void usage(void) "Usage: "IN_NAME" [OPTIONS]... [COMMANDS]...\n\n" "Sends rcon commands to Minecraft server.\n\n" "Option:\n" - " -h\t\tPrint usage.\n" - " -H\t\tServer address.\n" - " -P\t\tPort. Default is 25575.\n" - " -p\t\tRcon password.\"\".\n" - " -t\t\tTerminal mode. Acts as interactive terminal.\n" - " -s\t\tSilent mode. Do not print data received from rcon.\n" - " -c\t\tDisable colors.\n" - " -r\t\tOutput raw packets.\n\t\tGood for debugging and custom handling of the output.\n" + " -h\t\tPrint usage\n" + " -H\t\tServer address\n" + " -P\t\tPort (default is 25575)\n" + " -p\t\tRcon password\n" + " -t\t\tInteractive terminal mode\n" + " -s\t\tSilent mode (do not print received packets)\n" + " -c\t\tDisable colors\n" + " -r\t\tOutput raw packets (debugging and custom handling)\n" + " -v\t\tOutput version information\n" ,stdout ); - puts("\nCommands must be separated with spaces.\n"); - puts("Example:\n "IN_NAME" -c -H my.minecraft.server -P 25575 -p password cmd1 \"cmd2 arg1 arg2\"\n"); - puts(VER_STR"\nReport bugs to tiiffi_at_gmail_dot_com or http://github.com/tiiffi/mcrcon/issues/\n"); + puts("\nCommands with arguments must enclosed in quotes.\n"); + puts("Example:\n\t"IN_NAME" -H my.minecraft.server -p password \"say Server is restarting!\" save-all stop\n"); + puts(VER_STR"\nReport bugs to tiiffi_at_gmail_dot_com or https://github.com/Tiiffi/mcrcon/issues/\n"); #ifdef _WIN32 puts("Press enter to exit."); From f9595188d5bb81175d0a95124cf92a48f60d20f2 Mon Sep 17 00:00:00 2001 From: Tiiffi Date: Tue, 15 Nov 2016 19:48:28 +0200 Subject: [PATCH 17/29] manpage improvements. --- mcrcon.1 | 52 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 16 deletions(-) diff --git a/mcrcon.1 b/mcrcon.1 index 7c16312..20fa82a 100644 --- a/mcrcon.1 +++ b/mcrcon.1 @@ -1,7 +1,7 @@ .\" Process this file with .\" groff -man -Tascii mcrcon.1 .\" -.TH MCRCON 1 "November 2016" "Version 0.0.5" +.TH MCRCON 1 "November 2016" "Version 0.0.6" .SH NAME mcrcon \- sends rcon commands to a Minecraft server .SH SYNOPSIS @@ -11,23 +11,43 @@ options commands .B ] .SH DESCRIPTION -.B mcrcon -Mcrcon is Minecraft rcon client / terminal with bukkit coloring support. -It is well suited for remote administration and to be used as part of automated server maintenance scripts. +mcrcon is Minecraft rcon client / terminal with bukkit coloring support.\n\n\n +It is well suited for remote administration and server maintenance scripts. .SH OPTIONS .IP -h -Print usage instructions. -.IP -s -Silent mode. Do not print data received from rcon. -.IP -t -Terminal mode. Act as an interactive terminal. -.IP -p -Rcon password. Default is "". +Print usage .IP -H -Hostname or IP address to connect to. +Server address .IP -P -Port to connect to. Default is 25575. -.IP -C -Color off. Disables bukkit color printing. +Port (default is 25575) +.IP -p +Rcon password +.IP -t +Interactive terminal mode +.IP -s +Silent mode (do not print received packets) +.IP -c +Disable colors +.IP -r +Output raw packets (for debugging and custom handling) +.IP -v +Output version information +.PP +Commands with arguments must enclosed in quotes. +.SH EXAMPLES +Make rcon connection in terminal mode using default port +.RS +\fBmcrcon\fR -H my.minecraft.server -p password +.RE +.PP +Send "weather clear" command to server using custom port 1337 +.RS +\fBmcrcon\fR -H my.minecraft.server -P 1337 -p password "weather clear" +.RE +.PP +Send three commands to server (say, save-all and stop) +.RS +\fBmcrcon\fR -H my.minecraft.server -p password "say Server is restarting!" save-all stop +.RE .SH BUGS -Bugs can be reported to tiiffi@gmail.com or https://github.com/Tiiffi/mcrcon/issues/ +Bugs can be reported to \fBtiiffi_at_gmail_dot_com\fR or \fBhttps://github.com/Tiiffi/mcrcon/issues/\fR From a0e638edc99b756c58c7d42b202be8dbbf8c64f9 Mon Sep 17 00:00:00 2001 From: Tiiffi Date: Tue, 15 Nov 2016 20:28:33 +0200 Subject: [PATCH 18/29] Code style changes. --- mcrcon.c | 118 +++++++++++++++++++++++++++---------------------------- 1 file changed, 58 insertions(+), 60 deletions(-) diff --git a/mcrcon.c b/mcrcon.c index 20a16fd..25f80eb 100644 --- a/mcrcon.c +++ b/mcrcon.c @@ -31,7 +31,8 @@ #include #ifdef _WIN32 - /* for name resolving on windows */ + // for name resolving on windows + // enable this if you get compiler whine about getaddrinfo on windows //#define _WIN32_WINNT 0x0501 #include @@ -45,9 +46,9 @@ #include #endif -/* absolute value macro -#define absolute(x) (x < 0) ? (0 - x) : x -*/ +#define VERSION "0.0.6" +#define IN_NAME "mcrcon" +#define VER_STR IN_NAME" "VERSION" (built: "__DATE__" "__TIME__")" #define RCON_EXEC_COMMAND 2 #define RCON_AUTHENTICATE 3 @@ -58,10 +59,6 @@ /* Safe value I think. This should me made dynamic for more stable performance! */ #define DATA_BUFFSIZE 10240 -#define VERSION "0.0.6" -#define IN_NAME "mcrcon" -#define VER_STR IN_NAME" "VERSION" (built: "__DATE__" "__TIME__")" - // rcon packet structure typedef struct _rc_packet { int size; @@ -92,7 +89,6 @@ int net_clean_incoming(int sd, int size); // Misc stuff void usage(void); -void error(char *errstring); #ifndef _WIN32 void print_color(int color); #endif @@ -135,7 +131,7 @@ void sighandler(/*int sig*/) { connection_alive = 0; #ifndef _WIN32 - exit(-1); + exit(-1); #endif } @@ -176,11 +172,11 @@ int main(int argc, char *argv[]) break; case 'h': case '?': usage(); break; - /* - if(optopt == 'P' || optopt == 'H' || optopt == 'p') - fprintf (stderr, "Option -%c requires an argument.\n\n", optopt); - - else fprintf (stderr, "Unknown option -%c\n\n", optopt); */ + /* + if(optopt == 'P' || optopt == 'H' || optopt == 'p') + fprintf (stderr, "Option -%c requires an argument.\n\n", optopt); + else fprintf (stderr, "Unknown option -%c\n\n", optopt); + */ default: exit(-1); } @@ -202,25 +198,25 @@ int main(int argc, char *argv[]) terminal_mode = 1; - /* safety features to prevent "IO: Connection reset" bug on the server side */ + // safety features to prevent "IO: Connection reset" bug on the server side atexit(&exit_proc); signal(SIGABRT, &sighandler); signal(SIGTERM, &sighandler); signal(SIGINT, &sighandler); #ifdef _WIN32 - net_init_WSA(); - console_handle = GetStdHandle(STD_OUTPUT_HANDLE); - if(console_handle == INVALID_HANDLE_VALUE) console_handle = NULL; + net_init_WSA(); + console_handle = GetStdHandle(STD_OUTPUT_HANDLE); + if (console_handle == INVALID_HANDLE_VALUE) console_handle = NULL; #endif - /* open socket */ + // open socket rsock = net_connect(host, port); - /* auth & commands */ - if(rcon_auth(rsock, pass)) + // auth & commands + if (rcon_auth(rsock, pass)) { - if(terminal_mode) + if (terminal_mode) ret = run_terminal_mode(rsock); else ret = run_commands(argc, argv); @@ -261,19 +257,13 @@ void usage(void) puts(VER_STR"\nReport bugs to tiiffi_at_gmail_dot_com or https://github.com/Tiiffi/mcrcon/issues/\n"); #ifdef _WIN32 - puts("Press enter to exit."); - getchar(); + puts("Press enter to exit."); + getchar(); #endif exit(0); } -void error(char *errstring) -{ - fputs(errstring, stderr); - exit(-1); -} - #ifdef _WIN32 void net_init_WSA(void) { @@ -364,8 +354,6 @@ int net_connect(const char *host, const char *port) freeaddrinfo(server_info); - fprintf(stdout, "Connected to %s:%s\n", host, port); - return sd; } @@ -532,24 +520,25 @@ void packet_print(rc_packet *packet) int def_color = 0; #ifdef _WIN32 - CONSOLE_SCREEN_BUFFER_INFO console_info; - if(GetConsoleScreenBufferInfo(console_handle, &console_info) != 0) - def_color = console_info.wAttributes + 0x30; - else def_color = 0x37; + CONSOLE_SCREEN_BUFFER_INFO console_info; + if(GetConsoleScreenBufferInfo(console_handle, &console_info) != 0) + def_color = console_info.wAttributes + 0x30; + else def_color = 0x37; #endif /* colors enabled so try to handle the bukkit colors for terminal */ - if(print_colors == 1) { + if (print_colors == 1) { - for(i = 0; (unsigned char) packet->data[i] != 0; ++i) + for (i = 0; (unsigned char) packet->data[i] != 0; ++i) { - if((unsigned char) packet->data[i] == 0xa7) + if ((unsigned char) packet->data[i] == 0xa7) { ++i; print_color(packet->data[i]); continue; } - if(packet->data[i] == 0x0A) print_color(def_color); + if (packet->data[i] == 0x0A) print_color(def_color); + putchar(packet->data[i]); } print_color(def_color); /* cancel coloring */ @@ -558,19 +547,20 @@ void packet_print(rc_packet *packet) /* strip colors */ else { - for(i = 0; (unsigned char) packet->data[i] != 0; ++i) + for (i = 0; (unsigned char) packet->data[i] != 0; ++i) { - if((unsigned char) packet->data[i] == 0xa7) + if ((unsigned char) packet->data[i] == 0xa7) { ++i; continue; } + putchar(packet->data[i]); } } /* print newline if string has no newline */ - if(packet->data[i-1] != 10 && packet->data[i-1] != 13) + if (packet->data[i-1] != 10 && packet->data[i-1] != 13) putchar('\n'); } @@ -580,7 +570,7 @@ rc_packet *packet_build(int id, int cmd, char *s1) /* size + id + cmd + s1 + s2 NULL terminator */ int s1_len = strlen(s1); - if(s1_len > DATA_BUFFSIZE) + if (s1_len > DATA_BUFFSIZE) { fprintf(stderr, "Warning: Command string too long (%d). Maximum allowed: %d.\n", s1_len, DATA_BUFFSIZE); return NULL; @@ -659,13 +649,16 @@ int rcon_auth(int rsock, char *passwd) int ret; rc_packet *packet = packet_build(RCON_PID, RCON_AUTHENTICATE, passwd); - if(packet == NULL) return 0; + if (packet == NULL) + return 0; ret = net_send_packet(rsock, packet); - if(!ret) return 0; /* send failed */ + if (!ret) + return 0; /* send failed */ packet = net_recv_packet(rsock); - if(packet == NULL) return 0; + if (packet == NULL) + return 0; /* return 1 if authentication OK */ return packet->id == -1 ? 0 : 1; @@ -692,11 +685,13 @@ int rcon_command(int rsock, char *command) rc_packet *packet; packet = net_recv_packet(rsock); - if(packet == NULL) return 0; + if (packet == NULL) + return 0; - if(packet->id != RCON_PID) return 0; /* wrong packet id */ + if (packet->id != RCON_PID) + return 0; /* wrong packet id */ - if(!silent_mode) + if (!silent_mode) { /* if(packet->size == 10) { @@ -704,7 +699,7 @@ int rcon_command(int rsock, char *command) } else */ - if(packet->size > 10) + if (packet->size > 10) packet_print(packet); } @@ -716,7 +711,7 @@ int run_commands(int argc, char *argv[]) { int i, ok = 1, ret = 0; - for(i = optind; i < argc && ok; i++) + for (i = optind; i < argc && ok; i++) { ok = rcon_command(rsock, argv[i]); ret += ok; @@ -733,12 +728,14 @@ int run_terminal_mode(int rsock) puts("Logged in. Type \"Q\" to quit!"); - while(connection_alive) + while (connection_alive) { int len = get_line(command, DATA_BUFFSIZE); - if(command[0] == 'Q' && command[1] == 0) break; + if(command[0] == 'Q' && command[1] == 0) + break; - if(len > 0 && connection_alive) ret += rcon_command(rsock, command); + if(len > 0 && connection_alive) + ret += rcon_command(rsock, command); command[0] = len = 0; } @@ -751,10 +748,11 @@ int get_line(char *buffer, int bsize) { int ch, len; - fputs("> ", stdout); - fgets(buffer, bsize, stdin); + fputs("/", stdout); + (void) fgets(buffer, bsize, stdin); - if(buffer[0] == 0) connection_alive = 0; + if (buffer[0] == 0) + connection_alive = 0; /* remove unwanted characters from the buffer */ buffer[strcspn(buffer, "\r\n")] = '\0'; @@ -762,7 +760,7 @@ int get_line(char *buffer, int bsize) len = strlen(buffer); /* clean input buffer if needed */ - if(len == bsize - 1) + if (len == bsize - 1) while ((ch = getchar()) != '\n' && ch != EOF); return len; From 46af96a3a4bec9880ec8821f7d823f768cf20651 Mon Sep 17 00:00:00 2001 From: Tiiffi Date: Tue, 15 Nov 2016 20:41:58 +0200 Subject: [PATCH 19/29] Moved changelog and compiling to own files and updated usage info in README.md. --- CHANGELOG.md | 64 ++++++++++++++++++++++++++++++ COMPILING | 11 ++++++ README.md | 110 ++++++++------------------------------------------- 3 files changed, 92 insertions(+), 93 deletions(-) create mode 100644 CHANGELOG.md create mode 100644 COMPILING diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..67c1e9b --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,64 @@ +####Version history: +######0.0.5 + - IPv6 support! + * Thanks to 'Tanja84dk' for addressing the real need of IPv6. + + - Fixed bug causing crash / segmentation fault (invalid write) when receiving malformed rcon packet. + + - Program makes use of C99 feature (variable-length arrays) so "-std=gnu99" flag on + GCC-compiler must be used to avoid unecessary warnings. + + - Rcon receive buffer is now bigger (2024 bytes -> 10240 bytes). + * Thanks to 'gman_ftw' @ Bukkit forums. + + - Fixed invalid error message when receiving empty rcon packet (10 bytes). + * Thanks to 'pkmnfrk' @ bukkit forums. + + - Terminal mode now closes automatically when rcon socket is closed by server + or if packet size cannot be retrieved correctly. + + - Client now tries to clean the incoming socket data if last package was out of spec. + +######0.0.4 + - Reverted back to default getopts options error handler (opterr = 1). + Custom error handler requires rewriting. + - Some cosmetic changes in program output strings. + - Program usage(); function now waits for enter before exiting on Windows. + +######0.0.3 + - Colors are now supported on Windows too! + - Terminal mode is now triggered with "-t" flag. "-i" flag still works for + backwards compatibility. + - Bug fixes (Packet size check always evaluating false and color validity + check always evaluating true). + +######0.0.2 + - License changed from 'ISC License' to 'zlib/libpng License'. + - Bug fixes & code cleanups + - Interactive mode (-i flag). Client acts as interactive terminal. + - Program return value is now the number of rcon commmands sent successfully. + If connecting or authentication fails, the return value is -1. + - Colors are now enabled by default. Now '-c' flag disables the color support. + +######0.0.1 + - Added experimental support for bukkit colors. + Should work with any sh compatible shell. + - Packet string data limited to max 2048 (DATA_BUFFSIZE) bytes. + No idea how Minecraft handles multiple rcon packets. + If someone knows, please mail me so I can implement it. + +####TODO: + - Make the receive buffer dynamic?? + - Change some of the packet size issues to fatal errors. + - Code cleanups. + - Check global variables (remove if possible). + - Add some protocol checks (proper packet id check etc..). + - Preprocessor (#ifdef / #ifndef) cleanups. + - Follow valve rcon protocol standard strictly? + - Multiple packet support if minecraft supports it?! + - Investigate if player chat messages gets sent through rcon. + If they are, the messaging system requires rewriting. + - Name resolving should be integrated to connection creation function. + - Dont try to cleanup the socket if not authenticated + - Better sockets error reporting + - Better error function (VA_ARGS support) diff --git a/COMPILING b/COMPILING new file mode 100644 index 0000000..6bb1aab --- /dev/null +++ b/COMPILING @@ -0,0 +1,11 @@ +####Compiling: + +Compile with GCC or CLANG: +```cc -std=gnu11 -Wpedantic -Wall -Wextra -O2 -s -o mcrcon mcrcon.c``` + +or just run **make**. + +On windows, remember to link with winsockets. +Add ```-lws2_32``` to compiler command line on Mingw GCC. + +--- diff --git a/README.md b/README.md index 3d4e4db..f8cf14f 100644 --- a/README.md +++ b/README.md @@ -1,38 +1,28 @@ -####Compiling: - -Compile with GCC or CLANG: -```cc -std=gnu11 -Wpedantic -Wall -Wextra -O2 -s -o mcrcon mcrcon.c``` - -or just run **make**. - -On windows, remember to link with winsockets. -Add ```-lws2_32``` to compiler command line on Mingw GCC. - ---- - ####Usage: Usage: mcrcon [OPTIONS]... [COMMANDS]... -Sends rcon commands to minecraft server. + +Sends rcon commands to Minecraft server. ``` Option: - -h Print usage. - -s Silent mode. Do not print data received from rcon. - -t Terminal mode. Acts as interactive terminal. - -p Rcon password. Default: "". - -H Host address or ip. - -P Port. Default: 25575. - -c Disable colors. - -r Output raw packets. - Good for debugging and custom handling of the output. + -h Print usage + -H Server address + -P Port (default is 25575) + -p Rcon password + -t Interactive terminal mode + -s Silent mode (do not print received packets) + -c Disable colors + -r Output raw packets (debugging and custom handling) + -v Output version information ``` -Commands must be separated with spaces. + +Commands with arguments must enclosed in quotes. Example: - ```mcrcon -c -H 192.168.1.42 -P 25575 -p password cmd1 "cmd2 arg1 arg2"``` + ```mcrcon -H my.minecraft.server -p password "say Server is restarting!" save-all stop``` -#####Enable server rcon -Remember to enable rcon by changing / adding following lines in ```server.properties``` file. +#####Enable rcon on server +Remember to enable rcon by changing or adding following lines in ```server.properties``` file. ``` enable-rcon=true rcon.port=25575 @@ -43,74 +33,8 @@ rcon.password=your_rcon_pasword ####Contact: -* WWW: http://sourceforge.net/projects/mcrcon/ +* WWW: https://github.com/Tiiffi/mcrcon/ * MAIL: tiiffi_at_gmail_dot_com * IRC: tiiffi @ quakenet * BUG REPORTS: https://github.com/Tiiffi/mcrcon/issues/ ---- - -####Version history: -######0.0.5 - - IPv6 support! - * Thanks to 'Tanja84dk' for addressing the real need of IPv6. - - - Fixed bug causing crash / segmentation fault (invalid write) when receiving malformed rcon packet. - - - Program makes use of C99 feature (variable-length arrays) so "-std=gnu99" flag on - GCC-compiler must be used to avoid unecessary warnings. - - - Rcon receive buffer is now bigger (2024 bytes -> 10240 bytes). - * Thanks to 'gman_ftw' @ Bukkit forums. - - - Fixed invalid error message when receiving empty rcon packet (10 bytes). - * Thanks to 'pkmnfrk' @ bukkit forums. - - - Terminal mode now closes automatically when rcon socket is closed by server - or if packet size cannot be retrieved correctly. - - - Client now tries to clean the incoming socket data if last package was out of spec. - -######0.0.4 - - Reverted back to default getopts options error handler (opterr = 1). - Custom error handler requires rewriting. - - Some cosmetic changes in program output strings. - - Program usage(); function now waits for enter before exiting on Windows. - -######0.0.3 - - Colors are now supported on Windows too! - - Terminal mode is now triggered with "-t" flag. "-i" flag still works for - backwards compatibility. - - Bug fixes (Packet size check always evaluating false and color validity - check always evaluating true). - -######0.0.2 - - License changed from 'ISC License' to 'zlib/libpng License'. - - Bug fixes & code cleanups - - Interactive mode (-i flag). Client acts as interactive terminal. - - Program return value is now the number of rcon commmands sent successfully. - If connecting or authentication fails, the return value is -1. - - Colors are now enabled by default. Now '-c' flag disables the color support. - -######0.0.1 - - Added experimental support for bukkit colors. - Should work with any sh compatible shell. - - Packet string data limited to max 2048 (DATA_BUFFSIZE) bytes. - No idea how Minecraft handles multiple rcon packets. - If someone knows, please mail me so I can implement it. - -####TODO: - - Make the receive buffer dynamic?? - - Change some of the packet size issues to fatal errors. - - Code cleanups. - - Check global variables (remove if possible). - - Add some protocol checks (proper packet id check etc..). - - Preprocessor (#ifdef / #ifndef) cleanups. - - Follow valve rcon protocol standard strictly? - - Multiple packet support if minecraft supports it?! - - Investigate if player chat messages gets sent through rcon. - If they are, the messaging system requires rewriting. - - Name resolving should be integrated to connection creation function. - - Dont try to cleanup the socket if not authenticated - - Better sockets error reporting - - Better error function (VA_ARGS support) From 4d12f96e21283e26d648fb53c00b5f768f4b81ba Mon Sep 17 00:00:00 2001 From: Tiiffi Date: Tue, 15 Nov 2016 20:55:54 +0200 Subject: [PATCH 20/29] Update COMPILING --- COMPILING | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/COMPILING b/COMPILING index 6bb1aab..356cf89 100644 --- a/COMPILING +++ b/COMPILING @@ -1,11 +1,14 @@ -####Compiling: - Compile with GCC or CLANG: -```cc -std=gnu11 -Wpedantic -Wall -Wextra -O2 -s -o mcrcon mcrcon.c``` + cc -std=gnu99 -Wpedantic -Wall -Wextra -Os -s -o mcrcon mcrcon.c -or just run **make**. +Or you can just run "make". + + make - compiles mcrcon + make install - installs compiled binaries and manpage to the system + make uninstall - removes binaries and manpage from the system + + file install locations: + /usr/share/bin/mcrcon + /usr/share/man/man1/mcrcon.1 -On windows, remember to link with winsockets. -Add ```-lws2_32``` to compiler command line on Mingw GCC. - ---- +On Window remember to link with winsockets by adding "-lws2_32" to your compiler command line. From c9a740a3ce87a8b1a31b55c1f78a8eac7d944fdc Mon Sep 17 00:00:00 2001 From: Tiiffi Date: Tue, 15 Nov 2016 21:06:00 +0200 Subject: [PATCH 21/29] Added "Installing" paragraph. --- README.md | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f8cf14f..9db470a 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,16 @@ +####Installing: + +from sources: + +1. git clone https://github.com/Tiiffi/mcrcon.git +2. cd mcrcon/ +3. make +4. sudo make install + +You can also download precompiled binaries: https://github.com/Tiiffi/mcrcon/releases/latest + +--- + ####Usage: Usage: mcrcon [OPTIONS]... [COMMANDS]... @@ -21,7 +34,9 @@ Commands with arguments must enclosed in quotes. Example: ```mcrcon -H my.minecraft.server -p password "say Server is restarting!" save-all stop``` -#####Enable rcon on server +--- + +####Enable rcon on server Remember to enable rcon by changing or adding following lines in ```server.properties``` file. ``` enable-rcon=true From f8799373290c8dadd6afa3e55d7d9055c62fe543 Mon Sep 17 00:00:00 2001 From: Tiiffi Date: Tue, 15 Nov 2016 21:13:48 +0200 Subject: [PATCH 22/29] Typo fix. --- mcrcon.1 | 2 +- mcrcon.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mcrcon.1 b/mcrcon.1 index 20fa82a..481f556 100644 --- a/mcrcon.1 +++ b/mcrcon.1 @@ -33,7 +33,7 @@ Output raw packets (for debugging and custom handling) .IP -v Output version information .PP -Commands with arguments must enclosed in quotes. +Commands with arguments must be enclosed in quotes. .SH EXAMPLES Make rcon connection in terminal mode using default port .RS diff --git a/mcrcon.c b/mcrcon.c index 25f80eb..6ef0b70 100644 --- a/mcrcon.c +++ b/mcrcon.c @@ -252,7 +252,7 @@ void usage(void) ,stdout ); - puts("\nCommands with arguments must enclosed in quotes.\n"); + puts("\nCommands with arguments must be enclosed in quotes.\n"); puts("Example:\n\t"IN_NAME" -H my.minecraft.server -p password \"say Server is restarting!\" save-all stop\n"); puts(VER_STR"\nReport bugs to tiiffi_at_gmail_dot_com or https://github.com/Tiiffi/mcrcon/issues/\n"); From 6f0af9964ce202401dff1fb87a499120a2ca3f78 Mon Sep 17 00:00:00 2001 From: Tiiffi Date: Tue, 15 Nov 2016 21:14:30 +0200 Subject: [PATCH 23/29] Typo fixes. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9db470a..25fff8d 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ You can also download precompiled binaries: https://github.com/Tiiffi/mcrcon/rel --- ####Usage: -Usage: mcrcon [OPTIONS]... [COMMANDS]... +mcrcon [OPTIONS]... [COMMANDS]... Sends rcon commands to Minecraft server. @@ -29,7 +29,7 @@ Option: -v Output version information ``` -Commands with arguments must enclosed in quotes. +Commands with arguments must be enclosed in quotes. Example: ```mcrcon -H my.minecraft.server -p password "say Server is restarting!" save-all stop``` From 796fb23195b1a0b8524ab383144264d3523211fc Mon Sep 17 00:00:00 2001 From: Tiiffi Date: Tue, 15 Nov 2016 21:17:53 +0200 Subject: [PATCH 24/29] README.md update. --- README.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 25fff8d..79ab9b2 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,16 @@ ####Installing: from sources: - -1. git clone https://github.com/Tiiffi/mcrcon.git -2. cd mcrcon/ -3. make -4. sudo make install +``` +git clone https://github.com/Tiiffi/mcrcon.git +cd mcrcon/ +make +sudo make install +``` You can also download precompiled binaries: https://github.com/Tiiffi/mcrcon/releases/latest +Binaries are provided for Linux 32/64bit and Windows (only 32bit). --- ####Usage: From 1c5654de2d101f56c0e17e4ab83601d462f705df Mon Sep 17 00:00:00 2001 From: Tiiffi Date: Tue, 15 Nov 2016 21:19:20 +0200 Subject: [PATCH 25/29] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 79ab9b2..8e7527d 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,8 @@ sudo make install You can also download precompiled binaries: https://github.com/Tiiffi/mcrcon/releases/latest -Binaries are provided for Linux 32/64bit and Windows (only 32bit). +Binaries are provided for Linux and Windows. + --- ####Usage: From 16819a69927f24feea61c2ddf2939338a278b34d Mon Sep 17 00:00:00 2001 From: Tiiffi Date: Tue, 15 Nov 2016 21:21:03 +0200 Subject: [PATCH 26/29] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8e7527d..7d195e7 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ Example: --- ####Enable rcon on server -Remember to enable rcon by changing or adding following lines in ```server.properties``` file. +Remember to enable rcon by adding following lines to ```server.properties``` file. ``` enable-rcon=true rcon.port=25575 From 93e3e543571448304928a118e5783ea1a0fedc0d Mon Sep 17 00:00:00 2001 From: Tiiffi Date: Tue, 15 Nov 2016 21:44:07 +0200 Subject: [PATCH 27/29] Update and rename COMPILING to INSTALL --- COMPILING => INSTALL | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) rename COMPILING => INSTALL (61%) diff --git a/COMPILING b/INSTALL similarity index 61% rename from COMPILING rename to INSTALL index 356cf89..54cb5b8 100644 --- a/COMPILING +++ b/INSTALL @@ -1,8 +1,14 @@ -Compile with GCC or CLANG: +Compiling and installing +------------------------ + +Only dependency is C library with POSIX getopt support. + +Compiling with GCC or CLANG: + cc -std=gnu99 -Wpedantic -Wall -Wextra -Os -s -o mcrcon mcrcon.c -Or you can just run "make". - +Or you can just run "make": + make - compiles mcrcon make install - installs compiled binaries and manpage to the system make uninstall - removes binaries and manpage from the system @@ -12,3 +18,4 @@ Or you can just run "make". /usr/share/man/man1/mcrcon.1 On Window remember to link with winsockets by adding "-lws2_32" to your compiler command line. +Makefile should take care of this automatically but "install" and "uninstall" rules are disabled on windows. From 71d10a0af0a2868975edfd3f62703b277e477559 Mon Sep 17 00:00:00 2001 From: Tiiffi Date: Tue, 15 Nov 2016 21:46:02 +0200 Subject: [PATCH 28/29] Update README.md --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7d195e7..028b78c 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -####Installing: +###Installing: from sources: ``` @@ -7,6 +7,7 @@ cd mcrcon/ make sudo make install ``` +Check **INSTALL** for more details. You can also download precompiled binaries: https://github.com/Tiiffi/mcrcon/releases/latest @@ -14,7 +15,7 @@ Binaries are provided for Linux and Windows. --- -####Usage: +###Usage: mcrcon [OPTIONS]... [COMMANDS]... Sends rcon commands to Minecraft server. @@ -39,7 +40,7 @@ Example: --- -####Enable rcon on server +###Enable rcon on server Remember to enable rcon by adding following lines to ```server.properties``` file. ``` enable-rcon=true From 57d0cdbf9509cb3ea6866d2d98fabf1bd95a22d9 Mon Sep 17 00:00:00 2001 From: Tiiffi Date: Tue, 15 Nov 2016 21:59:30 +0200 Subject: [PATCH 29/29] Minor cleanups. --- mcrcon.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/mcrcon.c b/mcrcon.c index 6ef0b70..ca0a625 100644 --- a/mcrcon.c +++ b/mcrcon.c @@ -221,13 +221,12 @@ int main(int argc, char *argv[]) else ret = run_commands(argc, argv); } - else /* auth failed */ + else // auth failed { ret = -1; fprintf(stdout, "Authentication failed!\n"); } - /* cleanup */ net_close(rsock); rsock = -1; @@ -607,9 +606,9 @@ uint8_t *packet_build_malloc(size_t *size, int32_t id, int32_t cmd, char *string } /* rcon packet structure */ -#define MAX_PACKET_SIZE (size_t) 1460 // including size member -#define MIN_PACKET_SIZE (size_t) 10 -#define MAX_STRING_SIZE (size_t) (MAX_PACKET_SIZE - 2 - 3 * sizeof(int32_t)) +#define MAX_PACKET_SIZE (size_t) 1460 // including size member +#define MIN_PACKET_SIZE (size_t) 10 +#define MAX_STRING_SIZE (size_t) (MAX_PACKET_SIZE - 2 - 3 * sizeof(int32_t)) #define SIZEOF_PACKET(x) (size_t) (x.size + sizeof(int32_t)) struct rcon_packet @@ -743,7 +742,7 @@ int run_terminal_mode(int rsock) return ret; } -/* gets line from stdin and deals with rubbish left in input buffer */ +// gets line from stdin and deals with rubbish left in the input buffer int get_line(char *buffer, int bsize) { int ch, len; @@ -754,12 +753,12 @@ int get_line(char *buffer, int bsize) if (buffer[0] == 0) connection_alive = 0; - /* remove unwanted characters from the buffer */ + // remove unwanted characters from the buffer buffer[strcspn(buffer, "\r\n")] = '\0'; len = strlen(buffer); - /* clean input buffer if needed */ + // clean input buffer if needed if (len == bsize - 1) while ((ch = getchar()) != '\n' && ch != EOF);