diff options
Diffstat (limited to 'image.c')
-rw-r--r-- | image.c | 116 |
1 files changed, 107 insertions, 9 deletions
diff --git a/image.c b/image.c index 57e3a38..a55c3a0 100644 --- a/image.c +++ b/image.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2018 Curtis McEnroe <june@causal.agency> +/* Copyright (C) 2018, 2019 C. McEnroe <june@causal.agency> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by @@ -16,6 +16,7 @@ #include <err.h> #include <fcntl.h> +#include <stdbool.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> @@ -25,6 +26,21 @@ #include <sysexits.h> #include <unistd.h> +#ifdef __FreeBSD__ +#include <sys/capsicum.h> +#endif + +#ifdef HAVE_KCGI +#include <sys/types.h> +#include <stdarg.h> +#include <stdint.h> +#include <kcgi.h> +#endif + +// XXX: Include this after kcgi.h to avoid conflicts. +// <https://github.com/kristapsdz/kcgi/pull/58> +#include <stdnoreturn.h> + #include "png.h" #include "torus.h" @@ -105,12 +121,12 @@ static void tilesMap(const char *path) { if (error) err(EX_OSERR, "madvise"); } -static void render(uint32_t tileX, uint32_t tileY) { +static void render(FILE *stream, uint32_t tileX, uint32_t tileY) { uint32_t width = CellCols * font.glyph.width; uint32_t height = CellRows * font.glyph.height; - pngHead(stdout, width, height, 8, PNGIndexed); - pngPalette(stdout, (uint8_t *)Palette, sizeof(Palette)); + pngHead(stream, width, height, 8, PNGIndexed); + pngPalette(stream, (uint8_t *)Palette, sizeof(Palette)); uint8_t data[height][1 + width]; memset(data, PNGNone, sizeof(data)); @@ -137,21 +153,96 @@ static void render(uint32_t tileX, uint32_t tileY) { } } - pngData(stdout, (uint8_t *)data, sizeof(data)); - pngTail(stdout); + pngData(stream, (uint8_t *)data, sizeof(data)); + pngTail(stream); } +#ifdef HAVE_KCGI + +enum { KeyX, KeyY, KeysLen }; +static const struct kvalid Keys[KeysLen] = { + [KeyX] = { .name = "x", .valid = kvalid_int }, + [KeyY] = { .name = "y", .valid = kvalid_int }, +}; + +enum { PageIndex, PagesLen }; +static const char *Pages[PagesLen] = { + [PageIndex] = "index", +}; + +static noreturn void errkcgi(int eval, enum kcgi_err code, const char *str) { + errx(eval, "%s: %s", str, kcgi_strerror(code)); +} + +static int streamWrite(void *cookie, const char *buf, int len) { + struct kreq *req = cookie; + enum kcgi_err error = khttp_write(req, buf, (size_t)len); + if (error) errkcgi(EX_IOERR, error, "khttp_write"); + return len; +} + +static void worker(void) { + struct kfcgi *fcgi; + enum kcgi_err error = khttp_fcgi_init( + &fcgi, Keys, KeysLen, Pages, PagesLen, PageIndex + ); + if (error) errkcgi(EX_CONFIG, error, "khttp_fcgi_init"); + + for (;;) { + struct kreq req; + error = khttp_fcgi_parse(fcgi, &req); + if (error) errkcgi(EX_DATAERR, error, "khttp_fcgi_parse"); + + uint32_t tileX = TileInitX; + uint32_t tileY = TileInitY; + + for (size_t i = 0; i < req.fieldsz; ++i) { + if (req.fields[i].state != KPAIR_VALID) continue; + if (req.fields[i].keypos == KeyX) { + tileX = (uint32_t)req.fields[i].parsed.i % TileCols; + } else if (req.fields[i].keypos == KeyY) { + tileY = (uint32_t)req.fields[i].parsed.i % TileRows; + } + } + + error = khttp_head( + &req, kresps[KRESP_STATUS], "%s", khttps[KHTTP_200] + ); + if (error) errkcgi(EX_IOERR, error, "khttp_head"); + + error = khttp_head( + &req, kresps[KRESP_CONTENT_TYPE], "%s", kmimetypes[KMIME_IMAGE_PNG] + ); + if (error) errkcgi(EX_IOERR, error, "khttp_head"); + + error = khttp_body(&req); + if (error) errkcgi(EX_IOERR, error, "khttp_body"); + + FILE *stream = fwopen(&req, streamWrite); + if (!stream) err(EX_OSERR, "fwopen"); + + render(stream, tileX, tileY); + + fclose(stream); + khttp_free(&req); + } +} + +#endif /* HAVE_KCGI */ + int main(int argc, char *argv[]) { + bool kcgi = false; const char *fontPath = "default8x16.psfu"; const char *dataPath = "torus.dat"; uint32_t tileX = TileInitX; uint32_t tileY = TileInitY; int opt; - while (0 < (opt = getopt(argc, argv, "d:f:x:y:"))) { + while (0 < (opt = getopt(argc, argv, "d:f:kx:y:"))) { switch (opt) { break; case 'd': dataPath = optarg; break; case 'f': fontPath = optarg; + break; case 'k': kcgi = true; break; case 'x': tileX = strtoul(optarg, NULL, 0) % TileCols; break; case 'y': tileY = strtoul(optarg, NULL, 0) % TileRows; break; default: return EX_USAGE; @@ -161,7 +252,14 @@ int main(int argc, char *argv[]) { fontLoad(fontPath); tilesMap(dataPath); - render(tileX, tileY); +#ifdef __FreeBSD__ + int error = cap_enter(); + if (error) err(EX_OSERR, "cap_enter"); +#endif + +#ifdef HAVE_KCGI + if (kcgi) worker(); +#endif - return EX_OK; + render(stdout, tileX, tileY); } |