mirror of
https://github.com/sonertari/SSLproxy
synced 2024-11-19 21:25:28 +00:00
2411f79582
Fix child eof bug Flickr keeps redirecting to https with 301 unless we remove the Via line of squid, so apparently flickr assumes the existence of Via header field or squid keyword a sign of plain http, even if we are using https Also do not send the loopback address to the Internet Other fixes
490 lines
16 KiB
C
490 lines
16 KiB
C
/*
|
|
* SSLsplit - transparent SSL/TLS interception
|
|
* Copyright (c) 2009-2016, Daniel Roethlisberger <daniel@roe.ch>
|
|
* All rights reserved.
|
|
* http://www.roe.ch/SSLsplit
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions, and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include "pxythrmgr.h"
|
|
|
|
#include "sys.h"
|
|
#include "log.h"
|
|
#include "pxyconn.h"
|
|
|
|
#include <string.h>
|
|
#include <event2/bufferevent.h>
|
|
#include <pthread.h>
|
|
#include <assert.h>
|
|
|
|
/*
|
|
* Proxy thread manager: manages the connection handling worker threads
|
|
* and the per-thread resources (i.e. event bases). The load is shared
|
|
* across num_cpu * 2 connection handling threads, using the number of
|
|
* currently assigned connections as the sole metric.
|
|
*
|
|
* The attach and detach functions are thread-safe.
|
|
*/
|
|
|
|
#define THR_TIMER_TIMEOUT 10
|
|
#define THR_TIMER_PRINT_INFO_TIMEOUT 1*THR_TIMER_TIMEOUT
|
|
#define CONN_EXPIRE_TIME 120
|
|
|
|
static void
|
|
pxy_thrmgr_get_thr_expired_conns(pxy_thr_ctx_t *tctx, pxy_conn_ctx_t **expired_conns)
|
|
{
|
|
*expired_conns = NULL;
|
|
|
|
time_t now = time(NULL);
|
|
|
|
pxy_conn_ctx_t *ctx = tctx->conns;
|
|
while (ctx) {
|
|
unsigned long elapsed_time = now - ctx->atime;
|
|
if (elapsed_time > CONN_EXPIRE_TIME) {
|
|
ctx->next_expired = *expired_conns;
|
|
*expired_conns = ctx;
|
|
}
|
|
|
|
ctx = ctx->next;
|
|
}
|
|
|
|
ctx = *expired_conns;
|
|
if (ctx) {
|
|
log_dbg_level_printf(LOG_DBG_MODE_FINEST, ">>> pxy_thrmgr_get_thr_expired_conns: ----------------------------- Expired conns: thr=%d\n", tctx->thridx);
|
|
while (ctx) {
|
|
pxy_conn_ctx_t *next = ctx->next_expired;
|
|
log_dbg_level_printf(LOG_DBG_MODE_FINEST, ">>> pxy_thrmgr_get_expired_conns: thr=%d, fd=%d, child_fd=%d, time=%lld\n",
|
|
ctx->thr->thridx, ctx->fd, ctx->child_fd, (long int) now - ctx->atime);
|
|
ctx = next;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
pxy_thrmgr_print_child(pxy_conn_child_ctx_t *child_ctx, int count)
|
|
{
|
|
assert(child_ctx != NULL);
|
|
// log_dbg_level_printf(LOG_DBG_MODE_FINEST, ">>> .......... pxy_thrmgr_print_child: thr=%d, cont=%d, src=%d, dst=%d, c=%d-%d, i=%d\n",
|
|
// child_ctx->parent->thr->thridx, count, child_ctx->src_fd, child_ctx->dst_fd, child_ctx->src.closed, child_ctx->dst.closed, child_ctx->idx);
|
|
char *msg;
|
|
int rv;
|
|
rv = asprintf(&msg, "thr=%d, cont=%d, src=%d, dst=%d, c=%d-%d, i=%d\n",
|
|
child_ctx->parent->thr->thridx, count, child_ctx->src_fd, child_ctx->dst_fd, child_ctx->src.closed, child_ctx->dst.closed, child_ctx->idx);
|
|
|
|
log_dbg_level_printf(LOG_DBG_MODE_FINEST, ">>> .......... pxy_thrmgr_print_child: %s", msg);
|
|
if (child_ctx->parent->opts->statslog) {
|
|
if (log_stats_print_free(msg) == -1) {
|
|
free(msg);
|
|
log_err_printf("Warning: Stats logging failed\n");
|
|
}
|
|
} else {
|
|
free(msg);
|
|
}
|
|
|
|
if (child_ctx->next) {
|
|
pxy_thrmgr_print_child(child_ctx->next, count);
|
|
}
|
|
}
|
|
|
|
static void
|
|
pxy_thrmgr_print_thr_info(pxy_thr_ctx_t *tctx)
|
|
{
|
|
log_dbg_level_printf(LOG_DBG_MODE_FINEST, ">>> pxy_thrmgr_print_thr_info: thr=%d, load=%lu\n", tctx->thridx, tctx->load);
|
|
|
|
if (tctx->conns) {
|
|
time_t now = time(NULL);
|
|
|
|
pxy_conn_ctx_t *ctx = tctx->conns;
|
|
int count = 0;
|
|
while (ctx) {
|
|
char *host, *port;
|
|
char *msg;
|
|
int rv;
|
|
if (ctx->addrlen == 0 || (sys_sockaddr_str((struct sockaddr *)&ctx->addr, ctx->addrlen, &host, &port) != 0)) {
|
|
log_dbg_level_printf(LOG_DBG_MODE_FINEST, ">>> pxy_thrmgr_print_thr_info: Cannot get host:port: thr=%d, cont=%d, fd=%d, child_fd=%d\n", tctx->thridx, count, ctx->fd, ctx->child_fd);
|
|
// log_dbg_level_printf(LOG_DBG_MODE_FINEST, ">>> pxy_thrmgr_print_thr_info: thr=%d, cont=%d, fd=%d, child_fd=%d, dst=%d, srv_dst=%d, child_src=%d, child_dst=%d, p=%d-%d-%d c=%d-%d, ce=%d cc=%d, at=%lld ct=%lld\n",
|
|
// tctx->thridx, count, ctx->fd, ctx->child_fd, ctx->dst_fd, ctx->srv_dst_fd, ctx->child_src_fd, ctx->child_dst_fd,
|
|
// ctx->src.closed, ctx->dst.closed, ctx->srv_dst.closed, ctx->children ? ctx->children->src.closed : 0, ctx->children ? ctx->children->dst.closed : 0, ctx->children ? 1:0, ctx->child_count,(long int) now - ctx->atime, (long int) now - ctx->ctime);
|
|
rv = asprintf(&msg, "thr=%d, cont=%d, fd=%d, child_fd=%d, dst=%d, srv_dst=%d, child_src=%d, child_dst=%d, p=%d-%d-%d c=%d-%d, ce=%d cc=%d, at=%lld ct=%lld\n",
|
|
tctx->thridx, count, ctx->fd, ctx->child_fd, ctx->dst_fd, ctx->srv_dst_fd, ctx->child_src_fd, ctx->child_dst_fd,
|
|
ctx->src.closed, ctx->dst.closed, ctx->srv_dst.closed, ctx->children ? ctx->children->src.closed : 0, ctx->children ? ctx->children->dst.closed : 0, ctx->children ? 1:0, ctx->child_count,(long int) now - ctx->atime, (long int) now - ctx->ctime);
|
|
} else {
|
|
// log_dbg_level_printf(LOG_DBG_MODE_FINEST, ">>> pxy_thrmgr_print_thr_info: thr=%d, cont=%d, fd=%d, child_fd=%d, dst=%d, srv_dst=%d, child_src=%d, child_dst=%d, p=%d-%d-%d c=%d-%d, ce=%d cc=%d, at=%lld ct=%lld, addr=%s:%s\n",
|
|
// tctx->thridx, count, ctx->fd, ctx->child_fd, ctx->dst_fd, ctx->srv_dst_fd, ctx->child_src_fd, ctx->child_dst_fd,
|
|
// ctx->src.closed, ctx->dst.closed, ctx->srv_dst.closed, ctx->children ? ctx->children->src.closed : 0, ctx->children ? ctx->children->dst.closed : 0, ctx->children ? 1:0, ctx->child_count, (long int) now - ctx->atime, (long int) now - ctx->ctime, host ? host : "?", port ? port : "?");
|
|
|
|
rv = asprintf(&msg, "thr=%d, cont=%d, fd=%d, child_fd=%d, dst=%d, srv_dst=%d, child_src=%d, child_dst=%d, p=%d-%d-%d c=%d-%d, ce=%d cc=%d, at=%lld ct=%lld, addr=%s:%s\n",
|
|
tctx->thridx, count, ctx->fd, ctx->child_fd, ctx->dst_fd, ctx->srv_dst_fd, ctx->child_src_fd, ctx->child_dst_fd,
|
|
ctx->src.closed, ctx->dst.closed, ctx->srv_dst.closed, ctx->children ? ctx->children->src.closed : 0, ctx->children ? ctx->children->dst.closed : 0, ctx->children ? 1:0, ctx->child_count, (long int) now - ctx->atime, (long int) now - ctx->ctime, host ? host : "?", port ? port : "?");
|
|
|
|
|
|
free(host);
|
|
free(port);
|
|
}
|
|
|
|
log_dbg_level_printf(LOG_DBG_MODE_FINEST, ">>> pxy_thrmgr_print_thr_info: %s", msg);
|
|
|
|
if (ctx->opts->statslog) {
|
|
if (log_stats_print_free(msg) == -1) {
|
|
free(msg);
|
|
log_err_printf("Warning: Stats logging failed\n");
|
|
}
|
|
} else {
|
|
free(msg);
|
|
}
|
|
|
|
if (ctx->children) {
|
|
pxy_thrmgr_print_child(ctx->children, count);
|
|
}
|
|
|
|
count++;
|
|
ctx = ctx->next;
|
|
}
|
|
}
|
|
|
|
log_dbg_level_printf(LOG_DBG_MODE_FINEST, ">>> pxy_thrmgr_print_thr_info: EXIT\n");
|
|
}
|
|
|
|
/*
|
|
* Recurring timer event to prevent the event loops from exiting when
|
|
* they run out of events.
|
|
*/
|
|
static void
|
|
pxy_thrmgr_timer_cb(UNUSED evutil_socket_t fd, UNUSED short what,
|
|
UNUSED void *arg)
|
|
{
|
|
pxy_thr_ctx_t *ctx = arg;
|
|
|
|
log_dbg_level_printf(LOG_DBG_MODE_FINEST, ">>>>> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! pxy_thrmgr_timer_cb <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< THREAD TIMER thr=%d, load=%lu, to=%u\n", ctx->thridx, ctx->load, ctx->timeout_count);
|
|
pxy_conn_ctx_t *expired = NULL;
|
|
pxy_thrmgr_get_thr_expired_conns(ctx, &expired);
|
|
|
|
if (expired) {
|
|
time_t now = time(NULL);
|
|
while (expired) {
|
|
pxy_conn_ctx_t *next = expired->next_expired;
|
|
|
|
log_dbg_level_printf(LOG_DBG_MODE_FINE, ">>>>> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! pxy_thrmgr_timer_cb: DELETE thr=%d, fd=%d, child_fd=%d, at=%lld ct=%lld <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< TIMED OUT\n",
|
|
expired->thr->thridx, expired->fd, expired->child_fd, (long int) now - expired->atime, (long int) now - expired->ctime);
|
|
pxy_conn_free(expired, 1);
|
|
|
|
expired = next;
|
|
}
|
|
}
|
|
|
|
ctx->timeout_count++;
|
|
if (ctx->timeout_count * THR_TIMER_TIMEOUT > THR_TIMER_PRINT_INFO_TIMEOUT) {
|
|
ctx->timeout_count = 0;
|
|
pxy_thrmgr_print_thr_info(ctx);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Thread entry point; runs the event loop of the event base.
|
|
* Does not exit until the libevent loop is broken explicitly.
|
|
*/
|
|
static void *
|
|
pxy_thrmgr_thr(void *arg)
|
|
{
|
|
pxy_thr_ctx_t *ctx = arg;
|
|
struct timeval timer_delay = {THR_TIMER_TIMEOUT, 0};
|
|
struct event *ev;
|
|
|
|
ev = event_new(ctx->evbase, -1, EV_PERSIST, pxy_thrmgr_timer_cb, ctx);
|
|
if (!ev)
|
|
return NULL;
|
|
evtimer_add(ev, &timer_delay);
|
|
ctx->running = 1;
|
|
event_base_dispatch(ctx->evbase);
|
|
event_free(ev);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Create new thread manager but do not start any threads yet.
|
|
* This gets called before forking to background.
|
|
*/
|
|
pxy_thrmgr_ctx_t *
|
|
pxy_thrmgr_new(opts_t *opts)
|
|
{
|
|
pxy_thrmgr_ctx_t *ctx;
|
|
|
|
if (!(ctx = malloc(sizeof(pxy_thrmgr_ctx_t))))
|
|
return NULL;
|
|
memset(ctx, 0, sizeof(pxy_thrmgr_ctx_t));
|
|
|
|
ctx->opts = opts;
|
|
ctx->num_thr = 2 * sys_get_cpu_cores();
|
|
return ctx;
|
|
}
|
|
|
|
/*
|
|
* Start the thread manager and associated threads.
|
|
* This must be called after forking.
|
|
*
|
|
* Returns -1 on failure, 0 on success.
|
|
*/
|
|
int
|
|
pxy_thrmgr_run(pxy_thrmgr_ctx_t *ctx)
|
|
{
|
|
int idx = -1, dns = 0;
|
|
|
|
dns = opts_has_dns_spec(ctx->opts);
|
|
|
|
if (pthread_mutex_init(&ctx->mutex, NULL)) {
|
|
log_dbg_printf("Failed to initialize mutex\n");
|
|
goto leave;
|
|
}
|
|
|
|
if (!(ctx->thr = malloc(ctx->num_thr * sizeof(pxy_thr_ctx_t*)))) {
|
|
log_dbg_printf("Failed to allocate memory\n");
|
|
goto leave;
|
|
}
|
|
memset(ctx->thr, 0, ctx->num_thr * sizeof(pxy_thr_ctx_t*));
|
|
|
|
for (idx = 0; idx < ctx->num_thr; idx++) {
|
|
if (!(ctx->thr[idx] = malloc(sizeof(pxy_thr_ctx_t)))) {
|
|
log_dbg_printf("Failed to allocate memory\n");
|
|
goto leave;
|
|
}
|
|
memset(ctx->thr[idx], 0, sizeof(pxy_thr_ctx_t));
|
|
ctx->thr[idx]->evbase = event_base_new();
|
|
if (!ctx->thr[idx]->evbase) {
|
|
log_dbg_printf("Failed to create evbase %d\n", idx);
|
|
goto leave;
|
|
}
|
|
if (dns) {
|
|
/* only create dns base if we actually need it later */
|
|
ctx->thr[idx]->dnsbase = evdns_base_new(
|
|
ctx->thr[idx]->evbase, 1);
|
|
if (!ctx->thr[idx]->dnsbase) {
|
|
log_dbg_printf("Failed to create dnsbase %d\n",
|
|
idx);
|
|
goto leave;
|
|
}
|
|
}
|
|
ctx->thr[idx]->load = 0;
|
|
ctx->thr[idx]->running = 0;
|
|
ctx->thr[idx]->conns = NULL;
|
|
ctx->thr[idx]->thridx = idx;
|
|
ctx->thr[idx]->timeout_count = 0;
|
|
}
|
|
|
|
log_dbg_printf("Initialized %d connection handling threads\n",
|
|
ctx->num_thr);
|
|
|
|
for (idx = 0; idx < ctx->num_thr; idx++) {
|
|
if (pthread_create(&ctx->thr[idx]->thr, NULL,
|
|
pxy_thrmgr_thr, ctx->thr[idx]))
|
|
goto leave_thr;
|
|
while (!ctx->thr[idx]->running) {
|
|
sched_yield();
|
|
}
|
|
}
|
|
|
|
log_dbg_printf("Started %d connection handling threads\n",
|
|
ctx->num_thr);
|
|
|
|
return 0;
|
|
|
|
leave_thr:
|
|
idx--;
|
|
while (idx >= 0) {
|
|
pthread_cancel(ctx->thr[idx]->thr);
|
|
pthread_join(ctx->thr[idx]->thr, NULL);
|
|
idx--;
|
|
}
|
|
idx = ctx->num_thr - 1;
|
|
|
|
leave:
|
|
while (idx >= 0) {
|
|
if (ctx->thr[idx]) {
|
|
if (ctx->thr[idx]->dnsbase) {
|
|
evdns_base_free(ctx->thr[idx]->dnsbase, 0);
|
|
}
|
|
if (ctx->thr[idx]->evbase) {
|
|
event_base_free(ctx->thr[idx]->evbase);
|
|
}
|
|
free(ctx->thr[idx]);
|
|
}
|
|
idx--;
|
|
}
|
|
pthread_mutex_destroy(&ctx->mutex);
|
|
if (ctx->thr) {
|
|
free(ctx->thr);
|
|
ctx->thr = NULL;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* Destroy the event manager and stop all threads.
|
|
*/
|
|
void
|
|
pxy_thrmgr_free(pxy_thrmgr_ctx_t *ctx)
|
|
{
|
|
pthread_mutex_destroy(&ctx->mutex);
|
|
if (ctx->thr) {
|
|
for (int idx = 0; idx < ctx->num_thr; idx++) {
|
|
event_base_loopbreak(ctx->thr[idx]->evbase);
|
|
sched_yield();
|
|
}
|
|
for (int idx = 0; idx < ctx->num_thr; idx++) {
|
|
pthread_join(ctx->thr[idx]->thr, NULL);
|
|
}
|
|
for (int idx = 0; idx < ctx->num_thr; idx++) {
|
|
if (ctx->thr[idx]->dnsbase) {
|
|
evdns_base_free(ctx->thr[idx]->dnsbase, 0);
|
|
}
|
|
if (ctx->thr[idx]->evbase) {
|
|
event_base_free(ctx->thr[idx]->evbase);
|
|
}
|
|
free(ctx->thr[idx]);
|
|
}
|
|
free(ctx->thr);
|
|
}
|
|
free(ctx);
|
|
}
|
|
|
|
static void
|
|
pxy_thrmgr_remove_conn(pxy_conn_ctx_t *node, pxy_conn_ctx_t **head)
|
|
{
|
|
assert(node != NULL);
|
|
assert(*head != NULL);
|
|
log_dbg_level_printf(LOG_DBG_MODE_FINEST, ">>>>> pxy_thrmgr_remove_conn: DELETING, fd=%d, child_fd=%d\n", node->fd, node->child_fd);
|
|
|
|
// @attention We may get multiple conns with the same fd combinations, so they cannot uniquely define a conn; hence the need for uuids.
|
|
if (uuid_compare(node->uuid, (*head)->uuid, NULL) == 0) {
|
|
*head = (*head)->next;
|
|
return;
|
|
}
|
|
|
|
pxy_conn_ctx_t *current = (*head)->next;
|
|
pxy_conn_ctx_t *previous = *head;
|
|
while (current != NULL && previous != NULL) {
|
|
if (uuid_compare(node->uuid, current->uuid, NULL) == 0) {
|
|
previous->next = current->next;
|
|
return;
|
|
}
|
|
previous = current;
|
|
current = current->next;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Attach a new connection to a thread. Chooses the thread with the fewest
|
|
* currently active connections, returns the appropriate event bases.
|
|
* Returns the index of the chosen thread (for passing to _detach later).
|
|
* This function cannot fail.
|
|
*/
|
|
void
|
|
pxy_thrmgr_attach(pxy_conn_ctx_t *ctx)
|
|
{
|
|
int thridx;
|
|
size_t minload;
|
|
|
|
log_dbg_level_printf(LOG_DBG_MODE_FINEST, ">>>>> pxy_thrmgr_attach: ENTER\n");
|
|
|
|
thridx = 0;
|
|
|
|
pxy_thrmgr_ctx_t *tmctx = ctx->thrmgr;
|
|
pthread_mutex_lock(&tmctx->mutex);
|
|
|
|
minload = tmctx->thr[thridx]->load;
|
|
#ifdef DEBUG_THREAD
|
|
log_dbg_printf("===> Proxy connection handler thread status:\n"
|
|
"thr[%d]: %zu\n", thridx, minload);
|
|
#endif /* DEBUG_THREAD */
|
|
for (int idx = 1; idx < tmctx->num_thr; idx++) {
|
|
#ifdef DEBUG_THREAD
|
|
log_dbg_printf("thr[%d]: %zu\n", idx, tmctx->thr[idx]->load);
|
|
#endif /* DEBUG_THREAD */
|
|
if (minload > tmctx->thr[idx]->load) {
|
|
minload = tmctx->thr[idx]->load;
|
|
thridx = idx;
|
|
}
|
|
}
|
|
pthread_mutex_unlock(&tmctx->mutex);
|
|
|
|
ctx->thr = tmctx->thr[thridx];
|
|
|
|
ctx->evbase = ctx->thr->evbase;
|
|
ctx->dnsbase = ctx->thr->dnsbase;
|
|
ctx->thr->load++;
|
|
|
|
ctx->next = ctx->thr->conns;
|
|
ctx->thr->conns = ctx;
|
|
|
|
// @attention We are running on the thrmgr thread, do not call conn thread functions here.
|
|
//pxy_thrmgr_print_thr_info(ctx->thr);
|
|
|
|
log_dbg_level_printf(LOG_DBG_MODE_FINEST, ">>>>> pxy_thrmgr_attach: EXIT\n");
|
|
|
|
#ifdef DEBUG_THREAD
|
|
log_dbg_printf("thridx: %d\n", thridx);
|
|
#endif /* DEBUG_THREAD */
|
|
}
|
|
|
|
void
|
|
pxy_thrmgr_attach_child(pxy_conn_ctx_t *ctx)
|
|
{
|
|
log_dbg_level_printf(LOG_DBG_MODE_FINEST, ">>>>> pxy_thrmgr_attach_child\n");
|
|
pthread_mutex_lock(&ctx->thrmgr->mutex);
|
|
ctx->thr->load++;
|
|
pthread_mutex_unlock(&ctx->thrmgr->mutex);
|
|
}
|
|
|
|
/*
|
|
* Detach a connection from a thread by index.
|
|
* This function cannot fail.
|
|
*/
|
|
void
|
|
pxy_thrmgr_detach(pxy_conn_ctx_t *ctx)
|
|
{
|
|
assert(ctx->children == NULL);
|
|
|
|
pthread_mutex_lock(&ctx->thrmgr->mutex);
|
|
|
|
// log_dbg_level_printf(LOG_DBG_MODE_FINEST, ">>>>> pxy_thrmgr_detach: BEFORE pxy_thrmgr_remove_conn\n");
|
|
// pxy_thrmgr_print_thr_info(ctx->thr);
|
|
|
|
ctx->thr->load--;
|
|
pxy_thrmgr_remove_conn(ctx, &ctx->thr->conns);
|
|
|
|
// log_dbg_level_printf(LOG_DBG_MODE_FINER, ">>>>> pxy_thrmgr_detach: AFTER pxy_thrmgr_remove_conn\n");
|
|
// pxy_thrmgr_print_thr_info(ctx->thr);
|
|
|
|
pthread_mutex_unlock(&ctx->thrmgr->mutex);
|
|
}
|
|
|
|
void
|
|
pxy_thrmgr_detach_child(pxy_conn_ctx_t *ctx)
|
|
{
|
|
log_dbg_level_printf(LOG_DBG_MODE_FINEST, ">>>>> pxy_thrmgr_detach_child\n");
|
|
pthread_mutex_lock(&ctx->thrmgr->mutex);
|
|
ctx->thr->load--;
|
|
pthread_mutex_unlock(&ctx->thrmgr->mutex);
|
|
}
|
|
|
|
/* vim: set noet ft=c: */
|