* rename files, render_file -> file_main, render_node -> node_main, mandelbrot -> render_mandelbrot
authorTero Marttila <terom@fixme.fi>
Fri, 06 Jun 2008 23:37:45 +0300
changeset 12 43297144f196
parent 11 082bfaf38cf0
child 13 ee426f453cf5
* rename files, render_file -> file_main, render_node -> node_main, mandelbrot -> render_mandelbrot
* make the error message stuff in common a /lot/ neater (a single function and a set of macros)
* clean up rest of code to use those new macros

committer: Tero Marttila <terom@fixme.fi>
Makefile
common.c
common.h
file_main.c
http.c
mandelbrot.c
mandelbrot.h
node_main.c
render_file.c
render_local.c
render_mandelbrot.c
render_mandelbrot.h
render_node.c
web_main.c
--- a/Makefile	Fri Jun 06 18:35:46 2008 +0300
+++ b/Makefile	Fri Jun 06 23:37:45 2008 +0300
@@ -3,7 +3,7 @@
 
 EXECS = render_file web_main render_node
 
-all: render_file render_node web_main
+all: render_file render_node render_web
 
 common.o: common.c common.h
 http.o: http.c http.h
@@ -13,14 +13,15 @@
 render_remote.o: render_remote.c render_remote.h
 render_png.o: render_png.c render_png.h
 render_local.o: render_local.c render_local.h
+render_mandelbrot.o: render_mandelbrot.c render_mandelbrot.h
 
-render_file.o: render_file.c
-render_node.o: render_node.c
+file_main.o: file_main.c
+node_main.o: node_main.c
 web_main.o: web_main.c
 
-render_file: render_file.o common.o render.o render_png.o render_local.o mandelbrot.o
-render_node: render_node.o common.o render.o render_png.o render_local.o mandelbrot.o
-web_main: web_main.o common.o http.o render.o remote_node.o remote_pool.o render_remote.o
+render_file: file_main.o common.o render.o render_png.o render_local.o render_mandelbrot.o
+render_node: node_main.o common.o render.o render_png.o render_local.o render_mandelbrot.o
+render_web: web_main.o common.o http.o render.o remote_node.o remote_pool.o render_remote.o
 
 clean :
 	rm *.o ${EXECS}
--- a/common.c	Fri Jun 06 18:35:46 2008 +0300
+++ b/common.c	Fri Jun 06 23:37:45 2008 +0300
@@ -7,75 +7,23 @@
 
 #include "common.h"
 
-void die (const char *msg) {
-    perror(msg);
-    exit(EXIT_FAILURE);
-}
-
-void error (const char *fmt, ...) {
+void _generic_err (const char *func, int perr, int do_exit, const char *fmt, ...) {
     va_list va;
-
-    va_start(va, fmt);
-    vfprintf(stderr, fmt, va);
-    va_end(va);
-
-    fprintf(stderr, "\n");
-}
-
-void perr (const char *fmt, ...) {
-    va_list va;
-
-    va_start(va, fmt);
-    vfprintf(stderr, fmt, va);
-    va_end(va);
-
-    fprintf(stderr, ": %s\n", strerror(errno));
-}
-
-void perr_exit (const char *fmt, ...) {
-    va_list va;
-
+    
+    if (func)
+        fprintf(stderr, "%s: ", func);
+ 
     va_start(va, fmt);
     vfprintf(stderr, fmt, va);
     va_end(va);
-
-    fprintf(stderr, ": %s\n", strerror(errno));
-    exit(EXIT_FAILURE);
-}
-
-void err_exit (const char *fmt, ...) {
-    va_list va;
-
-    va_start(va, fmt);
-    vfprintf(stderr, fmt, va);
-    va_end(va);
+   
+    if (perr)
+        fprintf(stderr, ": %s\n", strerror(errno));
 
     fprintf(stderr, "\n");
-    exit(EXIT_FAILURE);
-}
-
-void err_func (const char *func, const char *fmt, ...) {
-    va_list va;
     
-    fprintf(stderr, "%s: ", func);
-
-    va_start(va, fmt);
-    vfprintf(stderr, fmt, va);
-    va_end(va);
-
-    fprintf(stderr, "\n");
-}
-
-void perr_func (const char *func, const char *fmt, ...) {
-    va_list va;
-    
-    fprintf(stderr, "%s: ", func);
-
-    va_start(va, fmt);
-    vfprintf(stderr, fmt, va);
-    va_end(va);
-
-    fprintf(stderr, ": %s\n", strerror(errno));
+    if (do_exit)
+        exit(EXIT_FAILURE);
 }
 
 int parse_hostport (char *hostport, char **host, char **port) {
--- a/common.h	Fri Jun 06 18:35:46 2008 +0300
+++ b/common.h	Fri Jun 06 23:37:45 2008 +0300
@@ -3,32 +3,25 @@
  * error handling
  */
 
-// perror + exit
-void die (const char *msg);
-
-// fprintf + newline
-void error (const char *fmt, ...);
-
-// fprintf + strerror + newline
-void perr (const char *fmt, ...);
+void _generic_err (const char *func, int perr, int do_exit, const char *fmt, ...);
 
-// fprintf + strerror + newline + exit
-void perr_exit (const char *fmt, ...);
-
-// fprintf + newline + exit
-void err_exit (const char *fmt, ...);
-
-// fprintf (__func__ + msg, ...)
-void err_func (const char *func, const char *fmt, ...);
-
-// fprintf (__func__ + msg + strerror, ...)
-void perr_func (const char *func, const char *fmt, ...);
+// various kinds of ways to handle an error, 2**3 of them, *g*
+#define error(...)                  _generic_err(NULL, 0, 0, __VA_ARGS__)
+#define err_exit(...)               _generic_err(NULL, 0, 1, __VA_ARGS__)
+#define perr(...)                   _generic_err(NULL, 1, 0, __VA_ARGS__)
+#define perr_exit(...)              _generic_err(NULL, 1, 1, __VA_ARGS__)
+#define err_func(func, ...)         _generic_err(func, 0, 0, __VA_ARGS__)
+#define err_func_exit(func, ...)    _generic_err(func, 0, 1, __VA_ARGS__)
+#define perr_func(func, ...)        _generic_err(func, 1, 0, __VA_ARGS__)
+#define perr_func_exit(func, ...)   _generic_err(func, 1, 1, __VA_ARGS__)
 
 // error(func + colon + msg, ...) + goto error
-#define ERROR(msg) do { err_func(__func__, "%s", msg); goto error; } while (0)
-#define ERROR_FMT(fmt, ...) do { err_func(__func__, fmt, __VA_ARGS__); goto error; } while (0)
-#define PERROR(msg) do { perr_func(__func__, "%s", msg); goto error; } while (0)
-#define PERROR_FMT(fmt, ...) do { perr_func(__func__, fmt, __VA_ARGS__); goto error; } while (0)
+#define ERROR(...) do { err_func(__func__, __VA_ARGS__); goto error; } while (0)
+#define PERROR(...) do { perr_func(__func__, __VA_ARGS__); goto error; } while (0)
+#define FATAL(...) err_func_exit(__func__, __VA_ARGS__)
+#define PFATAL(...) perr_func_exit(__func__, __VA_ARGS__)
+#define WARNING(...) err_func(__func__, __VA_ARGS__)
+#define PWARNING(...) perr_func(__func__, __VA_ARGS__)
 
 /*
  * Parse a host:port string.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/file_main.c	Fri Jun 06 23:37:45 2008 +0300
@@ -0,0 +1,191 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+#include "common.h"
+#include "render.h"
+#include "render_local.h"
+
+static int verbose;
+
+int render_file_local (struct render *ctx, FILE *fh) {
+    double duration;
+
+    if (render_io_stream(ctx, fh))
+        ERROR("render_io_stream");
+
+    if (render_local(ctx, &duration))
+        ERROR("render_local");
+
+    if (verbose) {
+        u_int32_t img_w, img_h;
+
+        if (render_get_size(ctx, &img_w, &img_h))
+            ERROR("render_get_size");
+
+        fprintf(stdout, "rendered %dx%d mandelbrot in %f seconds\n", img_w, img_h, duration);
+    }
+    
+    return 0;
+    
+error:
+    return -1;
+}
+
+int main (int argc, char **argv) {
+    int error = 1;
+
+    struct render *ctx = NULL;
+
+    // parse arguments
+    int opt;
+    FILE *output = NULL;
+    int img_w = 256, img_h = 256;
+
+    while ((opt = getopt(argc, argv, "w:h:o:v")) != -1) {
+        switch(opt) {
+            case 'w' :
+                img_w = atoi(optarg);
+                break;
+
+            case 'h' :
+                img_h = atoi(optarg);
+                break;
+
+            case 'o' :
+                if (output)
+                    err_exit("Only use -o once");
+
+                output = fopen(optarg, "w");
+
+                if (!output)
+                    PFATAL("fopen: %s", optarg);
+
+                break;
+
+            case 'v' :
+                verbose = 1;
+                break;
+
+
+            default :
+                err_exit("Usage: %s [-w img_w] [-h img_h] [-o output_file] [-v]", argv[0]);
+        }
+    }
+
+    if (!output)
+        output = stdout;
+    
+    // setup the struct render
+    if (!(ctx = render_alloc()))
+        ERROR("render_alloc");
+
+    if (render_set_mode(ctx, RENDER_PNG))
+        ERROR("render_set_mode");
+
+    if (render_set_size(ctx, img_w, img_h))
+        ERROR("render_set_size");
+
+    if (render_region_full(ctx))
+        ERROR("render_region_full");
+    
+    // do the render!
+    if (verbose)
+        fprintf(stderr, "Render [%dx%d] mandelbrot locally...\n", img_w, img_h);
+    
+    if (render_file_local(ctx, output))
+        ERROR("render_local");
+    
+    // success
+    error = 0;
+
+error:
+    if (output)
+        fclose(output);
+
+    free(ctx);
+
+    return error;
+}
+
+#if 0
+void render_remote (int img_w, int img_h, FILE *output, FILE *remote) {
+    render_t ctx;
+    struct render_cmd cmd;
+
+    render_init(&ctx, RENDER_PNG);
+    render_set_size(&ctx, img_w, img_h);
+    render_region_full(&ctx);
+
+    if (render_cmd_build(&ctx, &cmd))
+        err_exit("mandelbrot_render_remote failed");
+
+    int ret = fwrite((void *) &cmd, sizeof(cmd), 1, remote);
+    
+    if (ret != 1)
+        perr_exit("fwrite(remote)");
+        
+    if (verbose)
+        printf("sent render command of %zu bytes\n", sizeof(cmd));
+
+    // shuffle data around
+    while (!feof(remote)) {
+        char buf[1024];
+
+        int bytes = fread(buf, 1, sizeof(buf), remote);
+
+        if (bytes)
+            if (fwrite(buf, bytes, 1, output) != 1)
+                perr_exit("fwrite(output)");
+    }
+    
+    if (verbose)
+        printf("got PNG data\n");
+
+    if (ferror(remote))
+        perr_exit("fread(remote)");
+}
+
+FILE *open_remote (char *remote) {
+    char *addr_str, *port_str = NULL;
+
+    addr_str = strsep(&remote, ":");
+
+    if (remote)
+        port_str = remote;
+    
+    struct sockaddr_in addr;
+
+    addr.sin_family = AF_INET;
+    addr.sin_port = htons(port_str ? atoi(port_str) : RENDER_PORT);
+    
+    if (inet_aton(addr_str, &addr.sin_addr) == 0)
+        err_exit("invalid address: %s", addr_str);
+
+    int sock;
+    
+    if ((sock = socket(PF_INET, SOCK_STREAM, 0)) == -1)
+        perr_exit("socket");
+
+    if (verbose)
+        printf("connect(%s, %d)\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
+    
+    if (connect(sock, (const struct sockaddr *) &addr, sizeof(addr)) == -1)
+        perr_exit("connect(%s, %d)", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
+    
+    FILE *fh = fdopen(sock, "w+");
+
+    if (!fh || ferror(fh))
+        perr_exit("fdopen");
+
+    setbuffer(fh, NULL, 0);
+
+    return fh;
+}
+#endif
+
+
--- a/http.c	Fri Jun 06 18:35:46 2008 +0300
+++ b/http.c	Fri Jun 06 23:37:45 2008 +0300
@@ -9,10 +9,8 @@
 
 int http_qarg_parse (struct evhttp_request *request, struct http_qarg *qarg_spec) {
     // our return code
-    int error_flag = 0;
+    int error = -1;
 
-#define ERROR(msg, ...) do { error("http_qarg_parse: " msg, __VA_ARGS__); error_flag = -1; goto error; } while (0)
-    
     // get the uri from the request
     const char *uri = evhttp_request_get_uri(request);
     
@@ -41,7 +39,7 @@
                         int_val = strtol(qarg->value, &cptr, 10);
 
                         if (*qarg->value == '\0' || *cptr != '\0' || int_val < 0)
-                            ERROR("Invalid QARG_UINT: %s: %s -> %d", qarg->key, qarg->value, int_val);
+                            ERROR("invalid QARG_UINT: %s: %s -> %d", qarg->key, qarg->value, int_val);
 
                         *((unsigned long int *) qarg_info->hqa_addr) = (unsigned long int) int_val;
 
@@ -51,17 +49,18 @@
                         ERROR("QARG_INVALID: %s: %s", qarg->key, qarg->value);
 
                     default :
-                        err_exit("http_qarg_parse: Invalid qarg_info->hqa_type: %d", qarg_info->hqa_type);
+                        FATAL("invalid qarg_info->hqa_type: %d", qarg_info->hqa_type);
                 }
             }
         }
     }
-
-#undef ERROR    
+    
+    // success
+    error = 0;
 error:    
 
     // clean up the qargs (badly named functions :< )
     evhttp_clear_headers(&qargs);
     
-    return error_flag;
+    return error;
 }
--- a/mandelbrot.c	Fri Jun 06 18:35:46 2008 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-#include <stdlib.h>
-#include <time.h>
-
-#include "render_internal.h"
-#include "mandelbrot.h"
-#include "common.h"
-
-#define DETAIL 255
-
-#define absdelta(a, b) (a>b ? a-b : b-a)
-
-int render_mandelbrot (struct render *ctx) {
-    // render algorithm vars
-    u_int32_t img_x, img_y;
-    double x0, y0, x, y, _x, _y, w_scale, h_scale;
-    u_int8_t iter;
-    u_int8_t *row;
-
-    // calcluate the scale factors
-    w_scale = ctx->img_w/absdelta(ctx->x1, ctx->x2);
-    h_scale = ctx->img_h/absdelta(ctx->y1, ctx->y2);
-    
-    // start rendering!
-    for (img_y=0; img_y < ctx->img_h; img_y++) {
-        // render the current row
-        for (img_x=0; img_x < ctx->img_w; img_x++) {
-            x = 0;
-            y = 0;
-            x0 = img_x/w_scale + ctx->x1;
-            y0 = img_y/h_scale + ctx->y1;
-            iter = DETAIL; 
-
-            while (x*x + y*y < (2*2) && iter > 0) {
-                _x = x*x - y*y + x0;
-                _y = 2*x*y + y0;
-
-                x = _x;
-                y = _y;
-
-                iter--;
-            }
-            
-            (*ctx->local_rowbuf_addr)[img_x] = iter;
-        }
-
-        // row cb
-        if (ctx->local_row_fn(ctx->cb_arg, (*ctx->local_rowbuf_addr)))
-            ERROR("local_row_fn");
-    }
-   
-    // return succesfully
-    return 0;
-
-error:
-    return -1;
-}
-
-int render_mandelbrot_timed (struct render *ctx, double *duration) {
-    clock_t t1 = clock();
-    int ret = render_mandelbrot(ctx);
-    clock_t t2 = clock();
-
-    *duration = ((double)(t2 - t1))/CLOCKS_PER_SEC;
-
-    return ret;
-}
-
--- a/mandelbrot.h	Fri Jun 06 18:35:46 2008 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,18 +0,0 @@
-#include "render.h"
-
-/*
- * the mandelbrot-rendering algorithm
- */
-
-/*
- * return codes for mandelbrot_render
- */
-#define MANDELBROT_OK 0
-#define MANDELBROT_ERR 1
-
-/*
- * Render the image specified by the given render context
- */
-int render_mandelbrot (struct render *ctx);
-int render_mandelbrot_timed (struct render *ctx, double *duration);
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/node_main.c	Fri Jun 06 23:37:45 2008 +0300
@@ -0,0 +1,191 @@
+#include <stdio.h>
+#include <sys/types.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "common.h"
+#include "render.h"
+#include "render_remote.h"  // for RENDER_PORT_NAME
+#include "render_local.h"
+
+void sigpipe_handler (int signal) {
+    /* ignore */
+    fprintf(stderr, "SIGPIPE\n");
+}
+
+void sigpipe_ignore () {
+    struct sigaction sigpipe_action;
+
+    memset(&sigpipe_action, 0, sizeof(sigpipe_action));
+    sigpipe_action.sa_handler = SIG_IGN;
+
+    if (sigaction(SIGPIPE, &sigpipe_action, NULL))
+        perr_exit("sigaction");
+}
+
+int my_fread(FILE *fh, void *ptr, size_t size) {
+    int ret = fread(ptr, size, 1, fh);
+    
+    if (ret == 0) {
+        error("EOF");
+        return 0;
+
+    } else if (ret != 1) {
+        perror("fread");
+        return 0;
+    }
+
+    return 1;
+}
+
+int read_byte (FILE *fh, u_int8_t *byte) {
+    return my_fread(fh, byte, sizeof(*byte));
+}
+
+int read_int (FILE *fh, u_int32_t *i) {
+    if (!my_fread(fh, i, sizeof(*i)))
+        return 0;
+
+    *i = ntohl(*i);
+
+    return 1;
+}
+
+int read_double (FILE *fh, double *dbl) {
+    if (!my_fread(fh, dbl, sizeof(*dbl)))
+        return 0;
+
+    return 1;
+}
+
+void handle_client (int sock) {
+    double duration;
+    struct render *ctx;
+    FILE *fh;
+    u_int8_t mode;
+    u_int32_t img_w, img_h;
+    double x1, y1, x2, y2;
+
+    
+    // open it as a FILE*
+    if (!(fh = fdopen(sock, "r+")))
+        ERROR("fdopen");
+    
+    // read the parameters
+    if (
+            !read_byte(fh, &mode)
+         || !read_int(fh, &img_w)
+         || !read_int(fh, &img_h)
+         || !read_double(fh, &x1)
+         || !read_double(fh, &y1)
+         || !read_double(fh, &x2)
+         || !read_double(fh, &y2)
+    )
+        ERROR("read_{byte,int,double}");
+
+    printf("RENDER: [%ux%u] (%f, %f) -> (%f, %f): ... ", img_w, img_h, x1, y1, x2, y2);
+    fflush(stdout);
+
+    // set up the render_ctx
+    if (!(ctx = render_alloc()))
+        ERROR("render_alloc");
+
+    if (render_set_mode(ctx, mode))
+        ERROR("render_set_mode");
+
+    if (render_set_size(ctx, img_w, img_h))
+        ERROR("render_set_size");
+
+    if (render_region_raw(ctx, x1, y1, x2, y2))
+        ERROR("render_region_raw");
+
+    if (render_io_stream(ctx, fh))
+        ERROR("render_io_stream");
+  
+    
+    // render!
+    if (render_local(ctx, &duration))
+        ERROR("render_local");
+
+    printf("time=%fs\n", duration);
+
+error:
+    // close the FILE* and socket
+    fclose(fh);
+    
+    return;
+}
+
+
+int main (int argc, char** argv) {
+    int ssock, sock;
+    struct sockaddr_in addr;
+    socklen_t addr_len;
+    
+    // parse arguments
+    int opt;
+    const char *port_name = NULL;
+    unsigned short port;
+
+    while ((opt = getopt(argc, argv, "l:")) != -1) {
+        switch (opt) {
+            case 'l':
+                if (port_name)
+                    ERROR("only specify -l once");
+
+                port_name = optarg;
+                break;
+
+            default:
+                err_exit("Usage: %s [-l port]", argv[0]);
+        }
+    }
+    
+    // post-process arguments
+    if (!port_name)
+        port_name = RENDER_PORT_NAME;
+
+    if (!(port = atoi(port_name)))
+        ERROR("invalid port: %s", port_name);
+
+    // create the socket
+    if ((ssock = socket(PF_INET, SOCK_STREAM, 0)) == -1)
+        PERROR("socket");
+
+    addr.sin_family = AF_INET;
+    addr.sin_port = htons(port);
+    addr.sin_addr.s_addr = INADDR_ANY;
+
+    if (bind(ssock, (struct sockaddr *) &addr, sizeof(struct sockaddr_in)) == -1)
+        PERROR("bind");
+    
+    if (listen(ssock, 1) == -1)
+        PERROR("listen");
+    
+    // ignore sigpipe
+    sigpipe_ignore();
+    
+    // main accept loop
+    printf("RUN: %s:%hu\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
+
+    while (1) {
+        addr_len = sizeof(struct sockaddr_in);
+
+        // accept a new client
+        if ((sock = accept(ssock, (struct sockaddr *) &addr, &addr_len)) == -1)
+            PERROR("accept");
+        
+        printf("ACCEPT: %s:%hu\n", inet_ntoa(addr.sin_addr), addr.sin_port);
+        
+        // handle their resquest
+        handle_client(sock);
+    }
+
+error:
+    return 1;
+}
+
--- a/render_file.c	Fri Jun 06 18:35:46 2008 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,191 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
-
-#include "common.h"
-#include "render.h"
-#include "render_local.h"
-
-static int verbose;
-
-int render_file_local (struct render *ctx, FILE *fh) {
-    double duration;
-
-    if (render_io_stream(ctx, fh))
-        ERROR("render_io_stream");
-
-    if (render_local(ctx, &duration))
-        ERROR("render_local");
-
-    if (verbose) {
-        u_int32_t img_w, img_h;
-
-        if (render_get_size(ctx, &img_w, &img_h))
-            ERROR("render_get_size");
-
-        fprintf(stdout, "rendered %dx%d mandelbrot in %f seconds\n", img_w, img_h, duration);
-    }
-    
-    return 0;
-    
-error:
-    return -1;
-}
-
-int main (int argc, char **argv) {
-    int error = 1;
-
-    struct render *ctx = NULL;
-
-    // parse arguments
-    int opt;
-    FILE *output = NULL;
-    int img_w = 256, img_h = 256;
-
-    while ((opt = getopt(argc, argv, "w:h:o:v")) != -1) {
-        switch(opt) {
-            case 'w' :
-                img_w = atoi(optarg);
-                break;
-
-            case 'h' :
-                img_h = atoi(optarg);
-                break;
-
-            case 'o' :
-                if (output)
-                    err_exit("Only use -o once");
-
-                output = fopen(optarg, "w");
-
-                if (!output)
-                    die(optarg);
-
-                break;
-
-            case 'v' :
-                verbose = 1;
-                break;
-
-
-            default :
-                err_exit("Usage: %s [-w img_w] [-h img_h] [-o output_file] [-v]", argv[0]);
-        }
-    }
-
-    if (!output)
-        output = stdout;
-    
-    // setup the struct render
-    if (!(ctx = render_alloc()))
-        ERROR("render_alloc");
-
-    if (render_set_mode(ctx, RENDER_PNG))
-        ERROR("render_set_mode");
-
-    if (render_set_size(ctx, img_w, img_h))
-        ERROR("render_set_size");
-
-    if (render_region_full(ctx))
-        ERROR("render_region_full");
-    
-    // do the render!
-    if (verbose)
-        fprintf(stderr, "Render [%dx%d] mandelbrot locally...\n", img_w, img_h);
-    
-    if (render_file_local(ctx, output))
-        ERROR("render_local");
-    
-    // success
-    error = 0;
-
-error:
-    if (output)
-        fclose(output);
-
-    free(ctx);
-
-    return error;
-}
-
-#if 0
-void render_remote (int img_w, int img_h, FILE *output, FILE *remote) {
-    render_t ctx;
-    struct render_cmd cmd;
-
-    render_init(&ctx, RENDER_PNG);
-    render_set_size(&ctx, img_w, img_h);
-    render_region_full(&ctx);
-
-    if (render_cmd_build(&ctx, &cmd))
-        err_exit("mandelbrot_render_remote failed");
-
-    int ret = fwrite((void *) &cmd, sizeof(cmd), 1, remote);
-    
-    if (ret != 1)
-        perr_exit("fwrite(remote)");
-        
-    if (verbose)
-        printf("sent render command of %zu bytes\n", sizeof(cmd));
-
-    // shuffle data around
-    while (!feof(remote)) {
-        char buf[1024];
-
-        int bytes = fread(buf, 1, sizeof(buf), remote);
-
-        if (bytes)
-            if (fwrite(buf, bytes, 1, output) != 1)
-                perr_exit("fwrite(output)");
-    }
-    
-    if (verbose)
-        printf("got PNG data\n");
-
-    if (ferror(remote))
-        perr_exit("fread(remote)");
-}
-
-FILE *open_remote (char *remote) {
-    char *addr_str, *port_str = NULL;
-
-    addr_str = strsep(&remote, ":");
-
-    if (remote)
-        port_str = remote;
-    
-    struct sockaddr_in addr;
-
-    addr.sin_family = AF_INET;
-    addr.sin_port = htons(port_str ? atoi(port_str) : RENDER_PORT);
-    
-    if (inet_aton(addr_str, &addr.sin_addr) == 0)
-        err_exit("invalid address: %s", addr_str);
-
-    int sock;
-    
-    if ((sock = socket(PF_INET, SOCK_STREAM, 0)) == -1)
-        perr_exit("socket");
-
-    if (verbose)
-        printf("connect(%s, %d)\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
-    
-    if (connect(sock, (const struct sockaddr *) &addr, sizeof(addr)) == -1)
-        perr_exit("connect(%s, %d)", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
-    
-    FILE *fh = fdopen(sock, "w+");
-
-    if (!fh || ferror(fh))
-        perr_exit("fdopen");
-
-    setbuffer(fh, NULL, 0);
-
-    return fh;
-}
-#endif
-
-
--- a/render_local.c	Fri Jun 06 18:35:46 2008 +0300
+++ b/render_local.c	Fri Jun 06 23:37:45 2008 +0300
@@ -1,19 +1,23 @@
 #include <stdlib.h>
+#include <time.h>
 #include <assert.h>
 
 #include "common.h"
 #include "render_internal.h"
 #include "render_local.h"
 #include "render_png.h"
-#include "mandelbrot.h"
+#include "render_mandelbrot.h"
 
 int render_local (struct render *render, double *duration) {
     assert(render->mode == RENDER_PNG);
 
     unsigned char *rowbuf = NULL;
     struct render_png *png_ctx = NULL;
+    clock_t t1, t2;
 
-    *duration = -1;
+    
+    if (duration)
+        *duration = -1;
 
     // alloc the memory buffer
     if (!(rowbuf = malloc(render->img_w)))
@@ -28,9 +32,17 @@
         ERROR("render_local_mem");
    
     // then we can actually render
-    if (duration ? render_mandelbrot_timed(render, duration) : render_mandelbrot(render))
+    t1 = clock();
+
+    if (render_mandelbrot(render))
         ERROR("render_mandelbrot");
 
+    t2 = clock();
+    
+    // calculate the time taken
+    if (duration)
+        *duration = ((double)(t2 - t1))/CLOCKS_PER_SEC;
+
     // success
     return 0;
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/render_mandelbrot.c	Fri Jun 06 23:37:45 2008 +0300
@@ -0,0 +1,54 @@
+
+#include "common.h"
+#include "render_internal.h"
+#include "render_mandelbrot.h"
+
+#define DETAIL 255
+
+#define absdelta(a, b) (a>b ? a-b : b-a)
+
+int render_mandelbrot (struct render *ctx) {
+    // render algorithm vars
+    u_int32_t img_x, img_y;
+    double x0, y0, x, y, _x, _y, w_scale, h_scale;
+    u_int8_t iter;
+
+    // calcluate the scale factors
+    w_scale = ctx->img_w/absdelta(ctx->x1, ctx->x2);
+    h_scale = ctx->img_h/absdelta(ctx->y1, ctx->y2);
+    
+    // start rendering!
+    for (img_y=0; img_y < ctx->img_h; img_y++) {
+        // render the current row
+        for (img_x=0; img_x < ctx->img_w; img_x++) {
+            x = 0;
+            y = 0;
+            x0 = img_x/w_scale + ctx->x1;
+            y0 = img_y/h_scale + ctx->y1;
+            iter = DETAIL; 
+
+            while (x*x + y*y < (2*2) && iter > 0) {
+                _x = x*x - y*y + x0;
+                _y = 2*x*y + y0;
+
+                x = _x;
+                y = _y;
+
+                iter--;
+            }
+            
+            (*ctx->local_rowbuf_addr)[img_x] = iter;
+        }
+
+        // row cb
+        if (ctx->local_row_fn(ctx->cb_arg, (*ctx->local_rowbuf_addr)))
+            ERROR("local_row_fn");
+    }
+   
+    // return succesfully
+    return 0;
+
+error:
+    return -1;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/render_mandelbrot.h	Fri Jun 06 23:37:45 2008 +0300
@@ -0,0 +1,17 @@
+#include "render.h"
+
+/*
+ * the mandelbrot-rendering algorithm
+ */
+
+/*
+ * return codes for mandelbrot_render
+ */
+#define MANDELBROT_OK 0
+#define MANDELBROT_ERR 1
+
+/*
+ * Render the image specified by the given render context
+ */
+int render_mandelbrot (struct render *ctx);
+
--- a/render_node.c	Fri Jun 06 18:35:46 2008 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,192 +0,0 @@
-#include <stdio.h>
-#include <sys/types.h>
-#include <arpa/inet.h>
-#include <sys/socket.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "common.h"
-#include "render.h"
-#include "render_remote.h"
-#include "render_local.h"
-#include "mandelbrot.h"
-
-void sigpipe_handler (int signal) {
-    /* ignore */
-    fprintf(stderr, "SIGPIPE\n");
-}
-
-void sigpipe_ignore () {
-    struct sigaction sigpipe_action;
-
-    memset(&sigpipe_action, 0, sizeof(sigpipe_action));
-    sigpipe_action.sa_handler = SIG_IGN;
-
-    if (sigaction(SIGPIPE, &sigpipe_action, NULL))
-        perr_exit("sigaction");
-}
-
-int my_fread(FILE *fh, void *ptr, size_t size) {
-    int ret = fread(ptr, size, 1, fh);
-    
-    if (ret == 0) {
-        error("EOF");
-        return 0;
-
-    } else if (ret != 1) {
-        perror("fread");
-        return 0;
-    }
-
-    return 1;
-}
-
-int read_byte (FILE *fh, u_int8_t *byte) {
-    return my_fread(fh, byte, sizeof(*byte));
-}
-
-int read_int (FILE *fh, u_int32_t *i) {
-    if (!my_fread(fh, i, sizeof(*i)))
-        return 0;
-
-    *i = ntohl(*i);
-
-    return 1;
-}
-
-int read_double (FILE *fh, double *dbl) {
-    if (!my_fread(fh, dbl, sizeof(*dbl)))
-        return 0;
-
-    return 1;
-}
-
-void handle_client (int sock) {
-    double duration;
-    struct render *ctx;
-    FILE *fh;
-    u_int8_t mode;
-    u_int32_t img_w, img_h;
-    double x1, y1, x2, y2;
-
-    
-    // open it as a FILE*
-    if (!(fh = fdopen(sock, "r+")))
-        ERROR("fdopen");
-    
-    // read the parameters
-    if (
-            !read_byte(fh, &mode)
-         || !read_int(fh, &img_w)
-         || !read_int(fh, &img_h)
-         || !read_double(fh, &x1)
-         || !read_double(fh, &y1)
-         || !read_double(fh, &x2)
-         || !read_double(fh, &y2)
-    )
-        ERROR("read_{byte,int,double}");
-
-    printf("RENDER: [%ux%u] (%f, %f) -> (%f, %f): ... ", img_w, img_h, x1, y1, x2, y2);
-    fflush(stdout);
-
-    // set up the render_ctx
-    if (!(ctx = render_alloc()))
-        ERROR("render_alloc");
-
-    if (render_set_mode(ctx, mode))
-        ERROR("render_set_mode");
-
-    if (render_set_size(ctx, img_w, img_h))
-        ERROR("render_set_size");
-
-    if (render_region_raw(ctx, x1, y1, x2, y2))
-        ERROR("render_region_raw");
-
-    if (render_io_stream(ctx, fh))
-        ERROR("render_io_stream");
-  
-    
-    // render!
-    if (render_local(ctx, &duration))
-        ERROR("render_local");
-
-    printf("time=%fs\n", duration);
-
-error:
-    // close the FILE* and socket
-    fclose(fh);
-    
-    return;
-}
-
-
-int main (int argc, char** argv) {
-    int ssock, sock;
-    struct sockaddr_in addr;
-    socklen_t addr_len;
-    
-    // parse arguments
-    int opt;
-    const char *port_name = NULL;
-    unsigned short port;
-
-    while ((opt = getopt(argc, argv, "l:")) != -1) {
-        switch (opt) {
-            case 'l':
-                if (port_name)
-                    ERROR("only specify -l once");
-
-                port_name = optarg;
-                break;
-
-            default:
-                err_exit("Usage: %s [-l port]", argv[0]);
-        }
-    }
-    
-    // post-process arguments
-    if (!port_name)
-        port_name = RENDER_PORT_NAME;
-
-    if (!(port = atoi(port_name)))
-        ERROR_FMT("invalid port: %s", port_name);
-
-    // create the socket
-    if ((ssock = socket(PF_INET, SOCK_STREAM, 0)) == -1)
-        PERROR("socket");
-
-    addr.sin_family = AF_INET;
-    addr.sin_port = htons(port);
-    addr.sin_addr.s_addr = INADDR_ANY;
-
-    if (bind(ssock, (struct sockaddr *) &addr, sizeof(struct sockaddr_in)) == -1)
-        PERROR("bind");
-    
-    if (listen(ssock, 1) == -1)
-        PERROR("listen");
-    
-    // ignore sigpipe
-    sigpipe_ignore();
-    
-    // main accept loop
-    printf("RUN: %s:%hu\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
-
-    while (1) {
-        addr_len = sizeof(struct sockaddr_in);
-
-        // accept a new client
-        if ((sock = accept(ssock, (struct sockaddr *) &addr, &addr_len)) == -1)
-            PERROR("accept");
-        
-        printf("ACCEPT: %s:%hu\n", inet_ntoa(addr.sin_addr), addr.sin_port);
-        
-        // handle their resquest
-        handle_client(sock);
-    }
-
-error:
-    return 1;
-}
-
--- a/web_main.c	Fri Jun 06 18:35:46 2008 +0300
+++ b/web_main.c	Fri Jun 06 23:37:45 2008 +0300
@@ -1,18 +1,25 @@
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
 #include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <netinet/ip.h>
+#include <arpa/inet.h>
 #include <signal.h>
-#include <string.h>
 #include <unistd.h>
 
 #include <event2/event.h>
 #include <event2/event_compat.h>
+#include <event2/http.h>
 #include <event2/event_struct.h>
 
+#include "common.h"
+#include "http.h"
 #include "render.h"
 #include "render_remote.h"
 #include "remote_node.h"
 #include "remote_pool.h"
-#include "http.h"
-#include "common.h"
 
 #define MIN_CHUNK_SIZE 4096
 #define OVERFLOW_BUFFER 4096
@@ -156,11 +163,6 @@
 }
 
 void _http_render_execute (struct evhttp_request *request, u_int32_t img_w, u_int32_t img_h) {
-    // error message
-    const char *errmsg = NULL;
-
-#define ERROR(msg) do { errmsg = msg; goto error; } while (0)
-
     // render request context
     struct render_request *req_ctx = calloc(1, sizeof(struct render_request));
 
@@ -172,14 +174,18 @@
     req_ctx->bytes_sent = 0;
     
     // render context
-    render_t rend_ctx;
-    if (render_init(&rend_ctx, RENDER_PNG))
-        ERROR("render_init");
+    struct render *render;
+    
+    if (!(render = render_alloc()))
+        ERROR("render_alloc");
 
-    if (render_set_size(&rend_ctx, img_w, img_h))
+    if (render_set_mode(render, RENDER_PNG))
+        ERROR("render_set_mode");
+
+    if (render_set_size(render, img_w, img_h))
         ERROR("render_set_size");
 
-    if (render_region_full(&rend_ctx))
+    if (render_region_full(render))
         ERROR("render_region_full");
 
     // pick a render_node
@@ -189,7 +195,7 @@
         ERROR("remote_pool_get");
 
     // initiate the remote render operation
-    if ((req_ctx->remote_ctx = render_remote(&rend_ctx, node_info,
+    if ((req_ctx->remote_ctx = render_remote(render, node_info,
         &_render_sent,
         &_render_data,
         &_render_done,
@@ -198,8 +204,6 @@
     )) == NULL)
         ERROR("render_remote");
 
-#undef ERROR    /* can't be used after request has been sent */
-
     // set close cb
     evhttp_set_reply_abortcb(request, &_render_http_lost, req_ctx);
     
@@ -208,7 +212,6 @@
     return;
 
 error:
-    error("ERR: %s", errmsg);
     evhttp_send_error(request, 500, "Internal Server Error");
 
     free(req_ctx);
@@ -226,20 +229,19 @@
 
     evhttp_request_get_peer(request, &peer_address, &peer_port);
     
-    // request arguments
-    unsigned long int img_w = 256, img_h = 256;
-    
+    u_int32_t img_w = 256, img_h = 256;
+
+    // parse request arguments
     struct http_qarg qarg_spec[] = {
         { "w",      QARG_UINT,  &img_w  },
         { "h",      QARG_UINT,  &img_h  },
         { NULL,     QARG_END,   NULL    }
     };
 
-    // parse them
     http_qarg_parse(request, qarg_spec);
 
     // request log
-    printf("REQ: [%s:%d] method=%d, uri=%s, img_w=%lu, img_h=%lu\n", peer_address, peer_port, evhttp_request_get_type(request), uri, img_w, img_h);
+    printf("REQ: [%s:%d] method=%d, uri=%s, img_w=%d, img_h=%d\n", peer_address, peer_port, evhttp_request_get_type(request), uri, img_w, img_h);
     
     // do it
     _http_render_execute(request, img_w, img_h);
@@ -281,7 +283,7 @@
     ev_base = event_init();
 
     if (!ev_base)
-        die("event_init");
+        FATAL("event_init");
     
     // set up our render node pool
     remote_pool_init(&remote_pool);
@@ -323,9 +325,9 @@
 
     int pool_size = remote_pool_size(&remote_pool);
 
-    if (!pool_size) {
-        err_exit("No remote render nodes given");
-    }
+    if (!pool_size)
+        FATAL("No remote render nodes given");
+    
 
     printf("Registered %d render nodes in our pool\n", pool_size);
     
@@ -340,11 +342,11 @@
     struct evhttp *http_server = evhttp_new(ev_base);
 
     if (!http_server)
-        die("evhttp_new");
+        FATAL("evhttp_new");
     
     // bind to the correct interface/port
     if (evhttp_bind_socket(http_server, "0.0.0.0", 8117))
-        die("evhttp_bind_socket");
+        FATAL("evhttp_bind_socket");
     
     // add our http request handler
     evhttp_set_cb(http_server, "/render", &http_render, NULL);
@@ -354,7 +356,7 @@
     
     // run the libevent mainloop
     if (event_base_dispatch(ev_base))
-        die("event_dispatch");
+        WARNING("event_dispatch");
 
     printf("SHUTDOWN\n");