node_main.c
author Tero Marttila <terom@fixme.fi>
Tue, 17 Jun 2008 18:15:43 +0300
changeset 21 e2916f8ebaa6
parent 19 d18606bb6f20
child 23 31307efd7e78
permissions -rw-r--r--
fix memory alloc/free bugs, and one in render_threads where the last row was left out

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 "common.h"
#include "render.h"
#include "render_remote.h"  // for RENDER_PORT_NAME
#include "render_local.h"
#include "render_threads.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 = NULL;
    FILE *fh;
    u_int8_t mode;
    u_int32_t img_w, img_h;
    double x1, y1, x2, y2;

    struct render_threads *threads_info = NULL;
    
    // 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 threaded \o/
    if (!(threads_info = render_threads_alloc(ctx)))
        goto error;
    
    if (render_threads_wait(threads_info))
        goto error;
    
    printf("done!\n");
/*
    // render!
    if (render_local(ctx, &duration))
        ERROR("render_local");

    printf("time=%fs\n", duration);
*/
    
    // fall through to just clean up normally

error:
    if (ctx)
        render_free(ctx);

    if (threads_info)
        render_threads_free(threads_info);

    // 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;
}