static void proxy_io_cb(liIOStream *stream, liIOStreamEvent event) { proxy_connection *con = stream->data; liWorker *wrk = li_worker_from_iostream(stream); li_stream_simple_socket_io_cb_with_context(stream, event, &con->simple_socket_data); switch (event) { case LI_IOSTREAM_DESTROY: li_stream_simple_socket_close(stream, FALSE); li_event_io_set_fd(&con->bcon->watcher, -1); li_backend_put(wrk, con->ctx->pool, con->bcon, TRUE); con->bcon = NULL; proxy_context_release(con->ctx); g_slice_free(proxy_connection, con); stream->data = NULL; return; default: break; } if ((NULL == stream->stream_in.out || stream->stream_in.out->is_closed) && !(NULL == stream->stream_out.out || stream->stream_out.out->is_closed)) { stream->stream_out.out->is_closed = TRUE; li_stream_again_later(&stream->stream_out); } }
void li_connection_simple_tcp(liConnection **pcon, liIOStream *stream, gpointer *context, liIOStreamEvent event) { liConnection *con; goffset transfer_in = 0, transfer_out = 0; transfer_in = (NULL != stream->stream_in.out) ? stream->stream_in.out->bytes_in : 0; transfer_out = (NULL != stream->stream_out.out) ? stream->stream_out.out->bytes_out : 0; li_stream_simple_socket_io_cb_with_context(stream, event, context); /* li_stream_simple_socket_io_cb_with_context might lead to *pcon == NULL */ con = *pcon; if (NULL != con) { if (NULL != stream->stream_in.out) { transfer_in = stream->stream_in.out->bytes_in - transfer_in; if (transfer_in > 0) { li_connection_update_io_timeout(con); li_vrequest_update_stats_in(con->mainvr, transfer_in); } } if (NULL != stream->stream_out.out) { transfer_out = stream->stream_out.out->bytes_out - transfer_out; if (transfer_out > 0) { li_connection_update_io_timeout(con); li_vrequest_update_stats_out(con->mainvr, transfer_out); } } } switch (event) { case LI_IOSTREAM_DESTROY: li_stream_simple_socket_close(stream, FALSE); return; case LI_IOSTREAM_DISCONNECTED_DEST: if (NULL != stream->stream_in.out && !stream->stream_in.out->is_closed) { li_stream_simple_socket_close(stream, TRUE); return; } break; case LI_IOSTREAM_DISCONNECTED_SOURCE: if (NULL != stream->stream_out.out && !stream->stream_out.out->is_closed) { li_stream_simple_socket_close(stream, TRUE); return; } break; default: break; } if ((NULL == stream->stream_in.out || stream->stream_in.out->is_closed) && !(NULL == stream->stream_out.out || stream->stream_out.out->is_closed)) { stream->stream_out.out->is_closed = TRUE; li_stream_again_later(&stream->stream_out); } }
void li_filter_buffer_on_disk_stop(liStream *stream) { bod_state *state; if (NULL == stream) return; assert(bod_cb == stream->cb); li_stream_acquire(stream); state = LI_CONTAINER_OF(stream, bod_state, stream); bod_stop(state); li_stream_again_later(stream); li_stream_release(stream); }
static void li_connection_reset_keep_alive(liConnection *con) { liVRequest *vr = con->mainvr; if (NULL == con->con_sock.raw_in || NULL == con->con_sock.raw_out || con->in.source != con->con_sock.raw_in) { li_connection_reset(con); return; } /* only start keep alive watcher if there isn't more input data already */ if (con->con_sock.raw_in->out->length == 0) { li_event_stop(&con->keep_alive_data.watcher); { con->keep_alive_data.max_idle = CORE_OPTION(LI_CORE_OPTION_MAX_KEEP_ALIVE_IDLE).number; if (con->keep_alive_data.max_idle == 0) { con->state = LI_CON_STATE_CLOSE; con_iostream_shutdown(con); li_connection_reset(con); return; } con->keep_alive_data.timeout = li_cur_ts(con->wrk) + con->keep_alive_data.max_idle; if (con->keep_alive_data.max_idle == con->srv->keep_alive_queue_timeout) { /* queue is sorted by con->keep_alive_data.timeout */ gboolean need_start = (0 == con->wrk->keep_alive_queue.length); con->keep_alive_data.timeout = li_cur_ts(con->wrk) + con->srv->keep_alive_queue_timeout; g_queue_push_tail(&con->wrk->keep_alive_queue, con); con->keep_alive_data.link = g_queue_peek_tail_link(&con->wrk->keep_alive_queue); if (need_start) li_worker_check_keepalive(con->wrk); } else { li_event_timer_once(&con->keep_alive_data.watcher, con->keep_alive_data.max_idle); } } } else { li_stream_again_later(&con->in); } con->state = LI_CON_STATE_KEEP_ALIVE; con->response_headers_sent = FALSE; con->expect_100_cont = FALSE; con->out_has_all_data = FALSE; con->info.keep_alive = TRUE; li_connection_update_io_wait(con); li_vrequest_reset(con->mainvr, TRUE); li_http_request_parser_reset(&con->req_parser_ctx); li_stream_disconnect(&con->out); li_stream_disconnect_dest(&con->in); con->out.out->is_closed = FALSE; memset(&con->in_chunked_decode_state, 0, sizeof(con->in_chunked_decode_state)); /* restore chunkqueue limits */ 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); /* reset stats */ con->info.stats.bytes_in = G_GUINT64_CONSTANT(0); con->info.stats.bytes_in_5s = G_GUINT64_CONSTANT(0); con->info.stats.bytes_in_5s_diff = G_GUINT64_CONSTANT(0); con->info.stats.bytes_out = G_GUINT64_CONSTANT(0); con->info.stats.bytes_out_5s = G_GUINT64_CONSTANT(0); con->info.stats.bytes_out_5s_diff = G_GUINT64_CONSTANT(0); con->info.stats.last_avg = 0; }
static void stream_crypt_source_limit_notify_cb(gpointer context, gboolean locked) { liGnuTLSFilter *f = context; if (!locked) li_stream_again_later(&f->plain_drain); }
static void do_gnutls_write(liGnuTLSFilter *f) { const ssize_t blocksize = 16*1024; /* 16k */ char *block_data; off_t block_len; ssize_t r; off_t write_max; #ifdef USE_CORK gboolean corked = FALSE; #endif liChunkQueue *cq = f->plain_drain.out; f_acquire(f); f->write_wants_read = FALSE; /* use space in (encrypted) outgoing buffer as amounts of bytes we try to write from (plain) output * don't care if we write a little bit more than the limit allowed */ write_max = li_chunkqueue_limit_available(f->crypt_source.out); LI_FORCE_ASSERT(write_max >= 0); /* we set a limit! */ if (0 == write_max) goto out; /* if we start writing, try to write at least blocksize bytes */ if (write_max < blocksize) write_max = blocksize; if (NULL != f->session && !f->initial_handshaked_finished && !do_gnutls_handshake(f, TRUE)) goto out; if (NULL == f->session) { f_abort_gnutls(f); goto out; } #ifdef USE_CORK if (0 != cq->length && cq->queue.length > 1) { corked = TRUE; gnutls_record_cork(f->session); } #endif do { GError *err = NULL; liChunkIter ci; if (0 == cq->length) break; ci = li_chunkqueue_iter(cq); switch (li_chunkiter_read(ci, 0, blocksize, &block_data, &block_len, &err)) { case LI_HANDLER_GO_ON: break; case LI_HANDLER_ERROR: if (NULL != err) { _ERROR(f->srv, f->wrk, f->log_context, "Couldn't read data from chunkqueue: %s", err->message); g_error_free(err); } /* fall through */ default: f_abort_gnutls(f); goto out; } r = gnutls_record_send(f->session, block_data, block_len); if (r <= 0) { do_handle_error(f, "gnutls_record_send", r, TRUE); goto out; } li_chunkqueue_skip(cq, r); write_max -= r; } while (r == block_len && write_max > 0); if (cq->is_closed && 0 == cq->length) { r = gnutls_bye(f->session, GNUTLS_SHUT_RDWR); switch (r) { case GNUTLS_E_SUCCESS: case GNUTLS_E_AGAIN: case GNUTLS_E_INTERRUPTED: f->plain_source.out->is_closed = TRUE; f->crypt_source.out->is_closed = TRUE; f->crypt_drain.out->is_closed = TRUE; li_stream_disconnect(&f->crypt_source); /* plain in -> crypt out */ f_close_gnutls(f); break; default: do_handle_error(f, "gnutls_bye", r, TRUE); f_abort_gnutls(f); break; } } else if (0 < cq->length && 0 != li_chunkqueue_limit_available(f->crypt_source.out)) { li_stream_again_later(&f->plain_drain); } out: #ifdef USE_CORK if (NULL != f->session && corked) { corked = TRUE; gnutls_record_uncork(f->session, 0); } #endif f_release(f); }