//pkgnet/Makefile |
---|
14,8 → 14,8 |
copy pkgnet.lsm appinfo |
zip -9 -r -m pkgnet.zip bin appinfo |
pkgnet.exe: pkgnet.obj net.obj |
wcl -lr -k8192 $(LIB) *.obj -fe=pkgnet.exe |
pkgnet.exe: pkgnet.obj net.obj unchunk.obj |
wcl -lr -k8192 $(LIB) pkgnet.obj net.obj unchunk.obj -fe=pkgnet.exe |
pkgnet.obj: pkgnet.c |
*wcc $(CFLAGS) pkgnet.c |
23,6 → 23,15 |
net.obj: net.c |
*wcc $(CFLAGS) net.c |
unchunk.obj: unchunk.c |
*wcc $(CFLAGS) unchunk.c |
unchtest.obj: unchtest.c |
*wcc $(CFLAGS) unchtest.c |
unchtest.exe: unchtest.obj unchunk.obj |
wcl -lr $(LIB) unchtest.obj unchunk.obj -fe=unchtest.exe |
clean: .symbolic |
del *.obj |
del pkgnet.exe |
//pkgnet/unchtest.c |
---|
0,0 → 1,109 |
/* |
* test suite for the unchunk() function. |
* |
* Copyright (C) 2021 Mateusz Viste |
*/ |
#include <stdio.h> |
#include <stdlib.h> |
#include <string.h> |
#include <time.h> |
#include <unistd.h> |
#include "unchunk.h" |
static size_t randchunkdata(void *file_chunked, const void *file_raw, size_t file_raw_len, int maxchunksz) { |
size_t file_raw_read = 0; |
size_t file_chunked_len = 0; |
for (;;) { |
size_t chunklen = (rand() % maxchunksz) + 1; |
if (file_raw_read + chunklen > file_raw_len) chunklen = file_raw_len - file_raw_read; |
file_chunked_len += sprintf((char *)file_chunked + file_chunked_len, "%x\r\n", chunklen); |
if (chunklen > 0) memcpy((char *)file_chunked + file_chunked_len, (char *)file_raw + file_raw_read, chunklen); |
file_raw_read += chunklen; |
file_chunked_len += chunklen; |
file_chunked_len += sprintf((char *)file_chunked + file_chunked_len, "\r\n"); |
if (chunklen == 0) return(file_chunked_len); |
} |
} |
/* writes buffer of fsize bytes to file fname */ |
static void dumpfile(const char *fname, const void *buff, size_t fsize) { |
FILE *fd; |
fd = fopen(fname, "wb"); |
fwrite(buff, 1, fsize, fd); |
fclose(fd); |
} |
int main(int argc, char **argv) { |
static unsigned char file_raw[30000u]; /* original file */ |
static unsigned char file_chunked[60000u]; /* chunked version */ |
static unsigned char file_decoded[60000u]; /* after being un-chunked */ |
size_t file_raw_len; |
size_t file_chunked_len; |
FILE *fd; |
int trycount; |
if ((argc != 2) || (argv[1][0] == '/')) { |
puts("Usage: unchtest <file>"); |
return(1); |
} |
fd = fopen(argv[1], "rb"); |
if (fd == NULL) { |
puts("ERROR: failed to open file"); |
return(1); |
} |
file_raw_len = fread(file_raw, 1, sizeof(file_raw), fd); |
fclose(fd); |
printf("Loaded '%s' (%zu bytes)\r\n", argv[1], file_raw_len); |
srand(time(NULL)); |
for (trycount = 0; trycount < 1000; trycount++) { |
size_t bytesprocessed = 0; |
size_t file_decoded_len = 0; |
int maxchunksz; |
/* segment file into chunks of random size */ |
maxchunksz = (rand() % 1024) + 1; |
file_chunked_len = randchunkdata(file_chunked, file_raw, file_raw_len, maxchunksz); |
printf("=== TRY %d (CHUNKS: %d BYTES MAX) ======================\r\n", trycount + 1, maxchunksz); |
for (;;) { |
size_t bytes; |
int decodedbytes; |
unsigned char buffer[4096]; |
bytes = min((rand() % 256) + 1, file_chunked_len - bytesprocessed); |
printf("processing %4zu bytes of chunked data", bytes); |
memcpy(buffer, file_chunked + bytesprocessed, bytes); |
/* decode the chunked version reading random amounts of data and build a decoded version */ |
decodedbytes = unchunk(buffer, bytes); |
printf(" -> decoded into %4d raw bytes\r\n", decodedbytes); |
memcpy(file_decoded + file_decoded_len, buffer, decodedbytes); |
file_decoded_len += decodedbytes; |
bytesprocessed += bytes; |
if (bytesprocessed == file_chunked_len) break; |
} |
/* compare decoded and original */ |
if ((file_decoded_len != file_raw_len) || (memcmp(file_decoded, file_raw, file_raw_len) != 0)) { |
printf("ERROR: decoded file does not match the original. see tst-orig.dat, tst-chnk.txt and tst-unch.dat\r\n"); |
dumpfile("tst-orig.dat", file_raw, file_raw_len); |
dumpfile("tst-chnk.dat", file_chunked, file_chunked_len); |
dumpfile("tst-unch.dat", file_decoded, file_decoded_len); |
return(1); |
} |
} |
printf("OK\r\n"); |
return(0); |
} |
//pkgnet/unchunk.c |
---|
0,0 → 1,72 |
/* |
* unpacks a http "chunked" transfer into a raw data stream. |
* this file is part of the pkgnet tool from the SvarDOS project. |
* |
* Copyright (C) 2021 Mateusz Viste |
*/ |
#include <stdlib.h> /* atol() */ |
#include <string.h> |
#include "unchunk.h" |
/* transforms a http CHUNKED stream into actual data, returns the amount of raw data to read */ |
int unchunk(unsigned char *buff, int bufflen) { |
static long bytesleft; /* how many bytes are expected yet in the ongoing chunk */ |
static char partial_hdr[16]; /* a small buffer for storing partial chunk headers, if these are transmitted in separate parts */ |
int hdrstart, hdrend; |
/* if chunk header was being in progress, try to decode it now */ |
if (bytesleft == -1) { |
int partial_hdr_len = strlen(partial_hdr); |
/* locate header terminator, if available */ |
for (hdrend = 0; (hdrend < bufflen) && (buff[hdrend] != '\n'); hdrend++); |
if (partial_hdr_len + hdrend > 15) return(-1); /* error: chunk header too long */ |
/* copy header to buffer */ |
memcpy(partial_hdr + partial_hdr_len, buff, hdrend); |
partial_hdr[partial_hdr_len + hdrend] = 0; |
/* quit if header still no complete */ |
if (hdrend >= bufflen) return(0); |
/* good, got whole header */ |
bufflen -= hdrend + 1; |
memmove(buff, buff + hdrend + 1, bufflen); |
bytesleft = strtol(partial_hdr, NULL, 16); |
} |
AGAIN: |
if (bufflen <= bytesleft) { /* bufflen <= bytesleft */ |
bytesleft -= bufflen; |
return(bufflen); |
} |
/* else bufflen > bytesleft */ |
/* skip trailing \r\n after chunk */ |
for (hdrstart = bytesleft; hdrstart < bufflen; hdrstart++) if ((buff[hdrstart] != '\r') && (buff[hdrstart] != '\n')) break; |
/* skip chunk size (look for its \n terminator) */ |
for (hdrend = hdrstart; (hdrend < bufflen) && (buff[hdrend] != '\n'); hdrend++); |
if (hdrend < bufflen) { /* full header found */ |
long newchunklen; |
/* read the header length */ |
newchunklen = strtol((char *)buff + hdrstart, NULL, 16); |
/* move data over header to get a contiguous block of data */ |
memmove(buff + bytesleft, buff + hdrend + 1, bufflen - (hdrend + 1)); |
bufflen -= (hdrend + 1 - bytesleft); |
/* update bytesleft */ |
bytesleft += newchunklen; |
/* loop again */ |
goto AGAIN; |
} else { /* partial header */ |
if ((bufflen - bytesleft) > 15) return(-1); /* error: chunk header appears to be longer than 15 characters */ |
memset(partial_hdr, 0, sizeof(partial_hdr)); |
memcpy(partial_hdr, buff + bytesleft, bufflen - bytesleft); |
bufflen -= (bufflen - bytesleft); |
bytesleft = -1; /* "header in progress" */ |
return(bufflen); |
} |
} |
//pkgnet/unchunk.h |
---|
0,0 → 1,14 |
/* |
* unpacks a http "chunked" transfer into a raw data stream. |
* this file is part of the pkgnet tool from the SvarDOS project. |
* |
* Copyright (C) 2021 Mateusz Viste |
*/ |
#ifndef UNCHUNK_H |
#define UNCHUNK_H |
/* transforms a http CHUNKED stream into actual data, returns the amount of raw data to read */ |
int unchunk(unsigned char *buff, int bufflen); |
#endif |