From: misomosi Date: Mon, 8 Jun 2026 16:15:11 +0000 (-0400) Subject: Adding gists from github to gists repo X-Git-Url: http://git.misomosispi.com/?a=commitdiff_plain;h=76e1a00b5ab806ff1c192d429f1615c1089bfa88;p=gists.git Adding gists from github to gists repo --- diff --git a/AbstractPosix/README.md b/AbstractPosix/README.md new file mode 100644 index 0000000..de63767 --- /dev/null +++ b/AbstractPosix/README.md @@ -0,0 +1,3 @@ +## Abstract POSIX + +Faking UNIX abstract sockets without ancillary messages on POSIX by uinsg TCP sockets with a hashed port diff --git a/AbstractPosix/abstractposix.c b/AbstractPosix/abstractposix.c new file mode 100644 index 0000000..344d07a --- /dev/null +++ b/AbstractPosix/abstractposix.c @@ -0,0 +1,114 @@ +#include +#include +#include +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#include +#include +#pragma comment(lib, "ws2_32.lib") +#else +#include +#include +#include +#include +#include +#define INVALID_SOCKET -1 +#define SOCKET_ERROR -1 +#define SOCKET int +#define InetPtonA inet_pton +#endif + +#define HASH_PRIME 31 +static uint16_t memhash16(const uint8_t *mem, size_t len) +{ + uint16_t h = 0; + while (len--) { + h *= HASH_PRIME; + h += ((uint16_t)mem[len] + 1); + } + return h; +} + +// This port range is generally not used by normal +// services nor used as an ephemeral port so it's +// a good range to use as a hash for ports. +#define PORT_BEGIN 0x4000 +#define PORT_RANGE 0x4000 +static uint16_t porthash(const uint8_t *mem, size_t len) +{ + return PORT_BEGIN + memhash16(mem, len) % PORT_RANGE; +} + +static void socketassert(const char *file, int line, const char *expr, int condition) +{ + if (!condition) { +#ifdef _WIN32 + int code = WSAGetLastError(); +#else + int code = errno; +#endif + fflush(stdout); + fprintf(stderr, "[%s:%d] Socket error from '%s' : %d\n", file, line, expr, code); + exit(1); + } +} + +#define SOCKET_ASSERT(expr) socketassert(__FILE__, __LINE__, #expr, (expr)) + +int main(int argc, char **argv) +{ +#ifdef _WIN32 + WSADATA wsa_data; + int errcode = WSAStartup(MAKEWORD(2, 2), &wsa_data); + if (errcode) { + fprintf(stderr, "WSAStartup failed! %d\n", errcode); + return 1; + } + if (wsa_data.wVersion != MAKEWORD(2, 2)) { + fprintf(stderr, "WSA Version != 2.2!\n"); + return 1; + } +#endif + const char *name = "TheBestName"; + if (argc > 1) { + name = argv[1]; + } + uint16_t port = porthash(name, strlen(name)); + printf("Establishing abstract socket '%s' with port '%d'\n", name, port); + + struct sockaddr_in sin; + memset(&sin, 0, sizeof(sin)); + sin.sin_family = PF_INET; + sin.sin_port = htons(port); + InetPtonA(AF_INET, "127.0.0.1", &sin.sin_addr); + + SOCKET server = socket(AF_INET, SOCK_STREAM, 0); + SOCKET_ASSERT(server != INVALID_SOCKET); + SOCKET_ASSERT(bind(server, (struct sockaddr *)&sin, sizeof(sin)) != SOCKET_ERROR); + SOCKET_ASSERT(listen(server, 1) != SOCKET_ERROR); + printf("Server is listening...\n"); + + SOCKET client = socket(AF_INET, SOCK_STREAM, 0); + SOCKET_ASSERT(client != INVALID_SOCKET); + SOCKET_ASSERT(connect(client, (struct sockaddr *)&sin, sizeof(sin)) != SOCKET_ERROR); + printf("Client connected!\n"); + + SOCKET connection = accept(server, NULL, 0); + SOCKET_ASSERT(connection != INVALID_SOCKET); + printf("Server accepted connection!\n"); + + char message[] = "Hello World!"; + printf("Client is sending message!\n"); + SOCKET_ASSERT(send(client, message, sizeof(message), 0) != SOCKET_ERROR); + memset(message, 0, sizeof(message)); + printf("Server is receiving message!\n"); + SOCKET_ASSERT(recv(connection, message, sizeof(message), 0) != SOCKET_ERROR); + printf("Server received message!\n" + "Message: %s\n", message); + + close(server); + close(connection); + close(client); + return 0; +} diff --git a/EnableLBR/README.md b/EnableLBR/README.md new file mode 100644 index 0000000..7e7f6e5 --- /dev/null +++ b/EnableLBR/README.md @@ -0,0 +1,3 @@ +## Enable LBR + +Enable LBR for Threads in a Process on Windows (useful for some ETW tracing) diff --git a/EnableLBR/enablelbr.c b/EnableLBR/enablelbr.c new file mode 100644 index 0000000..7fe915b --- /dev/null +++ b/EnableLBR/enablelbr.c @@ -0,0 +1,98 @@ +#define WIN32_LEAN_AND_MEAN 1 +#include +#include +#include +static void EnableLBR(DWORD dwProcessId) +{ + if (dwProcessId == GetCurrentProcessId()) + { + printf("Wow, you magically guessed my PID! Can't enable LBR on myself though...\n"); + return; + } + + HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, dwProcessId); + if (hSnapshot == INVALID_HANDLE_VALUE) + { + printf("Failed to create snapshot!\n"); + return; + } + + THREADENTRY32 te; + te.dwSize = sizeof(te); + printf("Enabling LBR for threads in PID %u...\n", dwProcessId); + if (Thread32First(hSnapshot, &te)) do + { + DWORD cbPrev = te.dwSize; + te.dwSize = sizeof(te); + if (cbPrev < FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) + sizeof(te.th32OwnerProcessID)) + continue; + if (te.th32OwnerProcessID != dwProcessId) + continue; + + DWORD tid = te.th32ThreadID; + printf("\tEnabling LBR for TID %u...\n", tid); + DWORD flags = THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME; + HANDLE hThread = OpenThread(flags, FALSE, tid); + if (hThread == NULL) + { + printf("\tFailed to open thread for ctx update!\n", tid); + continue; + } + if (SuspendThread(hThread) == (DWORD)-1) + { + printf("\tFailed to suspend thread for updating context! %08X\n", GetLastError()); + CloseHandle(hThread); + continue; + } + + // This weird little quirk about enabling LBR described on a CodeProject page + // https://www.codeproject.com/Articles/517466/Last-branch-records-and-branch-tracing + // + // In a debugger, this can get From/To values on branches + // You can also break on branches when setting 0x200 in Dr7 + // + // Outside of a debugger, records the branch in LbrInserts when using ETW + CONTEXT ctx; + flags = CONTEXT_DEBUG_REGISTERS; + ctx.ContextFlags = flags; + BOOL status = GetThreadContext(hThread, &ctx); + ctx.Dr7 |= 0x100; + if (status) { + ctx.ContextFlags = flags; + SetThreadContext(hThread, &ctx); + } + ResumeThread(hThread); + CloseHandle(hThread); + + if (!status) + { + printf("\tFailed to update context for thread! %08x\n", GetLastError()); + continue; + } + printf("\tLBR enabled for TID %u!\n", tid); + } + while (Thread32Next(hSnapshot, &te)); else + { + fflush(stdout); + fprintf(stderr, "Failed to get a single thread in process? How?\n"); + return; + } + printf("Threads in PID %u have LBR enabled!\n", dwProcessId); +} + +int main(int argc, char **argv) +{ + if (argc < 2) + { + fprintf(stderr, "Usage: %s ProcessID\n", *argv); + return 1; + } + DWORD dwProcessId = (DWORD)atoi(argv[1]); + if (dwProcessId == 0) + { + fprintf(stderr, "Failed to parse process ID! Cannot enable LBR!\n"); + return 1; + } + EnableLBR(dwProcessId); + return 0; +} diff --git a/LaserEyesPNG/README.md b/LaserEyesPNG/README.md new file mode 100644 index 0000000..c034f47 --- /dev/null +++ b/LaserEyesPNG/README.md @@ -0,0 +1,3 @@ +## Laser Eyes PNG + +https://memed.io/laser-eyes-meme-maker export as PNG diff --git a/LaserEyesPNG/snippet.js b/LaserEyesPNG/snippet.js new file mode 100644 index 0000000..a24eafd --- /dev/null +++ b/LaserEyesPNG/snippet.js @@ -0,0 +1,21 @@ +/* + * Javascript has an API for adding custom HTML elements + * that memed.io uses to define their own class for exporting + * the image as whatever filetype that they want. + * + * window.customElements.define('add-images-on-image', AddImagesOnImage); + * + * However, the only option available, or that I could find right now, + * is to export as a JPG. This is a pain because I often have images with + * transparent backgrounds and JPG not only removes the transparency, the + * lossiness makes it so that I can't just select a key color to remove the background. + * + * No problem because we can use the browser console to export it to a PNG. + */ + +// Export the data URL of the image +document.querySelector('add-images-on-image').getCanvasDataUrl('png') + +// Or you can have memed.io temporarily host your image +// and this will give you a URL back to the blob +document.querySelector('add-images-on-image').getCanvasObjectUrl('png') diff --git a/MSVCCleanup/README.md b/MSVCCleanup/README.md new file mode 100644 index 0000000..97d9c96 --- /dev/null +++ b/MSVCCleanup/README.md @@ -0,0 +1,3 @@ +## MSVC Cleanup + +Cleanup macro for C++ which emulates gcc's \_\_cleanup\_\_ (which MSVC does not have) diff --git a/MSVCCleanup/msvccleanup.cpp b/MSVCCleanup/msvccleanup.cpp new file mode 100644 index 0000000..4f01c77 --- /dev/null +++ b/MSVCCleanup/msvccleanup.cpp @@ -0,0 +1,30 @@ +#include + +#ifdef __cplusplus +#define CLEANUP(t, v) t v; AutoCleanup ACV(&v); v + +template +class AutoCleanup { + T *wrapped; +public: + AutoCleanup(T *wrapped) : wrapped(wrapped) {} + ~AutoCleanup() { dtor(wrapped); } +}; +#else +#define CLEANUP(t, v) t __attribute__((__cleanup__(t##Cleanup))) v +#endif + +typedef struct S { + int x; +} S; + +void SCleanup(S *h) +{ + printf("Hello World! %d\n", h->x); +} + +int main(void) +{ + CLEANUP(S, v) = {2}; + return 0; +} diff --git a/QuranComExtractSurah/QuranComExtractSurah.js b/QuranComExtractSurah/QuranComExtractSurah.js new file mode 100644 index 0000000..96373a0 --- /dev/null +++ b/QuranComExtractSurah/QuranComExtractSurah.js @@ -0,0 +1,68 @@ +// The original ayaa and translation is stored in a translation view, +// so select the container and then, in that, select the texts. +// +// SeoText element has multiple divs, one text without diacritics +// and one text with diacritics. The one with diacritics appears +// to always show up as the last child, so use that one. +CONTAINER_SELECTOR = 'div[class^=TranslationView_container]'; +ORIGINAL_SELECTOR = 'div[class^=SeoText] div:last-of-type'; +TRANSLATION_SELECTOR = 'div[class^=TranslationText]'; +ACTION_TIMEOUT = 1000; + +ARAB_CODEPOINT_0 = 0x0660; +function arabic_number(nstr) { + let n = 0; + for (let char of nstr) { + n *= 10; + let digit = char.charCodeAt(0) - ARAB_CODEPOINT_0; + if (digit >= 0 && digit <= 9) + n += digit; + else + throw new Error("Invalid arabic numeral given in arabic_number"); + } + return n; +} +// Quran.com specific function, ayaa from the stored text +// has the number at the end of the text, so splitting by +// spaces and then extracting the last string gets the number +function ayaa_number(ayaa) { + return arabic_number(ayaa.split(' ').pop()); +} + +tsv_lines = {}; +keylen_check = -1; +keylen = 0; +function tsv_iterate() { + if (keylen_check == -1) { + keylen_check = 0; + window.scrollTo(0,0); + setTimeout(tsv_iterate, ACTION_TIMEOUT); + return; + } + keylen_check = keylen; + + containers = Array.from(document.querySelectorAll(CONTAINER_SELECTOR)); + originals = containers.map(e => e.querySelector(ORIGINAL_SELECTOR).innerText.replace(/\s+/, ' ')); + translations = containers.map(e => { + // Remove footnotes because they contribute to inner text, which we don't want + // Footnotes are enclosed in a "sup" element, so we can select based on this + node = e.querySelector(TRANSLATION_SELECTOR).cloneNode(true); + node.querySelectorAll('sup').forEach(e => e.remove()); + return node.innerText.replace(/\s+/, ' '); + }); + originals.forEach((e, i) => tsv_lines[e] = translations[i]); + + containers[containers.length-1].scrollIntoView(); + keylen = Object.keys(tsv_lines).length; + + if (keylen_check != keylen) { + setTimeout(tsv_iterate, ACTION_TIMEOUT); + } else { + tsv = Object.entries(tsv_lines) + .sort((a,b) => ayaa_number(a[0]) - ayaa_number(b[0])) + .map(e => e.join('\t')) + .join('\n'); + console.log(tsv); + } +} +tsv_iterate(); diff --git a/QuranComExtractSurah/README.md b/QuranComExtractSurah/README.md new file mode 100644 index 0000000..bd5f0cb --- /dev/null +++ b/QuranComExtractSurah/README.md @@ -0,0 +1,3 @@ +## Quran.com Surah Extraction + +Javascript to paste in dev console to extract surah and translation from quran.com/ as a TSV (for offline processing) diff --git a/RiichiWikiIntroExtract/README.md b/RiichiWikiIntroExtract/README.md new file mode 100644 index 0000000..0bd6e28 --- /dev/null +++ b/RiichiWikiIntroExtract/README.md @@ -0,0 +1,3 @@ +## Riichi Wiki Intro Extraction + +Extracting the intro of a Riichi wiki page (useful for importing Yakus from https://riichi.wiki/List_of_yaku into Anki for memorization) diff --git a/RiichiWikiIntroExtract/RiichiWikiIntroExtract.js b/RiichiWikiIntroExtract/RiichiWikiIntroExtract.js new file mode 100644 index 0000000..b4ec52d --- /dev/null +++ b/RiichiWikiIntroExtract/RiichiWikiIntroExtract.js @@ -0,0 +1,11 @@ +// Get nodes from the wiki page +nodes = Array.from(document.querySelector('.mw-parser-output').childNodes).filter(e => e.nodeType != Node.TEXT_NODE); + +// Extract the nodes corresponding to the intro of the page +desc = nodes.slice(nodes.findIndex(e => e.className == 'infobox') + 1, nodes.findIndex(e => e.id == 'toc')).map(e => e.cloneNode(true)); + +// For if you don't want links, just want the text in HTML form +// desc.forEach(e => e.querySelectorAll('a').forEach(a => { sp = document.createElement('span'); sp.innerHTML = a.innerHTML; a.replaceWith(sp); })); + +// Print out the HTML for use in Anki flash cards (or do anything else you want with the HTML) +console.log(desc.map(e => e.outerHTML).join('').replaceAll(/href="\//ig, "href=\"https://riichi.wiki/")); diff --git a/SelectiveDLLInit/README.md b/SelectiveDLLInit/README.md new file mode 100644 index 0000000..b58f27a --- /dev/null +++ b/SelectiveDLLInit/README.md @@ -0,0 +1,3 @@ +## Selective DLL Init + +Selectively initialize a DLL based on the exports of executable so that injections can be loaded in the injector itself diff --git a/SelectiveDLLInit/WindowsDLL.cpp b/SelectiveDLLInit/WindowsDLL.cpp new file mode 100644 index 0000000..01ad2ba --- /dev/null +++ b/SelectiveDLLInit/WindowsDLL.cpp @@ -0,0 +1,77 @@ +#define WIN32_LEAN_AND_MEAN +#include +#include +#include +#include +#include + +#define EXPORT_IGNORE "INJECTION_IGNORE" + +#define RvaTranslate(base, offset) ((ULONG_PTR)base + (ULONG_PTR)offset) +#define RvaTranslateT(t, base, offset) (t *)RvaTranslate(base, offset) + +typedef struct expdir +{ + DWORD ExportFlags; + DWORD TimeDateStamp; + WORD MajorVersion; + WORD MinorVersion; + DWORD NameRva; + DWORD OrdinalBase; + DWORD AddressTableEntries; + DWORD NumberOfNamePointers; + DWORD ExportAddressTableRva; + DWORD NamePointerRva; + DWORD OrdinalTableRva; +} +IMAGE_DATA_DIRECTORY_EXPORT; + +// Only x86_64 supported to keep things simple +static IMAGE_DOS_HEADER *GetExeBaseAddress(void) +{ + PTEB pteb = (PTEB)__readgsqword(0x30); + return (IMAGE_DOS_HEADER *)(((LPCVOID *)pteb->ProcessEnvironmentBlock)[2]); +} + +// Check for special export +static BOOL OnProcessAttach(void) +{ + IMAGE_DOS_HEADER *exehdr = GetExeBaseAddress(); + printf("Hello World! Image address=%p\n", exehdr); + IMAGE_NT_HEADERS *headers = RvaTranslateT(IMAGE_NT_HEADERS, exehdr, exehdr->e_lfanew); + if (headers->OptionalHeader.NumberOfRvaAndSizes == 0) + return FALSE; + IMAGE_DATA_DIRECTORY directory = headers->OptionalHeader.DataDirectory[0]; + if (directory.VirtualAddress == 0) + return FALSE; + IMAGE_DATA_DIRECTORY_EXPORT *ddexp = RvaTranslateT(IMAGE_DATA_DIRECTORY_EXPORT, exehdr, directory.VirtualAddress); + printf("Found Export directory table!\n"); + DWORD *nameptrs = RvaTranslateT(DWORD, exehdr, ddexp->NamePointerRva); + DWORD nameptrcount = ddexp->NumberOfNamePointers; + printf("Name pointers: %p,%u\n", nameptrs, nameptrcount); + + // EXEs don't normally export many names, so don't bother with bsearch + for (DWORD i = 0; i < nameptrcount; i++) { + const char *name = RvaTranslateT(const char, exehdr, nameptrs[i]); + printf("%s\n", name); + if (name != NULL && !strcmp(name, EXPORT_IGNORE)) + return TRUE; + } + + return FALSE; +} + +BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD fdwReason, LPVOID lpvReserved) +{ + switch (fdwReason) + { + case DLL_PROCESS_ATTACH: + BOOL marked = OnProcessAttach(); + if (marked) + printf("The process is marked with export '%s'. I will ignore it!\n", EXPORT_IGNORE); + else + printf("Injecting evil things into the process >:)\n"); + break; + } + return TRUE; +} diff --git a/SelectiveDLLInit/WindowsTarget.cpp b/SelectiveDLLInit/WindowsTarget.cpp new file mode 100644 index 0000000..0171405 --- /dev/null +++ b/SelectiveDLLInit/WindowsTarget.cpp @@ -0,0 +1,9 @@ +#define WIN32_LEAN_AND_MEAN +#include +#include +int main(void) +{ + fprintf(stderr, "Please don't hurt me...\n"); + LoadLibraryA("WindowsDLL.DLL"); + return 0; +} \ No newline at end of file diff --git a/SelectiveDLLInit/selectiveinit.cpp b/SelectiveDLLInit/selectiveinit.cpp new file mode 100644 index 0000000..623f36b --- /dev/null +++ b/SelectiveDLLInit/selectiveinit.cpp @@ -0,0 +1,16 @@ +#define WIN32_LEAN_AND_MEAN +#include + +#ifdef __cplusplus +#define EXPORT extern "C" __declspec(dllexport) +#else +#define EXPORT __declspec(dllexport) +#endif + +EXPORT void INJECTION_IGNORE(void) {} + +int main(void) +{ + LoadLibraryA("WindowsDLL.DLL"); + return 0; +} \ No newline at end of file diff --git a/TSDefragger/README.md b/TSDefragger/README.md new file mode 100644 index 0000000..38c04d9 --- /dev/null +++ b/TSDefragger/README.md @@ -0,0 +1,3 @@ +## MPEG-TS Packet Defragger + +Reassemble fragmented MPEG-TS packets from FFMPEG diff --git a/TSDefragger/TSDefragger.c b/TSDefragger/TSDefragger.c new file mode 100644 index 0000000..2331b4a --- /dev/null +++ b/TSDefragger/TSDefragger.c @@ -0,0 +1,142 @@ +/* + * FFMPEG and friends like to fragment big packets + * into datagrams that fit inside an ethernet MTU + * when sending to a UDP MPEG-TS stream. + * + * This is technically good practice, but FFMPEG receivers + * drop packets fragmented like this. Most video packets + * and some audio packets are fragmented like this. + * + * For localhost, the MTU can be made arbitrarily high, + * and IPv4 allows for packet fragmentation, so sending + * bigger packets is possible in most cases. + * + * Therefore, reassemble MPEG-TS packets and send them + * as singular datagrams so FFMPEG readers accept them. + */ +#include +#include +#include + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#pragma comment(lib, "ws2_32.lib") +#include +#include +#else +#error Linux not supported yet! +#endif + +#define SOCK_ERR_LIMIT 50 +#define SYNC_BYTE 0x47 +enum program_error { + ERROR_USAGE = 1, + ERROR_PARSE_SRC = 2, + ERROR_PARSE_DST = 3, + ERROR_SOCK_SRC = 4, + ERROR_SOCK_DST = 5, + ERROR_BIND_SRC = 6, + ERROR_COMMS = 7, + ERROR_PROG_EXIT = 8, + ERROR_WSA_INIT = 9, + ERROR_WSA_UNSUPPORTED = 10, +}; + +static int parse_addr(const char *url, SOCKADDR_IN *sin) { + if (!strncmp(url, "udp://", 6)) + url += 6; + uint8_t a[4]; + uint16_t p; + int nfields = sscanf(url, "%hhu.%hhu.%hhu.%hhu:%hu", a, a+1, a+2, a+3, &p); + + sin->sin_family = AF_INET; + sin->sin_port = htons(p); + memcpy(&sin->sin_addr, a, sizeof(sin->sin_addr)); + memset(&sin->sin_zero, 0, sizeof(sin->sin_zero)); + return nfields == 5; +} +int main(int argc, char **argv) { + // Parse arguments + SOCKADDR_IN src, dst; + if (argc != 3) { + fprintf(stderr, "Usage: %s SRC_URL DST_URL", *argv); + return ERROR_USAGE; + } else if (!parse_addr(argv[1], &src)) { + fprintf(stderr, "Source URL '%s' failed to parse!\n", argv[1]); + return ERROR_PARSE_SRC; + } else if (!parse_addr(argv[2], &dst)) { + fprintf(stderr, "Destination URL '%s' failed to parse!\n", argv[2]); + return ERROR_PARSE_DST; + } + +#if _WIN32 + WSADATA wsaData; + if (WSAStartup(MAKEWORD(2, 2), &wsaData)) { + fprintf(stderr, "WSAStartup failed!\n"); + return ERROR_WSA_INIT; + } + if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) { + fprintf(stderr, "WSAStartup does not support 2.2!\n"); + return ERROR_WSA_UNSUPPORTED; + } +#endif + + // Open sockets and bind to src + SOCKET ssock = socket(AF_INET, SOCK_DGRAM, 0); + if (ssock == INVALID_SOCKET) { + fprintf(stderr, "Source socket failed to create!\n"); + return ERROR_SOCK_SRC; + } + SOCKET dsock = socket(AF_INET, SOCK_DGRAM, 0); + if (dsock == INVALID_SOCKET) { + fprintf(stderr, "Destination socket failed to create!\n"); + return ERROR_SOCK_DST; + } + if (bind(ssock, (struct sockaddr *)&src, sizeof(src))) { + fprintf(stderr, "Failed to bind to destination URL '%s'\n", argv[2]); + return ERROR_BIND_SRC; + } + printf("%s -> %s flow started!\n", argv[1], argv[2]); + + // Main loop + static uint8_t buffer[65535]; + int sock_err_cnt = 0; + uint16_t top = 0; + while (1) { + // If there are excessive errors, just quit + if (sock_err_cnt > SOCK_ERR_LIMIT) { + fprintf(stderr, "Had %d consecutive socket errors! Exiting!\n"); + return ERROR_COMMS; + } + + // + int nbytes = recvfrom(ssock, buffer + top, sizeof(buffer) - top, 0, 0, 0); + if (nbytes < 0) { + fprintf(stderr, "Recvfrom failed!\n"); + sock_err_cnt++; + continue; + } + top += nbytes; + + for (uint16_t i = 1; i < top; i++) { + if (buffer[i] != SYNC_BYTE) + continue; + + nbytes = 0; + if (buffer[0] == SYNC_BYTE) + nbytes = sendto(dsock, buffer, i, 0, (struct sockaddr *)&dst, sizeof(dst)); + memmove(buffer, buffer + i, top - i); + top -= i; + i = 1; + + if (nbytes < 0) { + fprintf(stderr, "Sendto failed!\n"); + sock_err_cnt++; + break; + } + } + } + + // This shouldn't ever return + return ERROR_PROG_EXIT; +}