SlideShare une entreprise Scribd logo
1  sur  35
Télécharger pour lire hors ligne
Creating a BitTorrent Client 
with Scala and Akka 
Part I 
Dominik Gruber, @the_dom 
Scala Vienna User Group – Nov. 26, 2014
Agenda 
• Akka: Brief Introduction 
• BitTorrent: Basic Procedure 
• Bencoding 
• Tracker 
• Peer Wire Protocol 
• Software Architecture 
Dominik scala-torrent Gruber • @the_dom
• Actor Model for the JVM 
• Scala & Java API 
• Part of the Typesafe Platform 
• http://akka.io 
Dominik scala-torrent Gruber • @the_dom
• Simple Concurrency & Distribution 
Asynchronous and Distributed by design. High-level abstractions like Actors, 
Futures and STM. 
• Elastic & Decentralized 
Adaptive load balancing, routing, partitioning and configuration-driven 
remoting. 
• Resilient by Design 
Write systems that self-heal. Remote and/or local supervisor hierarchies. 
• High Performance 
50 million msg/sec on a single machine. Small memory footprint; ~2.5 million 
actors per GB of heap. 
Dominik scala-torrent Gruber • @the_dom
Dominik scala-torrent Gruber • @the_dom
BitTorrent 
• Most popular protocol for peer-to-peer file sharing 
• Designed in 2001 
• Est. over 250 million users/month 
• Currently responsible for 3.35% of all worldwide 
bandwidth 
Dominik scala-torrent Gruber • @the_dom
http://en.wikipedia.org/wiki/BitTorrent#mediaviewer/File:BitTorrent_network.svg 
Dominik scala-torrent Gruber • @the_dom
Basic Procedure 
1. Load information from a metainfo (.torrent) file 
2. Request peers from tracker 
3. Connect to peers via handshake 
4. Exchange data via predefined messages (Peer Wire 
Protocol) 
Dominik scala-torrent Gruber • @the_dom
Metainfo File 
• In Bencode format 
• Includes URL of the tracker, list of files / pieces,… 
• Info hash has to be calculated from the file to identify 
the torrent for communication with tracker and peers 
Dominik scala-torrent Gruber • @the_dom
Bencoding 
• Integers 
i<integer encoded in base ten ASCII>e 
e.g. i42e 
• Strings 
<string length>:<string data> 
e.g. 4:spam; 12:scala vienna 
Dominik scala-torrent Gruber • @the_dom
Bencoding 
• Lists 
l<bencoded values>e 
e.g. l5:scala7:torrente 
• Dictionaries 
d<bencoded string><bencoded element>e 
e.g. d5:scalal4:akka4:playe4:java15:enterprise helle 
Dominik scala-torrent Gruber • @the_dom
Example: Ubuntu 14.04.1 
d8:announce39:http://torrent.ubuntu.com:6969/ 
announce13:announce-listll39:http:// 
torrent.ubuntu.com:6969/announceel44:http:// 
ipv6.torrent.ubuntu.com:6969/ 
announceee7:comment29:Ubuntu CD 
releases.ubuntu.com13:creation 
datei1406245742e4:infod6:lengthi599785472e4:n 
ame31:ubuntu-14.04.1-server-amd64.iso12:piece 
lengthi524288e6:pieces22880:(…) 
Dominik scala-torrent Gruber • @the_dom
Parsing Bencode with Scala 
• Scala Parser Combinators 
• Since Scala 2.11 a separate library 
• Any structured format can be defined and parsed 
through its custom DSL 
Dominik scala-torrent Gruber • @the_dom
Parsing Bencode with Scala 
import scala.util.parsing.combinator._ 
object BencodeParser extends RegexParsers { 
def integer: Parser[Int] = 
"i" ~> """(0|-?[1-9]d*)""".r <~ "e" ^^ (_.toInt) 
// (…) 
} 
Dominik scala-torrent Gruber • @the_dom
Parsing Bencode with Scala 
object BencodeParser extends RegexParsers { 
// (…) 
def list: Parser[List[Any]] = 
"l" ~> rep1(bencodeElem) <~ "e" 
def dictionary: Parser[Map[String,Any]] = 
"d" ~> rep1(string ~ bencodeElem) <~ "e" ^^ 
(_.map(x => (x._1, x._2)).toMap) 
// (…) 
} 
Dominik scala-torrent Gruber • @the_dom
Parsing Bencode with Scala 
object BencodeParser extends RegexParsers { 
// (…) 
def string: Parser[String] = new Parser[String] { 
def apply(in: Input) = { 
val source = in.source 
val offset = in.offset 
val start = handleWhiteSpace(source, offset) 
"""(d+):([sS]+)""".r findPrefixMatchOf source.subSequence(start, source.length) match { 
case Some(matched) => 
val length = matched.group(1).toInt 
if (length <= matched.group(2).length) 
Success( 
matched.group(2).substring(0, length), 
in.drop(start + length.toString.length + 1 + length - offset) 
) 
else 
Failure("Provided length is longer than the remaining input", in.drop(start - offset)) 
case None => 
Failure("Input is not a string", in.drop(start - offset)) 
} 
} 
} 
// (…) 
} 
Dominik scala-torrent Gruber • @the_dom
Parsing Bencode with Scala 
object BencodeParser extends RegexParsers { 
// (…) 
def bencodeElem = 
string | integer | list | dictionary 
def apply(input: String) = 
parseAll(bencodeElem, input) 
} 
Dominik scala-torrent Gruber • @the_dom
Tracker 
• HTTP service which holds information about a torrent 
• Communication via GET-Request if a transfer is 
started, stopped, or completed 
• Responds with a list of peers as a bencoded 
dictionary 
• Tracker is a single point of failure -> DHT extension 
Dominik scala-torrent Gruber • @the_dom
Tracker: Example Request 
http://torrent.ubuntu.com:6969/announce 
?event=started 
&info_hash=-%06l%94H%0A%DC%F5%2B%FD 
%11%85%A7%5E%B4%DD%C1wvs 
&peer_id=-SC0001-546306326124 
&port=6881 
&numwant=50 
&downloaded=0 
&left=599785472 
&uploaded=0 
&compact=1 
Dominik scala-torrent Gruber • @the_dom
Tracker: Example Response 
d8:completei748e10:incompletei8e8:inter 
vali1800e5:peers300:(…)e 
Dominik scala-torrent Gruber • @the_dom
Peer Wire Protocol 
• Specifies communication with peers 
• TCP 
• Basic format of every messages besides handshake: 
<length prefix><message ID><payload> 
Dominik scala-torrent Gruber • @the_dom
PWP: Handshake 
• <pstrlen><pstr><reserved><info_hash><peer_id> 
• pstr = “BitTorrent protocol” 
• reserved: Eight bytes, used to indicate supported 
extensions 
Dominik scala-torrent Gruber • @the_dom
PWP: Bitfield 
• Sent immediately after handshake (optional) 
• <len=0001+X><id=5><bitfield> 
• X: length of bitfield 
• Bitfield represents the pieces that have successfully 
been downloaded 
Dominik scala-torrent Gruber • @the_dom
PWP: Request 
• <len=0013><id=6><index><begin><length> 
• Request a block of a piece 
• index: Piece number 
• begin / length: Specifies block with the piece 
• Requests can be canceled via the CANCEL message 
Dominik scala-torrent Gruber • @the_dom
PWP: Piece 
• <len=0009+X><id=7><index><begin><block> 
• X: Length of block 
• If a piece has been fully received, it is acknowledged 
via the HAVE message 
Dominik scala-torrent Gruber • @the_dom
PWP: Other Messages 
• keep-alive 
• choke / unchoke 
• interested / uninterested 
Dominik scala-torrent Gruber • @the_dom
scala-torrent 
• Akka/the actor model is a good fit for this project 
• The components can be clearly separated 
• Supervision is needed 
• TCP communication via Akka I/O 
• HTTP communication via spray 
Dominik scala-torrent Gruber • @the_dom
Actors 
Coordinator 
Peer 
ConnePcetioenr 
ConnePcetieorn 
Connection 
Connection 
Handler 
Torrent 
Tracker 
Torrent Tracker 
Incoming 
Connections 
Dominik scala-torrent Gruber • @the_dom
Connection Handler 
object ConnectionHandler { 
case class CreatePeerConnection(peer: PeerInformation) 
case class PeerConnectionCreated(connection: ActorRef, peer: 
PeerInformation) 
} 
class ConnectionHandler(endpoint: InetSocketAddress, internalPeerId: String) 
extends Actor { 
import Tcp._ 
import context.system 
import ConnectionHandler._ 
// Torrent coordinator actor 
val coordinator = context.parent 
// Start listening to incoming connections 
IO(Tcp) ! Tcp.Bind(self, endpoint) 
// (…) 
} 
Dominik scala-torrent Gruber • @the_dom
Connection Handler 
class ConnectionHandler(endpoint: InetSocketAddress, internalPeerId: String) 
extends Actor { 
// (…) 
override def receive = { 
case CommandFailed(_: Bind) => 
// TODO: Handle failure 
case c @ Connected(remoteAddress, _) => 
val handler = createPeerConnectionActor(remoteAddress) 
sender ! Register(handler) 
case CreatePeerConnection(peer) => 
val peerConnection = createPeerConnectionActor(peer.inetSocketAddress) 
sender ! PeerConnectionCreated(peerConnection, peer) 
} 
private def createPeerConnectionActor(remoteAddress: InetSocketAddress) = 
context.actorOf(Props(classOf[PeerConnection], remoteAddress, 
internalPeerId, coordinator), "peer-connection-" + 
remoteAddress.toString.replace("/", "")) 
} 
Dominik scala-torrent Gruber • @the_dom
Peer Connection 
class PeerConnection(remoteAddress: InetSocketAddress, internalPeerId: String, 
coordinator: ActorRef) extends Actor { 
// (…) 
override def receive: Receive = initialStage 
def initialStage: Receive = { 
case AttachToTorrent(t, m) => 
torrent = Some(t) 
metainfo = Some(m) 
case SendHandshake if torrent.isDefined => 
if (connection.isDefined) sendHandshake() 
else { 
IO(Tcp) ! Connect(remoteAddress) 
context become awaitConnectionForHandshake 
} 
case Received(data) => handleHandshakeIn(data) 
case PeerClosed => handlePeerClosed() 
} 
// (…) 
} 
Dominik scala-torrent Gruber • @the_dom
Peer Connection 
class PeerConnection(remoteAddress: InetSocketAddress, internalPeerId: 
String, coordinator: ActorRef) extends Actor { 
// (…) 
def handleHandshakeIn(data: ByteString) = { 
Handshake.unmarshal(data.toVector) match { 
case Some(handshake: Handshake) => 
connection = Some(context.sender()) 
if (torrent.isDefined) context become connected 
else coordinator ! IncomingPeerConnection(self, handshake) 
case None => 
// TODO: Handle failure 
} 
} 
def sendHandshake() = { 
val handshake = Handshake(metainfo.get.info.infoHash, internalPeerId) 
connection.get ! Write(ByteString(handshake.marshal.toArray)) 
} 
} 
Dominik scala-torrent Gruber • @the_dom
Current Status 
• Bencode parsing (and encoding) 
• Communication with tracker 
• Modelling of the PWP messages 
• Handshake with clients 
• TODO: File exchange (= the core) 
Dominik scala-torrent Gruber • @the_dom
Q & A 
Dominik scala-torrent Gruber • @the_dom
Source 
• https://github.com/TheDom/scala-torrent 
• http://www.bittorrent.org/beps/bep_0003.html 
• http://jonas.nitro.dk/bittorrent/bittorrent-rfc.html 
• https://wiki.theory.org/BitTorrentSpecification 
Dominik scala-torrent Gruber • @the_dom

Contenu connexe

Tendances

Learn Terraform on Azure
Learn Terraform on AzureLearn Terraform on Azure
Learn Terraform on Azure
Jorn Jambers
 

Tendances (20)

Kubernetes the Very Hard Way. Lisa Portland 2019
Kubernetes the Very Hard Way. Lisa Portland 2019Kubernetes the Very Hard Way. Lisa Portland 2019
Kubernetes the Very Hard Way. Lisa Portland 2019
 
HotPics 2021
HotPics 2021HotPics 2021
HotPics 2021
 
Socket programming-tutorial-sk
Socket programming-tutorial-skSocket programming-tutorial-sk
Socket programming-tutorial-sk
 
Reusable, composable, battle-tested Terraform modules
Reusable, composable, battle-tested Terraform modulesReusable, composable, battle-tested Terraform modules
Reusable, composable, battle-tested Terraform modules
 
Terraform Best Practices - DevOps Unicorns 2019
Terraform Best Practices - DevOps Unicorns 2019Terraform Best Practices - DevOps Unicorns 2019
Terraform Best Practices - DevOps Unicorns 2019
 
Evolution of kube-proxy (Brussels, Fosdem 2020)
Evolution of kube-proxy (Brussels, Fosdem 2020)Evolution of kube-proxy (Brussels, Fosdem 2020)
Evolution of kube-proxy (Brussels, Fosdem 2020)
 
Network programming in java - PPT
Network programming in java - PPTNetwork programming in java - PPT
Network programming in java - PPT
 
Docker Networking - Current Status and goals of Experimental Networking
Docker Networking - Current Status and goals of Experimental NetworkingDocker Networking - Current Status and goals of Experimental Networking
Docker Networking - Current Status and goals of Experimental Networking
 
Terraform modules and some of best-practices - March 2019
Terraform modules and some of best-practices - March 2019Terraform modules and some of best-practices - March 2019
Terraform modules and some of best-practices - March 2019
 
Kubernetes the Very Hard Way. Velocity Berlin 2019
Kubernetes the Very Hard Way. Velocity Berlin 2019Kubernetes the Very Hard Way. Velocity Berlin 2019
Kubernetes the Very Hard Way. Velocity Berlin 2019
 
Transforming Infrastructure into Code - Importing existing cloud resources u...
Transforming Infrastructure into Code  - Importing existing cloud resources u...Transforming Infrastructure into Code  - Importing existing cloud resources u...
Transforming Infrastructure into Code - Importing existing cloud resources u...
 
Docker networking Tutorial 101
Docker networking Tutorial 101Docker networking Tutorial 101
Docker networking Tutorial 101
 
Java sockets
Java socketsJava sockets
Java sockets
 
Docker networking
Docker networkingDocker networking
Docker networking
 
Infrastructure as Code with Terraform
Infrastructure as Code with TerraformInfrastructure as Code with Terraform
Infrastructure as Code with Terraform
 
10 Networking
10 Networking10 Networking
10 Networking
 
Simplifying open stack and kubernetes networking with romana
Simplifying open stack and kubernetes networking with romanaSimplifying open stack and kubernetes networking with romana
Simplifying open stack and kubernetes networking with romana
 
Learn Terraform on Azure
Learn Terraform on AzureLearn Terraform on Azure
Learn Terraform on Azure
 
Docker in 30 minutes
Docker in 30 minutesDocker in 30 minutes
Docker in 30 minutes
 
Docker Meetup: Docker Networking 1.11, by Madhu Venugopal
Docker Meetup: Docker Networking 1.11, by Madhu VenugopalDocker Meetup: Docker Networking 1.11, by Madhu Venugopal
Docker Meetup: Docker Networking 1.11, by Madhu Venugopal
 

Similaire à 2014-11-26 | Creating a BitTorrent Client with Scala and Akka, Part 1 (Vienna Scala User Group)

Socket programming
Socket programmingSocket programming
Socket programming
Divya Sharma
 

Similaire à 2014-11-26 | Creating a BitTorrent Client with Scala and Akka, Part 1 (Vienna Scala User Group) (20)

6 app-tcp
6 app-tcp6 app-tcp
6 app-tcp
 
Orchestrating Docker with Terraform and Consul by Mitchell Hashimoto
Orchestrating Docker with Terraform and Consul by Mitchell Hashimoto Orchestrating Docker with Terraform and Consul by Mitchell Hashimoto
Orchestrating Docker with Terraform and Consul by Mitchell Hashimoto
 
Openstack meetup lyon_2017-09-28
Openstack meetup lyon_2017-09-28Openstack meetup lyon_2017-09-28
Openstack meetup lyon_2017-09-28
 
Performance & Scalability Improvements in Perforce
Performance & Scalability Improvements in PerforcePerformance & Scalability Improvements in Perforce
Performance & Scalability Improvements in Perforce
 
A22 Introduction to DTrace by Kyle Hailey
A22 Introduction to DTrace by Kyle HaileyA22 Introduction to DTrace by Kyle Hailey
A22 Introduction to DTrace by Kyle Hailey
 
Wieldy remote apis with Kekkonen - ClojureD 2016
Wieldy remote apis with Kekkonen - ClojureD 2016Wieldy remote apis with Kekkonen - ClojureD 2016
Wieldy remote apis with Kekkonen - ClojureD 2016
 
Kafka zero to hero
Kafka zero to heroKafka zero to hero
Kafka zero to hero
 
Apache Kafka - From zero to hero
Apache Kafka - From zero to heroApache Kafka - From zero to hero
Apache Kafka - From zero to hero
 
Socket programming
Socket programmingSocket programming
Socket programming
 
Solaris DTrace, An Introduction
Solaris DTrace, An IntroductionSolaris DTrace, An Introduction
Solaris DTrace, An Introduction
 
Demystifying SharePoint Infrastructure – for NON-IT People
 Demystifying SharePoint Infrastructure – for NON-IT People  Demystifying SharePoint Infrastructure – for NON-IT People
Demystifying SharePoint Infrastructure – for NON-IT People
 
Docker Security Overview
Docker Security OverviewDocker Security Overview
Docker Security Overview
 
Clocker - The Docker Cloud Maker
Clocker - The Docker Cloud MakerClocker - The Docker Cloud Maker
Clocker - The Docker Cloud Maker
 
Clocker: Managing Container Networking and Placement
Clocker: Managing Container Networking and PlacementClocker: Managing Container Networking and Placement
Clocker: Managing Container Networking and Placement
 
Understanding the Node.js Platform
Understanding the Node.js PlatformUnderstanding the Node.js Platform
Understanding the Node.js Platform
 
Why and How to use Onion Networking - #EMFCamp2018
Why and How to use Onion Networking - #EMFCamp2018Why and How to use Onion Networking - #EMFCamp2018
Why and How to use Onion Networking - #EMFCamp2018
 
What is Socket Programming in Python | Edureka
What is Socket Programming in Python | EdurekaWhat is Socket Programming in Python | Edureka
What is Socket Programming in Python | Edureka
 
Kafka practical experience
Kafka practical experienceKafka practical experience
Kafka practical experience
 
Http2 in practice
Http2 in practiceHttp2 in practice
Http2 in practice
 
moscmy2016: Extending Docker
moscmy2016: Extending Dockermoscmy2016: Extending Docker
moscmy2016: Extending Docker
 

Dernier

Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
Joaquim Jorge
 

Dernier (20)

Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
Evaluating the top large language models.pdf
Evaluating the top large language models.pdfEvaluating the top large language models.pdf
Evaluating the top large language models.pdf
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 

2014-11-26 | Creating a BitTorrent Client with Scala and Akka, Part 1 (Vienna Scala User Group)

  • 1. Creating a BitTorrent Client with Scala and Akka Part I Dominik Gruber, @the_dom Scala Vienna User Group – Nov. 26, 2014
  • 2. Agenda • Akka: Brief Introduction • BitTorrent: Basic Procedure • Bencoding • Tracker • Peer Wire Protocol • Software Architecture Dominik scala-torrent Gruber • @the_dom
  • 3. • Actor Model for the JVM • Scala & Java API • Part of the Typesafe Platform • http://akka.io Dominik scala-torrent Gruber • @the_dom
  • 4. • Simple Concurrency & Distribution Asynchronous and Distributed by design. High-level abstractions like Actors, Futures and STM. • Elastic & Decentralized Adaptive load balancing, routing, partitioning and configuration-driven remoting. • Resilient by Design Write systems that self-heal. Remote and/or local supervisor hierarchies. • High Performance 50 million msg/sec on a single machine. Small memory footprint; ~2.5 million actors per GB of heap. Dominik scala-torrent Gruber • @the_dom
  • 6. BitTorrent • Most popular protocol for peer-to-peer file sharing • Designed in 2001 • Est. over 250 million users/month • Currently responsible for 3.35% of all worldwide bandwidth Dominik scala-torrent Gruber • @the_dom
  • 8. Basic Procedure 1. Load information from a metainfo (.torrent) file 2. Request peers from tracker 3. Connect to peers via handshake 4. Exchange data via predefined messages (Peer Wire Protocol) Dominik scala-torrent Gruber • @the_dom
  • 9. Metainfo File • In Bencode format • Includes URL of the tracker, list of files / pieces,… • Info hash has to be calculated from the file to identify the torrent for communication with tracker and peers Dominik scala-torrent Gruber • @the_dom
  • 10. Bencoding • Integers i<integer encoded in base ten ASCII>e e.g. i42e • Strings <string length>:<string data> e.g. 4:spam; 12:scala vienna Dominik scala-torrent Gruber • @the_dom
  • 11. Bencoding • Lists l<bencoded values>e e.g. l5:scala7:torrente • Dictionaries d<bencoded string><bencoded element>e e.g. d5:scalal4:akka4:playe4:java15:enterprise helle Dominik scala-torrent Gruber • @the_dom
  • 12. Example: Ubuntu 14.04.1 d8:announce39:http://torrent.ubuntu.com:6969/ announce13:announce-listll39:http:// torrent.ubuntu.com:6969/announceel44:http:// ipv6.torrent.ubuntu.com:6969/ announceee7:comment29:Ubuntu CD releases.ubuntu.com13:creation datei1406245742e4:infod6:lengthi599785472e4:n ame31:ubuntu-14.04.1-server-amd64.iso12:piece lengthi524288e6:pieces22880:(…) Dominik scala-torrent Gruber • @the_dom
  • 13. Parsing Bencode with Scala • Scala Parser Combinators • Since Scala 2.11 a separate library • Any structured format can be defined and parsed through its custom DSL Dominik scala-torrent Gruber • @the_dom
  • 14. Parsing Bencode with Scala import scala.util.parsing.combinator._ object BencodeParser extends RegexParsers { def integer: Parser[Int] = "i" ~> """(0|-?[1-9]d*)""".r <~ "e" ^^ (_.toInt) // (…) } Dominik scala-torrent Gruber • @the_dom
  • 15. Parsing Bencode with Scala object BencodeParser extends RegexParsers { // (…) def list: Parser[List[Any]] = "l" ~> rep1(bencodeElem) <~ "e" def dictionary: Parser[Map[String,Any]] = "d" ~> rep1(string ~ bencodeElem) <~ "e" ^^ (_.map(x => (x._1, x._2)).toMap) // (…) } Dominik scala-torrent Gruber • @the_dom
  • 16. Parsing Bencode with Scala object BencodeParser extends RegexParsers { // (…) def string: Parser[String] = new Parser[String] { def apply(in: Input) = { val source = in.source val offset = in.offset val start = handleWhiteSpace(source, offset) """(d+):([sS]+)""".r findPrefixMatchOf source.subSequence(start, source.length) match { case Some(matched) => val length = matched.group(1).toInt if (length <= matched.group(2).length) Success( matched.group(2).substring(0, length), in.drop(start + length.toString.length + 1 + length - offset) ) else Failure("Provided length is longer than the remaining input", in.drop(start - offset)) case None => Failure("Input is not a string", in.drop(start - offset)) } } } // (…) } Dominik scala-torrent Gruber • @the_dom
  • 17. Parsing Bencode with Scala object BencodeParser extends RegexParsers { // (…) def bencodeElem = string | integer | list | dictionary def apply(input: String) = parseAll(bencodeElem, input) } Dominik scala-torrent Gruber • @the_dom
  • 18. Tracker • HTTP service which holds information about a torrent • Communication via GET-Request if a transfer is started, stopped, or completed • Responds with a list of peers as a bencoded dictionary • Tracker is a single point of failure -> DHT extension Dominik scala-torrent Gruber • @the_dom
  • 19. Tracker: Example Request http://torrent.ubuntu.com:6969/announce ?event=started &info_hash=-%06l%94H%0A%DC%F5%2B%FD %11%85%A7%5E%B4%DD%C1wvs &peer_id=-SC0001-546306326124 &port=6881 &numwant=50 &downloaded=0 &left=599785472 &uploaded=0 &compact=1 Dominik scala-torrent Gruber • @the_dom
  • 20. Tracker: Example Response d8:completei748e10:incompletei8e8:inter vali1800e5:peers300:(…)e Dominik scala-torrent Gruber • @the_dom
  • 21. Peer Wire Protocol • Specifies communication with peers • TCP • Basic format of every messages besides handshake: <length prefix><message ID><payload> Dominik scala-torrent Gruber • @the_dom
  • 22. PWP: Handshake • <pstrlen><pstr><reserved><info_hash><peer_id> • pstr = “BitTorrent protocol” • reserved: Eight bytes, used to indicate supported extensions Dominik scala-torrent Gruber • @the_dom
  • 23. PWP: Bitfield • Sent immediately after handshake (optional) • <len=0001+X><id=5><bitfield> • X: length of bitfield • Bitfield represents the pieces that have successfully been downloaded Dominik scala-torrent Gruber • @the_dom
  • 24. PWP: Request • <len=0013><id=6><index><begin><length> • Request a block of a piece • index: Piece number • begin / length: Specifies block with the piece • Requests can be canceled via the CANCEL message Dominik scala-torrent Gruber • @the_dom
  • 25. PWP: Piece • <len=0009+X><id=7><index><begin><block> • X: Length of block • If a piece has been fully received, it is acknowledged via the HAVE message Dominik scala-torrent Gruber • @the_dom
  • 26. PWP: Other Messages • keep-alive • choke / unchoke • interested / uninterested Dominik scala-torrent Gruber • @the_dom
  • 27. scala-torrent • Akka/the actor model is a good fit for this project • The components can be clearly separated • Supervision is needed • TCP communication via Akka I/O • HTTP communication via spray Dominik scala-torrent Gruber • @the_dom
  • 28. Actors Coordinator Peer ConnePcetioenr ConnePcetieorn Connection Connection Handler Torrent Tracker Torrent Tracker Incoming Connections Dominik scala-torrent Gruber • @the_dom
  • 29. Connection Handler object ConnectionHandler { case class CreatePeerConnection(peer: PeerInformation) case class PeerConnectionCreated(connection: ActorRef, peer: PeerInformation) } class ConnectionHandler(endpoint: InetSocketAddress, internalPeerId: String) extends Actor { import Tcp._ import context.system import ConnectionHandler._ // Torrent coordinator actor val coordinator = context.parent // Start listening to incoming connections IO(Tcp) ! Tcp.Bind(self, endpoint) // (…) } Dominik scala-torrent Gruber • @the_dom
  • 30. Connection Handler class ConnectionHandler(endpoint: InetSocketAddress, internalPeerId: String) extends Actor { // (…) override def receive = { case CommandFailed(_: Bind) => // TODO: Handle failure case c @ Connected(remoteAddress, _) => val handler = createPeerConnectionActor(remoteAddress) sender ! Register(handler) case CreatePeerConnection(peer) => val peerConnection = createPeerConnectionActor(peer.inetSocketAddress) sender ! PeerConnectionCreated(peerConnection, peer) } private def createPeerConnectionActor(remoteAddress: InetSocketAddress) = context.actorOf(Props(classOf[PeerConnection], remoteAddress, internalPeerId, coordinator), "peer-connection-" + remoteAddress.toString.replace("/", "")) } Dominik scala-torrent Gruber • @the_dom
  • 31. Peer Connection class PeerConnection(remoteAddress: InetSocketAddress, internalPeerId: String, coordinator: ActorRef) extends Actor { // (…) override def receive: Receive = initialStage def initialStage: Receive = { case AttachToTorrent(t, m) => torrent = Some(t) metainfo = Some(m) case SendHandshake if torrent.isDefined => if (connection.isDefined) sendHandshake() else { IO(Tcp) ! Connect(remoteAddress) context become awaitConnectionForHandshake } case Received(data) => handleHandshakeIn(data) case PeerClosed => handlePeerClosed() } // (…) } Dominik scala-torrent Gruber • @the_dom
  • 32. Peer Connection class PeerConnection(remoteAddress: InetSocketAddress, internalPeerId: String, coordinator: ActorRef) extends Actor { // (…) def handleHandshakeIn(data: ByteString) = { Handshake.unmarshal(data.toVector) match { case Some(handshake: Handshake) => connection = Some(context.sender()) if (torrent.isDefined) context become connected else coordinator ! IncomingPeerConnection(self, handshake) case None => // TODO: Handle failure } } def sendHandshake() = { val handshake = Handshake(metainfo.get.info.infoHash, internalPeerId) connection.get ! Write(ByteString(handshake.marshal.toArray)) } } Dominik scala-torrent Gruber • @the_dom
  • 33. Current Status • Bencode parsing (and encoding) • Communication with tracker • Modelling of the PWP messages • Handshake with clients • TODO: File exchange (= the core) Dominik scala-torrent Gruber • @the_dom
  • 34. Q & A Dominik scala-torrent Gruber • @the_dom
  • 35. Source • https://github.com/TheDom/scala-torrent • http://www.bittorrent.org/beps/bep_0003.html • http://jonas.nitro.dk/bittorrent/bittorrent-rfc.html • https://wiki.theory.org/BitTorrentSpecification Dominik scala-torrent Gruber • @the_dom