render_file.c
author Tero Marttila <terom@fixme.fi>
Fri, 30 May 2008 14:24:23 +0300
changeset 0 5b010627d7ed
child 1 6aa1a0d1f88d
permissions -rw-r--r--
initial code, render_file(local+remote), render_node, web_main(local)

committer: Tero Marttila <terom@fixme.fi>
#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 "mandelbrot.h"
#include "common.h"

static int verbose;

int file_write (const unsigned char *data, size_t length, void *arg) {
    size_t ret = fwrite(data, length, 1, (FILE *) arg);
    
    return (ret == 1) ? RENDER_CB_OK : RENDER_CB_ERR;
}

void render_local (int img_w, int img_h, FILE *output) {
    struct render_ctx ctx;

    render_ctx_set(&ctx, &file_write, NULL, output);

    double duration;

    if (mandelbrot_render_full_timed(
            &ctx, 
            img_w, img_h, 
            &duration
    ) != MANDELBROT_OK)
        err_exit("mandelbrot_render_region failed");
    
    if (verbose) 
        fprintf(stdout, "rendered %dx%d mandelbrot in %f seconds\n", img_w, img_h, duration);
}

void render_remote (int img_w, int img_h, FILE *output, FILE *remote) {
    struct render_cmd cmd;

    if (render_cmd_set_full(&cmd, img_w, img_h) != MANDELBROT_OK) {
        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;
}

int main (int argc, char **argv) {
    int opt;
    
    FILE *output = NULL, *remote = NULL;
    int img_w = 256, img_h = 256;
    

    while ((opt = getopt(argc, argv, "w:h:o:vr:")) != -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;

            case 'r' :
                if (remote)
                    err_exit("Only use -r once");

                remote = open_remote(optarg);

                break;

            default :
                err_exit("Usage: %s [-w img_w] [-h img_h] [-o output_file] [-v] [-r host[:port]]", argv[0]);
        }
    }

    if (!output)
        output = stdout;
    
    if (remote) {
        if (verbose)
            fprintf(stderr, "Render [%dx%d] mandelbrot remotely\n", img_w, img_h);

        render_remote(img_w, img_h, output, remote);

        fclose(remote);
    } else {
        if (verbose)
            fprintf(stderr, "Render [%dx%d] mandelbrot locally\n", img_w, img_h);

        render_local(img_w, img_h, output);
    }

    fclose(output);

    return 0;
}