summaryrefslogtreecommitdiff
path: root/serve_image.c
diff options
context:
space:
mode:
Diffstat (limited to 'serve_image.c')
-rw-r--r--serve_image.c300
1 files changed, 0 insertions, 300 deletions
diff --git a/serve_image.c b/serve_image.c
deleted file mode 100644
index cbcf3b7..0000000
--- a/serve_image.c
+++ /dev/null
@@ -1,300 +0,0 @@
-#define PROGRAM_NAME "serve_image"
-#define _POSIX_C_SOURCE 200112L
-
-#include <time.h>
-#include <errno.h>
-#include <netdb.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/socket.h>
-#include <sys/mman.h>
-#include <netinet/in.h>
-#include <sys/time.h>
-#include <crc32.h>
-#include <inttypes.h>
-
-#include "mcast_image.h"
-
-int tx_rate = 80000;
-int pkt_delay;
-
-#undef RANDOMDROP
-
-int main(int argc, char **argv)
-{
- struct addrinfo *ai;
- struct addrinfo hints;
- struct addrinfo *runp;
- int ret;
- int sock;
- struct image_pkt pktbuf;
- int rfd;
- struct stat st;
- int writeerrors = 0;
- uint32_t erasesize;
- unsigned char *image, *blockptr = NULL;
- uint32_t block_nr, pkt_nr;
- int nr_blocks;
- struct timeval then, now, nextpkt;
- long time_msecs;
- int pkts_per_block;
- int total_pkts_per_block;
- struct fec_parms *fec;
- unsigned char *last_block;
- uint32_t *block_crcs;
- long tosleep;
- uint32_t sequence = 0;
-
- if (argc == 6) {
- tx_rate = atol(argv[5]) * 1024;
- if (tx_rate < PKT_SIZE || tx_rate > 20000000) {
- fprintf(stderr, "Bogus TX rate %d KiB/s\n", tx_rate);
- exit(1);
- }
- argc = 5;
- }
- if (argc != 5) {
- fprintf(stderr, "usage: %s <host> <port> <image> <erasesize> [<tx_rate>]\n",
- PROGRAM_NAME);
- exit(1);
- }
- pkt_delay = (sizeof(pktbuf) * 1000000) / tx_rate;
- printf("Inter-packet delay (avg): %dµs\n", pkt_delay);
- printf("Transmit rate: %d KiB/s\n", tx_rate / 1024);
-
- erasesize = atol(argv[4]);
- if (!erasesize) {
- fprintf(stderr, "erasesize cannot be zero\n");
- exit(1);
- }
-
- pkts_per_block = (erasesize + PKT_SIZE - 1) / PKT_SIZE;
- total_pkts_per_block = pkts_per_block * 3 / 2;
-
- /* We have to pad it with zeroes, so can't use it in-place */
- last_block = malloc(pkts_per_block * PKT_SIZE);
- if (!last_block) {
- fprintf(stderr, "Failed to allocate last-block buffer\n");
- exit(1);
- }
-
- fec = fec_new(pkts_per_block, total_pkts_per_block);
- 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;
-
- ret = getaddrinfo(argv[1], argv[2], &hints, &ai);
- if (ret) {
- fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(ret));
- exit(1);
- }
- runp = ai;
- for (runp = ai; runp; runp = runp->ai_next) {
- sock = socket(runp->ai_family, runp->ai_socktype,
- runp->ai_protocol);
- if (sock == -1) {
- perror("socket");
- continue;
- }
- if (connect(sock, runp->ai_addr, runp->ai_addrlen) == 0)
- break;
- perror("connect");
- close(sock);
- }
- if (!runp)
- exit(1);
-
- rfd = open(argv[3], O_RDONLY);
- if (rfd < 0) {
- perror("open");
- exit(1);
- }
-
- if (fstat(rfd, &st)) {
- perror("fstat");
- exit(1);
- }
-
- if (st.st_size % erasesize) {
- fprintf(stderr, "Image size %" PRIu64 " bytes is not a multiple of erasesize %d bytes\n",
- st.st_size, erasesize);
- exit(1);
- }
- image = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, rfd, 0);
- if (image == MAP_FAILED) {
- perror("mmap");
- exit(1);
- }
-
- nr_blocks = st.st_size / erasesize;
-
- block_crcs = malloc(nr_blocks * sizeof(uint32_t));
- if (!block_crcs) {
- fprintf(stderr, "Failed to allocate memory for CRCs\n");
- exit(1);
- }
-
- memcpy(last_block, image + (nr_blocks - 1) * erasesize, erasesize);
- memset(last_block + erasesize, 0, (PKT_SIZE * pkts_per_block) - erasesize);
-
- printf("Checking CRC....");
- fflush(stdout);
-
- pktbuf.hdr.resend = 0;
- pktbuf.hdr.totcrc = htonl(mtd_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(total_pkts_per_block);
-
- printf("%08x\n", ntohl(pktbuf.hdr.totcrc));
- printf("Checking block CRCs....");
- fflush(stdout);
- for (block_nr=0; block_nr < nr_blocks; block_nr++) {
- printf("\rChecking block CRCS.... %d/%d",
- block_nr + 1, nr_blocks);
- fflush(stdout);
- block_crcs[block_nr] = mtd_crc32(-1, image + (block_nr * erasesize), erasesize);
- }
-
- printf("\nImage size %ld KiB (0x%08lx). %d blocks at %d pkts/block\n"
- "Estimated transmit time per cycle: %ds\n",
- (long)st.st_size / 1024, (long) st.st_size,
- nr_blocks, pkts_per_block,
- nr_blocks * pkts_per_block * 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
- while (1) for (pkt_nr=0; pkt_nr < total_pkts_per_block; pkt_nr++) {
-
- if (blockptr && pkt_nr == 0) {
- unsigned long amt_sent = total_pkts_per_block * nr_blocks * sizeof(pktbuf);
- gettimeofday(&now, NULL);
-
- time_msecs = (now.tv_sec - then.tv_sec) * 1000;
- time_msecs += ((int)(now.tv_usec - then.tv_usec)) / 1000;
- printf("\n%ld KiB sent in %ldms (%ld KiB/s)\n",
- amt_sent / 1024, time_msecs,
- amt_sent / 1024 * 1000 / time_msecs);
- then = now;
- }
-
- for (block_nr = 0; block_nr < nr_blocks; block_nr++) {
-
- int actualpkt;
-
- /* Calculating the redundant FEC blocks is expensive;
- the first $pkts_per_block are cheap enough though
- because they're just copies. So alternate between
- simple and complex stuff, so that we don't start
- to choke and fail to keep up with the expected
- bitrate in the second half of the sequence */
- if (block_nr & 1)
- actualpkt = pkt_nr;
- else
- actualpkt = total_pkts_per_block - 1 - pkt_nr;
-
- blockptr = image + (erasesize * block_nr);
- if (block_nr == nr_blocks - 1)
- blockptr = last_block;
-
- fec_encode_linear(fec, blockptr, pktbuf.data, actualpkt, PKT_SIZE);
-
- pktbuf.hdr.thiscrc = htonl(mtd_crc32(-1, pktbuf.data, PKT_SIZE));
- pktbuf.hdr.block_crc = htonl(block_crcs[block_nr]);
- pktbuf.hdr.block_nr = htonl(block_nr);
- pktbuf.hdr.pkt_nr = htons(actualpkt);
- pktbuf.hdr.pkt_sequence = htonl(sequence++);
-
- printf("\rSending data block %08x packet %3d/%d",
- block_nr * erasesize,
- pkt_nr, total_pkts_per_block);
-
- if (pkt_nr && !block_nr) {
- unsigned long amt_sent = pkt_nr * nr_blocks * sizeof(pktbuf);
-
- gettimeofday(&now, NULL);
-
- time_msecs = (now.tv_sec - then.tv_sec) * 1000;
- time_msecs += ((int)(now.tv_usec - then.tv_usec)) / 1000;
- printf(" (%ld KiB/s) ",
- amt_sent / 1024 * 1000 / time_msecs);
- }
-
- fflush(stdout);
-
-#ifdef RANDOMDROP
- if ((rand() % 1000) < 20) {
- printf("\nDropping packet %d of block %08x\n", pkt_nr+1, block_nr * erasesize);
- continue;
- }
-#endif
- gettimeofday(&now, NULL);
-#if 1
- tosleep = nextpkt.tv_usec - now.tv_usec +
- (1000000 * (nextpkt.tv_sec - now.tv_sec));
-
- /* We need hrtimers for this to actually work */
- if (tosleep > 0) {
- struct timespec req;
-
- req.tv_nsec = (tosleep % 1000000) * 1000;
- req.tv_sec = tosleep / 1000000;
-
- 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;
- }
-
- /* If the time for the next packet has already
- passed (by some margin), then we've lost time
- Adjust our expected timings accordingly. If
- we're only a little way behind, don't slip yet */
- if (now.tv_usec > (now.tv_usec + (5 * pkt_delay) +
- 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);
- return 0;
-}