Compare commits
5 Commits
Author | SHA1 | Date |
---|---|---|
Juhani Krekelä | bd23f43cfa | |
Juhani Krekelä | 9a2efcce2e | |
Juhani Krekelä | ea2523e263 | |
Juhani Krekelä | 605bb9d26f | |
Juhani Krekelä | 27a8418f21 |
|
@ -22,12 +22,13 @@
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#define EM_PROTOCOL_VERSION 0
|
#define EM_PROTOCOL_VERSION 1
|
||||||
#define EM_MESSAGE_MAX_LENGTH (1500 - 2 - 2 - 2)
|
#define EM_MESSAGE_MAX_LENGTH (1500 - 2 - 2 - 2)
|
||||||
#define EM_STATUS_BROADCAST_TIME (60 * 1000 + 1000 * random_byte() / 64)
|
#define EM_STATUS_BROADCAST_TIME (60 * 1000 + 1000 * random_byte() / 64)
|
||||||
#define EM_RETRANSMIT_TIME (1000 + random_byte() * 2)
|
#define EM_RETRANSMIT_TIME (1000 + random_byte() * 2)
|
||||||
#define EM_MAX_RETRANSMIT 5
|
#define EM_MAX_RETRANSMIT 5
|
||||||
|
|
||||||
|
// Version 0
|
||||||
#define EMT_SPEAK_VERSION 0
|
#define EMT_SPEAK_VERSION 0
|
||||||
#define EMT_STATUS_REQUEST 1
|
#define EMT_STATUS_REQUEST 1
|
||||||
#define EMT_STATUS 2
|
#define EMT_STATUS 2
|
||||||
|
@ -36,6 +37,9 @@
|
||||||
#define EMT_MESSAGE 5
|
#define EMT_MESSAGE 5
|
||||||
#define EMT_ACK 6
|
#define EMT_ACK 6
|
||||||
|
|
||||||
|
// Version 1
|
||||||
|
#define EMT_FILE_OFFER 7
|
||||||
|
|
||||||
#define EMS_AVAILABLE 0
|
#define EMS_AVAILABLE 0
|
||||||
#define EMS_UNAVAILABLE 1
|
#define EMS_UNAVAILABLE 1
|
||||||
#define EMS_OFFLINE 2
|
#define EMS_OFFLINE 2
|
||||||
|
@ -272,7 +276,7 @@ void send_frame(const unsigned char *frame, size_t frame_length) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_headers(unsigned char frame[14], const unsigned char destination_mac[6], unsigned char packet_type) {
|
void write_headers(unsigned char frame[14], const unsigned char destination_mac[6], unsigned char version, unsigned char packet_type) {
|
||||||
// Destination MAC
|
// Destination MAC
|
||||||
memcpy(&frame[0], destination_mac, 6);
|
memcpy(&frame[0], destination_mac, 6);
|
||||||
|
|
||||||
|
@ -284,7 +288,7 @@ void write_headers(unsigned char frame[14], const unsigned char destination_mac[
|
||||||
frame[13] = 0x7a;
|
frame[13] = 0x7a;
|
||||||
|
|
||||||
// Ethermess version
|
// Ethermess version
|
||||||
frame[14] = EM_PROTOCOL_VERSION;
|
frame[14] = version;
|
||||||
|
|
||||||
// Ethermess packet type
|
// Ethermess packet type
|
||||||
frame[15] = packet_type;
|
frame[15] = packet_type;
|
||||||
|
@ -293,7 +297,7 @@ void write_headers(unsigned char frame[14], const unsigned char destination_mac[
|
||||||
void send_speak_version(const unsigned char destination[6]) {
|
void send_speak_version(const unsigned char destination[6]) {
|
||||||
unsigned char frame[14 + 2 + 1];
|
unsigned char frame[14 + 2 + 1];
|
||||||
|
|
||||||
write_headers(frame, destination, EMT_SPEAK_VERSION);
|
write_headers(frame, destination, 0, EMT_SPEAK_VERSION);
|
||||||
|
|
||||||
// Version to speak
|
// Version to speak
|
||||||
frame[16] = EM_PROTOCOL_VERSION;
|
frame[16] = EM_PROTOCOL_VERSION;
|
||||||
|
@ -304,7 +308,7 @@ void send_speak_version(const unsigned char destination[6]) {
|
||||||
void send_status_request(const unsigned char destination[6]) {
|
void send_status_request(const unsigned char destination[6]) {
|
||||||
unsigned char frame[14 + 2];
|
unsigned char frame[14 + 2];
|
||||||
|
|
||||||
write_headers(frame, destination, EMT_STATUS_REQUEST);
|
write_headers(frame, destination, 0, EMT_STATUS_REQUEST);
|
||||||
|
|
||||||
send_frame(frame, sizeof(frame));
|
send_frame(frame, sizeof(frame));
|
||||||
}
|
}
|
||||||
|
@ -312,7 +316,7 @@ void send_status_request(const unsigned char destination[6]) {
|
||||||
void send_status(const unsigned char destination[6]) {
|
void send_status(const unsigned char destination[6]) {
|
||||||
unsigned char frame[14 + 2 + 1 + 1 + own_nick_length];
|
unsigned char frame[14 + 2 + 1 + 1 + own_nick_length];
|
||||||
|
|
||||||
write_headers(frame, destination, EMT_STATUS);
|
write_headers(frame, destination, 0, EMT_STATUS);
|
||||||
|
|
||||||
// Status
|
// Status
|
||||||
frame[16] = own_status;
|
frame[16] = own_status;
|
||||||
|
@ -329,7 +333,7 @@ void send_status(const unsigned char destination[6]) {
|
||||||
void send_msgid_request(const unsigned char destination[6]) {
|
void send_msgid_request(const unsigned char destination[6]) {
|
||||||
unsigned char frame[14 + 2];
|
unsigned char frame[14 + 2];
|
||||||
|
|
||||||
write_headers(frame, destination, EMT_MSGID_REQUEST);
|
write_headers(frame, destination, 0, EMT_MSGID_REQUEST);
|
||||||
|
|
||||||
send_frame(frame, sizeof(frame));
|
send_frame(frame, sizeof(frame));
|
||||||
}
|
}
|
||||||
|
@ -337,7 +341,7 @@ void send_msgid_request(const unsigned char destination[6]) {
|
||||||
void send_msgid(const unsigned char destination[6]) {
|
void send_msgid(const unsigned char destination[6]) {
|
||||||
unsigned char frame[14 + 2 + 2];
|
unsigned char frame[14 + 2 + 2];
|
||||||
|
|
||||||
write_headers(frame, destination, EMT_MSGID);
|
write_headers(frame, destination, 0, EMT_MSGID);
|
||||||
|
|
||||||
// Look up destination in the ID cache
|
// Look up destination in the ID cache
|
||||||
ssize_t cache_index = msgid_cache_lookup(destination);
|
ssize_t cache_index = msgid_cache_lookup(destination);
|
||||||
|
@ -366,7 +370,7 @@ void send_msgid(const unsigned char destination[6]) {
|
||||||
void send_message(void) {
|
void send_message(void) {
|
||||||
unsigned char frame[14 + 2 + 2 + 2 + own_message_length];
|
unsigned char frame[14 + 2 + 2 + 2 + own_message_length];
|
||||||
|
|
||||||
write_headers(frame, own_message_destination_mac, EMT_MESSAGE);
|
write_headers(frame, own_message_destination_mac, 0, EMT_MESSAGE);
|
||||||
|
|
||||||
// Message ID
|
// Message ID
|
||||||
frame[16] = own_message_msgid >> 8;
|
frame[16] = own_message_msgid >> 8;
|
||||||
|
@ -385,7 +389,7 @@ void send_message(void) {
|
||||||
void send_ack(const unsigned char destination[6], uint16_t msgid) {
|
void send_ack(const unsigned char destination[6], uint16_t msgid) {
|
||||||
unsigned char frame[14 + 2 + 2];
|
unsigned char frame[14 + 2 + 2];
|
||||||
|
|
||||||
write_headers(frame, destination, EMT_ACK);
|
write_headers(frame, destination, 0, EMT_ACK);
|
||||||
|
|
||||||
// Message ID
|
// Message ID
|
||||||
frame[16] = msgid >> 8;
|
frame[16] = msgid >> 8;
|
||||||
|
@ -394,6 +398,14 @@ void send_ack(const unsigned char destination[6], uint16_t msgid) {
|
||||||
send_frame(frame, sizeof(frame));
|
send_frame(frame, sizeof(frame));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void send_file_offer(const unsigned char destination[6]) {
|
||||||
|
unsigned char frame[14 + 2];
|
||||||
|
|
||||||
|
write_headers(frame, destination, 1, EMT_FILE_OFFER);
|
||||||
|
|
||||||
|
send_frame(frame, sizeof(frame));
|
||||||
|
}
|
||||||
|
|
||||||
void readallx(int fd, unsigned char *buf, size_t length) {
|
void readallx(int fd, unsigned char *buf, size_t length) {
|
||||||
size_t completed = 0;
|
size_t completed = 0;
|
||||||
while (completed < length) {
|
while (completed < length) {
|
||||||
|
@ -495,6 +507,10 @@ void read_command(void) {
|
||||||
send_status(broadcast_mac);
|
send_status(broadcast_mac);
|
||||||
} else if (cmd == 'm') {
|
} else if (cmd == 'm') {
|
||||||
read_message();
|
read_message();
|
||||||
|
} else if (cmd == 'f') {
|
||||||
|
unsigned char mac[6];
|
||||||
|
readallx(0, mac, sizeof(mac));
|
||||||
|
send_file_offer(mac);
|
||||||
} else {
|
} else {
|
||||||
errx(1, "Frontend sent an unknown command %c", cmd);
|
errx(1, "Frontend sent an unknown command %c", cmd);
|
||||||
}
|
}
|
||||||
|
@ -630,6 +646,29 @@ bool check_utf8(const unsigned char *data, size_t data_length, bool newline_tab_
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void handle_speak_version(const unsigned char source_mac[6], const unsigned char *data, size_t data_length) {
|
||||||
|
if (data_length < 1) {
|
||||||
|
// Too short
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char version = data[0];
|
||||||
|
|
||||||
|
if (!check_padding(data, 1, data_length)) {
|
||||||
|
// Malformed padding
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type of event: Speak version
|
||||||
|
writeallx(1, "v", 1);
|
||||||
|
|
||||||
|
// MAC
|
||||||
|
writeallx(1, source_mac, 6);
|
||||||
|
|
||||||
|
// Version
|
||||||
|
writeallx(1, &version, 1);
|
||||||
|
}
|
||||||
|
|
||||||
void handle_status(const unsigned char source_mac[6], const unsigned char *data, size_t data_length) {
|
void handle_status(const unsigned char source_mac[6], const unsigned char *data, size_t data_length) {
|
||||||
if (data_length < 2) {
|
if (data_length < 2) {
|
||||||
// Too short
|
// Too short
|
||||||
|
@ -835,10 +874,13 @@ void process_frame(void) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool broadcast;
|
||||||
if (memcmp(frame, own_mac, 6) == 0) {
|
if (memcmp(frame, own_mac, 6) == 0) {
|
||||||
// Targetted at us
|
// Targetted at us
|
||||||
|
broadcast = false;
|
||||||
} else if (memcmp(frame, broadcast_mac, 6) == 0) {
|
} else if (memcmp(frame, broadcast_mac, 6) == 0) {
|
||||||
// Broadcast
|
// Broadcast
|
||||||
|
broadcast = true;
|
||||||
} else {
|
} else {
|
||||||
// Does not concern us
|
// Does not concern us
|
||||||
return;
|
return;
|
||||||
|
@ -852,43 +894,58 @@ void process_frame(void) {
|
||||||
unsigned char version = frame[14];
|
unsigned char version = frame[14];
|
||||||
|
|
||||||
// If they speak a version we don't understand, tell them to speak ours
|
// If they speak a version we don't understand, tell them to speak ours
|
||||||
|
// Exception: If it was a broadcast, just ingore it
|
||||||
if (version > EM_PROTOCOL_VERSION) {
|
if (version > EM_PROTOCOL_VERSION) {
|
||||||
send_speak_version(source_mac);
|
if (!broadcast) {
|
||||||
|
send_speak_version(source_mac);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract Ethermess packet type
|
// Extract Ethermess packet type
|
||||||
unsigned char packet_type = frame[15];
|
unsigned char packet_type = frame[15];
|
||||||
|
|
||||||
// Process the packet based on the packet type
|
// Process the packet based on the version and packet type
|
||||||
switch (packet_type) {
|
if (version == 0) {
|
||||||
case EMT_STATUS_REQUEST:
|
switch (packet_type) {
|
||||||
if (check_padding(&frame[16], 0, packet_length - 16)) {
|
case EMT_SPEAK_VERSION:
|
||||||
send_status(source_mac);
|
handle_speak_version(source_mac, &frame[16], packet_length - 16);
|
||||||
}
|
break;
|
||||||
break;
|
|
||||||
|
|
||||||
case EMT_STATUS:
|
case EMT_STATUS_REQUEST:
|
||||||
handle_status(source_mac, &frame[16], packet_length - 16);
|
if (check_padding(&frame[16], 0, packet_length - 16)) {
|
||||||
break;
|
send_status(source_mac);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case EMT_MSGID_REQUEST:
|
case EMT_STATUS:
|
||||||
if (check_padding(&frame[16], 0, packet_length - 16)) {
|
handle_status(source_mac, &frame[16], packet_length - 16);
|
||||||
send_msgid(source_mac);
|
break;
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case EMT_MSGID:
|
case EMT_MSGID_REQUEST:
|
||||||
handle_msgid(source_mac, &frame[16], packet_length - 16);
|
if (check_padding(&frame[16], 0, packet_length - 16)) {
|
||||||
break;
|
send_msgid(source_mac);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case EMT_MESSAGE:
|
case EMT_MSGID:
|
||||||
handle_message(source_mac, &frame[16], packet_length - 16);
|
handle_msgid(source_mac, &frame[16], packet_length - 16);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EMT_ACK:
|
case EMT_MESSAGE:
|
||||||
handle_ack(source_mac, &frame[16], packet_length - 16);
|
handle_message(source_mac, &frame[16], packet_length - 16);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case EMT_ACK:
|
||||||
|
handle_ack(source_mac, &frame[16], packet_length - 16);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (version == 1) {
|
||||||
|
switch (packet_type) {
|
||||||
|
case EMT_FILE_OFFER:
|
||||||
|
fprintf(stderr, "File offered\n"); //debg
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,10 @@ Version 1 EtherMess protocol version
|
||||||
Tells the recipient to speak the given version of the protocol.
|
Tells the recipient to speak the given version of the protocol.
|
||||||
Should be generated whenever an EtherMess packet with a version one doesn't
|
Should be generated whenever an EtherMess packet with a version one doesn't
|
||||||
speak is received.
|
speak is received.
|
||||||
|
.Pp
|
||||||
|
Note however that this packet shouldn't be generated if the packet was
|
||||||
|
sent to the Ethernet broadcast address
|
||||||
|
.Li ff:ff:ff:ff:ff:ff .
|
||||||
.It Status request (0x01)
|
.It Status request (0x01)
|
||||||
Requests the recipient to announce its status and nick.
|
Requests the recipient to announce its status and nick.
|
||||||
Upon receiving this packet, a status packet should be sent to the sender.
|
Upon receiving this packet, a status packet should be sent to the sender.
|
||||||
|
|
18
ethermess.py
18
ethermess.py
|
@ -208,6 +208,9 @@ def set_status_nick(backend, status, nick):
|
||||||
encoded = nick.encode('utf-8')
|
encoded = nick.encode('utf-8')
|
||||||
writeall(backend, b's' + bytes([status.value, len(encoded)]) + encoded)
|
writeall(backend, b's' + bytes([status.value, len(encoded)]) + encoded)
|
||||||
|
|
||||||
|
def send_file_offer(backend, mac):
|
||||||
|
writeall(backend, b'f' + mac)
|
||||||
|
|
||||||
def handle_user_command(backend, line):
|
def handle_user_command(backend, line):
|
||||||
global own_nick, own_status
|
global own_nick, own_status
|
||||||
global default_target_mac
|
global default_target_mac
|
||||||
|
@ -290,13 +293,17 @@ def handle_user_command(backend, line):
|
||||||
# Set default target of messages
|
# Set default target of messages
|
||||||
default_target_mac = mac_from_name(rest)
|
default_target_mac = mac_from_name(rest)
|
||||||
|
|
||||||
|
elif command == '/sendfile':
|
||||||
|
# Send an offer to transmit the file
|
||||||
|
send_file_offer(backend, mac_from_name(rest))
|
||||||
|
|
||||||
elif command == '/quit':
|
elif command == '/quit':
|
||||||
# Quit
|
# Quit
|
||||||
return 'quit'
|
return 'quit'
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# Display usage
|
# Display usage
|
||||||
print('--- / <message>; /msg <target> <message>; /status [<target>]; /peers; /available; /unavailable; /nick [<nick>]; /target <target>; /quit')
|
print('--- / <message>; /msg <target> <message>; /status [<target>]; /peers; /available; /unavailable; /nick [<nick>]; /target <target>; /sendfile <target>; /quit')
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# Send message
|
# Send message
|
||||||
|
@ -428,7 +435,14 @@ def eventloop(proc):
|
||||||
for fd, event in poll.poll(wait):
|
for fd, event in poll.poll(wait):
|
||||||
if fd == proc.stdout.fileno() and event & select.POLLIN:
|
if fd == proc.stdout.fileno() and event & select.POLLIN:
|
||||||
event_type = readall(proc.stdout, 1)
|
event_type = readall(proc.stdout, 1)
|
||||||
if event_type == b's':
|
if event_type == b'v':
|
||||||
|
# Speak version
|
||||||
|
source_mac = readall(proc.stdout, 6)
|
||||||
|
version, = readall(proc.stdout, 1)
|
||||||
|
|
||||||
|
print('--- Speak version %s %i' % (format_mac(source_mac), version)) #debg
|
||||||
|
|
||||||
|
elif event_type == b's':
|
||||||
# Status
|
# Status
|
||||||
source_mac = readall(proc.stdout, 6)
|
source_mac = readall(proc.stdout, 6)
|
||||||
status, = readall(proc.stdout, 1)
|
status, = readall(proc.stdout, 1)
|
||||||
|
|
|
@ -70,6 +70,12 @@ Events
|
||||||
|
|
||||||
Frontend receives events from the backend.
|
Frontend receives events from the backend.
|
||||||
|
|
||||||
|
### Speak version
|
||||||
|
Format: 'v' + MAC + version (u8)
|
||||||
|
|
||||||
|
Generated when an EtherMess Speak version packet is received by the
|
||||||
|
backend.
|
||||||
|
|
||||||
### Status
|
### Status
|
||||||
Format: 's' + MAC + status + nick length in bytes (u8) + nick
|
Format: 's' + MAC + status + nick length in bytes (u8) + nick
|
||||||
|
|
||||||
|
|
12
test.sh
12
test.sh
|
@ -1,4 +1,12 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
LIBEXECDIR=. make &&
|
LIBEXECDIR=. CFLAGS=-Werror make || exit 1
|
||||||
test -n "$(getcap ethermess-backend)" || sudo setcap CAP_NET_RAW=ep ethermess-backend &&
|
test -n "$(getcap ethermess-backend)" || sudo setcap CAP_NET_RAW=ep ethermess-backend || exit 1
|
||||||
|
if ip link show veth0a > /dev/null 2>&1 || ip link show veth0b > /dev/null 2>&1
|
||||||
|
then
|
||||||
|
true
|
||||||
|
else
|
||||||
|
sudo ip link add veth0a type veth peer name veth0b || exit 1
|
||||||
|
sudo ip link set veth0a up || exit 1
|
||||||
|
sudo ip link set veth0b up || exit 1
|
||||||
|
fi
|
||||||
./ethermess "$@"
|
./ethermess "$@"
|
||||||
|
|
Loading…
Reference in New Issue