diff options
-rw-r--r-- | .gitlab-ci.yml | 1 | ||||
-rw-r--r-- | changes/bug30187 | 5 | ||||
-rw-r--r-- | changes/ticket32178 | 3 | ||||
-rw-r--r-- | configure.ac | 8 | ||||
-rw-r--r-- | src/core/or/include.am | 1 | ||||
-rw-r--r-- | src/feature/control/control_events.c | 26 | ||||
-rw-r--r-- | src/feature/control/control_events.h | 2 | ||||
-rw-r--r-- | src/lib/thread/compat_winthreads.c | 124 | ||||
-rw-r--r-- | src/lib/thread/threads.h | 7 | ||||
-rw-r--r-- | src/test/test_controller_events.c | 28 |
10 files changed, 104 insertions, 101 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ba61c71b2b..a672d8ed39 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -170,6 +170,7 @@ debian-tracing: variables: TRACING: "yes" CHECK: "no" + DISTCHECK: "yes" script: - ./scripts/ci/ci-driver.sh # Ensure that we only run tracing when it's implemented. diff --git a/changes/bug30187 b/changes/bug30187 new file mode 100644 index 0000000000..2a3358d6be --- /dev/null +++ b/changes/bug30187 @@ -0,0 +1,5 @@ + o Major bugfixes (relay, windows): + - Fix bug where running a relay on Windows would use 100% + CPU after some time. Makes Windows >= Vista the required + Windows version to build and run tor. Fixes bug 30187; + bugfix on 0.4.5.1-alpha. Patch by Daniel Pinto. diff --git a/changes/ticket32178 b/changes/ticket32178 new file mode 100644 index 0000000000..c13e490cb0 --- /dev/null +++ b/changes/ticket32178 @@ -0,0 +1,3 @@ + o Minor bugfixes (logging): + - Remove trailing whitespaces from control event log messages. Fixes bug + 32178; bugfix on 0.1.1.1-alpha. Based on a patch by Amadeusz Pawlik. diff --git a/configure.ac b/configure.ac index 8bb6e6bbde..5e16884f74 100644 --- a/configure.ac +++ b/configure.ac @@ -574,14 +574,14 @@ fi AH_BOTTOM([ #ifdef _WIN32 -/* Defined to access windows functions and definitions for >=WinXP */ +/* Defined to access windows functions and definitions for >=WinVista */ # ifndef WINVER -# define WINVER 0x0501 +# define WINVER 0x0600 # endif -/* Defined to access _other_ windows functions and definitions for >=WinXP */ +/* Defined to access _other_ windows functions and definitions for >=WinVista */ # ifndef _WIN32_WINNT -# define _WIN32_WINNT 0x0501 +# define _WIN32_WINNT 0x0600 # endif /* Defined to avoid including some windows headers as part of Windows.h */ diff --git a/src/core/or/include.am b/src/core/or/include.am index 9ff92adbde..7c42268c46 100644 --- a/src/core/or/include.am +++ b/src/core/or/include.am @@ -71,6 +71,7 @@ noinst_HEADERS += \ src/core/or/entry_port_cfg_st.h \ src/core/or/extend_info_st.h \ src/core/or/listener_connection_st.h \ + src/core/or/lttng_circuit.inc \ src/core/or/onion.h \ src/core/or/or.h \ src/core/or/or_periodic.h \ diff --git a/src/feature/control/control_events.c b/src/feature/control/control_events.c index 2970745ca0..0dd52659ec 100644 --- a/src/feature/control/control_events.c +++ b/src/feature/control/control_events.c @@ -1352,6 +1352,27 @@ enable_control_logging(void) tor_assert(0); } +/** Remove newline and carriage-return characters from @a msg, replacing them + * with spaces, and discarding any that appear at the end of the message */ +void +control_logmsg_strip_newlines(char *msg) +{ + char *cp; + for (cp = msg; *cp; ++cp) { + if (*cp == '\r' || *cp == '\n') { + *cp = ' '; + } + } + if (cp == msg) + return; + /* Remove trailing spaces */ + for (--cp; *cp == ' '; --cp) { + *cp = '\0'; + if (cp == msg) + break; + } +} + /** We got a log message: tell any interested control connections. */ void control_event_logmsg(int severity, log_domain_mask_t domain, const char *msg) @@ -1380,11 +1401,8 @@ control_event_logmsg(int severity, log_domain_mask_t domain, const char *msg) char *b = NULL; const char *s; if (strchr(msg, '\n')) { - char *cp; b = tor_strdup(msg); - for (cp = b; *cp; ++cp) - if (*cp == '\r' || *cp == '\n') - *cp = ' '; + control_logmsg_strip_newlines(b); } switch (severity) { case LOG_DEBUG: s = "DEBUG"; break; diff --git a/src/feature/control/control_events.h b/src/feature/control/control_events.h index 6e3cfef4e9..0ac233cc6e 100644 --- a/src/feature/control/control_events.h +++ b/src/feature/control/control_events.h @@ -341,6 +341,8 @@ struct control_event_t { extern const struct control_event_t control_event_table[]; +void control_logmsg_strip_newlines(char *msg); + #ifdef TOR_UNIT_TESTS MOCK_DECL(STATIC void, send_control_event_string,(uint16_t event, const char *msg)); diff --git a/src/lib/thread/compat_winthreads.c b/src/lib/thread/compat_winthreads.c index 2ca5620d23..fcc9c0279b 100644 --- a/src/lib/thread/compat_winthreads.c +++ b/src/lib/thread/compat_winthreads.c @@ -10,18 +10,32 @@ * functions. */ +#include "orconfig.h" + #ifdef _WIN32 +/* For condition variable support */ +#ifndef WINVER +#error "orconfig.h didn't define WINVER" +#endif +#ifndef _WIN32_WINNT +#error "orconfig.h didn't define _WIN32_WINNT" +#endif +#if WINVER < 0x0600 +#error "winver too low" +#endif +#if _WIN32_WINNT < 0x0600 +#error "winver too low" +#endif #include <windows.h> #include <process.h> +#include <time.h> + #include "lib/thread/threads.h" #include "lib/log/log.h" #include "lib/log/util_bug.h" #include "lib/log/win32err.h" -/* This value is more or less total cargo-cult */ -#define SPIN_COUNT 2000 - /** Minimalist interface to run a void function in the background. On * Unix calls fork, on win32 calls beginthread. Returns -1 on failure. * func should not return, but rather should call spawn_exit. @@ -64,45 +78,24 @@ tor_get_thread_id(void) int tor_cond_init(tor_cond_t *cond) { - memset(cond, 0, sizeof(tor_cond_t)); - if (InitializeCriticalSectionAndSpinCount(&cond->lock, SPIN_COUNT)==0) { - return -1; - } - if ((cond->event = CreateEvent(NULL,TRUE,FALSE,NULL)) == NULL) { - DeleteCriticalSection(&cond->lock); - return -1; - } - cond->n_waiting = cond->n_to_wake = cond->generation = 0; + InitializeConditionVariable(&cond->cond); return 0; } void tor_cond_uninit(tor_cond_t *cond) { - DeleteCriticalSection(&cond->lock); - CloseHandle(cond->event); + (void) cond; } -static void -tor_cond_signal_impl(tor_cond_t *cond, int broadcast) -{ - EnterCriticalSection(&cond->lock); - if (broadcast) - cond->n_to_wake = cond->n_waiting; - else - ++cond->n_to_wake; - cond->generation++; - SetEvent(cond->event); - LeaveCriticalSection(&cond->lock); -} void tor_cond_signal_one(tor_cond_t *cond) { - tor_cond_signal_impl(cond, 0); + WakeConditionVariable(&cond->cond); } void tor_cond_signal_all(tor_cond_t *cond) { - tor_cond_signal_impl(cond, 1); + WakeAllConditionVariable(&cond->cond); } int @@ -152,66 +145,23 @@ int tor_cond_wait(tor_cond_t *cond, tor_mutex_t *lock_, const struct timeval *tv) { CRITICAL_SECTION *lock = &lock_->mutex; - int generation_at_start; - int waiting = 1; - int result = -1; - DWORD ms = INFINITE, ms_orig = INFINITE, startTime, endTime; - if (tv) - ms_orig = ms = tv->tv_sec*1000 + (tv->tv_usec+999)/1000; - - EnterCriticalSection(&cond->lock); - ++cond->n_waiting; - generation_at_start = cond->generation; - LeaveCriticalSection(&cond->lock); - - LeaveCriticalSection(lock); - - startTime = GetTickCount(); - do { - DWORD res; - res = WaitForSingleObject(cond->event, ms); - EnterCriticalSection(&cond->lock); - if (cond->n_to_wake && - cond->generation != generation_at_start) { - --cond->n_to_wake; - --cond->n_waiting; - result = 0; - waiting = 0; - goto out; - } else if (res != WAIT_OBJECT_0) { - result = (res==WAIT_TIMEOUT) ? 1 : -1; - --cond->n_waiting; - waiting = 0; - goto out; - } else if (ms != INFINITE) { - endTime = GetTickCount(); - if (startTime + ms_orig <= endTime) { - result = 1; /* Timeout */ - --cond->n_waiting; - waiting = 0; - goto out; - } else { - ms = startTime + ms_orig - endTime; - } - } - /* If we make it here, we are still waiting. */ - if (cond->n_to_wake == 0) { - /* There is nobody else who should wake up; reset - * the event. */ - ResetEvent(cond->event); - } - out: - LeaveCriticalSection(&cond->lock); - } while (waiting); - - EnterCriticalSection(lock); - - EnterCriticalSection(&cond->lock); - if (!cond->n_waiting) - ResetEvent(cond->event); - LeaveCriticalSection(&cond->lock); + DWORD ms = INFINITE; + if (tv) { + ms = tv->tv_sec*1000 + (tv->tv_usec+999)/1000; + } - return result; + BOOL ok = SleepConditionVariableCS(&cond->cond, lock, ms); + if (!ok) { + DWORD err = GetLastError(); + if (err == ERROR_TIMEOUT) { + return 1; + } + char *msg = format_win32_error(err); + log_err(LD_GENERAL, "Error waiting for condition variable: %s", msg); + tor_free(msg); + return -1; + } + return 0; } void diff --git a/src/lib/thread/threads.h b/src/lib/thread/threads.h index fcc0c23a87..ead4dc3874 100644 --- a/src/lib/thread/threads.h +++ b/src/lib/thread/threads.h @@ -42,12 +42,7 @@ typedef struct tor_cond_t { #ifdef USE_PTHREADS pthread_cond_t cond; #elif defined(USE_WIN32_THREADS) - HANDLE event; - - CRITICAL_SECTION lock; - int n_waiting; - int n_to_wake; - int generation; + CONDITION_VARIABLE cond; #else #error no known condition implementation. #endif /* defined(USE_PTHREADS) || ... */ diff --git a/src/test/test_controller_events.c b/src/test/test_controller_events.c index 60dfbd630a..3cd529fa10 100644 --- a/src/test/test_controller_events.c +++ b/src/test/test_controller_events.c @@ -437,6 +437,33 @@ test_cntev_signal(void *arg) } static void +test_cntev_log_fmt(void *arg) +{ + (void) arg; + char *result = NULL; +#define CHECK(pre, post) \ + do { \ + result = tor_strdup((pre)); \ + control_logmsg_strip_newlines(result); \ + tt_str_op(result, OP_EQ, (post)); \ + tor_free(result); \ + } while (0) + + CHECK("There is a ", "There is a"); + CHECK("hello", "hello"); + CHECK("", ""); + CHECK("Put spaces at the end ", "Put spaces at the end"); + CHECK(" ", ""); + CHECK("\n\n\n", ""); + CHECK("Testing\r\n", "Testing"); + CHECK("T e s t\ni n g\n", "T e s t i n g"); + + done: + tor_free(result); +#undef CHECK +} + +static void setup_orconn_state(orconn_state_msg_t *msg, uint64_t gid, uint64_t chan, int proxy_type) { @@ -718,6 +745,7 @@ struct testcase_t controller_event_tests[] = { TEST(event_mask, TT_FORK), TEST(format_stream, TT_FORK), TEST(signal, TT_FORK), + TEST(log_fmt, 0), T_PUBSUB(dirboot_defer_desc, TT_FORK), T_PUBSUB(dirboot_defer_orconn, TT_FORK), T_PUBSUB(orconn_state, TT_FORK), |