summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDirk Engling <erdgeist@erdgeist.org>2026-11-03 05:13:22 +0100
committerDirk Engling <erdgeist@erdgeist.org>2026-11-03 05:13:22 +0100
commitd501bbc97aeb87e6e4aa50bb2fa10a157d5909e9 (patch)
tree460846f5787dc8a94c4b3076eff3cc92370832e0
parent253432c918dacc8bfd5d9a6a46c45a9dc682c7ec (diff)
Let a tracker with live sync built in run without a cluster
-rw-r--r--Mk/tests.mk7
-rw-r--r--src/ot_livesync.c15
-rw-r--r--tests/integration/test_livesync.py34
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
70check-tsan: opentracker.tsan 70check-tsan: opentracker.tsan
71 OPENTRACKER=./opentracker.tsan $(PYTHON) -m unittest discover -s tests/integration 71 OPENTRACKER=./opentracker.tsan $(PYTHON) -m unittest discover -s tests/integration
72 72
73# Only the live sync tests: a build with WANT_SYNC_LIVE refuses to start 73# The whole suite against a build that has live sync, which is also the only
74# without a live sync address, so it cannot stand in for the plain binary in 74# way the live sync tests stop skipping.
75# the rest of the suite.
76check-livesync: opentracker.livesync 75check-livesync: opentracker.livesync
77 OPENTRACKER=./opentracker.livesync $(PYTHON) -m unittest discover -s tests/integration -p 'test_livesync.py' 76 OPENTRACKER=./opentracker.livesync $(PYTHON) -m unittest discover -s tests/integration
78 77
79# Cheapest first, so a quick failure comes back quickly. 78# Cheapest first, so a quick failure comes back quickly.
80check-all: 79check-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) {
60 uint32_t packet_type4 = htonl(OT_SYNC_PEER4); 60 uint32_t packet_type4 = htonl(OT_SYNC_PEER4);
61 61
62 if (g_socket_in == -1) 62 if (g_socket_in == -1)
63 exerr("No socket address for live sync specified."); 63 return;
64 64
65 /* Prepare outgoing peers buffer */ 65 /* Prepare outgoing peers buffer */
66 memcpy(g_v6_buf.data, &g_tracker_id, sizeof(g_tracker_id)); 66 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)
160 stuck when there's not enough traffic to fill udp packets fast 160 stuck when there's not enough traffic to fill udp packets fast
161 enough */ 161 enough */
162void livesync_ticker(void) { 162void livesync_ticker(void) {
163 if (g_socket_out == -1)
164 return;
165
163 /* livesync_issue_peersync sets g_next_packet_time */ 166 /* livesync_issue_peersync sets g_next_packet_time */
164 pthread_mutex_lock(&g_outbuf_mutex); 167 pthread_mutex_lock(&g_outbuf_mutex);
165 if (time_now_seconds() > g_v6_buf.next_packet_time && g_v6_buf.fill > sizeof(g_tracker_id) + sizeof(uint32_t)) 168 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) {
177/* Inform live sync about whats going on. */ 180/* Inform live sync about whats going on. */
178void livesync_tell(struct ot_workstruct *ws) { 181void livesync_tell(struct ot_workstruct *ws) {
179 size_t peer_size; /* initialized in next line */ 182 size_t peer_size; /* initialized in next line */
180 ot_peer *peer_src = peer_from_peer6(&ws->peer, &peer_size); 183 ot_peer *peer_src;
181 sync_buffer *dest_buf = peer_size == OT_PEER_SIZE6 ? &g_v6_buf : &g_v4_buf; 184 sync_buffer *dest_buf;
185
186 if (g_socket_out == -1)
187 return;
188
189 peer_src = peer_from_peer6(&ws->peer, &peer_size);
190 dest_buf = peer_size == OT_PEER_SIZE6 ? &g_v6_buf : &g_v4_buf;
182 191
183 pthread_mutex_lock(&g_outbuf_mutex); 192 pthread_mutex_lock(&g_outbuf_mutex);
184 193
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):
130 info_hash = self.hash_for("sync-unblessed") 130 info_hash = self.hash_for("sync-unblessed")
131 self.tracker.livesync_send(packet(SYNC_PEER4, [(info_hash, peer4("10.1.2.12", 6881, FLAG_SEEDING))])) 131 self.tracker.livesync_send(packet(SYNC_PEER4, [(info_hash, peer4("10.1.2.12", 6881, FLAG_SEEDING))]))
132 self.assertFalse(self.tracker.wait_until(lambda: self.tracker.torrent_count() != 0, timeout=1)) 132 self.assertFalse(self.tracker.wait_until(lambda: self.tracker.torrent_count() != 0, timeout=1))
133
134
135@unittest.skipUnless(has_livesync(), "this build has no WANT_SYNC_LIVE")
136class LiveSyncUnconfigured(TrackerTestCase):
137 """A binary that has the feature but no cluster to join. Somebody whose
138 packager turned WANT_SYNC_LIVE on did not ask for live sync and should
139 not be able to tell that it is there."""
140
141 config = ""
142
143 def test_the_tracker_runs_anyway(self):
144 info_hash = self.hash_for("no-cluster")
145 self.tracker.announce(info_hash, port=6881, left=0)
146 self.assertEqual(self.tracker.torrent_count(), 1)
147
148 def test_nothing_is_said_about_the_missing_cluster(self):
149 self.assertNotIn("sync", self.tracker.output().lower())
150
151 def test_no_socket_is_bound_for_it(self):
152 """A configured tracker holds the wildcard address on that port, so
153 taking it here proves nothing was started."""
154 sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
155 try:
156 sock.bind(("0.0.0.0", self.tracker.livesync_port))
157 finally:
158 sock.close()
159
160 def test_announcing_stays_clean(self):
161 """Enough announces to pass the watermark that would flush an
162 outgoing buffer, if there were one to flush. The sanitizers in this
163 build turn anything the attempt touched into a failure."""
164 for i in range(200):
165 self.tracker.announce(self.hash_for("no-cluster-%d" % i), port=6881 + i, left=0)
166 self.assertEqual(self.tracker.torrent_count(), 200)