summaryrefslogtreecommitdiff
path: root/serve_image.c
diff options
context:
space:
mode:
Diffstat (limited to 'serve_image.c')
-rw-r--r--serve_image.c184
1 files changed, 118 insertions, 66 deletions
diff --git a/serve_image.c b/serve_image.c
index dc434f0..0c7eab8 100644
--- a/serve_image.c
+++ b/serve_image.c
@@ -1,3 +1,7 @@
+#define _POSIX_C_SOURCE 199309
+
+#include <time.h>
+
#include <errno.h>
#include <error.h>
#include <netdb.h>
@@ -16,7 +20,9 @@
#include "mcast_image.h"
int tx_rate = 80000;
-int pkt_delay = 12500 * PKT_SIZE / 1024;
+int pkt_delay;
+
+#undef RANDOMDROP
int main(int argc, char **argv)
{
@@ -30,26 +36,36 @@ int main(int argc, char **argv)
struct stat st;
int writeerrors = 0;
uint32_t erasesize;
- unsigned char parbuf[PKT_SIZE];
unsigned char *image, *blockptr;
uint32_t block_nr;
- uint32_t block_ofs;
int nr_blocks;
- uint32_t droppoint = -1;
struct timeval then, now, nextpkt;
long time_msecs;
+ unsigned char **src_pkts;
+ unsigned char last_src_pkt[PKT_SIZE];
+ int pkts_extra = 6;
+ int pkts_per_block;
+ struct fec_parms *fec;
- if (argc == 6) {
- tx_rate = atol(argv[5]) * 1024;
+ if (argc == 7) {
+ tx_rate = atol(argv[6]) * 1024;
if (tx_rate < PKT_SIZE || tx_rate > 20000000) {
fprintf(stderr, "Bogus TX rate %d KiB/s\n", tx_rate);
exit(1);
}
+ argc = 6;
+ }
+ if (argc == 6) {
+ pkts_extra = atol(argv[5]);
+ if (pkts_extra < 0 || pkts_extra > 200) {
+ fprintf(stderr, "Bogus redundancy %d packets\n", pkts_extra);
+ exit(1);
+ }
argc = 5;
}
if (argc != 5) {
- fprintf(stderr, "usage: %s <host> <port> <image> <erasesize> [<tx_rate>]\n",
+ fprintf(stderr, "usage: %s <host> <port> <image> <erasesize> [<redundancy>] [<tx_rate>]\n",
(strrchr(argv[0], '/')?:argv[0]-1)+1);
exit(1);
}
@@ -62,6 +78,22 @@ int main(int argc, char **argv)
fprintf(stderr, "erasesize cannot be zero\n");
exit(1);
}
+
+ pkts_per_block = (erasesize + PKT_SIZE - 1) / PKT_SIZE;
+ src_pkts = malloc(pkts_per_block * sizeof(unsigned char *));
+ if (!src_pkts) {
+ fprintf(stderr, "Failed to allocate memory for packet pointers\n");
+ exit(1);
+ }
+ /* We have to pad it with zeroes, so can't use it in-place */
+ src_pkts[pkts_per_block-1] = last_src_pkt;
+
+ fec = fec_new(pkts_per_block, pkts_per_block + pkts_extra);
+ if (!fec) {
+ fprintf(stderr, "Error initialising FEC\n");
+ exit(1);
+ }
+
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_ADDRCONFIG;
hints.ai_socktype = SOCK_DGRAM;
@@ -118,85 +150,91 @@ int main(int argc, char **argv)
pktbuf.hdr.totcrc = htonl(crc32(-1, image, st.st_size));
pktbuf.hdr.nr_blocks = htonl(nr_blocks);
pktbuf.hdr.blocksize = htonl(erasesize);
+ pktbuf.hdr.thislen = htonl(PKT_SIZE);
+ pktbuf.hdr.nr_pkts = htons(pkts_per_block + pkts_extra);
printf("%08x\n", ntohl(pktbuf.hdr.totcrc));
+ again:
+ printf("Image size %ld KiB (%08lx). %d redundant packets per block (%d total)\n"
+ "Data to send %d KiB. Estimated transmit time: %ds\n",
+ (long)st.st_size / 1024, (long) st.st_size, pkts_extra, pkts_extra+pkts_per_block,
+ nr_blocks * PKT_SIZE * (pkts_per_block+pkts_extra) / 1024,
+ nr_blocks * (pkts_per_block+pkts_extra) * pkt_delay / 1000000);
gettimeofday(&then, NULL);
nextpkt = then;
+#ifdef RANDOMDROP
+ srand((unsigned)then.tv_usec);
+ printf("Random seed %u\n", (unsigned)then.tv_usec);
+#endif
blockptr = image;
for (block_nr = 0; block_nr < nr_blocks; block_nr++) {
- int len;
- int dropped = 0;
+ int i;
+ long tosleep;
+
+ blockptr = image + (erasesize * block_nr);
+
+ pktbuf.hdr.block_crc = htonl(crc32(-1, blockptr, erasesize));
+
+ for (i=0; i < pkts_per_block-1; i++)
+ src_pkts[i] = blockptr + (i*PKT_SIZE);
+
+ memcpy(last_src_pkt, blockptr + (i*PKT_SIZE),
+ erasesize - (i * PKT_SIZE));
pktbuf.hdr.block_nr = htonl(block_nr);
- for (block_ofs = 0; block_ofs <= erasesize; block_ofs += len) {
- int i;
+ for (i=0; i < pkts_per_block + pkts_extra; i++) {
+
+ fec_encode(fec, src_pkts, pktbuf.data, i, PKT_SIZE);
- if (block_ofs + PKT_SIZE > erasesize)
- len = erasesize - block_ofs;
- else
- len = PKT_SIZE;
+ printf("\rSending data block %08x packet %3d/%d",
+ block_nr * erasesize, i, pkts_per_block + pkts_extra);
- if (block_ofs == erasesize) {
+ if (block_nr && !i) {
gettimeofday(&now, NULL);
time_msecs = (now.tv_sec - then.tv_sec) * 1000;
time_msecs += ((int)(now.tv_usec - then.tv_usec)) / 1000;
-
- printf("\rSending parity block: %08x (%ld KiB/s) ",
- block_nr * erasesize,
- (block_ofs + (block_nr * (erasesize+sizeof(pktbuf)))) / 1024 * 1000 / time_msecs);
-
- len = PKT_SIZE;
- memcpy(pktbuf.data, parbuf, PKT_SIZE);
- } else {
- if (!block_ofs)
- memcpy(parbuf, blockptr, PKT_SIZE);
- else for (i=0; i < len; i++)
- parbuf[i] ^= blockptr[i];
-
- memcpy(pktbuf.data, blockptr, len);
- printf("\rSending data block at %08x",
- block_nr * erasesize + block_ofs);
- blockptr += len;
+ printf(" (%ld KiB/s) ",
+ (block_nr * sizeof(pktbuf) * (pkts_per_block+pkts_extra))
+ / 1024 * 1000 / time_msecs);
}
fflush(stdout);
- pktbuf.hdr.thislen = htonl(len);
- pktbuf.hdr.block_ofs = htonl(block_ofs);
- pktbuf.hdr.thiscrc = htonl(crc32(-1, pktbuf.data, len));
-
- if (droppoint == block_ofs && !dropped) {
- dropped = 1;
- if (droppoint == 0)
- droppoint = erasesize;
- else if (droppoint == erasesize)
- droppoint = ((erasesize - 1) / PKT_SIZE) * PKT_SIZE;
- else droppoint -= PKT_SIZE;
- printf("\nDropping data block at %08x\n", block_ofs);
+ pktbuf.hdr.pkt_nr = htons(i);
+ pktbuf.hdr.thiscrc = htonl(crc32(-1, pktbuf.data, PKT_SIZE));
+
+#ifdef RANDOMDROP
+ if ((rand() % 1000) < 20) {
+ printf("\nDropping packet %d\n", i+1);
continue;
}
+#endif
+ gettimeofday(&now, NULL);
+#if 1
+ tosleep = nextpkt.tv_usec - now.tv_usec +
+ (1000000 * (nextpkt.tv_sec - now.tv_sec));
- if (write(sock, &pktbuf, sizeof(pktbuf.hdr)+len) < 0) {
- perror("write");
- writeerrors++;
- if (writeerrors > 10) {
- fprintf(stderr, "Too many consecutive write errors\n");
- exit(1);
- }
- } else
- writeerrors = 0;
+ /* We need hrtimers for this to actually work */
+ if (tosleep > 0) {
+ struct timespec req;
- do {
- gettimeofday(&now, NULL);
- } while (now.tv_sec < nextpkt.tv_sec ||
- (now.tv_sec == nextpkt.tv_sec &&
- now.tv_usec < nextpkt.tv_usec));
+ req.tv_nsec = (tosleep % 1000000) * 1000;
+ req.tv_sec = tosleep / 1000000;
- nextpkt.tv_usec = now.tv_usec + pkt_delay;
+ nanosleep(&req, NULL);
+ }
+#else
+ while (now.tv_sec < nextpkt.tv_sec ||
+ (now.tv_sec == nextpkt.tv_sec &&
+ now.tv_usec < nextpkt.tv_usec)) {
+ gettimeofday(&now, NULL);
+ }
+#endif
+ nextpkt.tv_usec += pkt_delay;
if (nextpkt.tv_usec >= 1000000) {
nextpkt.tv_sec += nextpkt.tv_usec / 1000000;
nextpkt.tv_usec %= 1000000;
@@ -206,20 +244,34 @@ int main(int argc, char **argv)
passed, then we've lost time. Adjust our expected
timings accordingly. */
if (now.tv_usec > (now.tv_usec +
- 1000000 * (nextpkt.tv_sec - now.tv_sec)))
+ 1000000 * (nextpkt.tv_sec - now.tv_sec))) {
nextpkt = now;
+ }
+
+ if (write(sock, &pktbuf, sizeof(pktbuf)) < 0) {
+ perror("write");
+ writeerrors++;
+ if (writeerrors > 10) {
+ fprintf(stderr, "Too many consecutive write errors\n");
+ exit(1);
+ }
+ } else
+ writeerrors = 0;
+
+
}
}
- munmap(image, st.st_size);
- close(rfd);
- close(sock);
gettimeofday(&now, NULL);
time_msecs = (now.tv_sec - then.tv_sec) * 1000;
time_msecs += ((int)(now.tv_usec - then.tv_usec)) / 1000;
printf("\n%d KiB sent in %ldms (%ld KiB/s)\n",
- nr_blocks * (erasesize+sizeof(pktbuf)) / 1024, time_msecs,
- nr_blocks * (erasesize+sizeof(pktbuf)) / 1024 * 1000 / time_msecs);
+ nr_blocks * sizeof(pktbuf) * (pkts_per_block+pkts_extra) / 1024, time_msecs,
+ nr_blocks * sizeof(pktbuf) * (pkts_per_block+pkts_extra) / 1024 * 1000 / time_msecs);
+
+ munmap(image, st.st_size);
+ close(rfd);
+ close(sock);
return 0;
}