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()) |