static liHandlerResult proxy_handle(liVRequest *vr, gpointer param, gpointer *context) { liBackendWait *bwait = (liBackendWait*) *context; liBackendConnection *bcon = NULL; proxy_context *ctx = (proxy_context*) param; liBackendResult bres; if (li_vrequest_is_handled(vr)) return LI_HANDLER_GO_ON; LI_VREQUEST_WAIT_FOR_REQUEST_BODY(vr); if (vr->request.content_length < 0) { VR_ERROR(vr, "%s", "proxy can't handle progressive uploads yet. enable request body buffering!"); return LI_HANDLER_ERROR; } bres = li_backend_get(vr, ctx->pool, &bcon, &bwait); *context = bwait; switch (bres) { case LI_BACKEND_SUCCESS: LI_FORCE_ASSERT(NULL == bwait); LI_FORCE_ASSERT(NULL != bcon); break; case LI_BACKEND_WAIT: LI_FORCE_ASSERT(NULL != bwait); return LI_HANDLER_WAIT_FOR_EVENT; case LI_BACKEND_TIMEOUT: li_vrequest_backend_dead(vr); return LI_HANDLER_GO_ON; } proxy_connection_new(vr, bcon, ctx); return LI_HANDLER_GO_ON; }
void li_connection_free(liConnection *con) { LI_FORCE_ASSERT(NULL == con->con_sock.data); LI_FORCE_ASSERT(LI_CON_STATE_DEAD == con->state); con->response_headers_sent = FALSE; con->expect_100_cont = FALSE; con->out_has_all_data = FALSE; li_server_socket_release(con->srv_sock); con->srv_sock = NULL; g_string_free(con->info.remote_addr_str, TRUE); li_sockaddr_clear(&con->info.remote_addr); g_string_free(con->info.local_addr_str, TRUE); li_sockaddr_clear(&con->info.local_addr); li_vrequest_free(con->mainvr); li_http_request_parser_clear(&con->req_parser_ctx); con->info.keep_alive = TRUE; if (con->keep_alive_data.link && con->wrk) { g_queue_delete_link(&con->wrk->keep_alive_queue, con->keep_alive_data.link); con->keep_alive_data.link = NULL; } con->keep_alive_data.timeout = 0; con->keep_alive_data.max_idle = 0; li_event_clear(&con->keep_alive_data.watcher); /* remove from timeout queue */ li_waitqueue_remove(&con->wrk->io_timeout_queue, &con->io_timeout_elem); li_job_clear(&con->job_reset); g_slice_free(liConnection, con); }
static liHandlerResult core_handle_throttle_ip(liVRequest *vr, gpointer param, gpointer *context) { throttle_ip_pools *pools = param; liThrottleState *state = vr_get_throttle_out_state(vr); UNUSED(context); if (NULL != state) { refcounted_pool_entry *entry = create_ip_pool(vr->wrk->srv, pools, &vr->coninfo->remote_addr); if (NULL != entry) { if (!li_throttle_add_pool(vr->wrk, state, entry->pool)) { /* we already had a reference */ g_atomic_int_add(&pools->refcount, -1); LI_FORCE_ASSERT(g_atomic_int_get(&pools->refcount) > 0); g_atomic_int_add(&entry->refcount, -1); LI_FORCE_ASSERT(g_atomic_int_get(&entry->refcount) > 0); } else { GArray *vr_ip_pools = (GArray*) g_ptr_array_index(vr->plugin_ctx, pools->plugin_id); vr_ip_pools_entry ventry; if (NULL == vr_ip_pools) { vr_ip_pools = g_array_new(FALSE, TRUE, sizeof(vr_ip_pools_entry)); g_ptr_array_index(vr->plugin_ctx, pools->plugin_id) = vr_ip_pools; } ventry.pools = pools; ventry.remote_addr_copy = li_sockaddr_dup(vr->coninfo->remote_addr); g_array_append_val(vr_ip_pools, ventry); } } } return LI_HANDLER_GO_ON; }
static void simple_tcp_io_cb(liIOStream *stream, liIOStreamEvent event) { simple_tcp_connection *data = stream->data; LI_FORCE_ASSERT(NULL != data); LI_FORCE_ASSERT(NULL == data->con || data == data->con->con_sock.data); LI_FORCE_ASSERT(NULL == data->sock_stream || stream == data->sock_stream); li_connection_simple_tcp(&data->con, stream, &data->simple_tcp_context, event); if (NULL != data->con && data->con->out_has_all_data && (NULL == stream->stream_out.out || 0 == stream->stream_out.out->length)) { li_stream_simple_socket_flush(stream); li_connection_request_done(data->con); } switch (event) { case LI_IOSTREAM_DESTROY: LI_FORCE_ASSERT(NULL == data->con); LI_FORCE_ASSERT(NULL == data->sock_stream); stream->data = NULL; g_slice_free(simple_tcp_connection, data); break; default: break; } }
static void tcp_io_cb(liIOStream *stream, liIOStreamEvent event) { mod_connection_ctx *conctx = stream->data; LI_FORCE_ASSERT(NULL == conctx->sock_stream || conctx->sock_stream == stream); if (LI_IOSTREAM_DESTROY == event) { li_stream_simple_socket_close(stream, TRUE); /* kill it, ssl sent an close alert message */ } li_connection_simple_tcp(&conctx->con, stream, &conctx->simple_socket_data, event); if (NULL != conctx->con && conctx->con->out_has_all_data && (NULL == stream->stream_out.out || 0 == stream->stream_out.out->length) && li_streams_empty(conctx->con->con_sock.raw_out, NULL)) { li_stream_simple_socket_flush(stream); li_connection_request_done(conctx->con); } switch (event) { case LI_IOSTREAM_DESTROY: LI_FORCE_ASSERT(NULL == conctx->sock_stream); LI_FORCE_ASSERT(NULL == conctx->tls_filter); LI_FORCE_ASSERT(NULL == conctx->con); stream->data = NULL; g_slice_free(mod_connection_ctx, conctx); return; default: break; } }
static void free_ip_pool(liServer *srv, throttle_ip_pools *pools, liSocketAddress *remote_addr) { refcounted_pool_entry *entry; switch (remote_addr->addr->plain.sa_family) { case AF_INET: case AF_INET6: break; default: return; } g_mutex_lock(pools->lock); if (remote_addr->addr->plain.sa_family == AF_INET) { entry = li_radixtree_lookup_exact(pools->ipv4_pools, &remote_addr->addr->ipv4.sin_addr.s_addr, pools->masklen_ipv4); } else { entry = li_radixtree_lookup_exact(pools->ipv6_pools, &remote_addr->addr->ipv6.sin6_addr.s6_addr, pools->masklen_ipv6); } LI_FORCE_ASSERT(NULL != entry); LI_FORCE_ASSERT(g_atomic_int_get(&entry->refcount) > 0); if (g_atomic_int_dec_and_test(&entry->refcount)) { if (remote_addr->addr->plain.sa_family == AF_INET) { li_radixtree_remove(pools->ipv4_pools, &remote_addr->addr->ipv4.sin_addr.s_addr, pools->masklen_ipv4); } else { li_radixtree_remove(pools->ipv6_pools, &remote_addr->addr->ipv6.sin6_addr.s6_addr, pools->masklen_ipv6); } li_throttle_pool_release(entry->pool, srv); g_slice_free(refcounted_pool_entry, entry); } g_mutex_unlock(pools->lock); ip_pools_free(pools); }
static void close_cb(liGnuTLSFilter *f, gpointer data) { mod_connection_ctx *conctx = data; liConnection *con = conctx->con; LI_FORCE_ASSERT(conctx->tls_filter == f); conctx->tls_filter = NULL; li_gnutls_filter_free(f); gnutls_deinit(conctx->session); if (NULL != conctx->ctx) { mod_gnutls_context_release(conctx->ctx); conctx->ctx = NULL; } if (NULL != conctx->con) { liStream *raw_out = con->con_sock.raw_out, *raw_in = con->con_sock.raw_in; LI_FORCE_ASSERT(con->con_sock.data == conctx); conctx->con = NULL; con->con_sock.data = NULL; con->con_sock.callbacks = NULL; li_stream_acquire(raw_in); li_stream_reset(raw_out); li_stream_reset(raw_in); li_stream_release(raw_in); } #ifdef USE_SNI if (NULL != conctx->sni_db_wait) { li_fetch_cancel(&conctx->sni_db_wait); } if (NULL != conctx->sni_entry) { li_fetch_entry_release(conctx->sni_entry); conctx->sni_entry = NULL; } #endif if (NULL != conctx->client_hello_stream) { li_ssl_client_hello_stream_ready(conctx->client_hello_stream); li_stream_release(conctx->client_hello_stream); conctx->client_hello_stream = NULL; } #ifdef USE_SNI if (NULL != conctx->sni_jobref) { li_job_ref_release(conctx->sni_jobref); conctx->sni_jobref = NULL; } li_job_clear(&conctx->sni_job); if (NULL != conctx->sni_server_name) { g_string_free(conctx->sni_server_name, TRUE); conctx->sni_server_name = NULL; } #endif LI_FORCE_ASSERT(NULL != conctx->sock_stream); li_iostream_safe_release(&conctx->sock_stream); }
static void event_async_cb(struct ev_loop *loop, ev_async *w, int revents) { liEventAsync *async = LI_CONTAINER_OF(w, liEventAsync, libevmess.async); liEventLoop *my_loop = async->base.link_watchers.data; UNUSED(revents); LI_FORCE_ASSERT(NULL != my_loop); LI_FORCE_ASSERT(loop == my_loop->loop); async->base.callback(&async->base, LI_EV_WAKEUP); }
static void event_check_cb(struct ev_loop *loop, ev_check *w, int revents) { liEventCheck *check = LI_CONTAINER_OF(w, liEventCheck, libevmess.check); liEventLoop *my_loop = check->base.link_watchers.data; UNUSED(revents); LI_FORCE_ASSERT(NULL != my_loop); LI_FORCE_ASSERT(loop == my_loop->loop); check->base.callback(&check->base, LI_EV_WAKEUP); }
static void event_prepare_cb(struct ev_loop *loop, ev_prepare *w, int revents) { liEventPrepare *prepare = LI_CONTAINER_OF(w, liEventPrepare, libevmess.prepare); liEventLoop *my_loop = prepare->base.link_watchers.data; UNUSED(revents); LI_FORCE_ASSERT(NULL != my_loop); LI_FORCE_ASSERT(loop == my_loop->loop); prepare->base.callback(&prepare->base, LI_EV_WAKEUP); }
static void event_signal_cb(struct ev_loop *loop, ev_signal *w, int revents) { liEventSignal *sig = LI_CONTAINER_OF(w, liEventSignal, libevmess.sig); liEventLoop *my_loop = sig->base.link_watchers.data; UNUSED(revents); LI_FORCE_ASSERT(NULL != my_loop); LI_FORCE_ASSERT(loop == my_loop->loop); sig->base.callback(&sig->base, LI_EV_WAKEUP); }
static void event_io_cb(struct ev_loop *loop, ev_io *w, int revents) { liEventIO *io = LI_CONTAINER_OF(w, liEventIO, libevmess.io); liEventLoop *my_loop = io->base.link_watchers.data; int events = 0; LI_FORCE_ASSERT(NULL != my_loop); LI_FORCE_ASSERT(loop == my_loop->loop); if (revents & EV_READ) events |= LI_EV_READ; if (revents & EV_WRITE) events |= LI_EV_WRITE; io->base.callback(&io->base, events); }
static void mimetype_insert(liMimetypeNode *node, GString *suffix, GString *mimetype, guint depth) { guchar c, cdiff; gpointer ptr; liMimetypeNode *next_node; LI_FORCE_ASSERT(!MIME_IS_NODE(mimetype)); /* start of suffix reached */ if (depth == suffix->len) { if (node->mimetype) g_string_free(node->mimetype, TRUE); node->mimetype = mimetype; return; } c = (guchar) suffix->str[suffix->len - depth - 1]; LI_FORCE_ASSERT(c != '\0'); if (NULL == node->children) { node->cmin = node->cmax = c; node->children = g_malloc(sizeof(gpointer)); node->children[0] = NULL; } else if (c < node->cmin) { cdiff = node->cmin - c; /* how much space we need in front */ node->children = g_realloc(node->children, sizeof(gpointer) * (MIME_COUNT_CHILDREN(node) + cdiff)); /* make room for more children */ memmove(&node->children[(guint)cdiff], node->children, sizeof(gpointer) * MIME_COUNT_CHILDREN(node)); /* move existing children to the back */ memset(node->children, 0, cdiff * sizeof(gpointer)); node->cmin = c; } else if (c > node->cmax) { cdiff = c - node->cmax; node->children = g_realloc(node->children, sizeof(gpointer) * (MIME_COUNT_CHILDREN(node) + cdiff)); /* make room for more children */ memset(&node->children[MIME_COUNT_CHILDREN(node)], 0, cdiff * sizeof(gpointer)); node->cmax = c; } ptr = node->children[c - node->cmin]; if (NULL != ptr && MIME_IS_NODE(ptr)) { /* slot contains another node */ next_node = MIME_UNMARK_NODE(ptr); } else { /* slot not used yet or contains a mimetype, split into node */ next_node = g_slice_new(liMimetypeNode); next_node->mimetype = ptr; next_node->cmax = next_node->cmin = 0; next_node->children = NULL; node->children[c - node->cmin] = MIME_MARK_NODE(next_node); } mimetype_insert(next_node, suffix, mimetype, depth+1); }
void li_buffer_release(liBuffer *buf) { if (!buf) return; LI_FORCE_ASSERT(g_atomic_int_get(&buf->refcount) > 0); if (g_atomic_int_dec_and_test(&buf->refcount)) { _buffer_destroy(buf); } }
static void con_iostream_close(liConnection *con) { /* force close */ if (con->con_sock.callbacks) { con->info.aborted = TRUE; con->con_sock.callbacks->finish(con, TRUE); } LI_FORCE_ASSERT(NULL == con->con_sock.data); }
struct ev_loop* li_event_loop_clear(liEventLoop *loop) { struct ev_loop* evloop = loop->loop; GList *lnk; li_event_loop_end(loop); li_job_queue_clear(&loop->jobqueue); while (NULL != (lnk = loop->watchers.head)) { liEventBase *base = LI_CONTAINER_OF(lnk, liEventBase, link_watchers); LI_FORCE_ASSERT(li_event_attached_(base)); li_event_detach_(base); LI_FORCE_ASSERT(lnk != loop->watchers.head); } loop->loop = NULL; return evloop; }
static void event_child_cb(struct ev_loop *loop, ev_child *w, int revents) { liEventChild *child = LI_CONTAINER_OF(w, liEventChild, libevmess.child); liEventLoop *my_loop = child->base.link_watchers.data; UNUSED(revents); LI_FORCE_ASSERT(NULL != my_loop); LI_FORCE_ASSERT(loop == my_loop->loop); if (ev_is_active(w)) { if (!child->base.keep_loop_alive) ev_ref(loop); ev_child_stop(loop, w); } child->base.active = 0; child->base.callback(&child->base, LI_EV_WAKEUP); }
void li_memcached_con_release(liMemcachedCon* con) { if (!con) return; LI_FORCE_ASSERT(g_atomic_int_get(&con->refcount) > 0); if (g_atomic_int_dec_and_test(&con->refcount)) { li_memcached_con_free(con); } }
static void event_timer_cb(struct ev_loop *loop, ev_timer *w, int revents) { liEventTimer *timer = LI_CONTAINER_OF(w, liEventTimer, libevmess.timer); liEventLoop *my_loop = timer->base.link_watchers.data; UNUSED(revents); LI_FORCE_ASSERT(NULL != my_loop); LI_FORCE_ASSERT(loop == my_loop->loop); if (ev_is_active(w)) { if (!timer->base.keep_loop_alive) ev_ref(loop); ev_timer_stop(loop, w); } timer->base.active = 0; timer->base.callback(&timer->base, LI_EV_WAKEUP); }
static void mainvr_connection_upgrade(liVRequest *vr, liStream *backend_drain, liStream *backend_source) { liConnection* con = li_connection_from_vrequest(vr); LI_FORCE_ASSERT(NULL != con); if (con->response_headers_sent || NULL != con->out.source) { li_connection_error(con); return; } if (CORE_OPTION(LI_CORE_OPTION_DEBUG_REQUEST_HANDLING).boolean) { VR_DEBUG(vr, "%s", "connection upgrade: write response headers"); } con->response_headers_sent = TRUE; con->info.keep_alive = FALSE; li_response_send_headers(vr, con->out.out, NULL, TRUE); con->state = LI_CON_STATE_UPGRADED; vr->response.transfer_encoding = 0; li_connection_update_io_wait(con); li_stream_disconnect_dest(&con->in); con->in.out->is_closed = FALSE; li_stream_connect(&con->in, backend_drain); li_stream_connect(backend_source, &con->out); li_vrequest_reset(con->mainvr, TRUE); if (NULL != con->in.source) { li_chunkqueue_steal_all(con->out.out, backend_drain->out); } con->info.out_queue_length = con->out.out->length; li_stream_notify(&con->out); li_stream_notify(&con->in); }
static void auth_file_data_release(AuthFileData *data) { if (!data) return; LI_FORCE_ASSERT(g_atomic_int_get(&data->refcount) > 0); if (!g_atomic_int_dec_and_test(&data->refcount)) return; g_hash_table_destroy(data->users); g_free(data->contents); g_slice_free(AuthFileData, data); }
static void proxy_context_release(proxy_context *ctx) { if (!ctx) return; LI_FORCE_ASSERT(g_atomic_int_get(&ctx->refcount) > 0); if (g_atomic_int_dec_and_test(&ctx->refcount)) { li_backend_pool_free(ctx->pool); g_string_free(ctx->socket_str, TRUE); g_slice_free(proxy_context, ctx); } }
void li_value_wrap_in_list(liValue *val) { liValue *item; LI_FORCE_ASSERT(NULL != val); item = li_value_extract(val); val->type = LI_VALUE_LIST; val->data.list = g_ptr_array_new(); g_ptr_array_add(val->data.list, item); }
void li_connection_start(liConnection *con, liSocketAddress remote_addr, int s, liServerSocket *srv_sock) { LI_FORCE_ASSERT(NULL == con->con_sock.data); con->srv_sock = srv_sock; con->state = LI_CON_STATE_REQUEST_START; con->mainvr->ts_started = con->ts_started = li_cur_ts(con->wrk); con->info.remote_addr = remote_addr; li_sockaddr_to_string(remote_addr, con->info.remote_addr_str, FALSE); con->info.local_addr = li_sockaddr_dup(srv_sock->local_addr); li_sockaddr_to_string(con->info.local_addr, con->info.local_addr_str, FALSE); con->info.aborted = FALSE; li_stream_init(&con->in, &con->wrk->loop, _connection_http_in_cb); li_stream_init(&con->out, &con->wrk->loop, _connection_http_out_cb); con->info.req = &con->in; con->info.resp = &con->out; li_connection_update_io_wait(con); if (srv_sock->new_cb) { if (!srv_sock->new_cb(con, s)) { li_connection_error(con); return; } } else { simple_tcp_new(con, s); } LI_FORCE_ASSERT(NULL != con->con_sock.raw_in || NULL != con->con_sock.raw_out); li_chunkqueue_use_limit(con->con_sock.raw_in->out, LI_CONNECTION_DEFAULT_CHUNKQUEUE_LIMIT); li_chunkqueue_use_limit(con->con_sock.raw_out->out, LI_CONNECTION_DEFAULT_CHUNKQUEUE_LIMIT); li_stream_connect(&con->out, con->con_sock.raw_out); li_stream_connect(con->con_sock.raw_in, &con->in); li_chunk_parser_init(&con->req_parser_ctx.chunk_ctx, con->con_sock.raw_in->out); }
static void gnutls_tcp_finished(liConnection *con, gboolean aborted) { mod_connection_ctx *conctx = con->con_sock.data; UNUSED(aborted); con->info.is_ssl = FALSE; con->con_sock.callbacks = NULL; if (NULL != conctx) { LI_FORCE_ASSERT(con == conctx->con); close_cb(conctx->tls_filter, conctx); LI_FORCE_ASSERT(NULL == con->con_sock.data); } { liStream *raw_out = con->con_sock.raw_out, *raw_in = con->con_sock.raw_in; con->con_sock.raw_out = con->con_sock.raw_in = NULL; if (NULL != raw_out) { li_stream_reset(raw_out); li_stream_release(raw_out); } if (NULL != raw_in) { li_stream_reset(raw_in); li_stream_release(raw_in); } } }
void li_release_optionptr(liServer *srv, liOptionPtrValue *value) { liServerOptionPtr *sopt; LI_FORCE_ASSERT(NULL != srv); if (NULL == value) return; LI_FORCE_ASSERT(g_atomic_int_get(&value->refcount) > 0); if (!g_atomic_int_dec_and_test(&value->refcount)) return; sopt = value->sopt; value->sopt = NULL; if (!sopt->free_option) { switch (sopt->type) { case LI_VALUE_NONE: case LI_VALUE_BOOLEAN: case LI_VALUE_NUMBER: /* Nothing to free */ break; case LI_VALUE_STRING: if (value->data.string) g_string_free(value->data.string, TRUE); break; case LI_VALUE_LIST: if (value->data.list) li_value_list_free(value->data.list); break; case LI_VALUE_ACTION: if (value->data.action) li_action_release(srv, value->data.action); break; case LI_VALUE_CONDITION: if (value->data.cond) li_condition_release(srv, value->data.cond); break; } } else { sopt->free_option(srv, sopt->p, sopt->module_index, value->data.ptr); } g_slice_free(liOptionPtrValue, value); }
static void ip_pools_free(throttle_ip_pools *pools) { LI_FORCE_ASSERT(g_atomic_int_get(&pools->refcount) > 0); if (g_atomic_int_dec_and_test(&pools->refcount)) { g_mutex_free(pools->lock); pools->lock = NULL; /* entries keep references, so radix trees must be empty */ li_radixtree_free(pools->ipv4_pools, NULL, NULL); li_radixtree_free(pools->ipv6_pools, NULL, NULL); g_slice_free(throttle_ip_pools, pools); } }
void li_gnutls_filter_free(liGnuTLSFilter *f) { LI_FORCE_ASSERT(NULL != f->callbacks); f->callbacks = NULL; f->callback_data = NULL; f_close_gnutls(f); li_stream_release(&f->crypt_source); li_stream_release(&f->crypt_drain); li_stream_release(&f->plain_source); li_stream_release(&f->plain_drain); f_release(f); }
static refcounted_pool_entry* create_ip_pool(liServer *srv, throttle_ip_pools *pools, liSocketAddress *remote_addr) { refcounted_pool_entry *result; switch (remote_addr->addr->plain.sa_family) { case AF_INET: case AF_INET6: break; default: return NULL; } LI_FORCE_ASSERT(g_atomic_int_get(&pools->refcount) > 0); g_atomic_int_inc(&pools->refcount); g_mutex_lock(pools->lock); if (remote_addr->addr->plain.sa_family == AF_INET) { result = li_radixtree_lookup_exact(pools->ipv4_pools, &remote_addr->addr->ipv4.sin_addr.s_addr, pools->masklen_ipv4); } else { result = li_radixtree_lookup_exact(pools->ipv6_pools, &remote_addr->addr->ipv6.sin6_addr.s6_addr, pools->masklen_ipv6); } if (NULL == result) { result = g_slice_new0(refcounted_pool_entry); result->refcount = 1; result->pool = li_throttle_pool_new(srv, pools->rate, pools->burst); if (remote_addr->addr->plain.sa_family == AF_INET) { li_radixtree_insert(pools->ipv4_pools, &remote_addr->addr->ipv4.sin_addr.s_addr, pools->masklen_ipv4, result); } else { li_radixtree_insert(pools->ipv6_pools, &remote_addr->addr->ipv6.sin6_addr.s6_addr, pools->masklen_ipv6, result); } } else { LI_FORCE_ASSERT(g_atomic_int_get(&result->refcount) > 0); g_atomic_int_inc(&result->refcount); } g_mutex_unlock(pools->lock); return result; }
static void f_close_gnutls(liGnuTLSFilter *f) { if (NULL != f->session && !f->closing) { liCQLimit *limit; f->closing = TRUE; f->session = NULL; LI_FORCE_ASSERT(NULL != f->crypt_source.out); LI_FORCE_ASSERT(NULL != f->crypt_source.out->limit); limit = f->crypt_source.out->limit; limit->notify = NULL; limit->context = NULL; li_stream_disconnect(&f->plain_source); /* crypt in -> plain out */ li_stream_disconnect(&f->plain_drain); /* app -> plain in */ li_stream_disconnect_dest(&f->plain_source); /* plain out -> app */ f->log_context = NULL; if (NULL != f->callbacks && NULL != f->callbacks->closed_cb) { f->callbacks->closed_cb(f, f->callback_data); } } }