diff options
| author | Dirk Engling <erdgeist@erdgeist.org> | 2026-11-03 05:13:22 +0100 |
|---|---|---|
| committer | Dirk Engling <erdgeist@erdgeist.org> | 2026-11-03 05:13:22 +0100 |
| commit | d501bbc97aeb87e6e4aa50bb2fa10a157d5909e9 (patch) | |
| tree | 460846f5787dc8a94c4b3076eff3cc92370832e0 | |
| parent | 253432c918dacc8bfd5d9a6a46c45a9dc682c7ec (diff) | |
Let a tracker with live sync built in run without a cluster
| -rw-r--r-- | Mk/tests.mk | 7 | ||||
| -rw-r--r-- | src/ot_livesync.c | 15 | ||||
| -rw-r--r-- | 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 | |||
| 70 | check-tsan: opentracker.tsan | 70 | check-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. | ||
| 76 | check-livesync: opentracker.livesync | 75 | check-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. |
| 80 | check-all: | 79 | 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) { | |||
| 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 */ |
| 162 | void livesync_ticker(void) { | 162 | void 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. */ |
| 178 | void livesync_tell(struct ot_workstruct *ws) { | 181 | void 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") | ||
| 136 | class 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) | ||
