static ebb_request *ebb_request_create(ebb_connection *conn) { ebb_request *request; ebb_request_info *request_info; if (NULL == (request = calloc(1, sizeof(ebb_request)))) goto fail; if (NULL == (request_info = calloc(1, sizeof(ebb_request_info)))) goto fail; ebb_request_init(request); request->data = (void *)request_info; request->on_complete = on_request_complete; request->on_uri = on_uri_complete; request->on_body = on_body_complete; request->on_path = on_path_complete; request->on_header_field = on_header_field; request->on_header_value = on_header_value; request_info->conn = conn; ebb_connection_reset_timeout(conn); return request; fail: ebb_request_destroy(request); ebb_connection_schedule_close(conn); return NULL; }
/* Internal callback * called by connection->read_watcher */ static void on_readable(struct ev_loop *loop, ev_io *watcher, int revents) { ebb_connection *connection = watcher->data; char recv_buffer[4096]; ssize_t recved; //printf("on_readable\n"); // TODO -- why is this broken? //assert(ev_is_active(&connection->timeout_watcher)); assert(watcher == &connection->read_watcher); if(EV_ERROR & revents) { error("on_readable() got error event, closing connection."); goto error; } #ifdef HAVE_GNUTLS assert(!ev_is_active(&connection->handshake_watcher)); if(connection->server->secure) { recved = gnutls_record_recv( connection->session , recv_buffer , TCP_MAXWIN ); if(recved <= 0) { if(gnutls_error_is_fatal(recved)) goto error; if( (recved == GNUTLS_E_INTERRUPTED || recved == GNUTLS_E_AGAIN) && GNUTLS_NEED_WRITE ) ev_io_start(loop, &connection->write_watcher); return; } } else { #endif /* HAVE_GNUTLS */ recved = recv(connection->fd, recv_buffer, 4096, 0); if(recved <= 0) goto error; #ifdef HAVE_GNUTLS } #endif /* HAVE_GNUTLS */ ebb_connection_reset_timeout(connection); ebb_request_parser_execute(&connection->parser, recv_buffer, recved); /* parse error? just drop the client. screw the 400 response */ if(ebb_request_parser_has_error(&connection->parser)) goto error; return; error: ebb_connection_schedule_close(connection); }
/* Internal callback * called by connection->read_watcher */ static void on_readable(EV_P_ ev_io *watcher, int revents) { ebb_connection *connection = watcher->data; char base[TCP_MAXWIN]; char *recv_buffer = base; size_t recv_buffer_size = TCP_MAXWIN; ssize_t recved; //printf("on_readable\n"); // TODO -- why is this broken? //assert(ev_is_active(&connection->timeout_watcher)); assert(watcher == &connection->read_watcher); if(EV_ERROR & revents) { error("on_readable() got error event, closing connection."); goto error; } ebb_buf *buf = NULL; if(connection->new_buf) { buf = connection->new_buf(connection); if(buf == NULL) return; recv_buffer = buf->base; recv_buffer_size = buf->len; } recved = recv(connection->fd, recv_buffer, recv_buffer_size, 0); if(recved < 0) goto error; if(recved == 0) return; ebb_connection_reset_timeout(connection); ebb_request_parser_execute(&connection->parser, recv_buffer, recved); /* parse error? just drop the client. screw the 400 response */ if(ebb_request_parser_has_error(&connection->parser)) goto error; if(buf && buf->on_release) buf->on_release(buf); return; error: ebb_connection_schedule_close(connection); }
/* Internal callback * called by connection->write_watcher */ static void on_writable(struct ev_loop *loop, ev_io *watcher, int revents) { ebb_connection *connection = watcher->data; ssize_t sent; //printf("on_writable\n"); assert(CONNECTION_HAS_SOMETHING_TO_WRITE); assert(connection->written <= connection->to_write_len); // TODO -- why is this broken? //assert(ev_is_active(&connection->timeout_watcher)); assert(watcher == &connection->write_watcher); if(connection->to_write == 0) goto stop_writing; sent = nosigpipe_push( (void*)(long)connection->fd , connection->to_write + connection->written , connection->to_write_len - connection->written ); if(sent < 0) goto error; if(sent == 0) return; ebb_connection_reset_timeout(connection); connection->written += sent; if(connection->written == connection->to_write_len) { goto stop_writing; } return; stop_writing: ev_io_stop(loop, watcher); connection->to_write = NULL; if(connection->after_write_cb) connection->after_write_cb(connection); return; error: error("close connection on write."); ebb_connection_schedule_close(connection); }
/* Internal callback * called by connection->read_watcher */ static void on_readable(struct ev_loop *loop, ev_io *watcher, int revents) { ebb_connection *connection = watcher->data; size_t offset = connection->buffered_data; int left = EBB_READ_BUFFER - offset; char* recv_buffer = connection->read_buffer + offset; ssize_t recved; //printf("on_readable\n"); // TODO -- why is this broken? //assert(ev_is_active(&connection->timeout_watcher)); assert(watcher == &connection->read_watcher); // No more buffer space. if(left == 0) goto error; if(EV_ERROR & revents) { error("on_readable() got error event, closing connection."); goto error; } recved = recv(connection->fd, recv_buffer, left, 0); if(recved <= 0) goto error; connection->buffered_data += recved; ebb_connection_reset_timeout(connection); ebb_request_parser_execute(&connection->parser, connection->read_buffer, recved, offset); if(ebb_request_parser_is_finished(&connection->parser)) { connection->buffered_data = 0; } /* parse error? just drop the client. screw the 400 response */ if(ebb_request_parser_has_error(&connection->parser)) goto error; return; error: ebb_connection_schedule_close(connection); }
/* Internal callback * called by connection->timeout_watcher */ static void on_timeout(EV_P_ ev_timer *watcher, int revents) { ebb_connection *connection = watcher->data; assert(watcher == &connection->timeout_watcher); //printf("on_timeout\n"); /* if on_timeout returns true, we don't time out */ if(connection->on_timeout) { int r = connection->on_timeout(connection); if(r == EBB_AGAIN) { ebb_connection_reset_timeout(connection); return; } } ebb_connection_schedule_close(connection); }
static void on_handshake(struct ev_loop *loop ,ev_io *watcher, int revents) { ebb_connection *connection = watcher->data; //printf("on_handshake\n"); assert(ev_is_active(&connection->timeout_watcher)); assert(!ev_is_active(&connection->read_watcher)); assert(!ev_is_active(&connection->write_watcher)); if(EV_ERROR & revents) { error("on_handshake() got error event, closing connection.n"); goto error; } int r = gnutls_handshake(connection->session); if(r < 0) { if(gnutls_error_is_fatal(r)) goto error; if(r == GNUTLS_E_INTERRUPTED || r == GNUTLS_E_AGAIN) ev_io_set( watcher , connection->fd , (GNUTLS_NEED_WRITE ? EV_WRITE : EV_READ) ); return; } ebb_connection_reset_timeout(connection); ev_io_stop(loop, watcher); ev_io_start(loop, &connection->read_watcher); if(CONNECTION_HAS_SOMETHING_TO_WRITE) ev_io_start(loop, &connection->write_watcher); return; error: close_connection(connection); }
/* Internal callback * called by connection->write_watcher */ static void on_writable(struct ev_loop *loop, ev_io *watcher, int revents) { ebb_connection *connection = watcher->data; ssize_t sent; //printf("on_writable\n"); assert(CONNECTION_HAS_SOMETHING_TO_WRITE); assert(connection->written <= connection->to_write_len); // TODO -- why is this broken? //assert(ev_is_active(&connection->timeout_watcher)); assert(watcher == &connection->write_watcher); if(connection->to_write == 0) goto stop_writing; #ifdef HAVE_GNUTLS assert(!ev_is_active(&connection->handshake_watcher)); if(connection->server->secure) { sent = gnutls_record_send( connection->session , connection->to_write + connection->written , connection->to_write_len - connection->written ); if(sent < 0) { if(gnutls_error_is_fatal(sent)) goto error; if( (sent == GNUTLS_E_INTERRUPTED || sent == GNUTLS_E_AGAIN) && GNUTLS_NEED_READ ) ev_io_stop(loop, watcher); return; } } else { #endif /* HAVE_GNUTLS */ sent = nosigpipe_push( (void*)connection->fd , connection->to_write + connection->written , connection->to_write_len - connection->written ); if(sent < 0) goto error; if(sent == 0) return; #ifdef HAVE_GNUTLS } #endif /* HAVE_GNUTLS */ ebb_connection_reset_timeout(connection); connection->written += sent; if(connection->written == connection->to_write_len) { goto stop_writing; } return; stop_writing: ev_io_stop(loop, watcher); connection->to_write = NULL; if(connection->after_write_cb) connection->after_write_cb(connection); return; error: error("close connection on write."); ebb_connection_schedule_close(connection); }