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; }