commit b3eb133de68e8ce77fbf382e0df25ed523cd7f44
parent a40b58b3c9dfc45886d5213dda5a02701fbeaeeb
Author: Alexander Hansen Færøy <ahf@torproject.org>
Date: Wed, 28 Jan 2026 16:58:03 +0100
Merge branch 'pt-death' into 'main'
transports: handle process death better
See merge request tpo/core/tor!977
Diffstat:
2 files changed, 47 insertions(+), 6 deletions(-)
diff --git a/src/feature/client/transports.c b/src/feature/client/transports.c
@@ -90,6 +90,7 @@
**/
#include "lib/string/printf.h"
+#include "lib/evloop/compat_libevent.h"
#define PT_PRIVATE
#include "core/or/or.h"
#include "feature/client/bridges.h"
@@ -492,7 +493,9 @@ proxy_needs_restart(const managed_proxy_t *mp)
launched: */
tor_assert(smartlist_len(mp->transports_to_launch) > 0);
- tor_assert(mp->conf_state == PT_PROTO_COMPLETED);
+ if (BUG(mp->conf_state != PT_PROTO_COMPLETED)) {
+ goto needs_restart;
+ }
if (smartlist_len(mp->transports_to_launch) != smartlist_len(mp->transports))
goto needs_restart;
@@ -517,7 +520,12 @@ proxy_prepare_for_restart(managed_proxy_t *mp)
{
transport_t *t_tmp = NULL;
- tor_assert(mp->conf_state == PT_PROTO_COMPLETED);
+ /* Rate limit this log as a regurlarly dying PT would log this once every
+ * second (retry time). Every 5 minutes is likely loud enough to notice. */
+ static ratelim_t log_died_lim = RATELIM_INIT(300);
+ log_fn_ratelim(&log_died_lim, LOG_WARN, LD_PT,
+ "Managed proxy at '%s' died in state %s", mp->argv[0],
+ managed_proxy_state_to_string(mp->conf_state));
/* destroy the process handle and terminate the process. */
if (mp->process) {
@@ -543,9 +551,11 @@ proxy_prepare_for_restart(managed_proxy_t *mp)
mp->proxy_uri = get_pt_proxy_uri();
mp->proxy_supported = 0;
+ if (mp->conf_state == PT_PROTO_COMPLETED)
+ unconfigured_proxies_n++;
+
/* flag it as an infant proxy so that it gets launched on next tick */
managed_proxy_set_state(mp, PT_PROTO_INFANT);
- unconfigured_proxies_n++;
}
/** Launch managed proxy <b>mp</b>. */
@@ -643,6 +653,23 @@ pt_configure_remaining_proxies(void)
mark_my_descriptor_dirty("configured managed proxies");
}
+/** event callback to launch managed proxy after a delay */
+STATIC void
+launch_proxy_ev(mainloop_event_t *event, void *v)
+{
+ managed_proxy_t *mp = v;
+
+ (void) event;
+
+ tor_assert(mp);
+ tor_assert(mp->conf_state == PT_PROTO_WAITING);
+
+ if (launch_managed_proxy(mp) < 0) { /* launch fail */
+ managed_proxy_set_state(mp, PT_PROTO_FAILED_LAUNCH);
+ handle_finished_proxy(mp);
+ }
+}
+
/** Attempt to continue configuring managed proxy <b>mp</b>.
* Return 1 if the transport configuration finished, and return 0
* otherwise (if we still have more configuring to do for this
@@ -652,10 +679,13 @@ configure_proxy(managed_proxy_t *mp)
{
/* if we haven't launched the proxy yet, do it now */
if (mp->conf_state == PT_PROTO_INFANT) {
- if (launch_managed_proxy(mp) < 0) { /* launch fail */
- managed_proxy_set_state(mp, PT_PROTO_FAILED_LAUNCH);
- handle_finished_proxy(mp);
+ const struct timeval delay_tv = { 1, 0 };
+ if (!mp->process_launch_ev) {
+ mp->process_launch_ev = mainloop_event_new(launch_proxy_ev, mp);
}
+ mainloop_event_schedule(mp->process_launch_ev, &delay_tv);
+ managed_proxy_set_state(mp, PT_PROTO_WAITING);
+
return 0;
}
@@ -756,6 +786,9 @@ managed_proxy_destroy(managed_proxy_t *mp,
process_terminate(mp->process);
}
+ if (mp->process_launch_ev)
+ mainloop_event_free(mp->process_launch_ev);
+
tor_free(mp);
}
@@ -828,6 +861,7 @@ handle_finished_proxy(managed_proxy_t *mp)
managed_proxy_set_state(mp, PT_PROTO_COMPLETED);
break;
case PT_PROTO_INFANT:
+ case PT_PROTO_WAITING:
case PT_PROTO_LAUNCHED:
case PT_PROTO_ACCEPTING_METHODS:
case PT_PROTO_COMPLETED:
@@ -2205,6 +2239,8 @@ managed_proxy_state_to_string(enum pt_proto_state state)
switch (state) {
case PT_PROTO_INFANT:
return "Infant";
+ case PT_PROTO_WAITING:
+ return "Waiting";
case PT_PROTO_LAUNCHED:
return "Launched";
case PT_PROTO_ACCEPTING_METHODS:
diff --git a/src/feature/client/transports.h b/src/feature/client/transports.h
@@ -77,6 +77,7 @@ char *tor_escape_str_for_pt_args(const char *string,
/** State of the managed proxy configuration protocol. */
enum pt_proto_state {
PT_PROTO_INFANT, /* was just born */
+ PT_PROTO_WAITING, /* waiting to be launched */
PT_PROTO_LAUNCHED, /* was just launched */
PT_PROTO_ACCEPTING_METHODS, /* accepting methods */
PT_PROTO_CONFIGURED, /* configured successfully */
@@ -101,6 +102,9 @@ typedef struct {
/* A pointer to the process of this managed proxy. */
struct process_t *process;
+ /* timer event to launch proxy */
+ struct mainloop_event_t *process_launch_ev;
+
/** Boolean: We are re-parsing our config, and we are going to
* remove this managed proxy if we don't find it any transport
* plugins that use it. */
@@ -150,6 +154,7 @@ STATIC void managed_proxy_destroy(managed_proxy_t *mp,
STATIC managed_proxy_t *managed_proxy_create(const smartlist_t *transport_list,
char **proxy_argv, int is_server);
+STATIC void launch_proxy_ev(struct mainloop_event_t *event, void *v);
STATIC int configure_proxy(managed_proxy_t *mp);
STATIC char* get_pt_proxy_uri(void);