terom@0: #include terom@0: #include terom@0: #include terom@0: #include terom@0: #include terom@0: terom@0: #include terom@0: #include terom@0: terom@0: #include "mandelbrot.h" terom@0: #include "common.h" terom@0: terom@0: struct http_render_state { terom@0: struct evbuffer *buf; terom@0: terom@0: } _http_render_state = { NULL }; terom@0: terom@0: int _http_render_cb (const unsigned char *data, size_t length, void *arg) { terom@0: terom@0: // create a buffer terom@0: struct evbuffer *buf = evbuffer_new(); terom@0: terom@0: if (!buf) { terom@0: error("_http_render_cb: evbuffer_new failed"); terom@0: return RENDER_CB_ERR; terom@0: } terom@0: terom@0: // add the data to it terom@0: if (evbuffer_add(buf, data, length)) { terom@0: error("_http_render_cb: evbuffer_add(%d) failed", length); terom@0: return RENDER_CB_ERR; terom@0: } terom@0: terom@0: // send it terom@0: evhttp_send_reply_chunk((struct evhttp_request *) arg, buf); terom@0: terom@0: printf("_http_render_cb: sent chunk: %zu\n", length); terom@0: terom@0: // free the buffer (!!!) terom@0: evbuffer_free(buf); terom@0: terom@0: // return ok terom@0: return RENDER_CB_OK; terom@0: } terom@0: terom@0: void http_render (struct evhttp_request *request, void *arg) { terom@0: // gather some info about the request terom@0: const char *uri = evhttp_request_uri(request); terom@0: char *peer_address; terom@0: u_short peer_port; terom@0: terom@0: evhttp_connection_get_peer(request->evcon, &peer_address, &peer_port); terom@0: terom@0: // request arguments terom@0: u_int32_t img_w = 256, img_h = 256; terom@0: struct evkeyval *qarg; terom@0: struct evkeyvalq qargs; terom@0: terom@0: evhttp_parse_query(uri, &qargs); terom@0: terom@0: TAILQ_FOREACH(qarg, &qargs, next) { terom@0: if (strcmp(qarg->key, "w") == 0) terom@0: img_w = strtol(qarg->value, NULL, 10); terom@0: else if (strcmp(qarg->key, "h") == 0) terom@0: img_h = strtol(qarg->value, NULL, 10); terom@0: } terom@0: terom@0: // clean up the qargs (badly named functions :< ) terom@0: evhttp_clear_headers(&qargs); terom@0: terom@0: // request log terom@0: printf("REQ: [%s:%d] uri=%s, img_w=%d, img_h=%d\n", peer_address, peer_port, uri, img_w, img_h); terom@0: terom@0: // set headers terom@0: evhttp_add_header(request->output_headers, "Content-Type", "image/png"); terom@0: evhttp_send_reply_start(request, HTTP_OK, "OK"); terom@0: terom@0: // render terom@0: struct render_ctx ctx; terom@0: render_ctx_set(&ctx, &_http_render_cb, NULL, request); terom@0: terom@0: int err = mandelbrot_render_full(&ctx, img_w, img_h); terom@0: terom@0: if (err) { terom@0: fprintf(stderr, "ERR: mandelbrot_render_full(%d, %d): %d\n", img_w, img_h, err); terom@0: } terom@0: terom@0: // reply end terom@0: evhttp_send_reply_end(request); terom@0: } terom@0: terom@0: int main (void) { terom@0: // libevent/http init terom@0: struct event_base *ev_base = event_init(); terom@0: terom@0: if (!ev_base) terom@0: die("event_init"); terom@0: terom@0: struct evhttp *http_server = evhttp_new(ev_base); terom@0: terom@0: if (!http_server) terom@0: die("evhttp_new"); terom@0: terom@0: // bind to the correct interface/port terom@0: if (evhttp_bind_socket(http_server, "0.0.0.0", 8117)) terom@0: die("evhttp_bind_socket"); terom@0: terom@0: // add our http request handler terom@0: evhttp_set_cb(http_server, "/render", &http_render, NULL); terom@0: terom@0: // we shall now run terom@0: printf("RUN 0.0.0.0:8117\n"); terom@0: terom@0: // run the libevent mainloop terom@0: if (event_dispatch()) terom@0: die("event_dispatch"); terom@0: terom@0: // clean up terom@0: evhttp_free(http_server); terom@0: terom@0: // successfull exit terom@0: return 0; terom@0: }