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; }
static int ebb_connection_push_header(ebb_connection *conn, const char *msg) { ebb_connection_info *conninfo = (ebb_connection_info *)(conn->data); uint8_t *block; size_t msglen; msglen = strlen(msg); block = (uint8_t *)malloc(sizeof(size_t) + msglen); LOG_DEBUG("pushhdr, block = %p", block); LOG_DEBUG("********* ebb_connection_push_header str=%p", block); if (block == NULL) { LOG_ERROR("strdup failed, silently closing conn"); ebb_connection_schedule_close(conn); return 1; } else { memcpy(block, &msglen, sizeof(size_t)); memcpy(block + sizeof(size_t), msg, msglen); LOG_DEBUG("Pushed hdr %s", msg); tailq_push_head(conninfo->rsp_q, block); conninfo->push_len += msglen; connection_flush_write(conn); return 0; } }
static int ebb_connection_pushbin(ebb_connection *conn, const uint8_t *msg, size_t len, bool flush) { ebb_connection_info *conninfo = (ebb_connection_info *)(conn->data); uint8_t *block; block = (uint8_t *)malloc(sizeof(size_t) + len); LOG_DEBUG("********* ebb_connection_pushbin str=%p", msg); if (block == NULL) { LOG_ERROR("strdup failed, silently closing conn"); ebb_connection_schedule_close(conn); return 1; } else { memcpy(block, &len, sizeof(size_t)); memcpy(block + sizeof(size_t), msg, len); //LOG_INFO("Pushed block %u (+%u) bytes", len, sizeof(size_t)); //dump(block, len + sizeof(size_t)); tailq_push_tail(conninfo->rsp_q, block); // FIXME, error check conninfo->push_len += len; if (flush) connection_flush_write(conn); return 0; } }
void continue_responding(ebb_connection *connection) { AsyncConnection *connection_data = (AsyncConnection *)connection->data; if (connection_data->keep_alive_flag == false) { ebb_connection_schedule_close(connection); } else { // clear connection for next request connection_data->reset(); } }
/* 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); }
static void connection_flush_write(ebb_connection *conn) { ebb_connection_info *conninfo = (ebb_connection_info *)(conn->data); if (!conninfo->writing) { uint8_t *blockp; uint8_t *data; size_t len = 0; blockp = tailq_pop_head(conninfo->rsp_q); /* LOG_INFO("flush %p", blockp); if (NULL != blockp) dump(blockp, 16); */ if (NULL != blockp) { len = *((size_t *)blockp); data = blockp + sizeof(size_t); conninfo->writing = true; LOG_DEBUG("conn_write"); if (len > sizeof(conninfo->writebuf)) LOG_CRITICAL("block too big %u of %u", len, sizeof(conninfo->writebuf)); memcpy(conninfo->writebuf, data, len); conninfo->push_len -= len; free(blockp); if (len) ebb_connection_write(conn, conninfo->writebuf, len, on_write_complete); } else { // reached end of q LOG_DEBUG("End of write q"); if (conninfo->finished) { if (!conninfo->keepalive) ebb_connection_schedule_close(conn); } } } }
/* 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); }
void continue_responding(ebb_connection *connection) { delete(AsyncConnection *) connection->data; connection->data = nullptr; 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; #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); }