Add message sending and ack

This commit is contained in:
Juhani Krekelä 2019-07-09 20:22:55 +03:00
parent 3beda7742f
commit 539dbf9f14
1 changed files with 178 additions and 9 deletions

View File

@ -24,6 +24,7 @@
#include <unistd.h>
#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));