From 539dbf9f1470a39d3f16bbd7dc6374747b43b400 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juhani=20Krekel=C3=A4?= Date: Tue, 9 Jul 2019 20:22:55 +0300 Subject: [PATCH] Add message sending and ack --- ethermess.c | 187 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 178 insertions(+), 9 deletions(-) diff --git a/ethermess.c b/ethermess.c index 99a6ea8..6894c58 100644 --- a/ethermess.c +++ b/ethermess.c @@ -24,6 +24,7 @@ #include #define EM_PROTOCOL_VERSION 0 +#define EM_MESSAGE_MAX_LENGTH (1500 - 2 - 2 - 2) #define EMT_SPEAK_VERSION 0 #define EMT_STATUS_REQUEST 1 @@ -37,6 +38,9 @@ #define EMS_UNAVAILABLE 1 #define EMS_OFFLINE 2 +unsigned const char veth0a_mac[6] = {0xb2, 0xc8, 0x5b, 0x78, 0xb4, 0xef}; //debg +unsigned const char veth0b_mac[6] = {0xf6, 0x18, 0xfd, 0x2a, 0x80, 0xf3}; //debg + bool running = true; int packet_socket; @@ -46,15 +50,15 @@ unsigned char own_mac[6]; unsigned char broadcast_mac[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; unsigned char own_status = EMS_AVAILABLE; -unsigned char own_nick[256] = {'n', 'o', 'r', 't', 't', 'i'}; -unsigned char own_nick_length = 6; +unsigned char own_nick[256]; +unsigned char own_nick_length = 0; time_t next_status_broadcast; -bool own_message_queued = false; +enum message_send_states {IDLE, QUEUED, SENDING}; +enum message_send_states own_message_send_state = IDLE; unsigned char own_message_destination_mac[6]; -unsigned char own_message[1500 - 2 - 2 - 2]; +unsigned char own_message[EM_MESSAGE_MAX_LENGTH]; size_t own_message_length = 0; -bool own_message_msgid_known = false; uint16_t own_message_msgid = 0; struct msgid_cache_entry { @@ -245,6 +249,37 @@ void send_msgid(const unsigned char destination[6]) { send_frame(frame, sizeof(frame)); } +void send_message(void) { + unsigned char frame[14 + 2 + 2 + 2 + own_message_length]; + + write_headers(frame, own_message_destination_mac, EMT_MESSAGE); + + // Message ID + frame[16] = own_message_msgid >> 8; + frame[17] = own_message_msgid & 0xff; + + // Message length + frame[18] = own_message_length >> 8; + frame[19] = own_message_length & 0xff; + + // Message + memcpy(&frame[20], own_message, own_message_length); + + send_frame(frame, sizeof(frame)); +} + +void send_ack(const unsigned char destination[6], uint16_t msgid) { + unsigned char frame[14 + 2 + 2]; + + write_headers(frame, destination, EMT_ACK); + + // Message ID + frame[16] = msgid >> 8; + frame[17] = msgid & 0xff; + + send_frame(frame, sizeof(frame)); +} + void read_command(void) { errno = 0; int cmd = getchar(); @@ -252,12 +287,24 @@ void read_command(void) { err(1, "getchar"); } + unsigned const char *other_mac; + if (memcmp(own_mac, veth0a_mac, 6) == 0) { + other_mac = veth0b_mac; + } else { + other_mac = veth0a_mac; + } + if (cmd == 'q') { running = false; } else if (cmd == 's') { - send_status_request(broadcast_mac); + send_status_request(other_mac); } else if (cmd == 'i') { - send_msgid_request(broadcast_mac); + send_msgid_request(other_mac); + } else if (cmd == 'm') { + memcpy(own_message, "Hello, world!", 13); + own_message_length = 13; + memcpy(own_message_destination_mac, other_mac, 6); + own_message_send_state = QUEUED; } else if (cmd == '\n') { // Ignore } else { @@ -302,7 +349,7 @@ void handle_status(const unsigned char source_mac[6], const unsigned char *data, return; } - unsigned char nick[256]; + unsigned char nick[nick_length]; memcpy(nick, &data[2], nick_length); if (!check_padding(data, 2 + nick_length, data_length)) { @@ -356,7 +403,7 @@ void handle_msgid(const unsigned char source_mac[6], const unsigned char *data, return; } - uint16_t msgid = data[0] << 8 | data[1]; + uint16_t msgid = (data[0] << 8) | data[1]; if (!check_padding(data, 2, data_length)) { // Malformed padding @@ -386,6 +433,90 @@ void handle_msgid(const unsigned char source_mac[6], const unsigned char *data, } } +void handle_message(const unsigned char source_mac[6], const unsigned char *data, size_t data_length) { + if (data_length < 4) { + // Too short + fprintf(stderr, "Data too short: %zu\n", data_length); // debg + return; + } + + uint16_t msgid = (data[0] << 8) | data[1]; + + uint16_t message_length = (data[2] << 8) | data[3]; + + if (message_length > data_length - 4 || message_length > EM_MESSAGE_MAX_LENGTH) { + // Malformed length field + fprintf(stderr, "Message length %u, remaining packet length %zu, max message length %u\n", message_length, data_length, EM_MESSAGE_MAX_LENGTH); // debg + return; + } + + unsigned char message[message_length]; + memcpy(message, &data[4], message_length); + + if (!check_padding(data, 4 + message_length, data_length)) { + // Malformed padding + return; + } + + // TODO: Check that the message is valid utf-8 with newline as the only control char + + // TODO: Check whether we've received this message already and update msgid cache + + char mac[18]; + format_mac(source_mac, mac); + + errno = 0; + if (printf("%s (%" PRIu16 "): ", mac, msgid) == -1) { + err(1, "printf"); + } + + for (size_t i = 0; i < message_length; i++) { + errno = 0; + if (putchar(message[i]) == EOF) { + err(1, "putchar"); + } + } + + errno = 0; + if (putchar('\n') == EOF) { + err(1, "putchar"); + } + + errno = 0; + if (fflush(stdout) == EOF) { + err(1, "fflush"); + } + + send_ack(source_mac, msgid); +} + +void handle_ack(const unsigned char source_mac[6], const unsigned char *data, size_t data_length) { + if (data_length < 2) { + // Too short + fprintf(stderr, "Data too short: %zu\n", data_length); // debg + return; + } + + uint16_t msgid = (data[0] << 8) | data[1]; + + if (!check_padding(data, 2, data_length)) { + // Malformed padding + return; + } + + char mac[18]; + format_mac(source_mac, mac); + + errno = 0; + if (printf("%s ack %" PRIu16 "\n", mac, msgid) == -1) { + err(1, "printf"); + } + + if (own_message_send_state == SENDING && msgid == own_message_msgid) { + own_message_send_state = IDLE; + } +} + void process_frame(void) { unsigned char frame[1518]; // Largest a 802.3 frame can be without FCS @@ -454,6 +585,14 @@ void process_frame(void) { handle_msgid(source_mac, &frame[16], packet_length - 16); break; + case EMT_MESSAGE: + handle_message(source_mac, &frame[16], packet_length - 16); + break; + + case EMT_ACK: + handle_ack(source_mac, &frame[16], packet_length - 16); + break; + default: fprintf(stderr, "Ignoring packet of type %i\n", packet_type); } @@ -472,6 +611,27 @@ void eventloop(void) { pollfds[1].events = POLLIN; while (running) { + // (Attempt) to process a message send + if (own_message_send_state == QUEUED) { + // We need to have the correct msgid to be able to send + ssize_t cache_index = msgid_cache_lookup(own_message_destination_mac); + + if (cache_index == -1 || !msgid_cache[cache_index].know_send) { + // We don't know what the msgid should be + // -> ask the other side + // TODO: Implement a timer + send_msgid_request(own_message_destination_mac); + } else { + // It is in the cache + own_message_msgid = msgid_cache[cache_index].next_send++; + own_message_send_state = SENDING; + } + } + + if (own_message_send_state == SENDING) { + send_message(); + } + // Figure out how many ms to wait int wait_ms; time_t now = monotonic_time(); @@ -581,6 +741,15 @@ int main(int argc, char **argv) { format_mac(own_mac, own_mac_str); fprintf(stderr, "%s\n", own_mac_str); + // Set our nick + if (memcmp(own_mac, veth0a_mac, 6) == 0) { + memcpy(own_nick, "foo", 3); + own_nick_length = 3; + } else { + memcpy(own_nick, "bar", 3); + own_nick_length = 3; + } + // Initialize the message id cache memset(msgid_cache, 0, sizeof(msgid_cache));