From c59b2138f4c76bdf4602dc2fb72d5ffa580e289d Mon Sep 17 00:00:00 2001 From: Igor Socec Date: Fri, 18 Nov 2016 22:42:29 +0100 Subject: [PATCH] Extract telnet functions into a separate header --- moxerver.c | 4 +- moxerver.h | 29 +--------- telnet.c | 160 ++++++++++++++++++++++++++--------------------------- telnet.h | 25 +++++++++ 4 files changed, 110 insertions(+), 108 deletions(-) create mode 100644 telnet.h diff --git a/moxerver.c b/moxerver.c index d93f6a7..5c2332d 100644 --- a/moxerver.c +++ b/moxerver.c @@ -193,7 +193,9 @@ int main(int argc, char *argv[]) { continue; } /* put client in "character" mode */ - telnet_set_character_mode(&client); + char msg[TELNET_MSG_SIZE_CHARMODE]; + telnet_message_set_character_mode(msg); + client_write(&client, msg, TELNET_MSG_SIZE_CHARMODE); } /* setup parameters for select() */ diff --git a/moxerver.h b/moxerver.h index 4f0e9bc..6ade182 100644 --- a/moxerver.h +++ b/moxerver.h @@ -12,6 +12,8 @@ #include #include +#include + #define DATABUF_LEN 128 #define DEV_PATH 128 #define TIMESTAMP_FORMAT "%Y-%m-%dT%H:%M:%S" /* ISO 8601 */ @@ -159,34 +161,7 @@ int client_wait_line(client_t *client); int client_ask_username(client_t *client); -/* Functions handling details related to telnet protocol. */ -/** - * Tells client to go into "character" mode. - * - * Returns: - * - 0 on success - * - negative value if error occurred - */ -int telnet_set_character_mode(client_t *client); - -/** - * Handles special characters in data buffer after receiving them from client. - * Used to filter out handshake commands of telnet protocol. - * - * Returns: - * 0 always - */ -int telnet_handle_client_read(char *databuf, int *datalen); - -/** - * Handles special characters in data buffer before sending to client. - * Used for echoing characters correctly to telnet client. - * - * Returns: - * 0 always - */ -int telnet_handle_client_write(char *databuf, int *datalen); /* Functions handling communication with tty device. */ diff --git a/telnet.c b/telnet.c index a498a70..99c4e3c 100644 --- a/telnet.c +++ b/telnet.c @@ -1,8 +1,5 @@ -/* - * Handling details related to telnet protocol. - */ - -#include "moxerver.h" +#include +#include /* structure for holding telnet option name and value */ typedef struct @@ -12,7 +9,8 @@ typedef struct } telnet_option_t; /* supported telnet option values */ -telnet_option_t telnet_options[] = { +telnet_option_t telnet_options[] = +{ {"WILL", 251}, {"WONT", 252}, {"DO", 253}, @@ -25,118 +23,118 @@ telnet_option_t telnet_options[] = { /* this list must end with {NULL, 0} */ }; -/* Returns telnet option name based on the value. */ -static const char* telnet_option_name(int value) { - int i = 0; - while (telnet_options[i].name) { - if (telnet_options[i].value == value) return telnet_options[i].name; - i++; +/* Returns the name of a telnet option based on the value. */ +static const char* telnet_option_name(int value) +{ + int i; + for (i = 0; telnet_options[i].name != NULL; i++) + { + if (telnet_options[i].value == value) + { + return telnet_options[i].name; + } } + /* default value */ return '\0'; } -/* Returns telnet option value based on the name. */ -static char telnet_option_value(const char* name) { - int i = 0; - while (telnet_options[i].name) { - if (!strcmp(telnet_options[i].name, name)) return telnet_options[i].value; - i++; +/* Returns the value of a telnet option based on the name. */ +static char telnet_option_value(const char* name) +{ + int i; + for (i = 0; telnet_options[i].name != NULL; i++) + { + if (strcmp(telnet_options[i].name, name) == 0) + { + return telnet_options[i].value; + } } + /* default value */ return 0; } -/* Sends telnet option command. Returns 0 on success, -1 on failure. */ -static int telnet_send_command(client_t *client, const char* option, const char* command) { - - char data[3]; - - /* pack command */ - data[0] = telnet_option_value("IAC"); - data[1] = telnet_option_value(option); - data[2] = telnet_option_value(command); - - /* send command */ - if (client_write(client, data, 3) <= 0) { - fprintf(stderr, "[%s:%d] failed sending %s %s\n", __func__, __LINE__, option, command); - return -1; - } - - fprintf(stderr, "[%s] sent %s %s\n", __func__, option, command); - return 0; -} - -/* Handles received telnet option command. Always returns 0.*/ -static int telnet_handle_command(char *databuf, int datalen) { - - /* currently just print received commands because we set the client, we don't adapt to client commands */ - if (databuf[0] == telnet_option_value("IAC")) { +/* Handles a received telnet option command. */ +static void telnet_handle_command(char *databuf, int datalen) +{ + /* just print received commands: + * we set the client, we don't adapt to client commands */ + if (databuf[0] == telnet_option_value("IAC")) + { fprintf(stderr, "[%s] received %s %s\n", __func__, - telnet_option_name(databuf[1]), telnet_option_name(databuf[2])); + telnet_option_name(databuf[1]), + telnet_option_name(databuf[2])); } - - return 0; } -/* Tells client to go into "character" mode. */ -int telnet_set_character_mode(client_t *client) { - - int err = 0; - - /* send predefined commands and add up their return vaules */ - err += telnet_send_command(client, "WILL", "ECHO"); - err += telnet_send_command(client, "WILL", "SGA"); - err += telnet_send_command(client, "WONT", "LINEMODE"); /* this depends on telnet client */ +void telnet_message_set_character_mode(char *databuf) +{ + /* send a predefined set of commands proven to work */ + + databuf[0] = telnet_option_value("IAC"); + databuf[1] = telnet_option_value("WILL"); + databuf[2] = telnet_option_value("ECHO"); + + databuf[3] = telnet_option_value("IAC"); + databuf[4] = telnet_option_value("WILL"); + databuf[5] = telnet_option_value("SGA"); + + /* this one really depends on telnet client */ + databuf[6] = telnet_option_value("IAC"); + databuf[7] = telnet_option_value("WONT"); + databuf[8] = telnet_option_value("LINEMODE"); //TODO Do we verify client response? What do we do if the response is not how we expected? - - return err; } -/* Handles special characters in data buffer after receiving them from client. - * Used to filter out handshake commands of telnet protocol. */ -int telnet_handle_client_read(char *databuf, int *datalen) { - +void telnet_handle_client_read(char *databuf, int *datalen) +{ int i; char newdata[DATABUF_LEN]; int newlen = 0; /* process data using a new buffer */ - for (i = 0; i < *datalen; i++) { + for (i = 0; i < *datalen; i++) + { /* handle and discard telnet commands */ - if (databuf[i] == telnet_option_value("IAC")) { + if (databuf[i] == telnet_option_value("IAC")) + { telnet_handle_command((databuf+i), 3); i += 2; } /* let other data pass through */ - else { + else + { newdata[newlen++] = databuf[i]; } } - /* overwrite data with new buffer */ - for (i = 0; i < newlen; i++) databuf[i] = newdata[i]; + /* overwrite the data with the new buffer */ + for (i = 0; i < newlen; i++) + { + databuf[i] = newdata[i]; + } + /* update data length */ *datalen = newlen; - - return 0; } -/* Handles special characters in data buffer before sending to client. - * Used for echoing characters correctly to telnet client. */ -int telnet_handle_client_write(char *databuf, int *datalen) { - +void telnet_handle_client_write(char *databuf, int *datalen) +{ int i; - char newdata[DATABUF_LEN]; + char newdata[DATABUF_LEN]; // TODO: maybe use realloc, this is risky int newlen = 0; /* process data using a new buffer */ - for (i = 0; i < *datalen; i++) { + for (i = 0; i < *datalen; i++) + { /* pressed ENTER */ - if (databuf[i] == 13) { + if (databuf[i] == 13) + { fprintf(stderr, "[%s] handling ENTER\n", __func__); newdata[newlen++] = '\r'; newdata[newlen++] = '\n'; } /* pressed BACKSPACE */ - if (databuf[i] == 127) { + if (databuf[i] == 127) + { fprintf(stderr, "[%s] handling BACKSPACE\n", __func__); newdata[newlen++] = 8; newdata[newlen++] = ' '; @@ -146,9 +144,11 @@ int telnet_handle_client_write(char *databuf, int *datalen) { newdata[newlen++] = databuf[i]; } } - /* overwrite data with new buffer */ - for (i = 0; i < newlen; i++) databuf[i] = newdata[i]; + /* overwrite the data with the new buffer */ + for (i = 0; i < newlen; i++) + { + databuf[i] = newdata[i]; + } + /* update data length */ *datalen = newlen; - - return 0; } diff --git a/telnet.h b/telnet.h new file mode 100644 index 0000000..d864120 --- /dev/null +++ b/telnet.h @@ -0,0 +1,25 @@ +/* Handles details related to telnet protocol. */ + +#define TELNET_MSG_SIZE_CHARMODE 9 + +/** + * Creates a telnet protocol message that tells client to go into "character" + * mode. The passed data buffer must be big enough to hold the message payload + * with the size defined by TELNET_MSG_SIZE_CHARMODE. + * Operates directly on the passed data buffer. + */ +void telnet_message_set_character_mode(char *databuf); + +/** + * Handles special characters in the data buffer after receiving them from the + * client. Used to filter out the handshake commands of telnet protocol. + * Operates directly on the passed data buffer and modifies the payload length. + */ +void telnet_handle_client_read(char *databuf, int *datalen); + +/** + * Handles special characters in the data buffer before sending them to the + * client. Used to correctly echo the characters to the telnet client. + * Operates directly on the passed data buffer and modifies the payload length. + */ +void telnet_handle_client_write(char *databuf, int *datalen);