web_main.c
changeset 2 69f8c0acaac7
parent 0 5b010627d7ed
child 3 675be0a45157
equal deleted inserted replaced
1:6aa1a0d1f88d 2:69f8c0acaac7
     1 #include <sys/types.h>
     1 #include <sys/types.h>
     2 #include <sys/queue.h>
     2 #include <sys/queue.h>
       
     3 #include <sys/socket.h>
     3 #include <stdlib.h>
     4 #include <stdlib.h>
     4 #include <stdio.h>
     5 #include <stdio.h>
     5 #include <string.h>
     6 #include <string.h>
       
     7 #include <netinet/ip.h>
       
     8 #include <arpa/inet.h>
     6 
     9 
     7 #include <event.h>
    10 #include <event.h>
     8 #include <evhttp.h>
    11 #include <evhttp.h>
     9 
    12 
    10 #include "mandelbrot.h"
    13 #include "render.h"
       
    14 #include "render_remote.h"
    11 #include "common.h"
    15 #include "common.h"
    12 
    16 
    13 struct http_render_state {
    17 // what render node to use
    14     struct evbuffer *buf;
    18 static struct sockaddr_storage render_node;
    15 
    19 
    16 } _http_render_state = { NULL };
    20 // info on a render request
       
    21 struct render_request {
       
    22     struct evhttp_request *http_request;
    17 
    23 
    18 int _http_render_cb (const unsigned char *data, size_t length, void *arg) {
    24     int headers_sent;
       
    25 };
    19 
    26 
    20     // create a buffer
    27 void _render_sent (void *arg) {
    21     struct evbuffer *buf = evbuffer_new();
    28     struct render_request *ctx = arg;
    22 
    29 
    23     if (!buf) {
    30     // send headers
    24         error("_http_render_cb: evbuffer_new failed");
    31     evhttp_add_header(ctx->http_request->output_headers, "Content-Type", "image/png");
    25         return RENDER_CB_ERR;
    32     evhttp_send_reply_start(ctx->http_request, HTTP_OK, "OK");
       
    33 
       
    34     ctx->headers_sent = 1;
       
    35 
       
    36     printf("render [%p]: sent headers\n", ctx);
       
    37 }
       
    38 
       
    39 void _render_data (struct evbuffer *buf, void *arg) {
       
    40     struct render_request *ctx = arg;
       
    41 
       
    42     // send chunk
       
    43     evhttp_send_reply_chunk(ctx->http_request, buf);
       
    44     
       
    45     printf("render [%p]: sent chunk\n", ctx);
       
    46 }
       
    47 
       
    48 void _render_done (void *arg) {
       
    49     struct render_request *ctx = arg;
       
    50 
       
    51     // send end
       
    52     evhttp_send_reply_end(ctx->http_request);
       
    53 
       
    54     printf("render [%p]: done\n", ctx);
       
    55 
       
    56     // clean up
       
    57     free(ctx);
       
    58 }
       
    59 
       
    60 void _render_fail (void *arg) {
       
    61     struct render_request *ctx = arg;
       
    62 
       
    63     if (ctx->headers_sent) {
       
    64         // just terminate the PNG stream where it is
       
    65         evhttp_send_reply_end(ctx->http_request);
       
    66     } else {
       
    67         evhttp_send_error(ctx->http_request, 500, "Internal Server Error");
    26     }
    68     }
    27     
    69     
    28     // add the data to it
    70     printf("render [%p]: failed\n", ctx);
    29     if (evbuffer_add(buf, data, length)) {
    71 
    30         error("_http_render_cb: evbuffer_add(%d) failed", length);
    72     // clean up
    31         return RENDER_CB_ERR;
    73     free(ctx);
       
    74 }
       
    75 
       
    76 void _http_render_execute (struct evhttp_request *request, u_int32_t img_w, u_int32_t img_h) {
       
    77     // render request context
       
    78     struct render_request *req_ctx = calloc(1, sizeof(struct render_request));
       
    79     
       
    80     req_ctx->http_request = request;
       
    81     req_ctx->headers_sent = 0;
       
    82     
       
    83     // render context
       
    84     render_t rend_ctx;
       
    85     render_init(&rend_ctx, RENDER_PNG);
       
    86     render_set_size(&rend_ctx, img_w, img_h);
       
    87     render_region_full(&rend_ctx);
       
    88     
       
    89     // initiate the remote render operation
       
    90     if (render_remote(&rend_ctx, &render_node,
       
    91         &_render_sent,
       
    92         &_render_data,
       
    93         &_render_done,
       
    94         &_render_fail,
       
    95         req_ctx
       
    96     )) {
       
    97         free(req_ctx);
       
    98         fprintf(stderr, "ERR: render_remote\n");
       
    99         return;
    32     }
   100     }
    33     
   101     
    34     // send it
   102     printf("render [%p]: started\n", req_ctx);
    35     evhttp_send_reply_chunk((struct evhttp_request *) arg, buf);
       
    36 
       
    37     printf("_http_render_cb: sent chunk: %zu\n", length);
       
    38     
       
    39     // free the buffer (!!!)
       
    40     evbuffer_free(buf);
       
    41     
       
    42     // return ok
       
    43     return RENDER_CB_OK;
       
    44 }
   103 }
    45 
   104 
       
   105 /*
       
   106  * HTTP request handler
       
   107  */
    46 void http_render (struct evhttp_request *request, void *arg) {
   108 void http_render (struct evhttp_request *request, void *arg) {
    47     // gather some info about the request
   109     // gather some info about the request
    48     const char *uri = evhttp_request_uri(request);
   110     const char *uri = evhttp_request_uri(request);
    49     char *peer_address;
   111     char *peer_address;
    50     u_short peer_port;
   112     u_short peer_port;
    69     evhttp_clear_headers(&qargs);
   131     evhttp_clear_headers(&qargs);
    70 
   132 
    71     // request log
   133     // request log
    72     printf("REQ: [%s:%d] uri=%s, img_w=%d, img_h=%d\n", peer_address, peer_port, uri, img_w, img_h);
   134     printf("REQ: [%s:%d] uri=%s, img_w=%d, img_h=%d\n", peer_address, peer_port, uri, img_w, img_h);
    73     
   135     
    74     // set headers
   136     // do it
    75     evhttp_add_header(request->output_headers, "Content-Type", "image/png");
   137     _http_render_execute(request, img_w, img_h);
    76     evhttp_send_reply_start(request, HTTP_OK, "OK");
       
    77     
       
    78     // render
       
    79     struct render_ctx ctx;
       
    80     render_ctx_set(&ctx, &_http_render_cb, NULL, request);
       
    81 
       
    82     int err = mandelbrot_render_full(&ctx, img_w, img_h);
       
    83 
       
    84     if (err) {
       
    85         fprintf(stderr, "ERR: mandelbrot_render_full(%d, %d): %d\n", img_w, img_h, err);
       
    86     }
       
    87     
       
    88     // reply end
       
    89     evhttp_send_reply_end(request);
       
    90 }
   138 }
    91 
   139 
    92 int main (void) {
   140 int main (void) {
    93     // libevent/http init
   141     // libevent/http init
    94     struct event_base *ev_base = event_init();
   142     struct event_base *ev_base = event_init();
   105     if (evhttp_bind_socket(http_server, "0.0.0.0", 8117))
   153     if (evhttp_bind_socket(http_server, "0.0.0.0", 8117))
   106         die("evhttp_bind_socket");
   154         die("evhttp_bind_socket");
   107     
   155     
   108     // add our http request handler
   156     // add our http request handler
   109     evhttp_set_cb(http_server, "/render", &http_render, NULL);
   157     evhttp_set_cb(http_server, "/render", &http_render, NULL);
   110     
   158 
       
   159     // hack in our render node
       
   160     struct sockaddr_in *render_node_addr = (struct sockaddr_in *) &render_node;
       
   161 
       
   162     render_node_addr->sin_family = AF_INET;
       
   163     render_node_addr->sin_port = htons(RENDER_PORT);
       
   164     inet_aton("127.0.0.1", &render_node_addr->sin_addr);
       
   165 
   111     // we shall now run
   166     // we shall now run
   112     printf("RUN 0.0.0.0:8117\n");
   167     printf("RUN 0.0.0.0:8117\n");
   113     
   168     
   114     // run the libevent mainloop
   169     // run the libevent mainloop
   115     if (event_dispatch())
   170     if (event_dispatch())