BitTorrent on iOS
Michael Caylus / Simone Civetta
12/01/2017
Michael Simone
Quiz
‘How many of you need to
sync large quantity of files
periodically?’
BitTorrent
Designed: April 2001
First released: July 2001 Bram Cohen
A
Peer-To-Peer Protocol
#1 usage:
Sharing Large Media Files
170M active users* 40% of all Internet traffic**
10 popular clients
uTorrent, Xunlei, Transmission, Vuze, qBittorent,
Deluge, BitComet and Tixatit
* Wikipedia
CompaniesPiracy
** BitTorrent Inc.
Facilitates transfer of large/multiple files
Works on unreliable network connections
Downloads can be resumed any time
✔
✔
✔
In Detail
Basics
Files are
shared among
the users
Files to be shared
are split in
multiple chunks
Peers
contribute
Torrent (metadata)
Pieces / Segment
Swarm
Peers / Leechers
Seeds
Trackers
Stakeholders
Metainfo file (bencoded dictionary)
Torrent File
ANNOUNCE
Announce URL of the tracker
PIECE LENGTH
INFO
Dictionary describing the files’ chunks
PIECES (20-byte SHA1 Hash Values)
LENGTH
NAME
PIECE LENGTH
PIECES (20-byte SHA1 Hash Values)
NAME
FILES
LENGTH
PATH
Always-available seed
Firewall-friendly stream
Easy-to-manage service
Our Challenges
!
!
!
Torrent (metadata)
Pieces / Segment
Swarm
Peers / Leechers
Seeds
Trackers
WebSeed
2
WebSeed
Similar to HTTP direct download
Guarantees availability of resources
Independent of swarm sanity
Extension on bitTorrent protocol
Introduced in 2006
Quiz
‘How many of you have
already developed a
BitTorrent client?’
libtorrent
BitTorrent OSS Implementation
Developed by Arvid Norberg, since 2003
Written in C++, Cross Platform
Memory/CPU efficient, feature-packed
✔
✔
✔
✔
libtorrent
Pros
Easily configurable
Supports trackerless mode, with
DHT
Supports Web Seeds (i.e. a seed can
be a HTTP host), and SSL Torrents
Supports Local Service Discovery
Pros and Cons
Cons
No CocoaPods/Carthage distribution
Depends on other libraries
Not based on URLConnection
Does not support iOS background
sessions
Alternatives
MultiPeer
Connectivity
Couchbase Realm
Alternatives
Alternatives: Pros
MultiPeer
Connectivity
Couchbase
It’s a real DB
Sync based on
NSURLSession
Supports MPC
Realm
It’s a real DB
Sync based on
NSURLSession
Native
Supports
Bluetooth
Alternatives: Cons
MultiPeer
Connectivity
Couchbase
Depends on a
proprietary stack
Doesn’t work
with chunks
Realm
Depends on a
proprietary stack
No real P2P
8 devices per
session
Manual handling
of chunks
How to Build
OpenSSL
Boost C++ TLS/SSL and crypto C library
Requirements
How to Build
https://github.com/xebia-france/libtorrent-ios-resources
Option A: Pre-configured Xcode Project
- https://github.com/chublix/libtorrent-ios
- Adapt for OpenSSL
Option B: Qt Creator
- Build OpenSSL and Boost separately
- Build libtorrent, for all the platforms (e.g. iphoneos and iphonesimulator)
- lipo (i.e., merge the slices) of the different platforms
Option C: Bash Script
- cf. xebia-france/libtorrent-ios-resources/build-script
Sources
Popcorn Time iOS
https://github.com/danylokostyshyn/popcorntime-ios
Popcorn Time TV:
https://github.com/PopcornTimeTV/PopcornTimeTV
Popcorn Torrent:
https://github.com/PopcornTimeTV/PopcornTorrent (GCD WebServer / Torrent client for iOS)
Configuration
Configuration
session_settings settings = ses.settings();
settings.ssl_listen = 4443;
settings.active_loaded_limit = 1;
settings.max_peerlist_size = 10;
settings.min_announce_interval = 30;
settings.urlseed_wait_retry = 10;
ses.set_settings(settings);
// http://libtorrent.org/reference-Settings.html
settings.local_service_announce_interval = 30;
settings.active_lsd_limit = 1;
// ...
ses.start_lsd();
// ...
ses.stop_lsd();
Configuration (Local Service Discovery)
How Incremental
Download Works
How Incremental Download Works
No modification in the content: No Download
Modification in the content referenced changed: Download Starts
The SHA1 of each chunk is compared to the version on disk:
Implementation
C++ / Swift Bridging
03
04
01
02 Add wrapper class’s header file into bridging header
Implement a wrapper class in .mm file (Obj C++ )
Use wrapper class in Swift03
C++ / Swift Bridging
02 Implement a wrapper class
Wrapper Class (Header)
#import <Foundation/Foundation.h>
@interface LibTorrentWrapper : NSObject {
- (void)initSession:(NSInteger)fromPort toPort:(NSInteger)toPort;
- (void)addNewTorrentFromFile:(NSString *)filePath;
}
C++ / Swift Bridging
02 Implement a wrapper class
Wrapper Class (Implementation)
@interface LibtorrentWrapper()
@property libtorrent::session *session;
@end
@implementation LibtorrentWrapper
- (void)initSession:(NSInteger)fromPort toPort:(NSInteger)toPort {
self.session = new libtorrent::session();
session_settings settings = self.session->settings();
// Apply Settings here...
self.session->set_settings(settings);
libtorrent::error_code ec;
self.session->listen_on(std::make_pair(fromPort, toPort), ec)
}
C++ / Swift Bridging
02 Implement a wrapper class
Wrapper Class (Implementation)
//...
- (void)addNewTorrentWithData:(NSData *)data {
libtorrent::add_torrent_params params;
params.save_path = // Some dir...
libtorrent::error_code ec;
params.ti = new libtorrent::torrent_info((const char*)data.bytes, data.length, ec);
self.session->add_torrent(params, ec);
}
@end
C++ / Swift Bridging
02 Implement a wrapper class
Invoke Wrapper Class in Swift
func startTorrentSession() {
var torrentWrapper = LibtorrentWrapper()
torrentWrapper.initSession(6881, toPort: 6889)
torrentWrapper.addNewTorrentWithData(/* Some Data */)
}
Event loop
03
04
01
02 Pop alert events each time callback is invoked
Set-up a timer that triggers a callback periodically
Feed torrent progress info03
Fetch alerts
- (void)fetchAlerts {
std::deque<alert *> deque;
_session->pop_alerts(&deque);
for (std::deque<alert *>::iterator it=deque.begin(); it != deque.end(); ++it) {
std::unique_ptr<alert> alert(*it);
switch (alert->type()) {
case metadata_received_alert::alert_type:
//**
case piece_finished_alert::alert_type:
//** You can feed progress info here
case torrent_finished_alert::alert_type:
//**
default: break;
}
}
deque.clear();
}
Fetch torrent progress info
- (dl_info)getCurrentTorrentInfo:(piece_finished_alert *)alert {
dl_info result;
torrent_handle t = alert->handle;
try {
t->get_torrent_info();
} catch (libtorrent_exception &e) {
return result;
}
torrent_status ts = t->status(torrent_handle::query_pieces);
result.seeders = ts.num_seeds;
result.peers = ts.num_peers;
result.downloadRateBs = ts.download_rate;
result.uploadRateBs = ts.upload_rate;
torrent_info ti = t->get_torrent_info();
result.downloaded = ts.total_done;
result.progress = ts.progress_ppm;
result.completed_time = ts.completed_time;
return result
}
Caveats
Caveats
1 Needs fine tuning, i.e. for avoiding heavy
battery consumption
No background sessions
Almost no iOS help resource available
System proxy support to be manually
implemented (via
CFNetworkCopySystemProxySettings)
2
3
4
BitTorrent on iOS
BitTorrent on iOS

BitTorrent on iOS

  • 1.
    BitTorrent on iOS MichaelCaylus / Simone Civetta 12/01/2017
  • 2.
  • 3.
  • 4.
    ‘How many ofyou need to sync large quantity of files periodically?’
  • 5.
  • 8.
    Designed: April 2001 Firstreleased: July 2001 Bram Cohen A Peer-To-Peer Protocol #1 usage: Sharing Large Media Files
  • 9.
    170M active users*40% of all Internet traffic** 10 popular clients uTorrent, Xunlei, Transmission, Vuze, qBittorent, Deluge, BitComet and Tixatit * Wikipedia CompaniesPiracy ** BitTorrent Inc.
  • 10.
    Facilitates transfer oflarge/multiple files Works on unreliable network connections Downloads can be resumed any time ✔ ✔ ✔
  • 11.
  • 12.
    Basics Files are shared among theusers Files to be shared are split in multiple chunks Peers contribute
  • 13.
    Torrent (metadata) Pieces /Segment Swarm Peers / Leechers Seeds Trackers Stakeholders
  • 14.
    Metainfo file (bencodeddictionary) Torrent File ANNOUNCE Announce URL of the tracker PIECE LENGTH INFO Dictionary describing the files’ chunks PIECES (20-byte SHA1 Hash Values) LENGTH NAME PIECE LENGTH PIECES (20-byte SHA1 Hash Values) NAME FILES LENGTH PATH
  • 15.
  • 16.
    Torrent (metadata) Pieces /Segment Swarm Peers / Leechers Seeds Trackers WebSeed
  • 17.
    2 WebSeed Similar to HTTPdirect download Guarantees availability of resources Independent of swarm sanity Extension on bitTorrent protocol Introduced in 2006
  • 18.
  • 19.
    ‘How many ofyou have already developed a BitTorrent client?’
  • 20.
  • 21.
    BitTorrent OSS Implementation Developedby Arvid Norberg, since 2003 Written in C++, Cross Platform Memory/CPU efficient, feature-packed ✔ ✔ ✔ ✔ libtorrent
  • 22.
    Pros Easily configurable Supports trackerlessmode, with DHT Supports Web Seeds (i.e. a seed can be a HTTP host), and SSL Torrents Supports Local Service Discovery Pros and Cons Cons No CocoaPods/Carthage distribution Depends on other libraries Not based on URLConnection Does not support iOS background sessions
  • 23.
  • 24.
  • 25.
    Alternatives: Pros MultiPeer Connectivity Couchbase It’s areal DB Sync based on NSURLSession Supports MPC Realm It’s a real DB Sync based on NSURLSession Native Supports Bluetooth
  • 26.
    Alternatives: Cons MultiPeer Connectivity Couchbase Depends ona proprietary stack Doesn’t work with chunks Realm Depends on a proprietary stack No real P2P 8 devices per session Manual handling of chunks
  • 27.
  • 28.
    OpenSSL Boost C++ TLS/SSLand crypto C library Requirements
  • 29.
    How to Build https://github.com/xebia-france/libtorrent-ios-resources OptionA: Pre-configured Xcode Project - https://github.com/chublix/libtorrent-ios - Adapt for OpenSSL Option B: Qt Creator - Build OpenSSL and Boost separately - Build libtorrent, for all the platforms (e.g. iphoneos and iphonesimulator) - lipo (i.e., merge the slices) of the different platforms Option C: Bash Script - cf. xebia-france/libtorrent-ios-resources/build-script
  • 30.
    Sources Popcorn Time iOS https://github.com/danylokostyshyn/popcorntime-ios PopcornTime TV: https://github.com/PopcornTimeTV/PopcornTimeTV Popcorn Torrent: https://github.com/PopcornTimeTV/PopcornTorrent (GCD WebServer / Torrent client for iOS)
  • 31.
  • 32.
    Configuration session_settings settings =ses.settings(); settings.ssl_listen = 4443; settings.active_loaded_limit = 1; settings.max_peerlist_size = 10; settings.min_announce_interval = 30; settings.urlseed_wait_retry = 10; ses.set_settings(settings); // http://libtorrent.org/reference-Settings.html
  • 33.
    settings.local_service_announce_interval = 30; settings.active_lsd_limit= 1; // ... ses.start_lsd(); // ... ses.stop_lsd(); Configuration (Local Service Discovery)
  • 34.
  • 35.
    How Incremental DownloadWorks No modification in the content: No Download Modification in the content referenced changed: Download Starts The SHA1 of each chunk is compared to the version on disk:
  • 36.
  • 37.
    C++ / SwiftBridging 03 04 01 02 Add wrapper class’s header file into bridging header Implement a wrapper class in .mm file (Obj C++ ) Use wrapper class in Swift03
  • 38.
    C++ / SwiftBridging 02 Implement a wrapper class Wrapper Class (Header) #import <Foundation/Foundation.h> @interface LibTorrentWrapper : NSObject { - (void)initSession:(NSInteger)fromPort toPort:(NSInteger)toPort; - (void)addNewTorrentFromFile:(NSString *)filePath; }
  • 39.
    C++ / SwiftBridging 02 Implement a wrapper class Wrapper Class (Implementation) @interface LibtorrentWrapper() @property libtorrent::session *session; @end @implementation LibtorrentWrapper - (void)initSession:(NSInteger)fromPort toPort:(NSInteger)toPort { self.session = new libtorrent::session(); session_settings settings = self.session->settings(); // Apply Settings here... self.session->set_settings(settings); libtorrent::error_code ec; self.session->listen_on(std::make_pair(fromPort, toPort), ec) }
  • 40.
    C++ / SwiftBridging 02 Implement a wrapper class Wrapper Class (Implementation) //... - (void)addNewTorrentWithData:(NSData *)data { libtorrent::add_torrent_params params; params.save_path = // Some dir... libtorrent::error_code ec; params.ti = new libtorrent::torrent_info((const char*)data.bytes, data.length, ec); self.session->add_torrent(params, ec); } @end
  • 41.
    C++ / SwiftBridging 02 Implement a wrapper class Invoke Wrapper Class in Swift func startTorrentSession() { var torrentWrapper = LibtorrentWrapper() torrentWrapper.initSession(6881, toPort: 6889) torrentWrapper.addNewTorrentWithData(/* Some Data */) }
  • 42.
    Event loop 03 04 01 02 Popalert events each time callback is invoked Set-up a timer that triggers a callback periodically Feed torrent progress info03
  • 43.
    Fetch alerts - (void)fetchAlerts{ std::deque<alert *> deque; _session->pop_alerts(&deque); for (std::deque<alert *>::iterator it=deque.begin(); it != deque.end(); ++it) { std::unique_ptr<alert> alert(*it); switch (alert->type()) { case metadata_received_alert::alert_type: //** case piece_finished_alert::alert_type: //** You can feed progress info here case torrent_finished_alert::alert_type: //** default: break; } } deque.clear(); }
  • 44.
    Fetch torrent progressinfo - (dl_info)getCurrentTorrentInfo:(piece_finished_alert *)alert { dl_info result; torrent_handle t = alert->handle; try { t->get_torrent_info(); } catch (libtorrent_exception &e) { return result; } torrent_status ts = t->status(torrent_handle::query_pieces); result.seeders = ts.num_seeds; result.peers = ts.num_peers; result.downloadRateBs = ts.download_rate; result.uploadRateBs = ts.upload_rate; torrent_info ti = t->get_torrent_info(); result.downloaded = ts.total_done; result.progress = ts.progress_ppm; result.completed_time = ts.completed_time; return result }
  • 45.
  • 46.
    Caveats 1 Needs finetuning, i.e. for avoiding heavy battery consumption No background sessions Almost no iOS help resource available System proxy support to be manually implemented (via CFNetworkCopySystemProxySettings) 2 3 4