render_node.c
author Tero Marttila <terom@fixme.fi>
Fri, 06 Jun 2008 03:24:55 +0300
changeset 9 fb6632e6c1bb
parent 8 4d38ccbeb93e
child 11 082bfaf38cf0
permissions -rw-r--r--
two new modules, remote_node and remote_pool

committer: Tero Marttila <terom@fixme.fi>
#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 "render.h"
#include "render_remote.h"
#include "mandelbrot.h"
#include "common.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) {
    // open it as a FILE*
    FILE *fh = fdopen(sock, "r+");
    
    // read the parameters
    u_int8_t mode;
    u_int32_t img_w, img_h;
    double x1, y1, x2, y2;

    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("ERR: invalid arguments");
        fclose(fh);
        return;
    }

    printf("RENDER: [%ux%u] (%f, %f) -> (%f, %f): ...", img_w, img_h, x1, y1, x2, y2);
    fflush(stdout);

    double duration;

    // set up the render_ctx
    struct render_ctx ctx;
    render_init(&ctx, RENDER_PNG);
    render_set_size(&ctx, img_w, img_h);
    render_region_raw(&ctx, x1, y1, x2, y2);
    render_io_stream(&ctx, fh);
    
    sigpipe_ignore();
    
    // render!
    if (mandelbrot_render_timed(&ctx, &duration))
        printf("error\n");  // XXX: notify our client?
    else
        printf("time=%fs\n", duration);
    
    // 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;

    while ((opt = getopt(argc, argv, "l:")) != -1) {
        switch (opt) {
            case 'l':
                if (port_name)
                    err_exit("only specify -l once");

                port_name = optarg;
                break;

            default:
                err_exit("Usage: %s [-l port]", argv[0]);
        }
    }

    if (!port_name)
        port_name = RENDER_PORT_NAME;

    unsigned short port = atoi(port_name);

    if (!port)
        err_exit("invalid port: %s", port_name);

    // create the socket
    if ((ssock = socket(PF_INET, SOCK_STREAM, 0)) == -1)
        perr_exit("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)
        perr_exit("bind");
    
    if (listen(ssock, 1) == -1)
        perr_exit("listen");
    
    printf("RUN: %s:%hu\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));

    // main accept loop
    while (1) {
        addr_len = sizeof(struct sockaddr_in);

        // accept a new client
        if ((sock = accept(ssock, (struct sockaddr *) &addr, &addr_len)) == -1)
            perr_exit("accept");
        
        printf("ACCEPT: %s:%hu\n", inet_ntoa(addr.sin_addr), addr.sin_port);
        
        // handle their resquest
        handle_client(sock);
    }
}