Bt   java bittorrent done right

Release 1.5

Release 1.5 was published to Maven Central on September 26th, 2017. There are several cool features in this release.

Runtime events

The new centralized mechanism for publishing/receiving events is represented by two DI services: bt.event.EventSink for publishing and bt.event.EventSource for subscriptions. Library users have an easy access to the EventSource instance via bt.runtime.BtRuntime#getEventSource().

Currently there are the following types of events:

  • when a new peer has been discovered for some torrent;
  • when a new connection with some peer has been established;
  • when a connection with some peer has been terminated;
  • when local information about some peer’s data has been updated (received BITFIELD or HAVE message);
  • when processing of some torrent has begun;
  • when processing of some torrent has finished;

Torrent processing listeners

This is mostly an internal enhancement, but it brings two useful features for library users:

1) Ability to stop torrent processing as soon as the metadata has been fetched. It can be convenient, when one is using magnet links and doesn’t want to download the actual data, but just the info dictionary. See bt.TorrentClientBuilder#afterTorrentFetched.

2) Ability to stop torrent processing as soon as the data has been downloaded. It is supposed to replace the custom listeners, that periodically perform state.getPiecesRemaining() == 0 checks and then invoke client.stop(). The new alternative is much more efficient, because it does not use a separate thread. See bt.TorrentClientBuilder#stopWhenDownloaded.

I/O selector

Leveraging OS I/O multiplexing allowed to significantly reduce the number of system calls and slightly cut down on the CPU usage in message dispatching loop.

Module extenders

This feature is borrowed from Bootique project (which I strongly recommend to anyone, who is interested in runnable Java applications). It replaces contribution methods with a clearer and more concise API for contributing custom extensions into the core. Instead of invoking individual contributions methods, downstream modules should now call bt.module.ServiceModule#extend(Binder) or bt.module.ProtocolModule#extend(Binder) and use methods in the returned builder instance, e.g.:

import com.google.inject.Binder;
import com.google.inject.Module;

import bt.module.ProtocolModule;

public class MyModule implements Module {
    
    @Override
    public void configure(Binder binder) {
        ProtocolModule.extend(binder)
            .addMessageHandler(20, ExtendedProtocol.class)
            .addExtendedMessageHandler("ut_metadata", UtMetadataMessageHandler.class);
    }
}

…and more

As usual, here’s the complete list of what has been done:

Changes/New Features:

  • Introduce a unified, centralized mechanism for publishing/receiving events
  • Introduce a processing stage listener mechanism

Bug Fixes/Improvements:

  • Disallow to set client’s runtime other than via Bt factory method
  • Introduce module extenders for contributing custom extensions
  • Disable BEP-9 metadata exchange for private torrents
  • DefaultClient state fix when client is stopped PR#37
  • Announce stats to tracker on start, stop, complete
  • Use I/O selector for receiving incoming messages
  • Allow to override the number of peers to request from a tracker
  • Provide information on creation date and creator of the torrent
  • Support empty files

Release 1.4

Release 1.4 was published to Maven Central on August 14th, 2017.

It is mostly a maintenance release with some important bug fixes. We’ve also refactored FileSystemStorage to not depend on java.io.File and instead use java.nio.file.Path. This paves the way for some interesting possibilities, one of which is using Jimfs, an in-memory file system for Java 7+ to emulate in-memory file storage.

Changes/New Features:

  • Choose a specific network interface #20

Bug Fixes/Improvements:

  • Use generic java.nio.files interfaces in FileSystemStorage #21Jeremy L. Morris (MorrisLaw)
  • Switch integration tests to using in-memory storage #27
  • UDP tracker request contains 0 as the listening port
  • Download not starting when using standalone client with private runtime #34
  • java.lang.IllegalAccessError when running inside JBoss modules #32

Release 1.3

Release 1.3 was published to Maven Central on July 29th, 2017. It includes two major updates:

Officially called BEP-9: Extension for Peers to Send Metadata Files, this feature is highly important for any modern BitTorrent client. It allows the participants of a BitTorrent network to exchange torrent metadata without the need for downloading a .torrent file.

New methods in the client builder make using a magnet link in Bt very straight-forward:

// create a streaming torrent from a magnet link
BtClient client = Bt.client()
                    .storage(new FileSystemStorage(new File("~/Downloads")))
                    .selector(SequentialSelector.sequential())
                    .magnet("magnet:?xt=urn:btih:B5A725522B0B4DB73AD2491BA1AD58F13D853315")
                    .build();

Some magnet links also contain “bootstrapping” tracker and peer addresses, which can be used to quickly connect to the swarm. Of course, these are fully supported as well. For convenience, there’s also an overloaded version of builder method: bt.BaseClientBuilder#magnet(bt.magnet.MagnetUri), that accepts a programmatically created magnet link.

CLI launcher has also been updated to accommodate this new feature. E.g. streaming a media file is now as easy as copying the magnet link from browser and providing it to the launcher via -m parameter and adding an -S flag to download in sequential order:

$ java -jar bt-launcher.jar -m "magnet:?xt=urn:btih:B5A725522B0B4DB73AD2491BA1AD58F13D853315" -d ~/Downloads -S

DHT module is now available in Maven Central

Bt has had DHT support for nearly half a year already, but only now it’s become possible to publish the bt-dht module to Maven Central, removing the need to build it manually from source. It’s all thanks to the authors and maintainers of Bittorrent Mainline DHT implementation in Java, who have agreed to change the license from GPL 2.0 to a more permissive Mozilla License 2.0, which is compatible with Apache License 2.0, used by Bt. My personal thanks to The8472, who currently maintains mldht and have coordinated this change.


As usual, here’s the complete list of what has been done:

Official BEPs:

  • BEP-9: Extension for Peers to Send Metadata Files

Changes/New Features:

  • Added ByteRange for working with binary ranges based on byte arrays and byte buffers
  • Support creating torrents from binary representation of info dictionary

Bug Fixes/Improvements:

  • Introduced notion of torrent processing chain
  • Fixed bug in extended protocol (invalid message type id mapping for peers) that sometimes prevented peers from receiving extended messages from Bt
  • Reduced dependency on the presence of a torrent; using torrent ID where possible
  • Perform peers lookup for active torrents only
  • Support HTTPS trackers
  • Configurable list of bootstrap DHT nodes
  • Configurable MSE private key size
  • Headless mode in CLI client (Windows compatibility)
  • Fix for occasional UI crashes in CLI client
  • Allow to specify the desired log level in CLI client (normal, verbose, trace)

Release 1.2

Release 1.2 was published to Maven Central on May 24th, 2017. Aside from a couple of minor fixes and enhancements, it includes a new major feature: full support for official BitTorrent protocol encryption. Detailed information on how to enable and use encrypted protocol in Bt is available on a dedicated tutorial page.

Changes/New Features:

  • Message Stream Encryption
  • Added API for retrieving the full list of registered torrents

Bug Fixes/Improvements:

  • Last block in a chunk is incorrectly marked as complete even when partially written
  • Provide info on encryption support, local TCP port and version in extended handshake
  • Eliminate self-connections in tests
  • Don’t specify the recipient of a PEX message in the list of added peers

Release 1.1

Release 1.1 was published to Maven Central on April 10th, 2017. It includes a number of major performance and algorithmic improvements, critical bug fixes and API enhancements. It is strongly recommended for all users to switch to the new version.

Changes/New Features:

  • Support for auto-loading modules from the classpath
  • Enhanced API for building standalone and shared-runtime clients
  • Streaming (continuous) piece selectors
  • Improvements in piece selection and peer assignments algorithm
  • Support for multi-threaded hashing (verification) of torrent data on startup
  • Lifecycle binding API improvements; support for asynchronous bindings
  • Tools for creating custom protocol tests

Bug Fixes/Improvements:

  • Torrent processing should not terminate when interaction with the tracker failed
  • Announce key can be missing in trackerless torrents
  • Failures on receiving unexpected blocks should be optional
  • Peer connection occasionally stopped receiving/sending data due to a buffer compaction bug
  • Verification tasks should be submitted only for complete pieces
  • Chunk descriptor overlapping two files contained no blocks when the latter file was smaller than the leftovers from the former file
  • Calculate total size for multi-file torrents
  • NPE on UDP message worker shutdown
  • Multi-tracker does not announce to next trackers in tier if an exception was thrown
  • Querying trackers and other peer sources should be async
  • Adaptive message processing interval in message dispatcher to reduce the CPU load
  • Speed-up the initial startup by skipping verification if a storage unit is empty and by feeding larger blocks to the digester