diff --git a/.travis.yml b/.travis.yml index 9f7e1d7..36f2e51 100644 --- a/.travis.yml +++ b/.travis.yml @@ -98,13 +98,20 @@ jobs: - libpq-dev - libmysqlclient-dev - libhiredis-dev + - os: osx + osx_image: xcode11.3 + # - os: osx + # osx_image: xcode11.6 + - os: osx + osx_image: xcode12 - os: linux - dist: trusty + arch: ppc64le + dist: focal sudo: required addons: apt: packages: - - mysql-client-5.6 + - mysql-client - debhelper - dpkg-dev - libssl-dev @@ -115,13 +122,7 @@ jobs: - libpq-dev - libmysqlclient-dev - libhiredis-dev - - os: osx - osx_image: xcode11.3 - # - os: osx - # osx_image: xcode11.6 - - os: osx - osx_image: xcode12 - - os: linux + - os: linux arch: ppc64le dist: xenial sudo: required diff --git a/ChangeLog b/ChangeLog index c0ffece..367c125 100644 --- a/ChangeLog +++ b/ChangeLog @@ -9,7 +9,7 @@ Version 4.5.3 'dan Eider': - replace keep-address-family with allocation-default-address-family (keep-address-family deprecated and will be removed!!) - merge PR #703 (by j4zzc4t) * Restore no_stdout_log behavior - - merge PR #727 (by JoKoT3) + - merge PR #727 (by JoKoT3) * Support older mysql client version in configure - merge PR #721 (by KangLin) * Add to support cmake @@ -19,6 +19,8 @@ Version 4.5.3 'dan Eider': * Packaging scripts can miss out on these errors (exit code) - merge PR #679 (by rubo77) * Readme.turnserver: how to run server as a daemon + - merge PR #739 (by hills) + * SSL reload has hidden bugs which cause crashes 10/01/2021 Oleg Moskalenko Mihály Mészáros Version 4.5.2 'dan Eider': diff --git a/configure b/configure index 9560949..b8114a1 100755 --- a/configure +++ b/configure @@ -505,6 +505,15 @@ else fi fi +############################# +# Adjustments for Debian +############################# + +if [ -f "/etc/debian_version" ] ; then + # https://github.com/coturn/coturn/pull/754#issuecomment-824693226 + OSLIBS="${OSLIBS} -latomic" +fi + ############################# # Adjustments for Solaris ############################# diff --git a/docker/coturn/CHANGELOG.md b/docker/coturn/CHANGELOG.md index 43120fd..cb4182e 100644 --- a/docker/coturn/CHANGELOG.md +++ b/docker/coturn/CHANGELOG.md @@ -7,6 +7,10 @@ Coturn TURN server Docker image changelog ## [4.5.2-r1] · 2021-04-?? · To-be-done [4.5.2-r1]: /../../tree/docker/4.5.2-r1 +### Added + +- [Prometheus] support with [prometheus-client-c] 0.1.3: ([#754]) + ### Improved - Use DNS requests to discover external IP address in `detect-external-ip` script ([#753]). @@ -16,6 +20,7 @@ Coturn TURN server Docker image changelog - Incorrect linking with [mongo-c-driver] on [Debian Linux] image. [#753]: /../../pull/753 +[#754]: /../../pull/754 @@ -45,3 +50,5 @@ Coturn TURN server Docker image changelog [Coturn]: https://haraka.github.io [Debian Linux]: https://www.debian.org [mongo-c-driver]: https://github.com/mongodb/mongo-c-driver +[Prometheus]: https://prometheus.io +[prometheus-client-c]: https://github.com/digitalocean/prometheus-client-c diff --git a/docker/coturn/Makefile b/docker/coturn/Makefile index 40a6433..99b46f2 100644 --- a/docker/coturn/Makefile +++ b/docker/coturn/Makefile @@ -90,7 +90,7 @@ define docker.buildx docker buildx build --force-rm $(args) \ --platform $(platform) \ $(if $(call eq,$(no-cache),yes),--no-cache --pull,) \ - $(if $(call eq,$(git-ref),),,--build-arg git_ref=$(git-ref)) \ + $(if $(call eq,$(git-ref),),,--build-arg coturn_git_ref=$(git-ref)) \ -f docker/coturn/$(dockerfile)/Dockerfile \ -t $(namespace)/$(NAME):$(tag) ./ endef diff --git a/docker/coturn/alpine/Dockerfile b/docker/coturn/alpine/Dockerfile index ef47d1f..a05916f 100644 --- a/docker/coturn/alpine/Dockerfile +++ b/docker/coturn/alpine/Dockerfile @@ -7,6 +7,74 @@ ARG alpine_ver=3.13 +# +# Stage 'dist-libprom' creates prometheus-client-c distribution. +# + +# We compile prometheus-client-c from sources, because Alpine doesn't provide +# it as its package yet. +# +# TODO: Re-check this to be present in packages on next Alpine major version update. + +# https://hub.docker.com/_/alpine +FROM alpine:${alpine_ver} AS dist-libprom + +# Install tools for building. +RUN apk update \ + && apk add --no-cache \ + ca-certificates cmake g++ git make \ + && update-ca-certificates + +# Install prometheus-client-c build dependencies. +RUN apk add --no-cache \ + libmicrohttpd-dev + +# Prepare prometheus-client-c sources for building. +ARG prom_ver=0.1.3 +RUN mkdir -p /build/ && cd /build/ \ + && git init \ + && git remote add origin https://github.com/digitalocean/prometheus-client-c \ + && git fetch --depth=1 origin "v${prom_ver}" \ + && git checkout FETCH_HEAD + +# Build libprom.so from sources. +RUN mkdir -p /build/prom/build/ && cd /build/prom/build/ \ + && TEST=0 cmake -v -G "Unix Makefiles" \ + -DCMAKE_INSTALL_PREFIX=/usr \ + -DCMAKE_SKIP_BUILD_RPATH=TRUE \ + -DCMAKE_C_FLAGS="-DPROM_LOG_ENABLE -g -O3" \ + .. \ + && make + +# Build libpromhttp.so from sources. +RUN mkdir -p /build/promhttp/build/ && cd /build/promhttp/build/ \ + # Fix compiler warning: -Werror=incompatible-pointer-types + && sed -i 's/\&promhttp_handler/(MHD_AccessHandlerCallback)\&promhttp_handler/' \ + /build/promhttp/src/promhttp.c \ + && TEST=0 cmake -v -G "Unix Makefiles" \ + -DCMAKE_INSTALL_PREFIX=/usr \ + -DCMAKE_SKIP_BUILD_RPATH=TRUE \ + -DCMAKE_C_FLAGS="-g -O3" \ + .. \ + && make VERBOSE=1 + +# Install prometheus-client-c. +RUN LIBS_DIR=/out/$(dirname $(find /usr/ -name libc.so)) \ + && mkdir -p $LIBS_DIR/ \ + && cp -rf /build/prom/build/libprom.so \ + /build/promhttp/build/libpromhttp.so \ + $LIBS_DIR/ \ + && mkdir -p /out/usr/include/ \ + && cp -rf /build/prom/include/* \ + /build/promhttp/include/* \ + /out/usr/include/ \ + # Preserve license file. + && mkdir -p /out/usr/share/licenses/prometheus-client-c/ \ + && cp /build/LICENSE /out/usr/share/licenses/prometheus-client-c/ + + + + # # Stage 'dist-coturn' creates Coturn distribution. # @@ -27,7 +95,11 @@ RUN apk add --no-cache \ openssl-dev \ postgresql-dev mariadb-connector-c-dev sqlite-dev \ hiredis-dev \ - mongo-c-driver-dev + mongo-c-driver-dev \ + libmicrohttpd-dev + +# Install prometheus-client-c distribution. +COPY --from=dist-libprom /out/ / # Prepare local Coturn sources for building. COPY CMakeLists.txt \ @@ -86,6 +158,9 @@ RUN ln -s /usr/local/bin/detect-external-ip.sh \ /out/usr/local/bin/detect-external-ip RUN chown -R nobody:nogroup /out/var/lib/coturn/ +# Re-export prometheus-client-c distribution. +COPY --from=dist-libprom /out/ /out/ + @@ -110,6 +185,7 @@ RUN apk update \ libpq mariadb-connector-c sqlite-libs \ hiredis \ mongo-c-driver \ + libmicrohttpd \ # Install `dig` tool for `detect-external-ip.sh`. && apk add --no-cache \ bind-tools \ diff --git a/docker/coturn/debian/Dockerfile b/docker/coturn/debian/Dockerfile index 1945ecc..f859957 100644 --- a/docker/coturn/debian/Dockerfile +++ b/docker/coturn/debian/Dockerfile @@ -7,6 +7,75 @@ ARG debian_ver=buster +# +# Stage 'dist-libprom' creates prometheus-client-c distribution. +# + +# We compile prometheus-client-c from sources, because Alpine doesn't provide +# it as its package yet. +# +# TODO: Re-check this to be present in packages on next Debian major version update. + +# https://hub.docker.com/_/debian +# We use 'bullseye' here due to too old cmake on 'buster'. +FROM debian:bullseye-slim AS dist-libprom + +# Install tools for building. +RUN apt-get update \ + && apt-get install -y --no-install-recommends --no-install-suggests \ + ca-certificates cmake g++ git make \ + && update-ca-certificates + +# Install prometheus-client-c build dependencies. +RUN apt-get install -y --no-install-recommends --no-install-suggests \ + libmicrohttpd-dev + +# Prepare prometheus-client-c sources for building. +ARG prom_ver=0.1.3 +RUN mkdir -p /build/ && cd /build/ \ + && git init \ + && git remote add origin https://github.com/digitalocean/prometheus-client-c \ + && git fetch --depth=1 origin "v${prom_ver}" \ + && git checkout FETCH_HEAD + +# Build libprom.so from sources. +RUN mkdir -p /build/prom/build/ && cd /build/prom/build/ \ + && TEST=0 cmake -v -G "Unix Makefiles" \ + -DCMAKE_INSTALL_PREFIX=/usr \ + -DCMAKE_SKIP_BUILD_RPATH=TRUE \ + -DCMAKE_C_FLAGS="-DPROM_LOG_ENABLE -g -O3" \ + .. \ + && make + +# Build libpromhttp.so from sources. +RUN mkdir -p /build/promhttp/build/ && cd /build/promhttp/build/ \ + # Fix compiler warning: -Werror=incompatible-pointer-types + && sed -i 's/\&promhttp_handler/(MHD_AccessHandlerCallback)\&promhttp_handler/' \ + /build/promhttp/src/promhttp.c \ + && TEST=0 cmake -v -G "Unix Makefiles" \ + -DCMAKE_INSTALL_PREFIX=/usr \ + -DCMAKE_SKIP_BUILD_RPATH=TRUE \ + -DCMAKE_C_FLAGS="-g -O3" \ + .. \ + && make VERBOSE=1 + +# Install prometheus-client-c. +RUN LIBS_DIR=/out/$(dirname $(find /usr/ -name libc.so)) \ + && mkdir -p $LIBS_DIR/ \ + && cp -rf /build/prom/build/libprom.so \ + /build/promhttp/build/libpromhttp.so \ + $LIBS_DIR/ \ + && mkdir -p /out/usr/include/ \ + && cp -rf /build/prom/include/* \ + /build/promhttp/include/* \ + /out/usr/include/ \ + # Preserve license file. + && mkdir -p /out/usr/share/licenses/prometheus-client-c/ \ + && cp /build/LICENSE /out/usr/share/licenses/prometheus-client-c/ + + + + # # Stage 'dist-mongoc' creates mongo-c-driver distribution. # @@ -79,10 +148,13 @@ RUN apt-get install -y --no-install-recommends --no-install-suggests \ libevent-dev \ libssl-dev \ libpq-dev libmariadb-dev libsqlite3-dev \ - libhiredis-dev + libhiredis-dev \ + libmicrohttpd-dev # Install mongo-c-driver distribution. COPY --from=dist-mongoc /out/ / +# Install prometheus-client-c distribution. +COPY --from=dist-libprom /out/ / # Prepare local Coturn sources for building. COPY CMakeLists.txt \ @@ -111,7 +183,9 @@ RUN if [ "${coturn_git_ref}" != 'HEAD' ]; then true \ && true; fi # Build Coturn from sources. -RUN ./configure --prefix=/usr \ +# TODO: Remove `LDFLAGS` with next Coturn release containing `-latomic` flag in `configure`. +RUN LDFLAGS='-latomic' \ + ./configure --prefix=/usr \ --turndbdir=/var/lib/coturn \ --disable-rpath \ --sysconfdir=/etc/coturn \ @@ -143,6 +217,8 @@ RUN chown -R nobody:nogroup /out/var/lib/coturn/ # Re-export mongo-c-driver distribution. COPY --from=dist-mongoc /out/ /out/ +# Re-export prometheus-client-c distribution. +COPY --from=dist-libprom /out/ /out/ @@ -164,11 +240,13 @@ RUN apt-get update \ && update-ca-certificates \ # Install Coturn dependencies. && apt-get install -y --no-install-recommends --no-install-suggests \ + libatomic1 \ libevent-2.1-6 libevent-core-2.1-6 libevent-extra-2.1-6 \ libevent-openssl-2.1-6 libevent-pthreads-2.1-6 \ libssl1.1 \ libpq5 libmariadb3 libsqlite3-0 \ libhiredis0.14 \ + libmicrohttpd12 \ # Install `dig` tool for `detect-external-ip.sh`. && apt-get install -y --no-install-recommends --no-install-suggests \ dnsutils \ diff --git a/docker/coturn/tests/main.bats b/docker/coturn/tests/main.bats index c1a1f8d..73e238f 100644 --- a/docker/coturn/tests/main.bats +++ b/docker/coturn/tests/main.bats @@ -116,3 +116,12 @@ [ "$status" -eq 0 ] [ ! "$output" = '' ] } + +@test "Prometheus supported" { + # Support of Prometheus is not displayed in the output, + # but using --prometheus flag does the job. + run docker run --rm --platform $PLATFORM --entrypoint sh $IMAGE -c \ + "turnserver -o --log-file=stdout --prometheus | grep 'Version Coturn'" + [ "$status" -eq 0 ] + [ ! "$output" = '' ] +} diff --git a/examples/scripts/longtermsecuredb/secure_relay_with_db_redis.sh b/examples/scripts/longtermsecuredb/secure_relay_with_db_redis.sh index b01129f..3c796ca 100755 --- a/examples/scripts/longtermsecuredb/secure_relay_with_db_redis.sh +++ b/examples/scripts/longtermsecuredb/secure_relay_with_db_redis.sh @@ -36,4 +36,4 @@ fi export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib/:/usr/local/mysql/lib/ export DYLD_LIBRARY_PATH=${DYLD_LIBRARY_PATH}:/usr/local/lib/:/usr/local/mysql/lib/ -PATH="./bin/:../bin/:../../bin/:${PATH}" turnserver --server-name="blackdow.carleon.gov" --syslog -a -L 127.0.0.1 -L ::1 -E 127.0.0.1 -E ::1 ---allow-loopback-peers -max-bps=3000000 -f -m 3 --min-port=32355 --max-port=65535 -r north.gov --redis-userdb="ip=127.0.0.1 dbname=2 password=turn connect_timeout=30" --redis-statsdb="ip=127.0.0.1 dbname=3 password=turn connect_timeout=30" --cert=turn_server_cert.pem --pkey=turn_server_pkey.pem --log-file=stdout --cipher-list=ALL --oauth --cli-password=secret $@ +PATH="./bin/:../bin/:../../bin/:${PATH}" turnserver --server-name="blackdow.carleon.gov" --syslog -a -L 127.0.0.1 -L ::1 -E 127.0.0.1 -E ::1 --allow-loopback-peers -max-bps=3000000 -f -m 3 --min-port=32355 --max-port=65535 -r north.gov --redis-userdb="ip=127.0.0.1 dbname=2 password=turn connect_timeout=30" --redis-statsdb="ip=127.0.0.1 dbname=3 password=turn connect_timeout=30" --cert=turn_server_cert.pem --pkey=turn_server_pkey.pem --log-file=stdout --cipher-list=ALL --oauth --cli-password=secret $@ diff --git a/src/apps/relay/dtls_listener.c b/src/apps/relay/dtls_listener.c index 7689a13..9a5698c 100644 --- a/src/apps/relay/dtls_listener.c +++ b/src/apps/relay/dtls_listener.c @@ -55,12 +55,6 @@ struct dtls_listener_relay_server_info { ioa_engine_handle e; turn_turnserver *ts; int verbose; -#if DTLS_SUPPORTED - SSL_CTX *dtls_ctx; -#if DTLSv1_2_SUPPORTED - SSL_CTX *dtls_ctx_v1_2; -#endif -#endif struct event *udp_listen_ev; ioa_socket_handle udp_listen_s; ur_addr_map *children_ss; /* map of socket children on remote addr */ @@ -288,13 +282,13 @@ static ioa_socket_handle dtls_server_input_handler(dtls_listener_relay_server_ty #if DTLSv1_2_SUPPORTED if(get_dtls_version(ioa_network_buffer_data(nbh), (int)ioa_network_buffer_get_size(nbh)) == 1) { - connecting_ssl = SSL_new(server->dtls_ctx_v1_2); + connecting_ssl = SSL_new(server->e->dtls_ctx_v1_2); } else { - connecting_ssl = SSL_new(server->dtls_ctx); + connecting_ssl = SSL_new(server->e->dtls_ctx); } #else { - connecting_ssl = SSL_new(server->dtls_ctx); + connecting_ssl = SSL_new(server->e->dtls_ctx); } #endif @@ -573,13 +567,13 @@ static int create_new_connected_udp_socket( #if DTLSv1_2_SUPPORTED if(get_dtls_version(ioa_network_buffer_data(server->sm.m.sm.nd.nbh), (int)ioa_network_buffer_get_size(server->sm.m.sm.nd.nbh)) == 1) { - connecting_ssl = SSL_new(server->dtls_ctx_v1_2); + connecting_ssl = SSL_new(server->e->dtls_ctx_v1_2); } else { - connecting_ssl = SSL_new(server->dtls_ctx); + connecting_ssl = SSL_new(server->e->dtls_ctx); } #else { - connecting_ssl = SSL_new(server->dtls_ctx); + connecting_ssl = SSL_new(server->e->dtls_ctx); } #endif @@ -912,14 +906,6 @@ static int init_server(dtls_listener_relay_server_type* server, if(!server) return -1; -#if DTLS_SUPPORTED - server->dtls_ctx = e->dtls_ctx; - -#if DTLSv1_2_SUPPORTED - server->dtls_ctx_v1_2 = e->dtls_ctx_v1_2; -#endif -#endif - server->ts = ts; server->connect_cb = send_socket; @@ -935,36 +921,6 @@ static int init_server(dtls_listener_relay_server_type* server, server->verbose=verbose; server->e = e; - -#if DTLS_SUPPORTED - if(server->dtls_ctx) { - -#if defined(REQUEST_CLIENT_CERT) - /* If client has to authenticate, then */ - SSL_CTX_set_verify(server->dtls_ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, dtls_verify_callback); -#endif - - SSL_CTX_set_read_ahead(server->dtls_ctx, 1); - - SSL_CTX_set_cookie_generate_cb(server->dtls_ctx, generate_cookie); - SSL_CTX_set_cookie_verify_cb(server->dtls_ctx, verify_cookie); - } - -#if DTLSv1_2_SUPPORTED - if(server->dtls_ctx_v1_2) { - - #if defined(REQUEST_CLIENT_CERT) - /* If client has to authenticate, then */ - SSL_CTX_set_verify(server->dtls_ctx_v1_2, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, dtls_verify_callback); - #endif - - SSL_CTX_set_read_ahead(server->dtls_ctx_v1_2, 1); - - SSL_CTX_set_cookie_generate_cb(server->dtls_ctx_v1_2, generate_cookie); - SSL_CTX_set_cookie_verify_cb(server->dtls_ctx_v1_2, verify_cookie); - } -#endif -#endif return create_server_socket(server, report_creation); } @@ -980,6 +936,23 @@ static int clean_server(dtls_listener_relay_server_type* server) { /////////////////////////////////////////////////////////// +#if DTLS_SUPPORTED +void setup_dtls_callbacks(SSL_CTX *ctx) { + if (!ctx) + return; + +#if defined(REQUEST_CLIENT_CERT) + /* If client has to authenticate, then */ + SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, dtls_verify_callback); +#endif + + SSL_CTX_set_read_ahead(ctx, 1); + + SSL_CTX_set_cookie_generate_cb(ctx, generate_cookie); + SSL_CTX_set_cookie_verify_cb(ctx, verify_cookie); +} +#endif + dtls_listener_relay_server_type* create_dtls_listener_server(const char* ifname, const char *local_address, int port, diff --git a/src/apps/relay/dtls_listener.h b/src/apps/relay/dtls_listener.h index 9d7cab6..5ca4ec9 100644 --- a/src/apps/relay/dtls_listener.h +++ b/src/apps/relay/dtls_listener.h @@ -50,6 +50,10 @@ typedef struct dtls_listener_relay_server_info dtls_listener_relay_server_type; /////////////////////////////////////////// +#if DTLS_SUPPORTED +void setup_dtls_callbacks(SSL_CTX *ctx); +#endif + dtls_listener_relay_server_type* create_dtls_listener_server(const char* ifname, const char *local_address, int port, diff --git a/src/apps/relay/mainrelay.c b/src/apps/relay/mainrelay.c index d11a2cd..9d95186 100644 --- a/src/apps/relay/mainrelay.c +++ b/src/apps/relay/mainrelay.c @@ -3198,10 +3198,12 @@ static void openssl_load_certificates(void) set_ctx(&turn_params.dtls_ctx,"DTLS",DTLS_server_method()); set_ctx(&turn_params.dtls_ctx_v1_2,"DTLS1.2",DTLSv1_2_server_method()); SSL_CTX_set_read_ahead(turn_params.dtls_ctx_v1_2, 1); + setup_dtls_callbacks(turn_params.dtls_ctx_v1_2); #else set_ctx(&turn_params.dtls_ctx,"DTLS",DTLSv1_server_method()); #endif SSL_CTX_set_read_ahead(turn_params.dtls_ctx, 1); + setup_dtls_callbacks(turn_params.dtls_ctx); TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "DTLS cipher suite: %s\n",turn_params.cipher_list); diff --git a/src/apps/relay/netengine.c b/src/apps/relay/netengine.c index fa2be3f..e118c27 100644 --- a/src/apps/relay/netengine.c +++ b/src/apps/relay/netengine.c @@ -304,25 +304,38 @@ typedef struct update_ssl_ctx_cb_args { struct event *next; } update_ssl_ctx_cb_args_t; +static void replace_one_ssl_ctx(SSL_CTX **to, SSL_CTX *from) +{ + if (*to) + SSL_CTX_free(*to); + + SSL_CTX_up_ref(from); + *to = from; +} + +/* + * Synchronise the ioa_engine's SSL certificates with the global ones + */ static void update_ssl_ctx(evutil_socket_t sock, short events, update_ssl_ctx_cb_args_t *args) { ioa_engine_handle e = args->engine; turn_params_t *params = args->params; + /* No mutex with "e" as these are only used in the same event loop */ pthread_mutex_lock(&turn_params.tls_mutex); - e->tls_ctx_ssl23 = params->tls_ctx_ssl23; - e->tls_ctx_v1_0 = params->tls_ctx_v1_0; + replace_one_ssl_ctx(&e->tls_ctx_ssl23, params->tls_ctx_ssl23); + replace_one_ssl_ctx(&e->tls_ctx_v1_0, params->tls_ctx_v1_0); #if TLSv1_1_SUPPORTED - e->tls_ctx_v1_1 = params->tls_ctx_v1_1; + replace_one_ssl_ctx(&e->tls_ctx_v1_1, params->tls_ctx_v1_1); #if TLSv1_2_SUPPORTED - e->tls_ctx_v1_2 = params->tls_ctx_v1_2; + replace_one_ssl_ctx(&e->tls_ctx_v1_2, params->tls_ctx_v1_2); #endif #endif #if DTLS_SUPPORTED - e->dtls_ctx = params->dtls_ctx; + replace_one_ssl_ctx(&e->dtls_ctx, params->dtls_ctx); #endif #if DTLSv1_2_SUPPORTED - e->dtls_ctx_v1_2 = params->dtls_ctx_v1_2; + replace_one_ssl_ctx(&e->dtls_ctx_v1_2, params->dtls_ctx_v1_2); #endif struct event *next = args->next; pthread_mutex_unlock(&turn_params.tls_mutex);