OUT NOW: FrostWire 7.1.0 for desktop, with distributed torrent search

FrostWire 7.1.0 for desktop turns Distributed Search into something you can rely on. Your computer can now find torrents that other FrostWire users are sharing, browse everything a person shares, and download straight from them, all without a central server. It also brings YouTube downloads with sound, a smarter search, a new identity and backup screen, and a long list of security and stability fixes.

What’s new

Distributed Search that finds more, faster

FrostWire users now form a network that searches together. Your search reaches computers and phones that only share files (and don’t help relay searches for others), which were previously missed. Results are signed by the person sharing them, answers from the mesh follow the live connection when a phone changes network, and the app stays responsive even when the network is busy. Finding the network is faster and more dependable too: FrostWire checks the dedicated IceBridge servers first, tries many peers at once instead of one by one, remembers which ones are dead, and always knows one built-in server to fall back on. Computers on the same home or office network now find each other directly, even though a router will not let them connect through their shared public address.

Browse what other people share

Right-click a Distributed Search result and choose Browse Shared Torrents to see everything that person is sharing, then download any of it straight from them. Results from people who share their catalog also show a Browse icon in the Actions column, so you do not have to find the menu. You can also open it from Tools > Browse Shared Torrents. The icon appears for results from peers running FrostWire 7.1.0 or Android 3.2.2 or newer.

Signature: boUcPuRatTn7eB4Ox/wStwfaC2k2s8f2HlZhohFQhMDezHSFu4PRWTHbUc/gTzaKnhBl49bSff5H496xbanx3L3dnsSk6rHHFVYNUKNm1CgeEg4eC9iyPsD3+boFSg7odkIqRwYaHZAjOgLXO/BiZg4tLYqdJV+RyDrzZINGZjJDAyd/9y+49cgrqvvQj99d54GaYGqI7JxwS8hl6BHVxHe7f+tYMTXsSTabaNyAyCf5k7fDB2zCdkrLreQIqG3mex/1nYdQtYyDcc0klLouLodFJE6LtSkLn/HmRrMpBUUDrb13bJy2uu/dERCxW/uDJa/8vMvWAhvl3Wbgi4LjSw9HpE2yGOImmSwgv/mNNa6DxDuYQwj/If/Dq+/3fLmiquTrdO+c6yUHRTbwtPecIGblfE3Tcl1irmcWTdvf/P1gFRapG8jhzLetkXnLYbwcl5R7sUT92FAoLC9ez9s2vVGRrYUcayQ/s4Z+WdO+Uh1k/tsITn/Hpqg8O8sGdRGYrSGM22OtlStkq/tEY+xfM8wKlr0yGNngUr9uxYee82zgy6lK7TfTplXp5ew8SZDZPaQhRM3KljtZsfgHr3X6ekAKSDhQTXnYCM4httyLDrPM4sxKKRfDYx83bvgqGLbUwpYFPI6SFhNTKonw9MGoHFW9AyhOJbuEW/ctN0Q0nMvEgbaaxrdtu6xOWtw9XtNV

Seeding is publishing, and you are in control

A new page in the setup wizard explains that seeding a torrent makes it discoverable on the BitTorrent network, and gives you two separate choices, both on by default:

  • Join the IceBridge network. You can use Distributed Search, and people searching can find the torrents you are actively seeding by keyword, whether or not you share your catalog.
  • Share my catalog. People can browse everything you are actively seeding, and crawlers can index it. This is only available while you are on the network.

Only torrents you are actively seeding are ever shared. Your download history, paused transfers and private torrents are never published. You can change either choice in the setup wizard or in Tools > Options > IceBridge.

YouTube videos now play with sound

Videos that YouTube serves as separate video and audio streams are now downloaded together and merged automatically, so what you save has sound. If something goes wrong, you still keep the silent video.

Smarter search

  • Search now also matches file names inside a torrent, so looking for readme.txt can find torrents that don’t mention it in their title.
  • Bitsearch joins the list of search engines.
  • Seeds and Size columns now sort as numbers (436 seeds ranks above 64).
  • The dead Idope engine was removed and the default tracker list was refreshed with trackers that actually respond.

Your identity, with a backup you can write on paper

Options > Identity shows your node ID, karma and shared torrents, and lets you back up your identity as a 24-word recovery phrase, restore it, and export or import the identity file. New Karma, Peers and Shared Torrents screens show what the network knows about you and your neighbors.

Tools for power users

  • Tools > IceBridge Console: a live, filterable log of what the distributed search network is doing.
  • The built-in MCP server (off by default, and it only listens on your own computer) can now observe and control IceBridge, so AI assistants can inspect peers, metrics and your local index.
  • Transfer details can recheck local data with a progress bar, toggle sequential download, and add trackers safely.
  • The IP Filter now understands P2P, DAT, CIDR and Hosts block lists, including ZIP files.
  • Powered by jlibtorrent 2.0.12.9, with new NAT-PMP and multiple-connection controls in Advanced BitTorrent settings.

Meet IceBridge: the network layer under Distributed Search

7.1.0 is the first desktop release where FrostWire talks to other FrostWire users directly through IceBridge, a small peer-to-peer network layer built into the app. If BitTorrent is how files move, IceBridge is how FrostWire users talk to each other about them.

What it does. Every install gets its own cryptographic identity (the one you can back up with a 24-word phrase). IceBridge uses that identity to open authenticated, reliable connections over UDP with other FrostWire users, finds them through the BitTorrent DHT (no central server), the local network, and a short list of servers it already knows, and keeps working for people behind routers and phone networks by letting willing peers help each other connect. Desktop computers and the Android app (3.2.2) join the same network.

Where it sits. IceBridge sits underneath search and on top of the networking you already use:

FrostWire (search window, downloads, transfers)
|
Distributed Search -- signed questions and answers about torrents
|
IceBridge -- identity, peers, routing, delivery
|
UDP + BitTorrent DHT

IceBridge never looks inside the messages it carries, and it never moves your files; BitTorrent still does that. Distributed Search is simply the first thing built on it. Alongside search, it already carries the small “who has what” summaries that make routing smart, and the shared-torrent catalogs that power Browse Shared Torrents.

You are in control. IceBridge can be turned off in the settings, you choose whether your active seeds can be browsed, and your download history is never shared. Its local control interface only listens on your own computer and requires a secret token. Power users can also run IceBridge on their own server as a standalone forwarder to help the network (see ICEBRIDGE.md in the repository).

Where it could go. Because IceBridge is deliberately generic, each kind of message is labeled with a protocol number, and the code already reserves slots for things such as chat between peers, publish/subscribe channels, exchanging torrent metadata, file synchronization, node health reports, and AI-assisted tools. These are ideas we are exploring, not promises or dates. The point is that new peer-to-peer features can be added without building a new network each time, and without a company’s servers in the middle.

Compatibility, ports and firewalls

For network admins, hackers and anyone running a strict firewall:

  • Peers are verified over UDP. Peers used to be checked on a separate TCP “identity port”. They are now verified with the same authenticated rUDP handshake the network already uses (Ed25519 keys), so a peer that can be reached over UDP can be found, and no inbound TCP port is needed. The identity port setting is gone. Older versions (desktop 7.0.x and earlier, Android 3.2.1 and earlier) only announce a TCP port, so they and 7.1.0 / Android 3.2.2 do not discover each other through the DHT. Please update both.
  • UDP mesh port. Each install picks its own UDP port automatically (setting ICEBRIDGE_RUDP_PORT, 0 means automatic) so several computers behind one router no longer fight over 6889, and announces the real port on the DHT. Standalone forwarders and the built-in seed use UDP 6889.
  • Built-in seed. virginia1.frostwire.com:6889 is always tried when looking for the network. Override it with -Dfrostwire.icebridge.seeds=host:port,... (an empty value disables it).
  • LAN beacon. Every 10 seconds FrostWire multicasts its rUDP port to 239.255.70.88, UDP 6890, and listens for other nodes. Only private IPv4 senders are believed, nothing is ever answered, and every address it finds still has to pass the rUDP identity handshake before it is trusted. Android 3.2.2 does the same on Wi-Fi.
  • Local control API. The IceBridge control HTTP port listens on 127.0.0.1 only and requires an X-IceBridge-Token header on everything except /health.
  • Firewalls. The installers do not add firewall rules. If a firewall blocks inbound UDP, allow FrostWire’s UDP port so other people can reach you; outgoing connections work either way. On a server running a standalone forwarder, open UDP 6889.
  • Debugging. Use Tools > IceBridge Console or the control API /metrics endpoint. Standalone forwarder setup is in ICEBRIDGE.md in the repository.

Security and safety

This release includes a broad security hardening pass over the distributed search network:

  • Signatures: signed search results now also cover the matched file name, which a man-in-the-middle could previously alter. Responses and registrations use length-prefixed canonical forms.
  • Authentication: the local control interface needs a secret token; unauthenticated rUDP application packets are rejected; relayed messages and hole-punch requests need an authenticated session that matches the claimed sender.
  • Replays and abuse: rUDP handshakes carry a timestamp and stale ones are rejected, a timestamp-skew bypass was fixed, ingress is rate-limited before any signature is verified, sessions are capped (including per /24), and servers rate-limit abusive peers and catalog browsing per verified requester.
  • Denial of service: a crafted fragment index that could force a multi-billion-iteration loop was fixed, oversized or truncated payloads are rejected, HTTP bodies are capped (16 MB for search, 32 MB for torrents), and search results and queries are validated and sanitized.
  • IP filter: block lists that were silently being allowed now really block (#1291).
  • TLS: hostname checks use suffix matching instead of substring matching.
  • Debug ports: release builds no longer expose JMX or JDWP listeners.
  • Privacy: crawler data stays anonymous; presence is stored as hashed endpoints and catalogs by publisher peer id only, never IP addresses.

Fixes you may notice

  • macOS: the app no longer crashes at startup when an old link handler fails to load, rich file icons are back, file icons no longer stall the window, VPN detection no longer reports a VPN that is off, and installers now sign the embedded networking libraries, so they pass Apple’s checks.
  • Linux (Wayland): opening the Transfers tab no longer freezes or crashes the app.
  • Torrents: restarting no longer restores torrents at 0%, files you share from a finished download are saved correctly, and sharing a file that no longer exists is refused with a clear message.
  • Transfers: buttons stop flickering, rows refresh only when they change, and the Files tab keeps your selection and shows live progress.
  • Translations: the new screens and the setup wizard are translated into most of our 57 languages. Fourteen (Breton, Persian, Finnish, Irish, Galician, Hungarian, Icelandic, Lithuanian, Macedonian, Maltese, Norwegian Nynorsk, Punjabi, Slovak and Serbian Latin) still show the new text in English. Translators are welcome.
  • Many other search, YouTube and IP Filter reliability fixes. See the full list below.

By the numbers: how this release got built

7.1.0 is also the product of a very different way of working. Since 7.0.4 (April 20, 2026), the shared common and desktop code was developed by one maintainer directing AI coding agents, with an automated test suite as the referee. Figures below cover only common/ and desktop/ (the Android app has hundreds more commits of its own) and come straight from the git history.

PeriodApr 20 to Oct 8, 2026 (170 calendar days)
Days with commits83 (about every other day)
Commits1,077 (about 13 per active day, 6 per calendar day)
Code added (Java, Kotlin, Gradle, scripts)~127,900 lines written, ~37,800 removed along the way
Code in the final diff+104,600 / -14,500 lines, +90,100 net
Of which tests~38,500 lines, 203 new test classes, about 1,370 new tests
New Java files408
Documentation and plans~7,900 lines of Markdown/text added
Translations61 language files refreshed
Average outputabout 1,100 net lines per active day (about 530 per calendar day)

Who wrote it. About a third of the commits (366) carry the name of the model that did the work in their message. The ones that say so: DeepSeek V4.1 Flash (185 commits), Grok 4.6 (51), Grok 4.7 (36), GPT-6 Sol (30), Claude Sonnet 5.5 (23), Muse Spark 1.3 (21), GPT-6.1 Sol (17), and GPT-6 Luna (3). The rest were committed without a model label. Model credits were recounted on October 10, after we corrected some commit labels that had been copied from older commits; the other figures in the table were measured on October 8. The maintainer chose what to build, reviewed the results, and used the 1,400-test suite and the CI builds to decide what was good enough to keep.

How much human work is that? The commit timestamps cluster into about 135 to 160 working sessions, roughly 135 to 185 hours of active work over the whole period (about two hours per active day). That is a lower bound, since agents think and run tests between commits, but it is the time a person was actually in the loop.

To estimate what the same result would cost without the agents, we used a deliberately generous rate for careful, tested, security-sensitive protocol code: 100 to 200 finished lines of code per developer per day. At that rate, 104,600 lines is about 520 to 1,050 developer-days, or roughly 4,200 to 8,400 hours, which is 2 to 4 developer-years, before design docs, reviews, and the translations. Compared with 135 to 185 hours of actual work, that is something like a 20x to 60x speedup.

These are estimates, not measurements, and lines of code is a blunt tool: many of those lines are tests and mechanical changes, and the rate varies a lot between developers. But the direction is not subtle. A distributed, signed, NAT-traversing search network with a full UI, a security pass, and a test suite used to be a multi-year, multi-person project. This time it shipped in under six months.

Installers for macOS (Intel and Apple Silicon), Linux (x86_64 and arm64) and Windows are attached below.

Full changelog

  • new:Computers on the same network find each other — nodes multicast their rUDP port on the LAN, since the public address the DHT reports cannot be reached from inside the same router
  • new:Distributed search results from peers that share their catalog show a “Browse Shared Torrents” icon in the Actions column, so browsing a peer’s catalog no longer depends on discovering the right-click menu
  • new:Browse the torrents a peer shares — right-click a Distributed search result whose holder allows crawling (“Browse Shared Torrents”) to list everything that peer is sharing, download any of it straight from that peer, or copy its magnet; also available from Tools → Browse Shared Torrents and the IceBridge Console
  • fix:The “Seeding & Publishing” setup page and Tools > Options > IceBridge now separate two choices: joining the IceBridge network (you can search, and anyone searching can find the torrents you are seeding by keyword, whether or not you share a catalog) and sharing your catalog (people can browse everything you are actively seeding and crawlers can index it); unchecking the catalog no longer reads as hiding from search, and sharing the catalog is disabled while you are off the network
  • new:Seeding is publishing — a new setup-wizard page explains that seeding a torrent makes it discoverable on the BitTorrent network, and lets you opt out (on by default) of having the torrents you are actively seeding browsable by the network’s crawlers
  • fix:Peers are now verified over rUDP instead of a TCP identity port, so a peer behind NAT that can be reached over UDP can be found; the DHT announces the rUDP port, servers and phones no longer need an open TCP port, and the “Relay listen port (identity)” setting is gone (peers on older versions that only announce a TCP port are not discovered)
  • new:IceBridge distributed search architecture — FrostWire now launches a local IceBridge daemon (standalone rUDP relay servent) that provides a reliable, fragmented, authenticated mesh transport between peers. The DistributedSearchPerformer sends signed search requests through the daemon’s HTTP control API; the daemon routes them over rUDP to remote peers’ daemons, which process them and send signed responses back. A single poller thread drains the daemon’s /poll endpoint and dispatches payloads to all registered listeners
  • new:YouTube video downloads now play with sound — DASH video-only rows auto-fetch a hidden m4a/Opus sibling and merge it (pure-Java MP4 restitch or WebM remux, same-container pairs only); sibling fetch retries with resume on throttled connections; any failure keeps the silent video
  • new:Tools → IceBridge Console — a live, filterable IceBridge/distributed-search event log (filter by level, category, text, or peer; pause, clear, save, copy)
  • new:Identity settings screen (Options > Identity) — displays node ID, fingerprint, public key, identity difficulty (leading zero bits), karma score, and shared torrent count. Buttons: Show Seed Phrase (24-word BIP39 mnemonic with copy-to-clipboard), Restore from Seed Phrase, Export Identity File, Import Identity File, Copy Fingerprint. Restore and import create a .bak backup before overwriting and trigger a restart
  • new:BIP39 mnemonic support for identity backup — com.frostwire.crypto.Bip39Mnemonic encodes/decodes the 32-byte Ed25519 seed as a 24-word mnemonic using the standard BIP39 English wordlist with SHA-256 checksum. Enables offline paper backup of FrostWire identities
  • new:Identity settings — Initialize Identity button with off-EDT proof-of-work mining (progress bar) and restart; import/restore/export now use the same libtorrent/identity.dat path as the relay stack
  • new:The MCP server now exposes IceBridge observability and control — logs query/tail/clear, relay metrics, peer list/remove/block, local index list/search, digest status, host-cache list/ping/add, remote relay logs, MCP status/control, and IceBridge settings via settings get/set
  • new:File-level search indexing — individual file paths within torrents are now indexed in a separate shared_files FTS5 table, enabling search matches on file names (e.g. “readme.txt”) even when the torrent name doesn’t contain the query. Search results that match on a file path populate the matchedFile field, surfaced as the result filename in the UI
  • new:Local search (and remote answers from this node) only return actively seeded/swarming transfers with full metadata by default — historical LocalIndex rows excluded unless Options → Shared Torrents Database → “Include inactive / historical shares” is enabled
  • new:Bitsearch added as a new REST-API torrent search engine (bitsearch.eu) — clean JSON, 200 free requests/day per IP, magnet links built client-side from DefaultTrackers. No crawling, replaces the gap left by the Idope removal
  • new:IP Filter now supports multiple block list formats — P2P, DAT, CIDR, and Hosts formats are auto-detected and parsed. ZIP archives are now supported alongside existing GZIP decompression. Extracted format readers into separate classes (P2PIPFilterInputStreamReader, DatFilterInputStreamReader, CidrFilterInputStreamReader, HostsFilterInputStreamReader) with shared IPFilterFormat enum
  • update:jlibtorrent to 2.0.12.9 with libtorrent RC_2_0 cb6fe6b9c (86 commits ahead of previous) — includes tracker URL validation hardening, SOCKS5 parsing fixes, resume-data sanitization, peer encryption improvements, symbolic link support (BEP 47), and 4 new Java APIs (natpmpGateway, allowMultipleConnectionsPerPid, natpmpLeaseDuration, pieceSizeForReq). OpenSSL upgraded to 3.6.0. Build now requires -frtti flag across all platforms due to upstream dynamic_cast in smart_ban.cpp
  • fix:Distributed search finds the IceBridge servers again — discovery probed DHT candidates one at a time and ran out of its 15 second budget on unreachable phones, so no peer was ever registered; probes now run in parallel, known and bootstrap servers go first, and dead endpoints back off so later passes reach the rest of the list
  • fix:The DHT bootstrap topic, where the dedicated IceBridge servers announce, is always queried first instead of only when the crowded relay and peer topics are empty
  • fix:Known IceBridge servers are retried even if they never answered before, a built-in seed server is always tried, and the Settings host ping verifies servers like discovery does instead of with a request they reject (which evicted healthy hosts)
  • fix:The IceBridge helper process no longer announces on the DHT with port 0, which republished our identity with a useless port and filled the shared topics with unreachable endpoints
  • fix:Results from peers that share their catalog are marked browsable again when a search returns more than a handful of results — the browsable flag was lost when larger result sets were streamed back in chunks, so only small answers showed the Browse Shared Torrents action
  • fix:Packaged desktop builds retain the IceBridge metrics used by the search transport, preventing distributed search startup from failing with a missing class; regression tests load the real application JAR without the daemon JAR
  • fix:Desktop IncomingSearchRequestHandler now receives LocalIndex so catalog browse works (parity with Android)
  • fix:Distributed search and relay responses follow live rUDP sessions after cellular NAT rebinding instead of stale registry endpoints
  • fix:Desktop clients now choose an automatic IceBridge UDP port instead of all using 6889 behind the same router; identity records and mesh registration advertise the actual bound port, supervised restarts retain it, and unknown peer ports are never guessed from our own port
  • fix:Distributed search now reaches peers that share content but do not relay (leaf/CLIENT nodes) — their published keyword fingerprint was being dropped by forwarders, so searches reached them only by fan-out luck and their torrents looked missing
  • fix:Distributed search and the relay stay responsive under heavy search traffic — rUDP packet processing is handed off the socket event loop, response delivery runs on a bounded lane, and concurrent torrent-metadata fetches are capped instead of exhausting threads
  • fix:IceBridge child supervision prevents orphan processes and preserves distributed search/TORRENT_FETCH across crashes and restarts
  • fix:Linux/Wayland startup no longer freezes or crashes when opening the Transfers tab — Java2D was forced onto the legacy software X11 pipeline, where on-screen icon and text blits are ~1000x slower; rendering now uses the XRender pipeline, which is fast and stable under XWayland
  • fix:JDK 26 HTTPS requests no longer fail after IceBridge identity initialization; Bouncy Castle is kept scoped to identity crypto instead of overriding the JVM-wide XDH provider
  • fix:macOS startup no longer crashes when the legacy libGURL JNI handler fails to load; magnet URLs use the Java Desktop OpenURIHandler included since Java 9, and obsolete libGURL code and binaries were removed
  • fix:Restored torrents stop landing at 0% — the session .torrent and its .resume sidecar now share one canonical hash (they used v1 vs v2), and restore heals installs written with the old mismatched names
  • fix:Born-complete torrents (per-file Share, auto-seed) now persist resume data at check completion and on every forced save — restarts no longer restore them under the default data dir at 0%
  • fix:Missing resume files are backfilled when a torrent is constructed, covering zero-piece torrents that never trigger a check
  • fix:Session .torrent files are ensured alongside resume data so magnet-origin torrents survive restarts instead of vanishing from restore
  • fix:SearchManager no longer cancels all global HTTP requests on stop — OkHttpClientWrapper.cancelAllRequests() was nuking non-search HTTP traffic (updates, FrostClick). Stopped performers now abort via the ‘stopped’ flag
  • fix:SearchMediator onResults IndexOutOfBoundsException — results.get(0) without null/empty check crashed the executor thread when a performer called onResults([])
  • fix:macOS installs ship icebridge.jar beside frostwire.jar and both jars’ native libraries are signed; frostwire.jar no longer duplicates daemon-only IceBridge classes
  • fix:Packaged JARs preserve dependency licenses without file/directory name collisions on case-insensitive filesystems, allowing macOS notarization to unpack embedded native libraries
  • fix:Idope search engine removed from commons, desktop, and android — idope.pics now requires TLS 1.3 and was failing handshakes on macOS arm64 and other TLS-1.2-only stacks. Removed IdopeSearchPattern, createIdopeTorrentSearch, SearchEngineID.IDOPE_ID, IDOPE_SEARCH_ENABLED, PREF_KEY_SEARCH_USE_IDOPE, all 39 localized use_idope strings, the android settings entry, and the desktop MCP engine registry. Added IdopeRemovalTest regression suite
  • fix:Standalone IceBridge forwarders launch with DHT and bootstrap discovery enabled, while release packages include icebridge.jar
  • fix:TORRENT_FETCH returns holder-signed full torrent metadata through EC2 relay hops, including piece layers for hybrid torrents
  • fix:The crawler sharing setting now gates both mesh browsing and DHT catalog publication; opting out withdraws the previous catalog, and only active non-private seeds are listed while ordinary distributed search still finds active downloads
  • fix:Only torrents you are actively seeding are shared with catalog crawlers — previously downloaded torrents that are not seeding are no longer published
  • fix:Crawler data stays anonymous — presence is stored as hashed endpoints and catalogs by publisher peer id only (never IP addresses)
  • fix:CRITICAL: matchedFile excluded from RemoteSearchResponse canonical bytes — Ed25519 signature did not cover the matched file path, allowing MITM tampering. Now included in appendRowBencode as “mf” key
  • fix:IP Filter critical blocking bug — add_rule() was passing flags=0 (allow) instead of ip_filter.access_flags.blocked.swigValue()=1, so blocked IP ranges were silently allowed through libtorrent (#1291) — caught by new IPFilterBlockingTest regression suite
  • fix:TLS hostname verification now uses proper suffix matching instead of substring contains — prevents attacker-controlled hostnames from matching whitelisted domains
  • fix:Timestamp-skew bypass via Math.abs(Long.MIN_VALUE) — Math.abs(Long.MIN_VALUE) returns a negative value, bypassing the >60s skew check in registration and response verification. Replaced with manual sign flip
  • fix:rUDP HELLO replay prevention — 8-byte Unix timestamp added to the signed message. HELLOs with timestamp skew > 300s are rejected (104-byte format only)
  • fix:IceBridge control API requires auth token (X-IceBridge-Token header) on all endpoints except /health — 32-byte random hex string generated at startup
  • fix:RegisterRequest canonical string uses length-prefixed fields to prevent delimiter injection
  • fix:RudpPacketCodec silent payload truncation — payloads >65535 bytes silently truncated the 2-byte length field, corrupting framing. Now rejected before encoding
  • fix:rUDP relay source verification — handleRelay verifies sourcePub matches the sender’s authenticated session identity
  • fix:rUDP hole-punch requires authenticated session — unauthenticated peers can no longer trigger amplification
  • fix:rUDP binds to 127.0.0.1 for local daemon profile — was 0.0.0.0, exposing unauthenticated handlers to the internet
  • fix:rUDP max sessions cap (256) — prevents memory exhaustion from unbounded session creation
  • fix:HTTP response body size capped at 16 MB (search) and 32 MB (torrent downloads) to prevent OOM from malicious or misconfigured servers
  • fix:SearchMediator search query sanitization — control characters stripped and query length capped at 1024 characters before dispatching to performers, preventing injection into URL templates, regex patterns, and JSON request bodies
  • fix:matchedFile length validation (max 4096 chars) in DistributedSearchPerformer and LocalSharedTorrentSearchPerformer — rejects pathologically long values from malicious remote peers
  • fix:DistributedSearchPerformer validates search result row fields — name max 2048 chars, infoHash must be 20 bytes, per-row try/catch prevents NPE from malformed responses
  • fix:IncomingSearchRequestHandler rate-limits per source to 30 requests/minute
  • fix:IncomingSearchRequestHandler rate-limits catalog browse by verified requesterPub after signature check (not transport sourcePub); search rate-limit owned by RelaySearchService
  • fix:FragmentReassembler DoS vulnerability — DATA_END with fragIndex=Integer.MAX_VALUE forced a 2-billion-iteration loop; assemble() had int overflow causing NegativeArraySizeException that killed the rUDP channel. Added MAX_FRAGMENTS_PER_GROUP (4096), MAX_ASSEMBLED_SIZE (16MB), and long accumulation
  • fix:IceBridge P0 hardening — cheap-reject-first ingress (rate-limit before Ed25519 verify), per-IP + global HELLO budgets, per-/24 session caps, empty HELLO_ACK removed; helloRejected/relayRateLimited/searchRateLimited/powRejected/spamMarkedDropped counters in /metrics
  • fix:IceBridge rejects unauthenticated rUDP application packets and applies backpressure instead of acknowledging messages that could not be delivered
  • fix:IceBridge mesh security — HELLO_ACK carries signed identity so initiators learn remotePub (fixes rejected multi-hop RELAY); RELAY_RESPONSE requires authenticated session (no fire-and-forget spoof); RELAY app payload capped to single rUDP fragment; hop TTL default 3; mesh fan-out 3; per-peer RELAY rate limit; local registry targets delivered via /poll without self-UDP
  • fix:Desktop release distributions no longer expose unauthenticated JMX or JDWP listeners
  • fix:IceBridge rUDP and relay TCP listeners now default to bind 0.0.0.0 (publicly reachable). Desktop bind host default changed from 127.0.0.1; IncomingRelayServer now supports explicit bind host (used by IceBridgeServer with config.host()).
  • new:Transfer Detail Files row context menu now offers Share for completed files, creating and seeding a torrent from that file (same behavior as the row’s share button)
  • new:Transfer Detail General tab offers Check Local Data and a per-torrent Sequential download toggle; Trackers menu offers Add Tracker with strong URL validation, and Edit Trackers now trims entries and names the offending line
  • new:Transfer Detail Check Local Data disables while the recheck runs and swaps in a progress bar with live phase and percent, then reports the outcome
  • new:Advanced BitTorrent settings now expose jlibtorrent 2.0.12.9 controls for NAT-PMP gateway override, NAT-PMP lease duration, and allowing multiple connections from the same peer ID
  • new:icebridge:// URL protocol handler — handles URLs of the form icebridge://<peer_pubkey_hex>/. Commands: /browse (fetch and display peer’s shared torrent catalog from DHT), /search/ (send a signed search request to a specific peer), /info (show peer details from PeerDirectory or DHT identity record). Integrated into the search bar — typing an icebridge:// URL triggers the handler instead of a normal search. Clipboard monitoring for icebridge:// URLs
  • new:About window shows the current Telluride build number
  • new:Transfers default columns — Actions, Name, Seeding, Size, Status, Progress, Down Speed, Downloaded, Uploaded, Up Speed, Time, Seeds; Tips/Donations hidden, Uploaded shown (existing custom layouts untouched)
  • new:Karma settings screen (Options > Karma) — displays own karma chain status (current epoch, available endorsement energy, total endorsements given, karma score) and a top-peers-by-karma leaderboard (top 20, with score, endorsement count, last-endorsed timestamp). Right-click to copy peer public keys
  • new:Peer directory settings screen (Options > Peers) — shows all known peers in a table with public key, hostname, uTP port, trust score, verified/spam status, endorser count, and last-updated time. Right-click to copy key, block (mark as spam), remove, or browse the peer’s shared torrents catalog (fetched via DHT BEP 46 using RemoteIndexFetcher)
  • new:Shared torrents database viewer (Options > Shared Torrents) — browse the local shared torrents index with search, showing name, size, file count, info hash, publisher key, timestamps, and matched file. Right-click to copy info hash, copy magnet link, or copy publisher key
  • new:IP Filter table right-click context menu with Edit and Remove actions — edit opens the Add Range dialog pre-populated with the selected range’s values, remove deletes the range and rebuilds the IP filter and BTEngine
  • new:IP Filter panel description now lists supported file formats (.p2p, .dat, .cidr, .hosts) and compression types (.gz, .zip)
  • new:Added MCP auto-configuration support for Grok Build in the shared AgentDetector / AgentConfigWriter (common module). Grok is now detected via grok binary in PATH + ~/.grok/config.toml presence. “Configure” writes a native TOML entry under [mcp_servers.frostwire] with url + enabled=true using the HTTP/Streamable transport. This allows direct MCP connection from Grok Build TUI to the local FrostWire MCP server (port 8796 by default).
  • update:Share dialog posts to X (x.com) with an X icon instead of the retired Twitter branding
  • cleanup:Local search is diagnostic only (default off) — same LocalIndex path as inbound IceBridge answers; peer discovery is Distributed Search
  • fix:IP Filter persistence restored (#1291) — jlibtorrent session state does not persist ip_filter across restarts, so custom ip_filter.db persistence is required
  • fix:IP Filter ip_filter.db corruption root cause (#1291) — atomic writes with synchronized access prevent concurrent corruption during import and clear operations
  • fix:IP Filter ip_filter.db hardened against corruption (#1291) — version-byte validation, break on bad entries, graceful recovery when loading a damaged database
  • fix:IP Filter options pane now visible on Java 26 (#1291) — made IPFilterPaneItem constructor package-private and added setAccessible(true) in OptionsPaneFactory to prevent IllegalAccessException when creating pane items via reflection
  • fix:IP Filter pane duplicate settings key crash (#1291) — made IPFilterTableMediator.getInstance() thread-safe (synchronized+volatile), guarded IPFilterPaneItem.initOptions() against mediator creation failures with ipFilterTable null check, and made OptionsPaneManager.show() cache panes before initOptions to prevent infinite re-creation loops
  • fix:IP Filter DataLine creation on Java 26 (#1291) — added setAccessible(true) in BasicDataLineModel.createDataLine() to allow reflection access to DataLine constructors across package boundaries
  • fix:IP Filter edit disappearance bug (#1291) — fixed off-by-one in BasicDataLineModel.refresh() causing edited rows to vanish from the table after an edit
  • fix:IP Filter robust db loading + Import button disabled when empty (#1291)
  • fix:IP Filter disabled tooltips on table to prevent macOS Input Method EDT freeze (#1291)
  • fix:IP Filter HTTP errors now shown in panel + blocklist site links added (#1291)
  • fix:IP Filter JNI calls moved off EDT to background threads to prevent UI stalls (#1291)
  • fix:IP Filter JPopupMenu background theming on dark themes (#1291)
  • fix:Hybrid torrents use their metadata v1 hash consistently in the shared index and transfer lookup; successful canonical indexing removes only metadata-proven truncated-v2 duplicates
  • fix:YouTube audio muxing and other HTTP post-processing finish before automatic torrent creation or sharing, so the seeded torrent describes the final file; cancellation and failed-mux fallback are covered by completion-order regressions
  • fix:ThreadPool stack size increased from 4 KB to 512 KB — the previous 4 KB stack was far below the JVM default and caused StackOverflowError on deep call chains
  • fix:Sharing a file that no longer exists on disk is refused with a clear error instead of creating a torrent that can never complete
  • fix:VPN detection false positive on macOS — system utun interfaces (iCloud, Back to My Mac) were falsely detected as active VPN tunnels even when VPN was off, because they match the “utun” interface name pattern. Now validates that utun interfaces have a real routable IPv4 address before counting them as VPN. Also added “vpn” to interface name checks for broader VPN detection coverage
  • fix:HTTP search responses now check for 4xx/5xx error codes before returning the body — Cloudflare challenge pages and rate-limit responses are no longer passed to parsers as if they were valid search results
  • fix:DHT peer discovery ConcurrentModificationException — snapshot TcpEndpoint lists from dhtGetPeers before iterating (jlibtorrent alert threads can mutate live lists)
  • fix:MCP streamable HTTP handshake for Grok + other agents: notifications/initialized now returns 202 Accepted + “accepted” body (text/plain) + data: accepted on SSE stream. No initial data on GET SSE open. Allows grok mcp doctor frostwire (and rmcp-based clients) to complete connect instead of hanging on “Sse(session)”.
  • fix:YouTube downloads preserve headers, ranges, cancellation, and resume behavior; Telluride build 47 uses yt-dlp 2026.8.19
  • fix:YouTube search returns both best video and best audio streams, including muxed-only responses
  • fix:Newly created YouTube/HTTP torrents are indexed immediately after auto-seeding
  • fix:Search result table Seeds and Size columns now sort numerically — clicking Seeds ranks 436 above 64; previously sorted lexicographically as strings or by relevance score instead of seed count
  • fix:Default tracker list in TorrentUtil, CreateTorrentDialog, and UrlUtils updated to 16 trackers that responded to a BEP 15 connect_request probe on 2026-06-08 — removed 6 dead trackers (opentrackr, openbittorrent, exodus, moeking, explodie, coppersurfer) and added reliable replacements from ngosang/trackerslist per #1004. New DefaultTrackerListTest regression suite asserts all three files stay in sync
  • fix:SoundCloud default credentials refreshed to the values published at update.frostwire.com/android (client_id=A8wpv6WPWhcpz9BhiL66KfK8IHy6NLoz, app_version=1780910323) — pre-existing drift across SoundCloudConfigFetcher, SoundcloudSearchPattern, SoundcloudUtils, and SoftwareUpdater fallbacks now also aligned
  • fix:shared_files_fts switched from external content FTS5 table (with triggers) to standalone FTS5 table with manual index management — external content “delete” triggers failed silently when rowids were reused, causing stale FTS entries
  • fix:INSERT OR REPLACE on shared_torrents orphaned shared_files rows — REPLACE assigns a new rowid, leaving old file rows unreferenced. Now pre-deletes old shared_files rows before the replace
  • fix:sanitizeFtsQuery now replaces non-alphanumeric separators (underscore, dot, dash, slash) with spaces instead of dropping them — prevents mismatch between FTS5 tokenizer (which splits on these chars) and the query sanitizer (which was concatenating tokens like “real_file” into “realfile”)
  • fix:Knaben search query JSON now properly escaped via Gson
  • fix:Metadata-less magnets are replaced by the real libtorrent transfer, preserving x.pe peers and avoiding invalid piece-layer reconstruction
  • fix:Mesh magnets no longer advertise BitTorrent port 0 from failed listeners
  • fix:Stop seeding PeerDirectory with unverified IceBridge host-cache placeholders (reduces self/auth spam); host cache remains UI/history only
  • fix:Distributed search multi-hop disabled (ttl=0) — re-signing forwarded requests with the forwarder key while keeping original requesterPub always failed verification; v1 is direct verified-peer search only until dual-envelope hop protocol
  • fix:RudpSession sequence-wrap deadlock — after ~2^31 packets, signed comparison treated the wrapped sequence as a duplicate, permanently stalling the session. Fixed with Integer.compareUnsigned for all sequence comparisons and ConcurrentSkipListMap comparator
  • fix:RudpSessionManager pending-packet memory leak — unacked reliable packets were never purged after timeout; only cleared by ackLocal(). Now removed after MAX_RETRIES or RETRANSMIT_TIMEOUT_MS
  • fix:IceBridgeServer peerTtlSec*1000 overflow — for large config values, long multiply overflowed to negative, disabling eviction. Fixed with Math.multiplyExact
  • fix:PeerRegistry capacity enforcement — the maxPeers limit was checked AFTER merge(), so byPubHex.containsKey(key) was always true for a just-added peer; new peers were never rejected. Now checked BEFORE merge
  • fix:FragmentReassembler cross-session collision — group key changed from int groupId to String (sender + groupId)
  • fix:TORRENT_FETCH serves torrents up to 256KB (was 64KB) with signed TOO_LARGE above; holder-signed chunks are cached and restamped per request nonce (metadata protocol v2)
  • fix:IdentityRecord.fromEntry accepts v1/v2 again (read path) — still writes v3 with caps; fixes self-ping / peer handshake decode after capability bump
  • fix:SearchManager checkIfFinished race — crawl() and submitSimpleSearchTask() now add tasks inside synchronized(tasks) blocks, closing the race where a CrawlTask was enqueued between checkIfFinished’s ‘no pending’ check and the onStopped callback
  • fix:SearchResultDisplayer entries list now synchronized — the static ArrayList was mutated from EDT and iterated from search executor threads without synchronization, risking ConcurrentModificationException. Now a Collections.synchronizedList with synchronized blocks on all iteration paths
  • fix:AbstractSearchPerformer thread-safety — ‘stopped’ and ‘listener’ fields were not volatile; stop() from EDT was not visible to executor threads, causing results to be delivered after user clicked Stop
  • fix:DistributedSearchPerformer pending-map leak and NPE — timed-out searches leaked PendingRequest entries; malformed response rows with null infoHash caused NPE before latch countdown. Pending cleared in finally; rows validated
  • fix:SearchEngine TPB _domainName not volatile — background thread wrote _domainName; isReady() read it on EDT. Without volatile, TPB might never become ready. Also added try/catch and named daemon thread for mirror fetch
  • fix:Newly indexed torrents trigger a coalesced routing-digest refresh instead of waiting for the periodic rebuild; writes during an announcement schedule a follow-up and removing the last row withdraws previous holdership
  • fix:macOS native icon preloading reuses the existing Aqua file view instead of constructing a new file chooser for every file extension, avoiding repeated multi-second stalls on the Swing event thread
  • fix:Library media-type rescans are coalesced, so a burst of completed downloads no longer overflows the background executor and spams RejectedExecutionException
  • fix:right-clicking the transfer detail Files tab with no row selected no longer throws a NullPointerException
  • fix:Desktop UI repaints only rows that actually changed instead of every table row each second, theme icons decode once instead of on every paint, and Tip of the Day renders without subpixel-text stalls
  • fix:SearchMediator onResults no longer blocks search executor threads on the EDT — changed safeInvokeAndWait to safeInvokeLater so results are dispatched asynchronously
  • fix:JdkHttpClient.head reads response code before disconnect and drains error stream to prevent socket leaks
  • fix:IdentityKeys.generate() now uses jlibtorrent’s native Ed25519 for keypair generation instead of the JDK’s KeyPairGenerator — the JDK’s pure-Java Ed25519 implementation is 50-100x slower than native on some platforms (macOS arm64), causing first-run identity PoW mining to take >2 minutes instead of ~1-2 seconds
  • fix:InboundMessageQueue O(n²) performance — ConcurrentLinkedQueue.size() (O(n)) was called in a while-loop for overflow eviction. Replaced with AtomicInteger counter
  • fix:SearchMediator filter token-mutation fragility — searchTokens list was passed to filter2 which could mutate it via internal token removal. Now a defensive copy is made at the filter entry point
  • fix:SearchEngine.getSearchEngineByName prefix matching — fragile name.startsWith() replaced with exact name match or name + space prefix to prevent short engine names from matching longer ones
  • fix:SearchEngine TPB mirror fetch error handling — added try/catch and named daemon thread instead of raw new Thread()
  • fix:IceBridgeProcessLauncher temp log directory leak — every start/stop cycle leaked a temp directory with log files. Now recursively deleted in close()
  • fix:IceBridgeServer.parseArgs now skips –auth-token (handled separately by parseAuthToken) — previously threw IllegalArgumentException on unknown option
  • fix:Torrent crawl cache replaced with LRU eviction (LinkedHashMap, max 500 entries) — old cache had no eviction, causing unbounded memory growth in long-running sessions
  • fix:CrawlPagedWebSearchPerformer cache no longer uses global synchronized lock — the underlying DatabaseCrawlCache handles its own thread safety. Cache field is now volatile with local-variable snapshots
  • fix:parseFilesJson capped at MAX_FILES_PER_TORRENT (10000) — prevents unbounded row growth for torrents with tens of thousands of files
  • fix:SearchEngine.getEngines cached as static final — was allocating a new Arrays.asList on every call (per search, per result lookup, per engine lookup)
  • fix:SearchManager removed O(n²) nextOrdinal — the method iterated all tasks per crawlable result and was never used for sorting (no priority queue). Removed Comparable, ordinal field, and nextOrdinal method
  • fix:SearchMediator stripHtml regex precompiled — two String.replaceAll calls per result were recompiling regex on every search result. Now static final Pattern
  • fix:CrawlPagedWebSearchPerformer crawl counter is now AtomicInteger
  • fix:PerformersHelper.reduceHtml no longer double-allocates strings
  • fix:PerformersHelper relevance-ranking hot path — eliminate per-result regex compilation in sanitize/normalize (www. stripping and combining-mark removal after NFKD), speeding up fuzzy matching and result normalization on large search result sets
  • fix:CompositeFileSearchResult Builder no longer allocates 5 Optional wrappers per build() — nullable fields with Optional created at accessor boundary only
  • fix:Regex search patterns (Nyaa, Torrentz2) are now compiled once as static final fields
  • fix:Removed Sec-Fetch-Mode: navigate header from all HTTP requests
  • fix:NullTrustManager certificate list is now thread-safe (CopyOnWriteArrayList)
  • fix:Mesh log volume — per-packet/per-rejection logs demoted to DEBUG (metrics counters carry the signal); systemd unit caps journal spam (LogRateLimit 2000/30s)
  • fix:Transfer Detail Files tab keeps the selected file row highlighted while the view refreshes every second, and skips the rebuild entirely when the visible rows are unchanged
  • fix:transfer action buttons no longer flicker between enabled and disabled while a download is in progress; share/play availability is computed per row off the EDT instead of being cached on the single shared renderer
  • fix:Transfer Detail Files tab no longer freezes per-file progress while a transfer is still moving — holders rebuild on torrent progress drift, settled torrents skip native calls
  • fix:Slideshow / MISC HTTP no longer dies on OkHttp HTTP/2 stream header timeout (o2.php) — MISC client is HTTP/1.1, shared clients send HTTP/2 pings, slideshow retries once after evicting a stale pool
  • fix:macOS file rows show rich native icons again — the JFileChooser native view is used (FileSystemView returns only generic icons on JDK 26) and the bundled app passes –add-exports for com.apple.laf like frostwire.sh does
  • fix:Transfer detail Pieces tab now uses jlibtorrent’s v2-aware pieceSizeForReq() API for accurate piece-size display
  • new:rUDP (Reliable UDP) transport implemented from scratch — Ed25519-authenticated HELLO handshake, sequence-numbered DATA with ACK and retransmission (500ms interval, 5 retries, 5s timeout), application-level fragmentation/reassembly for payloads exceeding the UDP MTU (DATA_FRAG + DATA_END packet types, 1024-byte chunks with 12-byte fragment headers), HOLE_PUNCH for NAT traversal, and RELAY forwarding through forwarder peers. Built on Netty NioDatagramChannel
  • new:IceBridge control API — localhost-only HTTP server with endpoints: /health, /register (Ed25519-signed peer registration), /route (localhost-trusted unsigned peer routing), /lookup, /send (opaque payload delivery), /poll (drain inbound messages), /metrics
  • new:IceBridge multi-hop mesh RELAY — hop TTL frame, Type.RELAY delivery, forwarder mesh via RelayMesh; MultiRelayMeshSearchTest (3 FORWARDER + seeder/searcher clients)
  • new:IceBridge multi-protocol fabric — all mesh payloads IBP1-framed with protocolId on /send and /poll (SEARCH=1)
  • new:Node capability advertisement — IdentityRecord v3 caps bitflags (RELAY/SEARCH/INDEX/STORE/DHT/TORRENT/AI); PeerDirectory filters by capability; roles still derived for DHT topics
  • new:Streaming distributed search responses — RESULT chunks with final flag; large result sets stream multiple signed frames; performer accumulates until final
  • new:Distributed search forwarding (v2) — search requests now use ttl=1 and include the requester’s pubkey in the path array, enabling one-hop forwarding through trusted peers. IncomingSearchRequestHandler forwards requests to up to 3 trusted peers not already in the path, re-signing each forwarded request. Anti-amplification: max 3 forward targets, existing rate limits apply
  • new:Standalone IceBridge embedded DHT announce — pure FORWARDER nodes publish on frostwire-relays-v1 (+ optional bootstrap) via minimal jlibtorrent SessionManager without FrostWire desktop; ICEBRIDGE_DHT / –dht / –no-dht; DhtAdvertiser accepts SessionManager supplier
  • new:Remote peer catalog fetch protocol — RemoteIndexFetcher fetches a peer’s shared torrent catalog from the DHT via BEP 46 (IndexAnnouncementPublisher manifest). RemoteCatalogBrowseRequest provides a signed request/response protocol for browsing a specific peer’s catalog over the IceBridge transport. IncomingSearchRequestHandler handles both search requests and catalog browse requests
  • new:IndexAnnouncementPublisher wired into DhtAdvertiser — shared torrent index manifests are now published to the DHT every 5 minutes alongside identity records, enabling peers to discover each other’s shared catalogs
  • new:IceBridge topology limits — IceBridgeTopology + env ICEBRIDGE_MESH_FANOUT / SEARCH_PEER_FANOUT / MESH_HOP_TTL / SEARCH_TTL / SOFT_MAX (remote-config ready)
  • new:Headless IceBridge presence crawler and mirror tooling (DHT heartbeat-topic presence counts, catalog crawler, allowlist-driven re-sharing)
  • new:Pipeline saturation is observable — /metrics reports poll runs/errors, drain volume, request-queue depth, rejected work, and verification failures
  • new:IceBridge rUDP bind host configurable (ICEBRIDGE_BIND_HOST setting) — use “0.0.0.0” to accept rUDP from remote peers (cloud forwarder mode) or “127.0.0.1” for local-only daemon mode (default). Control HTTP server always binds to localhost
  • new:IceBridge software version announce — IdentityRecord v4 ib_ver + control /register+/lookup; Peers table IceBridge column; constants SOFTWARE_VERSION=1.1.0 / SOFTWARE_VERSION_CODE=1 for future crawler penetration stats
  • new:Dual-envelope distributed search multi-hop (v2) — requester signature covers query only; hops preserve sig; default ttl=2; PeerRegistrySync registers self and imports IceBridge mesh peers (forwarder-first discovery)
  • cleanup:Removed the legacy doctor-servlet bug report dialogs; errors report silently through Icebase, deadlocks through the crash spooler, and the fatal dialog no longer contacts the retired endpoint
  • fix:common/ relay identity and IceBridge file I/O no longer use java.nio.file (Android-safe File streams)
  • new:IdentityKeys.fromSeed() — deterministically reconstructs an Ed25519 keypair from a 32-byte seed via jlibtorrent’s Ed25519.createKeypair, enabling identity restore from a BIP39 mnemonic. X25519 keypair is freshly generated (not derivable from the Ed25519 seed). IdentityKeys.save/load are now public for import/export
  • new:DistributedSearchTransport abstraction — transport-agnostic listener-based interface that decouples the search performer from the concrete transport (IceBridge or future alternatives). A single background poller feeds all listeners, preventing races between the performer and incoming-request handler
  • new:IceBridgeClient and IceBridgeProcessLauncher — desktop HTTP client for the local IceBridge daemon, plus subprocess launcher that starts icebridge.jar with auto-allocated ports, shared identity, and redirected log output
  • new:IncomingSearchRequestHandler — permanent listener that processes incoming search requests through RelaySearchService and sends signed responses back via the transport
  • new:PeerRegistrySync — periodic daemon thread that syncs verified PeerDirectory entries into the IceBridge daemon’s registry via /route every 30 seconds, using the well-known rUDP port 6889
  • new:KeyspaceRouter ranks peers by XOR distance of SHA-1(keywords) for future responsibility-based routing (search still fans out trust-ordered peers first)
  • refactor:DistributedSearchPerformer refactored from direct-TCP OutgoingRelayClient to transport-agnostic DistributedSearchTransport — the performer now sends requests via transport.send() and collects responses through a temporary PayloadListener registered for the duration of the search. Removed thread pool; the transport’s poller handles delivery
  • refactor:OutgoingRelayClient verification extracted into shared SearchResponseVerifier (DRY) — both the direct-TCP and IceBridge paths now apply identical nonce, timestamp-skew, and Ed25519 signature checks
  • refactor:IceBridge client classes (IceBridgeClient, IceBridgeSearchTransport, IncomingSearchRequestHandler, PeerRegistrySync) moved from desktop to common for Android reuse. IceBridgeClient rewritten with OkHttp (replaces java.net.http.HttpClient). IceBridgeServer auth token stdout leak removed
  • refactor:PeerDiscoveryScheduler, DhtAdvertiser, KarmaChainWriter, KarmaChainPublisher, KarmaChainCommitScheduler moved from desktop to common for Android reuse. KarmaChainStore interface extracted — KarmaChainTable now implements it. KarmaChainWriter depends on the interface instead of the concrete table
  • new:Multi-instance distributed search test — headless integration test that simulates two FrostWire instances on the same machine with different identities, ports, and local indexes, verifying cross-instance search via real rUDP
  • new:LocalIndex.listAll() — enumerate all shared torrents in the local index for UI browsing
  • new:DistributedSearchEngineWire.getPeerDirectory() — static accessor for the shared PeerDirectory instance, enabling UI panels to access peer data
  • new:IceBridge hybrid EC2 topology benchmark + TopologyAutoResearch auto-loop optimizes N/M/TTLs for hit-rate vs traffic on fat EC2 hub mesh + FrostWire leaves; hybrid profile N=16 M=30; LimeWire ultrapeer baseline retained
  • new:Standalone IceBridge (icebridge-run-local.sh / AWS) logs successful mesh traffic at INFO — HELLO, HELLO_ACK, RELAY, SEARCH, TELEMETRY/PING and other known protocolIds
  • fix:PeerRegistrySync rUDP port is now configurable via constructor parameter
  • fix:Removed dead estimateRowsBytes() method from RemoteSearchResponse
  • fix:SCHEMA_VERSION bumped to 2 to reflect shared_files and shared_files_fts table additions
  • refactor:Tracker list consolidated into a single source of truth at com.frostwire.bittorrent.DefaultTrackers (#1004) — TorrentUtil, CreateTorrentDialog, and TorrentsCSVSearchPattern now consume DefaultTrackers.ANNOUNCE_URLS / MAGNET_URL_PARAMETERS. Removed duplicated UrlUtils.USUAL_TORRENT_TRACKERS_MAGNET_URL_PARAMETERS
  • cleanup:Desktop builds support JDK 26 by upgrading google-java-format from 1.24.0 to 1.36.1
  • fix:IceBridge ops scripts — run-local kills previous instances and detaches safely on Ctrl+C; systemd install is one-step (builds the jar, sudo self-elevation with JAVA_HOME passthrough, stops port strays, no crash-loops)
  • cleanup:GPL header on all post-2020 Java files missing it (79 files)
  • cleanup:Identity settings UI uses shared IdentityLifecycle (common/) for generate/install/seed/import/export — same logic as Android
  • new:ICEBRIDGE_ARCHITECTURE_REVIEW.md north-star layering + implementation status matrix
  • cleanup:Drop pre-alpha wire shims — no bare SEARCH payloads, no dual response signature domain, no IdentityRecord v1/v2 parse, no 96-byte HELLO auth
  • fix:IceBridge CLI prints identity load vs proof-of-work mining progress on stdout (first-run no longer looks hung); non-protocol TCP 6888 probes at DEBUG without stack spam
  • fix:IceBridge ops scripts — systemd install creates writable /opt dir; control URL is SSH tunnel only (127.0.0.1 bind); install uses absolute java path and preserves icebridge.env; no –background+–gradle; default control HTTP 8081 aligns run-local/fromEnv/.env.example
  • new:IceBridge fat JAR multi-arch jlibtorrent natives (Linux x86_64/arm64 + macOS) so Mac-built icebridge.jar runs DHT on EC2; scripts/icebridge-systemd-install.sh
  • new:ICEBRIDGE.md operator stub (ports, local vs remote, tokens, co-located pitfalls, security model)