220 handler->sh.create_iostream = create_connection_iostream; |
220 handler->sh.create_iostream = create_connection_iostream; |
221 return (SessionHandler*)handler; |
221 return (SessionHandler*)handler; |
222 } |
222 } |
223 |
223 |
224 void evt_enq_conn(SessionHandler *handler, Connection *conn) { |
224 void evt_enq_conn(SessionHandler *handler, Connection *conn) { |
|
225 Event *event = malloc(sizeof(Event)); |
|
226 if(!event) { |
|
227 connection_destroy(conn); |
|
228 return; |
|
229 } |
|
230 |
|
231 EventHttpIO *io = evt_req_init(handler, conn); |
|
232 if(!io) { |
|
233 connection_destroy(conn); |
|
234 free(event); |
|
235 return; |
|
236 } |
|
237 |
|
238 /* |
|
239 * to start the request handling, we begin with a poll on the socket, |
|
240 * |
|
241 * evt_enq_conn() --> event handler --> handle_request() |
|
242 */ |
|
243 |
|
244 ZERO(event, sizeof(Event)); |
|
245 event->fn = conn->ssl && !conn->ssl_accepted ? evt_request_ssl_accept : evt_request_input; |
|
246 event->finish = evt_request_finish; |
|
247 event->cookie = io; |
|
248 |
|
249 EventHandler *ev = ev_instance(((EventSessionHandler*)handler)->eventhandler); |
|
250 |
|
251 if(ev_pollin(ev, conn->fd, event) != 0) { |
|
252 // TODO: ev_pollin should log, intercept some errors here |
|
253 log_ereport(LOG_FAILURE, "Cannot enqueue connection"); |
|
254 evt_request_error(ev, event); |
|
255 } |
|
256 } |
|
257 |
|
258 EventHttpIO* evt_req_init(SessionHandler *handler, Connection *conn) { |
225 // set socket non blocking |
259 // set socket non blocking |
226 int flags; |
260 int flags; |
227 if ((flags = fcntl(conn->fd, F_GETFL, 0)) == -1) { |
261 if ((flags = fcntl(conn->fd, F_GETFL, 0)) == -1) { |
228 flags = 0; |
262 flags = 0; |
229 } |
263 } |
230 if (fcntl(conn->fd, F_SETFL, flags | O_NONBLOCK) != 0) { |
264 if (fcntl(conn->fd, F_SETFL, flags | O_NONBLOCK) != 0) { |
231 log_ereport(LOG_FAILURE, "sessionhandler: fcntl failed: %s", strerror(errno)); |
265 log_ereport(LOG_FAILURE, "sessionhandler: fcntl failed: %s", strerror(errno)); |
232 connection_destroy(conn); |
266 return NULL; |
233 return; |
|
234 } |
267 } |
235 |
268 |
236 HTTPRequest *request = malloc(sizeof(HTTPRequest)); |
269 HTTPRequest *request = malloc(sizeof(HTTPRequest)); |
237 if(!request) { |
270 if(!request) { |
238 connection_destroy(conn); |
271 return NULL; |
239 return; |
|
240 } |
272 } |
241 http_request_init(request); |
273 http_request_init(request); |
242 request->connection = conn; |
274 request->connection = conn; |
243 conn->session_handler = handler; |
275 conn->session_handler = handler; |
244 |
276 |
245 // TODO: remove code redundancy (basic_run_session) |
277 // TODO: remove code redundancy (basic_run_session) |
246 |
278 |
247 // read request |
279 // read request |
248 netbuf *buf = malloc(sizeof(netbuf)); |
280 netbuf *buf = malloc(sizeof(netbuf)); |
249 if(!buf) { |
281 if(!buf) { |
250 connection_destroy(conn); |
|
251 http_request_cleanup(request); |
282 http_request_cleanup(request); |
252 return; |
283 return NULL; |
253 } |
284 } |
254 buf->rdtimeout = 120; |
285 buf->rdtimeout = 120; |
255 buf->pos = 0; |
286 buf->pos = 0; |
256 buf->cursize = 0; |
287 buf->cursize = 0; |
257 buf->maxsize = 2048; |
288 buf->maxsize = 2048; |
258 buf->sd = &conn->fd; |
289 buf->sd = &conn->fd; |
259 buf->errmsg = NULL; |
290 buf->errmsg = NULL; |
260 buf->inbuf = malloc(2048); |
291 buf->inbuf = malloc(2048); |
261 if(!buf->inbuf) { |
292 if(!buf->inbuf) { |
262 connection_destroy(conn); |
|
263 http_request_cleanup(request); |
293 http_request_cleanup(request); |
264 free(buf); |
294 free(buf); |
265 return; |
295 return NULL; |
266 } |
296 } |
267 |
297 |
268 request->netbuf = buf; |
298 request->netbuf = buf; |
269 |
299 |
270 HttpParser *parser = http_parser_new(request); |
300 HttpParser *parser = http_parser_new(request); |
271 if(!parser) { |
301 if(!parser) { |
272 connection_destroy(conn); |
|
273 http_request_cleanup(request); |
302 http_request_cleanup(request); |
274 free(buf->inbuf); |
303 free(buf->inbuf); |
275 free(buf); |
304 free(buf); |
276 return; |
305 return NULL; |
277 } |
306 } |
278 |
307 |
279 EventHttpIO *io = malloc(sizeof(EventHttpIO)); |
308 EventHttpIO *io = malloc(sizeof(EventHttpIO)); |
280 if(io == NULL) { |
309 if(io == NULL) { |
281 connection_destroy(conn); |
|
282 http_request_cleanup(request); |
310 http_request_cleanup(request); |
283 free(buf->inbuf); |
311 free(buf->inbuf); |
284 free(buf); |
312 free(buf); |
285 http_parser_free(parser); |
313 http_parser_free(parser); |
286 return; |
314 return NULL; |
287 } |
315 } |
288 io->request = request; |
316 io->request = request; |
289 io->parser = parser; |
317 io->parser = parser; |
290 io->error = 0; |
318 io->error = 0; |
291 |
319 |
292 /* |
320 return io; |
293 * to start the request handling, we begin with a poll on the socket, |
|
294 * |
|
295 * evt_enq_conn() --> event handler --> handle_request() |
|
296 */ |
|
297 |
|
298 Event *event = malloc(sizeof(Event)); |
|
299 ZERO(event, sizeof(Event)); |
|
300 event->fn = conn->ssl && !conn->ssl_accepted ? evt_request_ssl_accept : evt_request_input; |
|
301 event->finish = evt_request_finish; |
|
302 event->cookie = io; |
|
303 |
|
304 EventHandler *ev = ev_instance(((EventSessionHandler*)handler)->eventhandler); |
|
305 |
|
306 if(ev_pollin(ev, conn->fd, event) != 0) { |
|
307 // TODO: ev_pollin should log, intercept some errors here |
|
308 log_ereport(LOG_FAILURE, "Cannot enqueue connection"); |
|
309 evt_request_error(ev, event); |
|
310 } |
|
311 } |
321 } |
312 |
322 |
313 int evt_request_ssl_accept(EventHandler *handler, Event *event) { |
323 int evt_request_ssl_accept(EventHandler *handler, Event *event) { |
314 EventHttpIO *io = event->cookie; |
324 EventHttpIO *io = event->cookie; |
315 Connection *conn = io->request->connection; |
325 Connection *conn = io->request->connection; |
479 |
489 |
480 return 0; |
490 return 0; |
481 } |
491 } |
482 |
492 |
483 void evt_keep_alive(SessionHandler *handler, Connection *conn) { |
493 void evt_keep_alive(SessionHandler *handler, Connection *conn) { |
484 // TODO: set timeout |
494 Event *event = malloc(sizeof(Event)); |
485 |
495 if(!event) { |
486 /* TODO: |
496 connection_destroy(conn); |
487 * Don't just re-enqueue the connection |
497 return; |
488 * create a evt_req_init function which does most of the evt_enq_conn stuff |
498 } |
489 * but don't poll. |
499 |
490 * evt_keep_alive should poll and if an event occurs: |
500 EVWatchList *keepalive = malloc(sizeof(EVWatchList)); |
491 * evt_req_init |
501 if(!keepalive) { |
492 * evt_request_input |
502 free(event); |
493 * evt_enq_conn should do: |
503 connection_destroy(conn); |
494 * evt_req_init |
504 return; |
495 * ev_pollin |
505 } |
496 */ |
506 |
497 evt_enq_conn(handler, conn); |
507 ZERO(keepalive, sizeof(EVWatchList)); |
498 } |
508 keepalive->destroy = evt_keep_alive_destroy; |
|
509 keepalive->data = conn; |
|
510 |
|
511 ZERO(event, sizeof(Event)); |
|
512 event->fn = evt_keep_alive_enqueue; |
|
513 event->finish = ev_free_event; // this will free the event obj at the end |
|
514 event->cookie = keepalive; |
|
515 |
|
516 EventHandler *ev = ev_instance(((EventSessionHandler*)handler)->eventhandler); |
|
517 if(event_send(ev, event)) { |
|
518 log_ereport(LOG_FAILURE, "Keep-Alive: ev_send failed"); |
|
519 connection_destroy(conn); |
|
520 free(event); |
|
521 free(keepalive); |
|
522 } |
|
523 } |
|
524 |
|
525 int evt_keep_alive_enqueue(EventHandler *h, Event *event) { |
|
526 EVWatchList *keepalive = event->cookie; |
|
527 Connection *conn = keepalive->data; |
|
528 |
|
529 Event *ioevent = malloc(sizeof(Event)); |
|
530 if(!ioevent) { |
|
531 connection_destroy(conn); |
|
532 free(keepalive); |
|
533 return 0; |
|
534 } |
|
535 |
|
536 // add keepalive object to the eventhandler watchlist |
|
537 // the watchlist will check the timeout |
|
538 keepalive->created = time(NULL); |
|
539 keepalive->expire = keepalive->created + 60; // TODO: config |
|
540 ev_watchlist_add(h, keepalive); |
|
541 |
|
542 // wait for input |
|
543 ZERO(ioevent, sizeof(Event)); |
|
544 ioevent->fn = evt_keep_alive_input_event; |
|
545 ioevent->finish = ev_free_event; |
|
546 ioevent->cookie = keepalive; |
|
547 if(ev_pollin(h, conn->fd, ioevent) != 0) { |
|
548 log_ereport(LOG_FAILURE, "Cannot enqueue connection"); |
|
549 ev_watchlist_remove(h, keepalive); |
|
550 connection_destroy(conn); |
|
551 free(keepalive); |
|
552 free(ioevent); |
|
553 } |
|
554 |
|
555 return 0; |
|
556 } |
|
557 |
|
558 int evt_keep_alive_input_event(EventHandler *h, Event *event) { |
|
559 EVWatchList *keepalive = event->cookie; |
|
560 Connection *conn = keepalive->data; |
|
561 |
|
562 // remove connection from the keep-alive list |
|
563 ev_watchlist_remove(h, keepalive); |
|
564 free(keepalive); |
|
565 |
|
566 // prepare http io |
|
567 EventHttpIO *io = evt_req_init(conn->session_handler, conn); |
|
568 if(!io) { |
|
569 connection_destroy(conn); |
|
570 return 0; |
|
571 } |
|
572 |
|
573 // pass this event to the request input function |
|
574 // the event object needs some adjustments for this (see evt_enq_conn) |
|
575 event->cookie = io; |
|
576 event->fn = conn->ssl && !conn->ssl_accepted ? evt_request_ssl_accept : evt_request_input; |
|
577 event->finish = evt_request_finish; |
|
578 return event->fn(h, event); |
|
579 } |
|
580 |
|
581 void evt_keep_alive_destroy(EventHandler *h, EVWatchList *item) { |
|
582 |
|
583 } |