Add network coding test app to the build

This commit is contained in:
Jeremy Lakeman 2013-11-25 15:13:06 +10:30
parent c1a7abdaa9
commit d67dfa22b2
5 changed files with 40 additions and 57 deletions

View File

@ -111,9 +111,6 @@ fakeradio: fakeradio.o
@echo LINK $@ @echo LINK $@
@$(CC) $(CFLAGS) -Wall -o $@ fakeradio.o @$(CC) $(CFLAGS) -Wall -o $@ fakeradio.o
network_coding: network_coding.c
@$(CC) -DRUNTESTS -Wall -o $@ network_coding.c
# This does not build on 64 bit elf platforms as NaCL isn't built with -fPIC # This does not build on 64 bit elf platforms as NaCL isn't built with -fPIC
# DOC 20120615 # DOC 20120615
libservald.so: $(OBJS) version.o libservald.so: $(OBJS) version.o

View File

@ -16,6 +16,7 @@ HDRS= fifo.h \
strbuf.h \ strbuf.h \
strbuf_helpers.h \ strbuf_helpers.h \
sha2.h \ sha2.h \
network_coding.h \
conf.h \ conf.h \
conf_schema.h \ conf_schema.h \
crypto.h \ crypto.h \

View File

@ -24,9 +24,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include <assert.h> #include <assert.h>
#include <inttypes.h> #include <inttypes.h>
#include <stdarg.h> #include <stdarg.h>
#include "network_coding.h"
#include "dataformats.h"
#define FLAG_NEW 1 #define FLAG_NEW 1
#define HEADER_LEN 7
struct nc_packet{ struct nc_packet{
uint8_t sequence; uint8_t sequence;
@ -56,21 +58,6 @@ struct nc{
struct nc_half rx; struct nc_half rx;
}; };
void write_uint32(unsigned char *o,uint32_t v)
{
int i;
for(i=0;i<4;i++)
{ *(o++)=v&0xff; v=v>>8; }
}
uint32_t read_uint32(unsigned char *o)
{
int i;
uint32_t v=0;
for(i=0;i<4;i++) v=(v<<8)|o[4-1-i];
return v;
}
static void _nc_free_half(struct nc_half *n) static void _nc_free_half(struct nc_half *n)
{ {
int i; int i;
@ -265,7 +252,7 @@ static int _nc_tx_combine_random_payloads(struct nc_half *n, struct nc_packet *p
int nc_tx_produce_packet(struct nc *n, uint8_t *datagram, uint32_t buffer_size) int nc_tx_produce_packet(struct nc *n, uint8_t *datagram, uint32_t buffer_size)
{ {
// TODO: Don't waste more bytes than we need to on the bitmap and sequence number // TODO: Don't waste more bytes than we need to on the bitmap and sequence number
if (buffer_size < n->tx.datagram_size+HEADER_LEN) if (buffer_size < n->tx.datagram_size+NC_HEADER_LEN)
return -1; return -1;
if (_nc_get_ack(&n->rx, &datagram[0], &datagram[1])) if (_nc_get_ack(&n->rx, &datagram[0], &datagram[1]))
@ -281,7 +268,7 @@ int nc_tx_produce_packet(struct nc *n, uint8_t *datagram, uint32_t buffer_size)
struct nc_packet packet={ struct nc_packet packet={
.sequence = n->tx.window_start, .sequence = n->tx.window_start,
.combination = 0, .combination = 0,
.payload = &datagram[HEADER_LEN], .payload = &datagram[NC_HEADER_LEN],
}; };
if (_nc_tx_combine_random_payloads(&n->tx, &packet)) if (_nc_tx_combine_random_payloads(&n->tx, &packet))
@ -291,7 +278,7 @@ int nc_tx_produce_packet(struct nc *n, uint8_t *datagram, uint32_t buffer_size)
// Write out bitmap of actual combinations involved // Write out bitmap of actual combinations involved
datagram[2] = packet.sequence; datagram[2] = packet.sequence;
write_uint32(&datagram[3], packet.combination); write_uint32(&datagram[3], packet.combination);
return HEADER_LEN+n->tx.datagram_size; return NC_HEADER_LEN+n->tx.datagram_size;
} }
static int _nc_rx_combine_packet(struct nc_half *n, struct nc_packet *packet) static int _nc_rx_combine_packet(struct nc_half *n, struct nc_packet *packet)
@ -372,14 +359,14 @@ static void _nc_rx_advance_window(struct nc_half *n, uint8_t new_window_start)
int nc_rx_packet(struct nc *n, uint8_t *payload, size_t len) int nc_rx_packet(struct nc *n, uint8_t *payload, size_t len)
{ {
if (len!=2 && len != HEADER_LEN+n->rx.datagram_size){ if (len!=2 && len != NC_HEADER_LEN+n->rx.datagram_size){
fprintf(stderr, "len=%zd\n",len); fprintf(stderr, "len=%zd\n",len);
return -1; return -1;
} }
_nc_ack(&n->tx, payload[0], payload[1]); _nc_ack(&n->tx, payload[0], payload[1]);
if (len < HEADER_LEN+n->rx.datagram_size) if (len < NC_HEADER_LEN+n->rx.datagram_size)
return 0; return 0;
uint8_t new_window_start = payload[2]; uint8_t new_window_start = payload[2];
@ -387,7 +374,7 @@ int nc_rx_packet(struct nc *n, uint8_t *payload, size_t len)
struct nc_packet packet={ struct nc_packet packet={
.sequence = new_window_start, .sequence = new_window_start,
.combination = read_uint32(&payload[3]), .combination = read_uint32(&payload[3]),
.payload = &payload[HEADER_LEN], .payload = &payload[NC_HEADER_LEN],
}; };
int r = _nc_rx_combine_packet(&n->rx, &packet); int r = _nc_rx_combine_packet(&n->rx, &packet);
@ -419,12 +406,19 @@ int nc_rx_next_delivered(struct nc *n, uint8_t *payload, int buffer_size)
return n->rx.datagram_size; return n->rx.datagram_size;
} }
static void _hexdump(uint8_t *bytes, size_t len) #ifdef RUNTESTS
{ /* TODO: Tests that should be written.
size_t i; 1. nc_new() works, and rejects bad input.
for (i=0;i<len;i++) 2. nc_free() works, including on partially initialised structures.
fprintf(stderr, "%02x ", bytes[i]); 3. nc_tx_enqueue_datagram() works, including failing on bad input and when the
} queue is full.
4. nc_tx_ack_dof() works, rejects bad input, and correctly releases buffers.
5. nc_tx_random_linear_combination() works, rejects bad input, and produces valid
linear combinations of the enqueued datagrams, and never produces all zeroes.
6. nc_rx_linear_combination() works, rejects bad input
7. nc_rx_linear_combination() rejects when RX queue full, when combination starts
before current window.
*/
static int _nc_dump_half(struct nc_half *n) static int _nc_dump_half(struct nc_half *n)
{ {
@ -440,8 +434,6 @@ static int _nc_dump_half(struct nc_half *n)
int j; int j;
for(j=0;j<32;j++) for(j=0;j<32;j++)
fprintf(stderr, "%0d",(n->packets[i].combination>>(31-j))&1); fprintf(stderr, "%0d",(n->packets[i].combination>>(31-j))&1);
fprintf(stderr, " ");
_hexdump(n->packets[i].payload, 16);
fprintf(stderr, "\n"); fprintf(stderr, "\n");
} }
return 0; return 0;
@ -456,20 +448,6 @@ static void _nc_dump(struct nc *n)
_nc_dump_half(&n->rx); _nc_dump_half(&n->rx);
} }
#ifdef RUNTESTS
/* TODO: Tests that should be written.
1. nc_new() works, and rejects bad input.
2. nc_free() works, including on partially initialised structures.
3. nc_tx_enqueue_datagram() works, including failing on bad input and when the
queue is full.
4. nc_tx_ack_dof() works, rejects bad input, and correctly releases buffers.
5. nc_tx_random_linear_combination() works, rejects bad input, and produces valid
linear combinations of the enqueued datagrams, and never produces all zeroes.
6. nc_rx_linear_combination() works, rejects bad input
7. nc_rx_linear_combination() rejects when RX queue full, when combination starts
before current window.
*/
void FAIL(const char *fmt,...){ void FAIL(const char *fmt,...){
va_list ap; va_list ap;
fprintf(stderr, "FAIL: "); fprintf(stderr, "FAIL: ");
@ -530,7 +508,7 @@ int nc_test()
int j=0; int j=0;
for(i=0;i<10;i++) { for(i=0;i<10;i++) {
uint8_t outbuffer[HEADER_LEN+200]; uint8_t outbuffer[NC_HEADER_LEN+200];
int len=sizeof(outbuffer); int len=sizeof(outbuffer);
int written = nc_tx_produce_packet(tx, outbuffer, len); int written = nc_tx_produce_packet(tx, outbuffer, len);
if (written==-1) if (written==-1)
@ -543,7 +521,7 @@ int nc_test()
if (i==9) if (i==9)
PASS("Should not produce empty linear combination bitmap"); PASS("Should not produce empty linear combination bitmap");
if (memcmp(&outbuffer[HEADER_LEN], datagrams[0], 200)!=0) if (memcmp(&outbuffer[NC_HEADER_LEN], datagrams[0], 200)!=0)
FAIL("Output identity datagram when only one in queue"); FAIL("Output identity datagram when only one in queue");
if (i==9) if (i==9)
PASS("Output identity datagram when only one in queue"); PASS("Output identity datagram when only one in queue");
@ -583,7 +561,7 @@ int nc_test()
// now can we receive this first packet? // now can we receive this first packet?
{ {
uint8_t outbuffer[HEADER_LEN+200]; uint8_t outbuffer[NC_HEADER_LEN+200];
int written = nc_tx_produce_packet(tx, outbuffer, sizeof(outbuffer)); int written = nc_tx_produce_packet(tx, outbuffer, sizeof(outbuffer));
ASSERT(written!=-1, "Produce packet"); ASSERT(written!=-1, "Produce packet");
int r=nc_rx_packet(rx, outbuffer, written); int r=nc_rx_packet(rx, outbuffer, written);
@ -602,7 +580,7 @@ int nc_test()
// acknowledging this first packet advances the window // acknowledging this first packet advances the window
{ {
uint8_t outbuffer[HEADER_LEN+200]; uint8_t outbuffer[NC_HEADER_LEN+200];
int written = nc_tx_produce_packet(rx, outbuffer, sizeof(outbuffer)); int written = nc_tx_produce_packet(rx, outbuffer, sizeof(outbuffer));
ASSERT(written!=-1, "Produce ACK"); ASSERT(written!=-1, "Produce ACK");
int r=nc_rx_packet(tx, outbuffer, written); int r=nc_rx_packet(tx, outbuffer, written);
@ -621,7 +599,7 @@ int nc_test()
int decoded=0; int decoded=0;
for(i=0;i<100;i++) { for(i=0;i<100;i++) {
uint8_t outbuffer[HEADER_LEN+200]; uint8_t outbuffer[NC_HEADER_LEN+200];
int len=sizeof(outbuffer); int len=sizeof(outbuffer);
int written = nc_tx_produce_packet(tx, outbuffer, len); int written = nc_tx_produce_packet(tx, outbuffer, len);
if (written==-1) if (written==-1)
@ -636,7 +614,7 @@ int nc_test()
for(j=0;j<200;j++) { for(j=0;j<200;j++) {
int k; int k;
uint8_t x = outbuffer[HEADER_LEN+j]; uint8_t x = outbuffer[NC_HEADER_LEN+j];
for (k=0;k<8;k++){ for (k=0;k<8;k++){
if (combination&(0x80000000>>k)) if (combination&(0x80000000>>k))
x^=datagrams[k+1][j]; x^=datagrams[k+1][j];
@ -668,7 +646,7 @@ int nc_test()
// acknowledging first 8 packets advances the tx window // acknowledging first 8 packets advances the tx window
{ {
uint8_t outbuffer[HEADER_LEN+200]; uint8_t outbuffer[NC_HEADER_LEN+200];
int written = nc_tx_produce_packet(rx, outbuffer, sizeof(outbuffer)); int written = nc_tx_produce_packet(rx, outbuffer, sizeof(outbuffer));
ASSERT(written!=-1, "Produce ACK"); ASSERT(written!=-1, "Produce ACK");
int r=nc_rx_packet(tx, outbuffer, written); int r=nc_rx_packet(tx, outbuffer, written);
@ -682,7 +660,7 @@ int nc_test()
int dropped=0; int dropped=0;
bzero(histogram, sizeof(histogram)); bzero(histogram, sizeof(histogram));
uint8_t packets[8][HEADER_LEN+200]; uint8_t packets[8][NC_HEADER_LEN+200];
while(decoded < 10000 && sent <=1000000){ while(decoded < 10000 && sent <=1000000){
// fill the transmit window whenever there is space // fill the transmit window whenever there is space
@ -693,8 +671,8 @@ int nc_test()
// generate a packet in each direction // generate a packet in each direction
sent++; sent++;
int wone = nc_tx_produce_packet(tx, packets[sent&7], HEADER_LEN+200); int wone = nc_tx_produce_packet(tx, packets[sent&7], NC_HEADER_LEN+200);
int wtwo = nc_tx_produce_packet(rx, packets[(sent+4)&7], HEADER_LEN+200); int wtwo = nc_tx_produce_packet(rx, packets[(sent+4)&7], NC_HEADER_LEN+200);
if (sent <13) if (sent <13)
continue; continue;

6
network_coding.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef __SERVALD_NETWORK_CODING_H
#define __SERVALD_NETWORK_CODING_H
#define NC_HEADER_LEN 7
#endif

View File

@ -30,6 +30,7 @@ SERVAL_SOURCES = \
$(SERVAL_BASE)monitor-client.c \ $(SERVAL_BASE)monitor-client.c \
$(SERVAL_BASE)monitor-cli.c \ $(SERVAL_BASE)monitor-cli.c \
$(SERVAL_BASE)net.c \ $(SERVAL_BASE)net.c \
$(SERVAL_BASE)network_coding.c \
$(SERVAL_BASE)nonce.c \ $(SERVAL_BASE)nonce.c \
$(SERVAL_BASE)overlay.c \ $(SERVAL_BASE)overlay.c \
$(SERVAL_BASE)overlay_address.c \ $(SERVAL_BASE)overlay_address.c \