From d501bbc97aeb87e6e4aa50bb2fa10a157d5909e9 Mon Sep 17 00:00:00 2001 From: Dirk Engling Date: Tue, 3 Nov 2026 05:13:22 +0100 Subject: Let a tracker with live sync built in run without a cluster --- Mk/tests.mk | 7 +++---- src/ot_livesync.c | 15 ++++++++++++--- tests/integration/test_livesync.py | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 7 deletions(-) diff --git a/Mk/tests.mk b/Mk/tests.mk index a7d4fbc..2efdd72 100644 --- a/Mk/tests.mk +++ b/Mk/tests.mk @@ -70,11 +70,10 @@ check-integration: opentracker.integration check-tsan: opentracker.tsan OPENTRACKER=./opentracker.tsan $(PYTHON) -m unittest discover -s tests/integration -# Only the live sync tests: a build with WANT_SYNC_LIVE refuses to start -# without a live sync address, so it cannot stand in for the plain binary in -# the rest of the suite. +# The whole suite against a build that has live sync, which is also the only +# way the live sync tests stop skipping. check-livesync: opentracker.livesync - OPENTRACKER=./opentracker.livesync $(PYTHON) -m unittest discover -s tests/integration -p 'test_livesync.py' + OPENTRACKER=./opentracker.livesync $(PYTHON) -m unittest discover -s tests/integration # Cheapest first, so a quick failure comes back quickly. check-all: diff --git a/src/ot_livesync.c b/src/ot_livesync.c index 18dae0d..9770bbc 100644 --- a/src/ot_livesync.c +++ b/src/ot_livesync.c @@ -60,7 +60,7 @@ void livesync_init(void) { uint32_t packet_type4 = htonl(OT_SYNC_PEER4); if (g_socket_in == -1) - exerr("No socket address for live sync specified."); + return; /* Prepare outgoing peers buffer */ memcpy(g_v6_buf.data, &g_tracker_id, sizeof(g_tracker_id)); @@ -160,6 +160,9 @@ static void livesync_handle_peersync(struct ot_workstruct *ws, size_t peer_size) stuck when there's not enough traffic to fill udp packets fast enough */ void livesync_ticker(void) { + if (g_socket_out == -1) + return; + /* livesync_issue_peersync sets g_next_packet_time */ pthread_mutex_lock(&g_outbuf_mutex); if (time_now_seconds() > g_v6_buf.next_packet_time && g_v6_buf.fill > sizeof(g_tracker_id) + sizeof(uint32_t)) @@ -177,8 +180,14 @@ void livesync_ticker(void) { /* Inform live sync about whats going on. */ void livesync_tell(struct ot_workstruct *ws) { size_t peer_size; /* initialized in next line */ - ot_peer *peer_src = peer_from_peer6(&ws->peer, &peer_size); - sync_buffer *dest_buf = peer_size == OT_PEER_SIZE6 ? &g_v6_buf : &g_v4_buf; + ot_peer *peer_src; + sync_buffer *dest_buf; + + if (g_socket_out == -1) + return; + + peer_src = peer_from_peer6(&ws->peer, &peer_size); + dest_buf = peer_size == OT_PEER_SIZE6 ? &g_v6_buf : &g_v4_buf; pthread_mutex_lock(&g_outbuf_mutex); diff --git a/tests/integration/test_livesync.py b/tests/integration/test_livesync.py index 1659a41..3a9ee58 100644 --- a/tests/integration/test_livesync.py +++ b/tests/integration/test_livesync.py @@ -130,3 +130,37 @@ class LiveSyncAccess(TrackerTestCase): info_hash = self.hash_for("sync-unblessed") self.tracker.livesync_send(packet(SYNC_PEER4, [(info_hash, peer4("10.1.2.12", 6881, FLAG_SEEDING))])) self.assertFalse(self.tracker.wait_until(lambda: self.tracker.torrent_count() != 0, timeout=1)) + + +@unittest.skipUnless(has_livesync(), "this build has no WANT_SYNC_LIVE") +class LiveSyncUnconfigured(TrackerTestCase): + """A binary that has the feature but no cluster to join. Somebody whose + packager turned WANT_SYNC_LIVE on did not ask for live sync and should + not be able to tell that it is there.""" + + config = "" + + def test_the_tracker_runs_anyway(self): + info_hash = self.hash_for("no-cluster") + self.tracker.announce(info_hash, port=6881, left=0) + self.assertEqual(self.tracker.torrent_count(), 1) + + def test_nothing_is_said_about_the_missing_cluster(self): + self.assertNotIn("sync", self.tracker.output().lower()) + + def test_no_socket_is_bound_for_it(self): + """A configured tracker holds the wildcard address on that port, so + taking it here proves nothing was started.""" + sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + sock.bind(("0.0.0.0", self.tracker.livesync_port)) + finally: + sock.close() + + def test_announcing_stays_clean(self): + """Enough announces to pass the watermark that would flush an + outgoing buffer, if there were one to flush. The sanitizers in this + build turn anything the attempt touched into a failure.""" + for i in range(200): + self.tracker.announce(self.hash_for("no-cluster-%d" % i), port=6881 + i, left=0) + self.assertEqual(self.tracker.torrent_count(), 200) -- cgit v1.3