]> git.rkrishnan.org Git - functorrent.git/commitdiff
Merge branch 'piece-manager'
authorRamakrishnan Muthukrishnan <ram@rkrishnan.org>
Sun, 12 Jul 2015 10:53:54 +0000 (16:23 +0530)
committerRamakrishnan Muthukrishnan <ram@rkrishnan.org>
Sun, 12 Jul 2015 10:53:54 +0000 (16:23 +0530)
README.md
cabal.config [deleted file]
data/ubuntu-14.10-desktop-i386.iso.torrent [new file with mode: 0644]
functorrent.cabal
src/FuncTorrent.hs
src/FuncTorrent/Metainfo.hs
src/FuncTorrent/Peer.hs
src/FuncTorrent/Tracker.hs
src/Main.hs
stack.yaml [new file with mode: 0644]

index 06af0f49bf7ddc02c0f56b6c7a6ef3d066012302..61001971eae1fd0818a427a1b13f886c04466b17 100644 (file)
--- a/README.md
+++ b/README.md
@@ -37,7 +37,7 @@ shell which has all the package dependencies installed.
 - Become more profient with Haskell.
 - Implement something non-trivial with Haskell (crypto, file operations, network
   operations, concurrency, bit twiddling, DHT).
-- Follow the spec - https://wiki.theory.org/BitTorrentSpecification
+- Follow the spec ([official spec](http://bittorrent.org/beps/bep_0003.html), [unofficial spec](https://wiki.theory.org/BitTorrentSpecification))
 - Easy for newbies like me to read and understand along side the spec.
 - doctest and quickcheck tests.
 - Follow Haskell Style Guide - https://github.com/tibbe/haskell-style-guide/blob/master/haskell-style.md
diff --git a/cabal.config b/cabal.config
deleted file mode 100644 (file)
index af9cb28..0000000
+++ /dev/null
@@ -1,1063 +0,0 @@
--- Stackage snapshot from: http://www.stackage.org/snapshot/lts-2.5
--- Please place this file next to your .cabal file as cabal.config
--- To only use tested packages, uncomment the following line:
--- remote-repo: stackage-lts-2.5:http://www.stackage.org/snapshot/lts-2.5
-constraints: abstract-deque ==0.3,
-             abstract-par ==0.3.3,
-             accelerate ==0.15.0.0,
-             ace ==0.6,
-             action-permutations ==0.0.0.1,
-             active ==0.1.0.19,
-             AC-Vector ==2.3.2,
-             ad ==4.2.1.1,
-             adjunctions ==4.2,
-             aeson ==0.8.0.2,
-             aeson-pretty ==0.7.2,
-             aeson-qq ==0.7.4,
-             aeson-utils ==0.3,
-             alarmclock ==0.2.0.5,
-             alex ==3.1.4,
-             amazonka ==0.3.4,
-             amazonka-autoscaling ==0.3.4,
-             amazonka-cloudformation ==0.3.4,
-             amazonka-cloudfront ==0.3.4,
-             amazonka-cloudhsm ==0.3.4,
-             amazonka-cloudsearch ==0.3.4,
-             amazonka-cloudsearch-domains ==0.3.4,
-             amazonka-cloudtrail ==0.3.4,
-             amazonka-cloudwatch ==0.3.4,
-             amazonka-cloudwatch-logs ==0.3.4,
-             amazonka-codedeploy ==0.3.4,
-             amazonka-cognito-identity ==0.3.4,
-             amazonka-cognito-sync ==0.3.4,
-             amazonka-config ==0.3.4,
-             amazonka-core ==0.3.4,
-             amazonka-datapipeline ==0.3.4,
-             amazonka-directconnect ==0.3.4,
-             amazonka-dynamodb ==0.3.4,
-             amazonka-ec2 ==0.3.4,
-             amazonka-ecs ==0.3.4,
-             amazonka-elasticache ==0.3.4,
-             amazonka-elasticbeanstalk ==0.3.4,
-             amazonka-elastictranscoder ==0.3.4,
-             amazonka-elb ==0.3.4,
-             amazonka-emr ==0.3.4,
-             amazonka-glacier ==0.3.4,
-             amazonka-iam ==0.3.4,
-             amazonka-importexport ==0.3.4,
-             amazonka-kinesis ==0.3.4,
-             amazonka-kms ==0.3.4,
-             amazonka-lambda ==0.3.4,
-             amazonka-opsworks ==0.3.4,
-             amazonka-rds ==0.3.4,
-             amazonka-redshift ==0.3.4,
-             amazonka-route53 ==0.3.4,
-             amazonka-route53-domains ==0.3.4,
-             amazonka-s3 ==0.3.4,
-             amazonka-sdb ==0.3.4,
-             amazonka-ses ==0.3.4,
-             amazonka-sns ==0.3.4,
-             amazonka-sqs ==0.3.4,
-             amazonka-ssm ==0.3.4,
-             amazonka-storagegateway ==0.3.4,
-             amazonka-sts ==0.3.4,
-             amazonka-support ==0.3.4,
-             amazonka-swf ==0.3.4,
-             amqp ==0.12.2,
-             ansi-terminal ==0.6.2.1,
-             ansi-wl-pprint ==0.6.7.2,
-             appar ==0.1.4,
-             applicative-quoters ==0.1.0.8,
-             approximate ==0.2.1.1,
-             arbtt ==0.9.0.2,
-             arithmoi ==0.4.1.2,
-             array installed,
-             arrow-list ==0.7,
-             asn1-data ==0.7.1,
-             asn1-encoding ==0.9.0,
-             asn1-parse ==0.9.0,
-             asn1-types ==0.3.0,
-             async ==2.0.2,
-             atto-lisp ==0.2.2,
-             attoparsec ==0.12.1.6,
-             attoparsec-enumerator ==0.3.3,
-             attoparsec-expr ==0.1.1.1,
-             authenticate ==1.3.2.11,
-             authenticate-oauth ==1.5.1.1,
-             auto-update ==0.1.2.1,
-             aws ==0.11.4,
-             bake ==0.2,
-             bank-holidays-england ==0.1.0.2,
-             base installed,
-             base16-bytestring ==0.1.1.6,
-             base64-bytestring ==1.0.0.1,
-             base64-string ==0.2,
-             base-compat ==0.6.0,
-             base-prelude ==0.1.19,
-             base-unicode-symbols ==0.2.2.4,
-             basic-prelude ==0.3.12,
-             bcrypt ==0.0.6,
-             bifunctors ==4.2.1,
-             binary installed,
-             binary-conduit ==1.2.3,
-             binary-list ==1.1.1.0,
-             bindings-DSL ==1.0.22,
-             bin-package-db installed,
-             bioace ==0.0.1,
-             bioalign ==0.0.5,
-             biocore ==0.3.1,
-             biofasta ==0.0.3,
-             biofastq ==0.1,
-             biophd ==0.0.5,
-             biopsl ==0.4,
-             biosff ==0.3.7.1,
-             bits ==0.4,
-             blank-canvas ==0.5,
-             BlastHTTP ==1.0.1,
-             blastxml ==0.3.2,
-             blaze-builder ==0.4.0.1,
-             blaze-builder-enumerator ==0.2.1.0,
-             blaze-html ==0.8.0.2,
-             blaze-markup ==0.7.0.2,
-             blaze-svg ==0.3.4.1,
-             blaze-textual ==0.2.0.9,
-             bloodhound ==0.5.0.1,
-             bmp ==1.2.5.2,
-             Boolean ==0.2.3,
-             boolsimplifier ==0.1.8,
-             bound ==1.0.4,
-             BoundedChan ==1.0.3.0,
-             broadcast-chan ==0.1.0,
-             bson ==0.3.1,
-             bumper ==0.6.0.3,
-             byteable ==0.1.1,
-             bytedump ==1.0,
-             byteorder ==1.0.4,
-             bytes ==0.15,
-             bytestring installed,
-             bytestring-builder ==0.10.6.0.0,
-             bytestring-conversion ==0.3.0,
-             bytestring-lexing ==0.4.3.2,
-             bytestring-mmap ==0.2.2,
-             bytestring-progress ==1.0.5,
-             bytestring-trie ==0.2.4.1,
-             bzlib ==0.5.0.5,
-             bzlib-conduit ==0.2.1.3,
-             c2hs ==0.25.2,
-             Cabal installed,
-             cabal-file-th ==0.2.3,
-             Cabal-ide-backend ==1.23.0.0,
-             cabal-install ==1.18.0.8,
-             cabal-rpm ==0.9.5,
-             cabal-src ==0.2.5,
-             cabal-test-quickcheck ==0.1.4,
-             cairo ==0.13.1.0,
-             cartel ==0.14.2.6,
-             case-insensitive ==1.2.0.4,
-             cases ==0.1.2,
-             cassava ==0.4.2.3,
-             cereal ==0.4.1.1,
-             cereal-conduit ==0.7.2.3,
-             certificate ==1.3.9,
-             charset ==0.3.7.1,
-             Chart ==1.3.3,
-             Chart-diagrams ==1.3.3,
-             ChasingBottoms ==1.3.0.11,
-             check-email ==1.0,
-             checkers ==0.4.2,
-             chell ==0.4.0.1,
-             chell-quickcheck ==0.2.5,
-             chunked-data ==0.1.0.1,
-             cipher-aes ==0.2.10,
-             cipher-aes128 ==0.6.4,
-             cipher-blowfish ==0.0.3,
-             cipher-camellia ==0.0.2,
-             cipher-des ==0.0.6,
-             cipher-rc4 ==0.1.4,
-             circle-packing ==0.1.0.4,
-             classy-prelude ==0.11.1.1,
-             classy-prelude-conduit ==0.11.1,
-             classy-prelude-yesod ==0.11.1,
-             clay ==0.10.1,
-             clientsession ==0.9.1.1,
-             clock ==0.4.5.0,
-             cmdargs ==0.10.12,
-             code-builder ==0.1.3,
-             colour ==2.3.3,
-             comonad ==4.2.5,
-             comonads-fd ==4.0,
-             comonad-transformers ==4.0,
-             compdata ==0.9,
-             compensated ==0.6.1,
-             composition ==1.0.1.0,
-             compressed ==3.10,
-             concatenative ==1.0.1,
-             concurrent-extra ==0.7.0.9,
-             concurrent-supply ==0.1.7.1,
-             cond ==0.4.1.1,
-             conduit ==1.2.4,
-             conduit-combinators ==0.3.1,
-             conduit-extra ==1.1.7.2,
-             configurator ==0.3.0.0,
-             connection ==0.2.4,
-             constraints ==0.4.1.3,
-             consul-haskell ==0.1,
-             containers installed,
-             containers-unicode-symbols ==0.3.1.1,
-             contravariant ==1.3.1,
-             control-monad-free ==0.6.1,
-             control-monad-loop ==0.1,
-             convertible ==1.1.1.0,
-             cookie ==0.4.1.4,
-             courier ==0.1.0.15,
-             cpphs ==1.19,
-             cprng-aes ==0.6.1,
-             cpu ==0.1.2,
-             criterion ==1.1.0.0,
-             crypto-api ==0.13.2,
-             crypto-api-tests ==0.3,
-             cryptocipher ==0.6.2,
-             crypto-cipher-tests ==0.0.11,
-             crypto-cipher-types ==0.0.9,
-             cryptohash ==0.11.6,
-             cryptohash-conduit ==0.1.1,
-             cryptohash-cryptoapi ==0.1.3,
-             cryptol ==2.2.2,
-             crypto-numbers ==0.2.7,
-             crypto-pubkey ==0.2.8,
-             crypto-pubkey-types ==0.4.3,
-             crypto-random ==0.0.9,
-             crypto-random-api ==0.2.0,
-             css-text ==0.1.2.1,
-             csv ==0.1.2,
-             csv-conduit ==0.6.6,
-             cubicspline ==0.1.1,
-             curl ==1.3.8,
-             data-accessor ==0.2.2.6,
-             data-accessor-mtl ==0.2.0.4,
-             data-binary-ieee754 ==0.4.4,
-             data-default ==0.5.3,
-             data-default-class ==0.0.1,
-             data-default-instances-base ==0.0.1,
-             data-default-instances-containers ==0.0.1,
-             data-default-instances-dlist ==0.0.1,
-             data-default-instances-old-locale ==0.0.1,
-             data-inttrie ==0.1.0,
-             data-lens-light ==0.1.2.1,
-             data-memocombinators ==0.5.1,
-             data-reify ==0.6,
-             DAV ==1.0.5,
-             Decimal ==0.4.2,
-             deepseq installed,
-             deepseq-generics ==0.1.1.2,
-             derive ==2.5.22,
-             descriptive ==0.9.3,
-             diagrams ==1.2,
-             diagrams-cairo ==1.2.0.7,
-             diagrams-canvas ==0.3.0.4,
-             diagrams-contrib ==1.1.2.6,
-             diagrams-core ==1.2.0.6,
-             diagrams-lib ==1.2.0.9,
-             diagrams-postscript ==1.1.0.5,
-             diagrams-rasterific ==0.1.0.8,
-             diagrams-svg ==1.1.0.5,
-             Diff ==0.3.1,
-             digest ==0.0.1.2,
-             digestive-functors ==0.7.1.5,
-             dimensional ==0.13.0.2,
-             directory installed,
-             directory-tree ==0.12.0,
-             direct-sqlite ==2.3.15,
-             distributed-process ==0.5.3,
-             distributed-process-async ==0.2.1,
-             distributed-process-client-server ==0.1.2,
-             distributed-process-execution ==0.1.1,
-             distributed-process-extras ==0.2.0,
-             distributed-process-simplelocalnet ==0.2.2.0,
-             distributed-process-supervisor ==0.1.2,
-             distributed-process-task ==0.1.1,
-             distributed-static ==0.3.1.0,
-             distributive ==0.4.4,
-             djinn-ghc ==0.0.2.3,
-             djinn-lib ==0.0.1.2,
-             dlist ==0.7.1.1,
-             dlist-instances ==0.1,
-             doctest ==0.9.13,
-             double-conversion ==2.0.1.0,
-             DRBG ==0.5.4,
-             dual-tree ==0.2.0.6,
-             easy-file ==0.2.0,
-             ede ==0.2.8.2,
-             edit-distance ==0.2.1.2,
-             effect-handlers ==0.1.0.6,
-             either ==4.3.3.2,
-             elm-core-sources ==1.0.0,
-             email-validate ==2.0.1,
-             enclosed-exceptions ==1.0.1.1,
-             entropy ==0.3.6,
-             enumerator ==0.4.20,
-             eq ==4.0.3,
-             erf ==2.0.0.0,
-             errorcall-eq-instance ==0.2.0.1,
-             errors ==1.4.7,
-             ersatz ==0.3,
-             esqueleto ==2.1.3,
-             exception-mtl ==0.3.0.5,
-             exceptions ==0.8.0.2,
-             exception-transformers ==0.3.0.4,
-             executable-hash ==0.2.0.0,
-             executable-path ==0.0.3,
-             extensible-exceptions ==0.1.1.4,
-             extra ==1.1,
-             fast-logger ==2.3.1,
-             fay ==0.23.1.4,
-             fay-base ==0.20.0.0,
-             fay-builder ==0.2.0.5,
-             fay-dom ==0.5.0.1,
-             fay-jquery ==0.6.0.3,
-             fay-text ==0.3.2.2,
-             fay-uri ==0.2.0.0,
-             fb ==1.0.9,
-             fb-persistent ==0.3.4,
-             fclabels ==2.0.2.2,
-             FenwickTree ==0.1.2.1,
-             fgl ==5.5.1.0,
-             file-embed ==0.0.8.2,
-             file-location ==0.4.7.1,
-             filemanip ==0.3.6.3,
-             filepath installed,
-             fingertree ==0.1.0.2,
-             fixed ==0.2.1.1,
-             fixed-list ==0.1.5,
-             fixed-vector ==0.7.0.3,
-             flexible-defaults ==0.0.1.1,
-             flock ==0.3.1.8,
-             fmlist ==0.9,
-             focus ==0.1.4,
-             foldl ==1.0.9,
-             FontyFruity ==0.5.1.1,
-             force-layout ==0.3.0.11,
-             foreign-store ==0.2,
-             formatting ==6.2.0,
-             free ==4.11,
-             freenect ==1.2,
-             frisby ==0.2,
-             fsnotify ==0.1.0.3,
-             fuzzcheck ==0.1.1,
-             gd ==3000.7.3,
-             generic-aeson ==0.2.0.4,
-             generic-deriving ==1.6.3,
-             GenericPretty ==1.2.1,
-             generics-sop ==0.1.1.2,
-             generic-xmlpickler ==0.1.0.0,
-             ghc installed,
-             ghc-heap-view ==0.5.3,
-             ghcid ==0.3.6,
-             ghc-mod ==5.2.1.2,
-             ghc-mtl ==1.2.1.0,
-             ghc-paths ==0.1.0.9,
-             ghc-prim installed,
-             ghc-syb-utils ==0.2.3,
-             gio ==0.13.1.0,
-             gipeda ==0.1.0.2,
-             git-embed ==0.1.0,
-             gitlib ==3.1.0.1,
-             gitlib-libgit2 ==3.1.0.3,
-             gitlib-test ==3.1.0.2,
-             gitrev ==1.0.0,
-             gitson ==0.5.1,
-             gl ==0.7.5,
-             glib ==0.13.1.0,
-             Glob ==0.7.5,
-             GLURaw ==1.5.0.0,
-             GLUT ==2.7.0.0,
-             graph-core ==0.2.2.0,
-             graphs ==0.6.0.1,
-             GraphSCC ==1.0.4,
-             graphviz ==2999.17.0.2,
-             gravatar ==0.8.0,
-             groundhog ==0.7.0.3,
-             groundhog-mysql ==0.7.0.1,
-             groundhog-postgresql ==0.7.0.2,
-             groundhog-sqlite ==0.7.0.1,
-             groundhog-th ==0.7.0,
-             groupoids ==4.0,
-             groups ==0.4.0.0,
-             gtk ==0.13.6,
-             gtk2hs-buildtools ==0.13.0.3,
-             gtk3 ==0.13.6,
-             hackage-mirror ==0.1.0.0,
-             haddock-api ==2.15.0.2,
-             haddock-library ==1.1.1,
-             hakyll ==4.6.8.1,
-             half ==0.2.0.1,
-             HandsomeSoup ==0.3.5,
-             happstack-server ==7.4.2,
-             happy ==1.19.5,
-             hashable ==1.2.3.2,
-             hashable-extras ==0.2.0.1,
-             hashmap ==1.3.0.1,
-             hashtables ==1.2.0.2,
-             haskeline installed,
-             haskell2010 installed,
-             haskell98 installed,
-             haskell-lexer ==1.0,
-             haskell-names ==0.5.2,
-             HaskellNet ==0.4.4,
-             haskell-packages ==0.2.4.4,
-             haskell-src ==1.0.2.0,
-             haskell-src-exts ==1.16.0.1,
-             haskell-src-meta ==0.6.0.9,
-             haskintex ==0.5.0.3,
-             hasql ==0.7.3,
-             hasql-backend ==0.4.1,
-             hasql-postgres ==0.10.3,
-             hastache ==0.6.1,
-             HaTeX ==3.16.1.1,
-             HaXml ==1.25.3,
-             haxr ==3000.10.4.2,
-             HCodecs ==0.5,
-             hdaemonize ==0.5.0.0,
-             hdevtools ==0.1.0.8,
-             hdocs ==0.4.1.3,
-             heap ==1.0.2,
-             heaps ==0.3.2.1,
-             hebrew-time ==0.1.1,
-             heist ==0.14.1,
-             here ==1.2.7,
-             heredoc ==0.2.0.0,
-             hexpat ==0.20.9,
-             hflags ==0.4,
-             highlighting-kate ==0.5.12,
-             hindent ==4.4.2,
-             hinotify ==0.3.7,
-             hint ==0.4.2.2,
-             histogram-fill ==0.8.4.1,
-             hit ==0.6.3,
-             hjsmin ==0.1.4.7,
-             hledger ==0.24.1,
-             hledger-lib ==0.24.1,
-             hledger-web ==0.24.1,
-             hlibgit2 ==0.18.0.14,
-             hlint ==1.9.20,
-             hmatrix ==0.16.1.5,
-             hmatrix-gsl ==0.16.0.3,
-             hmatrix-gsl-stats ==0.2.1,
-             hmatrix-repa ==0.1.2.1,
-             hoauth2 ==0.4.7,
-             holy-project ==0.1.1.1,
-             hoogle ==4.2.40,
-             hoopl installed,
-             hOpenPGP ==2.0,
-             hopenpgp-tools ==0.14.1,
-             hostname ==1.0,
-             hostname-validate ==1.0.0,
-             hourglass ==0.2.9,
-             hpc installed,
-             hpc-coveralls ==0.9.0,
-             hPDB ==1.2.0.2,
-             hPDB-examples ==1.2.0.1,
-             hs-bibutils ==5.5,
-             hscolour ==1.22,
-             hsdev ==0.1.3.4,
-             hse-cpp ==0.1,
-             hsignal ==0.2.7,
-             hslogger ==1.2.8,
-             hslua ==0.3.13,
-             HsOpenSSL ==0.11.1.1,
-             hspec ==2.1.6,
-             hspec-attoparsec ==0.1.0.2,
-             hspec-core ==2.1.6,
-             hspec-discover ==2.1.6,
-             hspec-expectations ==0.6.1.1,
-             hspec-meta ==2.1.5,
-             hspec-smallcheck ==0.3.0,
-             hspec-wai ==0.6.3,
-             hspec-wai-json ==0.6.0,
-             hstatistics ==0.2.5.2,
-             HStringTemplate ==0.8.3,
-             hsyslog ==2.0,
-             HTF ==0.12.2.4,
-             html ==1.0.1.2,
-             html-conduit ==1.1.1.2,
-             HTTP ==4000.2.19,
-             http-client ==0.4.11.1,
-             http-client-openssl ==0.2.0.1,
-             http-client-tls ==0.2.2,
-             http-conduit ==2.1.5,
-             http-date ==0.0.6,
-             http-media ==0.6.1,
-             http-reverse-proxy ==0.4.1.2,
-             http-types ==0.8.6,
-             HUnit ==1.2.5.2,
-             hweblib ==0.6.3,
-             hxt ==9.3.1.15,
-             hxt-charproperties ==9.2.0.1,
-             hxt-curl ==9.1.1.1,
-             hxt-expat ==9.1.1,
-             hxt-http ==9.1.5.2,
-             hxt-pickle-utils ==0.1.0.3,
-             hxt-regex-xmlschema ==9.2.0.2,
-             hxt-relaxng ==9.1.5.5,
-             hxt-tagsoup ==9.1.3,
-             hxt-unicode ==9.0.2.4,
-             hybrid-vectors ==0.1.2.1,
-             hyphenation ==0.4.2.1,
-             iconv ==0.4.1.2,
-             ide-backend ==0.9.0.7,
-             ide-backend-common ==0.9.1,
-             ide-backend-rts ==0.1.3.1,
-             idna ==0.3.0,
-             ieee754 ==0.7.6,
-             IfElse ==0.85,
-             imagesize-conduit ==1.1,
-             immortal ==0.2,
-             include-file ==0.1.0.2,
-             incremental-parser ==0.2.3.4,
-             indents ==0.3.3,
-             ini ==0.3.1,
-             integer-gmp installed,
-             integration ==0.2.1,
-             interpolate ==0.1.0,
-             interpolatedstring-perl6 ==0.9.0,
-             intervals ==0.7.1,
-             io-choice ==0.0.5,
-             io-manager ==0.1.0.2,
-             io-memoize ==1.1.1.0,
-             iproute ==1.3.2,
-             iterable ==3.0,
-             ixset ==1.0.6,
-             jmacro ==0.6.11,
-             jmacro-rpc ==0.3,
-             jmacro-rpc-happstack ==0.3.1,
-             jmacro-rpc-snap ==0.3,
-             jose-jwt ==0.4.2,
-             js-flot ==0.8.3,
-             js-jquery ==1.11.2,
-             json ==0.9.1,
-             json-autotype ==0.2.5.13,
-             json-schema ==0.7.3.4,
-             JuicyPixels ==3.2.4,
-             JuicyPixels-repa ==0.7,
-             kan-extensions ==4.2.1,
-             kansas-comet ==0.3.1,
-             kdt ==0.2.3,
-             keter ==1.3.9.2,
-             keys ==3.10.1,
-             kmeans ==0.1.3,
-             koofr-client ==1.0.0.3,
-             kure ==2.16.10,
-             language-c ==0.4.7,
-             language-c-quote ==0.10.2.1,
-             language-ecmascript ==0.17,
-             language-glsl ==0.1.1,
-             language-haskell-extract ==0.2.4,
-             language-java ==0.2.7,
-             language-javascript ==0.5.13.3,
-             lattices ==1.2.1.1,
-             lazy-csv ==0.5,
-             lca ==0.3,
-             lens ==4.7.0.1,
-             lens-action ==0.1.0.1,
-             lens-aeson ==1.0.0.3,
-             lens-family-core ==1.2.0,
-             lens-family-th ==0.4.1.0,
-             lhs2tex ==1.19,
-             libgit ==0.3.0,
-             libnotify ==0.1.1.0,
-             lifted-async ==0.7.0,
-             lifted-base ==0.2.3.6,
-             linear ==1.18.0.1,
-             linear-accelerate ==0.2,
-             List ==0.5.2,
-             ListLike ==4.2.0,
-             list-t ==0.4.5.1,
-             loch-th ==0.2.1,
-             log-domain ==0.10.0.1,
-             logict ==0.6.0.2,
-             loop ==0.2.0,
-             lrucache ==1.2.0.0,
-             lucid ==2.9.2,
-             lucid-svg ==0.4.0.4,
-             lzma-conduit ==1.1.3,
-             machines ==0.4.1,
-             machines-directory ==0.2.0.0,
-             machines-io ==0.2.0.0,
-             machines-process ==0.2.0.0,
-             mainland-pretty ==0.2.7.2,
-             managed ==1.0.0,
-             mandrill ==0.2.1.0,
-             map-syntax ==0.2,
-             markdown ==0.1.13.1,
-             markdown-unlit ==0.2.0.1,
-             math-functions ==0.1.5.2,
-             matrix ==0.3.4.3,
-             maximal-cliques ==0.1.1,
-             MaybeT ==0.1.2,
-             mbox ==0.3.1,
-             MemoTrie ==0.6.2,
-             mersenne-random-pure64 ==0.2.0.4,
-             messagepack ==0.3.0,
-             messagepack-rpc ==0.1.0.3,
-             MFlow ==0.4.5.9,
-             mime-mail ==0.4.8.2,
-             mime-mail-ses ==0.3.2.2,
-             mime-types ==0.1.0.6,
-             missing-foreign ==0.1.1,
-             MissingH ==1.3.0.1,
-             mmap ==0.5.9,
-             mmorph ==1.0.4,
-             MonadCatchIO-transformers ==0.3.1.3,
-             monad-control ==1.0.0.4,
-             monad-coroutine ==0.9.0.1,
-             monadcryptorandom ==0.6.1,
-             monadic-arrays ==0.2.1.4,
-             monad-journal ==0.7,
-             monadLib ==3.7.3,
-             monadloc ==0.7.1,
-             monad-logger ==0.3.13.1,
-             monad-logger-json ==0.1.0.0,
-             monad-logger-syslog ==0.1.1.1,
-             monad-loops ==0.4.2.1,
-             monad-par ==0.3.4.7,
-             monad-parallel ==0.7.1.4,
-             monad-par-extras ==0.3.3,
-             monad-primitive ==0.1,
-             monad-products ==4.0.0.1,
-             MonadPrompt ==1.0.0.5,
-             MonadRandom ==0.3.0.2,
-             monad-st ==0.2.4,
-             monads-tf ==0.1.0.2,
-             mongoDB ==2.0.4,
-             monoid-extras ==0.3.3.5,
-             monoid-subclasses ==0.4.0.4,
-             mono-traversable ==0.9.1,
-             mtl ==2.1.3.1,
-             mtl-compat ==0.2.1.3,
-             mtlparse ==0.1.4.0,
-             mtl-prelude ==1.0.3,
-             multiarg ==0.30.0.8,
-             multimap ==1.2.1,
-             multipart ==0.1.2,
-             MusicBrainz ==0.2.3,
-             mutable-containers ==0.3.0,
-             mwc-random ==0.13.3.2,
-             mysql ==0.1.1.8,
-             mysql-simple ==0.2.2.5,
-             nanospec ==0.2.0,
-             nats ==1,
-             neat-interpolation ==0.2.2,
-             nettle ==0.1.0,
-             network ==2.6.0.2,
-             network-anonymous-i2p ==0.10.0,
-             network-attoparsec ==0.12.2,
-             network-conduit ==1.1.0,
-             network-conduit-tls ==1.1.2,
-             network-info ==0.2.0.5,
-             network-multicast ==0.0.11,
-             network-simple ==0.4.0.4,
-             network-transport ==0.4.1.0,
-             network-transport-tcp ==0.4.1,
-             network-transport-tests ==0.2.2.0,
-             network-uri ==2.6.0.1,
-             newtype ==0.2,
-             nsis ==0.2.5,
-             numbers ==3000.2.0.1,
-             numeric-extras ==0.0.3,
-             NumInstances ==1.4,
-             numtype ==1.1,
-             ObjectName ==1.1.0.0,
-             Octree ==0.5.4.2,
-             old-locale installed,
-             old-time installed,
-             OneTuple ==0.2.1,
-             opaleye ==0.3.1.2,
-             OpenGL ==2.12.0.0,
-             OpenGLRaw ==2.4.1.0,
-             openpgp-asciiarmor ==0.1,
-             operational ==0.2.3.2,
-             options ==1.2.1.1,
-             optparse-applicative ==0.11.0.2,
-             osdkeys ==0.0,
-             pagerduty ==0.0.3,
-             palette ==0.1.0.2,
-             pandoc ==1.13.2.1,
-             pandoc-citeproc ==0.6.0.1,
-             pandoc-types ==1.12.4.2,
-             pango ==0.13.1.0,
-             parallel ==3.2.0.6,
-             parallel-io ==0.3.3,
-             parseargs ==0.1.5.2,
-             parsec ==3.1.9,
-             parsers ==0.12.1.1,
-             partial-handler ==0.1.1,
-             path-pieces ==0.2.0,
-             patience ==0.1.1,
-             pcre-heavy ==0.2.2,
-             pcre-light ==0.4.0.3,
-             pdfinfo ==1.5.4,
-             pem ==0.2.2,
-             persistent ==2.1.3,
-             persistent-mongoDB ==2.1.2.1,
-             persistent-mysql ==2.1.3,
-             persistent-postgresql ==2.1.4,
-             persistent-sqlite ==2.1.4.1,
-             persistent-template ==2.1.3,
-             phantom-state ==0.2.0.2,
-             picoparsec ==0.1.2.1,
-             pipes ==4.1.5,
-             pipes-aeson ==0.4.1.2,
-             pipes-attoparsec ==0.5.1.1,
-             pipes-binary ==0.4.0.4,
-             pipes-bytestring ==2.1.1,
-             pipes-concurrency ==2.0.3,
-             pipes-group ==1.0.2,
-             pipes-network ==0.6.4,
-             pipes-parse ==3.0.2,
-             pipes-safe ==2.2.2,
-             placeholders ==0.1,
-             plot ==0.2.3.4,
-             plot-gtk ==0.2.0.2,
-             plot-gtk3 ==0.1,
-             pointed ==4.2,
-             polyparse ==1.11,
-             postgresql-binary ==0.5.2,
-             postgresql-libpq ==0.9.0.2,
-             postgresql-simple ==0.4.10.0,
-             post-mess-age ==0.1.0.0,
-             prednote ==0.32.0.6,
-             prefix-units ==0.1.0.2,
-             prelude-extras ==0.4,
-             presburger ==1.3.1,
-             present ==2.2,
-             pretty installed,
-             prettyclass ==1.0.0.0,
-             pretty-class ==1.0.1.1,
-             pretty-show ==1.6.8.2,
-             primes ==0.2.1.0,
-             primitive ==0.6,
-             process installed,
-             process-extras ==0.3.3.4,
-             product-profunctors ==0.6.1,
-             profunctor-extras ==4.0,
-             profunctors ==4.4.1,
-             project-template ==0.1.4.2,
-             PSQueue ==1.1,
-             publicsuffixlist ==0.1,
-             punycode ==2.0,
-             pure-io ==0.2.1,
-             pureMD5 ==2.1.2.1,
-             pwstore-fast ==2.4.4,
-             quandl-api ==0.2.0.0,
-             QuasiText ==0.1.2.5,
-             QuickCheck ==2.7.6,
-             quickcheck-assertions ==0.2.0,
-             quickcheck-instances ==0.3.11,
-             quickcheck-io ==0.1.1,
-             quickcheck-unicode ==1.0.0.1,
-             rainbow ==0.22.0.2,
-             random ==1.1,
-             random-fu ==0.2.6.2,
-             random-shuffle ==0.0.4,
-             random-source ==0.3.0.6,
-             rank1dynamic ==0.2.0.1,
-             Rasterific ==0.5.2.1,
-             rasterific-svg ==0.1.0.3,
-             raw-strings-qq ==1.0.2,
-             ReadArgs ==1.2.2,
-             reducers ==3.10.3.1,
-             reflection ==1.5.1.2,
-             RefSerialize ==0.3.1.4,
-             regex-applicative ==0.3.1,
-             regex-base ==0.93.2,
-             regex-compat ==0.95.1,
-             regex-pcre-builtin ==0.94.4.8.8.35,
-             regex-posix ==0.95.2,
-             regexpr ==0.5.4,
-             regex-tdfa ==1.2.0,
-             regex-tdfa-rc ==1.1.8.3,
-             regular ==0.3.4.4,
-             regular-xmlpickler ==0.2,
-             rematch ==0.2.0.0,
-             repa ==3.3.1.2,
-             repa-algorithms ==3.3.1.2,
-             repa-devil ==0.3.2.6,
-             repa-io ==3.3.1.2,
-             reroute ==0.2.3.0,
-             resource-pool ==0.2.3.2,
-             resourcet ==1.1.4.1,
-             rest-client ==0.5.0.2,
-             rest-core ==0.35.1,
-             rest-gen ==0.17.0.3,
-             rest-happstack ==0.2.10.7,
-             rest-snap ==0.1.17.17,
-             rest-stringmap ==0.2.0.4,
-             rest-types ==1.13.1,
-             rest-wai ==0.1.0.7,
-             rethinkdb-client-driver ==0.0.16,
-             retry ==0.6,
-             rev-state ==0.1,
-             rfc5051 ==0.1.0.3,
-             RSA ==2.1.0.1,
-             rts installed,
-             runmemo ==1.0.0.1,
-             rvar ==0.2.0.2,
-             safe ==0.3.8,
-             safecopy ==0.8.5,
-             sbv ==4.2,
-             scientific ==0.3.3.8,
-             scotty ==0.9.1,
-             scrobble ==0.2.1.1,
-             sdl2 ==1.3.0,
-             securemem ==0.1.7,
-             semigroupoid-extras ==4.0,
-             semigroupoids ==4.3,
-             semigroups ==0.16.2.2,
-             semver ==0.3.3.1,
-             sendfile ==0.7.9,
-             seqloc ==0.6.1.1,
-             servant ==0.2.2,
-             servant-client ==0.2.2,
-             servant-docs ==0.3.1,
-             servant-jquery ==0.2.2.1,
-             servant-server ==0.2.4,
-             setenv ==0.1.1.3,
-             set-monad ==0.2.0.0,
-             SHA ==1.6.4.2,
-             shake ==0.15.1,
-             shake-language-c ==0.6.4,
-             shakespeare ==2.0.4.1,
-             shakespeare-text ==1.1.0,
-             shell-conduit ==4.5.2,
-             shelltestrunner ==1.3.5,
-             shelly ==1.6.1.2,
-             silently ==1.2.4.1,
-             simple-reflect ==0.3.2,
-             simple-sendfile ==0.2.18,
-             singletons ==1.1.1,
-             siphash ==1.0.3,
-             skein ==1.0.9.3,
-             slave-thread ==0.1.6,
-             smallcheck ==1.1.1,
-             smoothie ==0.1.3,
-             smtLib ==1.0.7,
-             snap ==0.14.0.2,
-             snap-core ==0.9.7.0,
-             snaplet-fay ==0.3.3.11,
-             snap-server ==0.9.5.0,
-             snowflake ==0.1.1.1,
-             soap ==0.2.2.5,
-             soap-openssl ==0.1.0.2,
-             soap-tls ==0.1.1.2,
-             socks ==0.5.4,
-             sodium ==0.11.0.3,
-             sourcemap ==0.1.3.0,
-             speculation ==1.5.0.2,
-             sphinx ==0.6.0.1,
-             split ==0.2.2,
-             Spock ==0.7.9.0,
-             Spock-digestive ==0.1.0.0,
-             Spock-worker ==0.2.1.3,
-             spoon ==0.3.1,
-             sqlite-simple ==0.4.8.0,
-             srcloc ==0.4.1,
-             stackage ==0.6.0.1,
-             stackage-curator ==0.7.4,
-             stackage-types ==1.0.0,
-             stateref ==0.3,
-             statestack ==0.2.0.4,
-             StateVar ==1.1.0.0,
-             statistics ==0.13.2.3,
-             statistics-linreg ==0.3,
-             stm ==2.4.4,
-             stm-chans ==3.0.0.3,
-             stm-conduit ==2.5.4,
-             stm-containers ==0.2.9,
-             stm-stats ==0.2.0.0,
-             storable-complex ==0.2.2,
-             storable-endian ==0.2.5,
-             streaming-commons ==0.1.12,
-             streams ==3.2,
-             strict ==0.3.2,
-             stringable ==0.1.3,
-             stringbuilder ==0.5.0,
-             string-conversions ==0.3.0.3,
-             stringprep ==1.0.0,
-             stringsearch ==0.3.6.6,
-             stylish-haskell ==0.5.13.0,
-             SVGFonts ==1.4.0.3,
-             svg-tree ==0.1.1,
-             syb ==0.4.4,
-             syb-with-class ==0.6.1.5,
-             symbol ==0.2.4,
-             system-canonicalpath ==0.3.2.0,
-             system-fileio ==0.3.16.2,
-             system-filepath ==0.4.13.3,
-             system-posix-redirect ==1.1.0.1,
-             tabular ==0.2.2.7,
-             tagged ==0.7.3,
-             tagshare ==0.0,
-             tagsoup ==0.13.3,
-             tagstream-conduit ==0.5.5.3,
-             tar ==0.4.1.0,
-             tardis ==0.3.0.0,
-             tasty ==0.10.1.1,
-             tasty-ant-xml ==1.0.1,
-             tasty-golden ==2.3.0.1,
-             tasty-hunit ==0.9.2,
-             tasty-kat ==0.0.3,
-             tasty-quickcheck ==0.8.3.2,
-             tasty-smallcheck ==0.8.0.1,
-             tasty-th ==0.1.3,
-             TCache ==0.12.0,
-             template-haskell installed,
-             temporary ==1.2.0.3,
-             temporary-rc ==1.2.0.3,
-             terminal-progress-bar ==0.0.1.4,
-             terminal-size ==0.3.0,
-             terminfo installed,
-             test-framework ==0.8.1.1,
-             test-framework-hunit ==0.3.0.1,
-             test-framework-quickcheck2 ==0.3.0.3,
-             test-framework-th ==0.2.4,
-             testing-feat ==0.4.0.2,
-             testpack ==2.1.3.0,
-             texmath ==0.8.1,
-             text ==1.2.0.4,
-             text-binary ==0.1.0,
-             text-format ==0.3.1.1,
-             text-icu ==0.7.0.1,
-             text-manipulate ==0.1.3.1,
-             tf-random ==0.5,
-             th-desugar ==1.5.3,
-             th-expand-syns ==0.3.0.6,
-             th-extras ==0.0.0.2,
-             th-lift ==0.7.2,
-             th-orphans ==0.11.1,
-             threads ==0.5.1.3,
-             th-reify-many ==0.1.3,
-             thyme ==0.3.5.5,
-             time installed,
-             time-compat ==0.1.0.3,
-             time-lens ==0.4.0.1,
-             time-locale-compat ==0.1.0.1,
-             timezone-olson ==0.1.6,
-             timezone-series ==0.1.4,
-             tls ==1.2.17,
-             tls-debug ==0.3.4,
-             tostring ==0.2.1.1,
-             transformers installed,
-             transformers-base ==0.4.4,
-             transformers-compat ==0.4.0.3,
-             traverse-with-class ==0.2.0.3,
-             tree-view ==0.4,
-             trifecta ==1.5.1.3,
-             tttool ==1.3,
-             tuple ==0.3.0.2,
-             turtle ==1.0.2,
-             type-eq ==0.5,
-             type-list ==0.0.0.1,
-             udbus ==0.2.1,
-             unbounded-delays ==0.1.0.9,
-             unbound-generics ==0.1,
-             union-find ==0.2,
-             uniplate ==1.6.12,
-             unix installed,
-             unix-compat ==0.4.1.4,
-             unix-time ==0.3.5,
-             unordered-containers ==0.2.5.1,
-             uri-encode ==1.5.0.4,
-             url ==2.1.3,
-             users ==0.1.0.0,
-             users-postgresql-simple ==0.1.0.1,
-             users-test ==0.1.0.0,
-             utf8-light ==0.4.2,
-             utf8-string ==1,
-             uuid ==1.3.10,
-             uuid-types ==1.0.1,
-             vault ==0.3.0.4,
-             vector ==0.10.12.3,
-             vector-algorithms ==0.6.0.4,
-             vector-binary-instances ==0.2.1.0,
-             vector-buffer ==0.4.1,
-             vector-instances ==3.3.0.1,
-             vector-space ==0.9,
-             vector-space-points ==0.2.1.1,
-             vector-th-unbox ==0.2.1.2,
-             vhd ==0.2.2,
-             void ==0.7,
-             wai ==3.0.2.3,
-             wai-app-static ==3.0.1,
-             wai-conduit ==3.0.0.2,
-             wai-eventsource ==3.0.0,
-             wai-extra ==3.0.7.1,
-             wai-handler-launch ==3.0.0.3,
-             wai-logger ==2.2.4,
-             wai-middleware-consul ==0.1.0.2,
-             wai-middleware-static ==0.6.0.1,
-             waitra ==0.0.3.0,
-             wai-websockets ==3.0.0.5,
-             warp ==3.0.12.1,
-             warp-tls ==3.0.3,
-             webdriver ==0.6.1,
-             web-fpco ==0.1.1.0,
-             websockets ==0.9.3.1,
-             wizards ==1.0.2,
-             wl-pprint ==1.1,
-             wl-pprint-extras ==3.5.0.4,
-             wl-pprint-terminfo ==3.7.1.3,
-             wl-pprint-text ==1.1.0.4,
-             word8 ==0.1.2,
-             wordpass ==1.0.0.3,
-             Workflow ==0.8.1,
-             wrap ==0.0.0,
-             wreq ==0.3.0.1,
-             X11 ==1.6.1.2,
-             x509 ==1.5.0.1,
-             x509-store ==1.5.0,
-             x509-system ==1.5.0,
-             x509-validation ==1.5.1,
-             xenstore ==0.1.1,
-             xhtml installed,
-             xml ==1.3.14,
-             xml-conduit ==1.2.4,
-             xml-conduit-writer ==0.1.1.1,
-             xmlgen ==0.6.2.1,
-             xml-hamlet ==0.4.0.10,
-             xmlhtml ==0.2.3.4,
-             xml-to-json ==2.0.1,
-             xml-to-json-fast ==2.0.0,
-             xml-types ==0.3.4,
-             xss-sanitize ==0.3.5.5,
-             yackage ==0.7.0.7,
-             yaml ==0.8.11,
-             Yampa ==0.9.6.1,
-             YampaSynth ==0.2,
-             yarr ==1.3.3.3,
-             yesod ==1.4.1.5,
-             yesod-auth ==1.4.4,
-             yesod-auth-deskcom ==1.4.0,
-             yesod-auth-fb ==1.6.6,
-             yesod-auth-hashdb ==1.4.2.1,
-             yesod-auth-oauth ==1.4.0.1,
-             yesod-auth-oauth2 ==0.0.12,
-             yesod-bin ==1.4.7.1,
-             yesod-core ==1.4.9.1,
-             yesod-eventsource ==1.4.0.1,
-             yesod-fay ==0.7.1,
-             yesod-fb ==0.3.4,
-             yesod-form ==1.4.4.1,
-             yesod-gitrepo ==0.1.1.0,
-             yesod-newsfeed ==1.4.0.1,
-             yesod-persistent ==1.4.0.2,
-             yesod-sitemap ==1.4.0.1,
-             yesod-static ==1.4.0.4,
-             yesod-test ==1.4.3.1,
-             yesod-text-markdown ==0.1.7,
-             yesod-websockets ==0.2.1.1,
-             zeromq4-haskell ==0.6.3,
-             zip-archive ==0.2.3.7,
-             zlib ==0.5.4.2,
-             zlib-bindings ==0.1.1.5,
-             zlib-enum ==0.2.3.1,
-             zlib-lens ==0.1.1.2
diff --git a/data/ubuntu-14.10-desktop-i386.iso.torrent b/data/ubuntu-14.10-desktop-i386.iso.torrent
new file mode 100644 (file)
index 0000000..7e453ce
Binary files /dev/null and b/data/ubuntu-14.10-desktop-i386.iso.torrent differ
index 5e3bf0d959616a3381e3a5beb95ed9bc2a2eec45..0086a735a3491216ac96aec0405037a51de1223d 100644 (file)
@@ -12,7 +12,7 @@ maintainer:          ram@rkrishnan.org
 -- copyright:
 category:            Network
 build-type:          Simple
-extra-source-files:  README
+extra-source-files:  README.md
 cabal-version:       >=1.18
 
 library
index 8289da5bae88ce73801cb0edb9d11c407ebf6855..59fe32f446dac27ed82807b209240408f118f294 100644 (file)
@@ -4,16 +4,16 @@ module FuncTorrent
      Metainfo(..),
      Peer,
      TrackerResponse(..),
-     tracker,
+     getTrackerResponse,
      decode,
      encode,
      handShake,
+     msgLoop,
      initLogger,
      logMessage,
      logStop,
      mkInfo,
-     mkMetaInfo,
-     mkTrackerResponse
+     mkMetaInfo
     ) where
 
 import FuncTorrent.Bencode
index a3313d18cbb5c6338de4a38466719af25ad47258..4eece7d5248a0ff257c1f9e02dd9d2e31b924a9e 100644 (file)
@@ -46,7 +46,7 @@ mkInfo (Bdict m) = let (Bint pieceLength') = m ! "piece length"
                                 , md5sum = md5sum'}
 mkInfo _ = Nothing
 
-mkMetaInfo :: BVal   -> Maybe Metainfo
+mkMetaInfo :: BVal   -> Either String Metainfo
 mkMetaInfo (Bdict m)  =
     let (Just info')  = mkInfo $ m ! "info"
         announce'     = lookup "announce" m
@@ -55,18 +55,18 @@ mkMetaInfo (Bdict m)  =
         comment'      = lookup "comment" m
         createdBy'    = lookup "created by" m
         encoding'     = lookup "encoding" m
-    in Just Metainfo {
-             info         = info'
-           , announceList = maybeToList (announce' >>= bstrToString)
-                            ++ getAnnounceList announceList'
-           , creationDate = bValToInteger =<< creationDate'
-           , comment      = bstrToString  =<< comment'
-           , createdBy    = bstrToString  =<< createdBy'
-           , encoding     = bstrToString  =<< encoding'
-           , infoHash     = hash . encode $ (m ! "info")
-        }
+    in Right Metainfo {
+               info         = info'
+             , announceList = maybeToList (announce' >>= bstrToString)
+                              ++ getAnnounceList announceList'
+             , creationDate = bValToInteger =<< creationDate'
+             , comment      = bstrToString  =<< comment'
+             , createdBy    = bstrToString  =<< createdBy'
+             , encoding     = bstrToString  =<< encoding'
+             , infoHash     = hash . encode $ (m ! "info")
+             }
 
-mkMetaInfo _ = Nothing
+mkMetaInfo _ = Left "mkMetaInfo: expect an input dict"
 
 getAnnounceList :: Maybe BVal -> [String]
 getAnnounceList Nothing = []
index 798f60acf0712eef0c0644b320c8fe97750cb212..d04d886e7de7f429275809117bf0eacee6da8c32 100644 (file)
 {-# LANGUAGE OverloadedStrings #-}
 module FuncTorrent.Peer
     (Peer(..),
-     handShake
+     handShake,
+     msgLoop
     ) where
 
-import Prelude hiding (lookup, concat, replicate, splitAt)
+import Prelude hiding (lookup, concat, replicate, splitAt, empty, writeFile)
 
-import System.IO
-import Data.ByteString (ByteString, unpack, concat, hGet, hPut, singleton)
-import Data.ByteString.Char8 (replicate, pack)
+import System.IO (Handle, BufferMode(..), hSetBuffering)
+import Data.ByteString (ByteString, pack, unpack, concat, hGet, hPut, singleton, writeFile)
+import Data.ByteString.Lazy (fromStrict, fromChunks)
+import qualified Data.ByteString.Char8 as BC (replicate, pack, length)
 import Network (connectTo, PortID(..))
+import Data.Binary (Binary(..), decode)
+import Data.Binary.Put (putWord32be, putWord16be, putWord8)
+import Data.Binary.Get (getWord32be, getWord16be, getWord8, runGet)
+import Control.Monad (replicateM, liftM, forever)
+import Control.Applicative ((<$>), liftA3)
+import Data.Bits
+import Data.Word (Word8)
 
 type ID = String
 type IP = String
 type Port = Integer
 
-data PeerState = PeerState { am_choking :: Bool
+data PeerState = PeerState { handle :: Handle
+                           , am_choking :: Bool
                            , am_interested :: Bool
                            , peer_choking :: Bool
-                           , peer_interested :: Bool }
+                           , peer_interested :: Bool}
+
+-- Maintain info on every piece and the current state of it.
+-- should probably be a TVar.
+type Pieces = [PieceData]
+
+data PieceState = Pending
+                | InProgress
+                | Have
+                deriving (Show)
+
+data PieceData = PieceData { index :: Int           -- ^ Piece number
+                           , peers :: [Peer]        -- ^ list of peers who have this piece
+                           , state :: PieceState }  -- ^ state of the piece from download perspective.
 
 -- | Peer is a PeerID, IP address, port tuple
 data Peer = Peer ID IP Port
           deriving (Show, Eq)
 
-data Msg = HandShakeMsg ByteString ID
-         | KeepAliveMsg
-         | ChokeMsg
-         | UnChokeMsg
-         | InterestedMsg
-         | NotInterestedMsg
-         | HaveMsg Integer
-         | BitFieldMsg Integer
-         | RequestMsg Integer Integer Integer
-         | PieceMsg Integer Integer Integer
-         | CancelMsg Integer Integer Integer
-         | PortMsg Port
-         deriving (Show)
+data PeerMsg = KeepAliveMsg
+             | ChokeMsg
+             | UnChokeMsg
+             | InterestedMsg
+             | NotInterestedMsg
+             | HaveMsg Integer
+             | BitFieldMsg ByteString
+             | RequestMsg Integer Integer Integer
+             | PieceMsg Integer Integer ByteString
+             | CancelMsg Integer Integer Integer
+             | PortMsg Port
+             deriving (Show)
 
 genHandShakeMsg :: ByteString -> String -> ByteString
 genHandShakeMsg infoHash peer_id = concat [pstrlen, pstr, reserved, infoHash, peerID]
   where pstrlen = singleton 19
-        pstr = pack "BitTorrent protocol"
-        reserved = replicate 8 '\0'
-        peerID = pack peer_id
+        pstr = BC.pack "BitTorrent protocol"
+        reserved = BC.replicate 8 '\0'
+        peerID = BC.pack peer_id
 
-handShake :: Peer -> ByteString -> String -> IO ByteString
+handShake :: Peer -> ByteString -> String -> IO Handle
 handShake (Peer _ ip port) infoHash peerid = do
   let hs = genHandShakeMsg infoHash peerid
-  handle <- connectTo ip (PortNumber (fromIntegral port))
-  hSetBuffering handle LineBuffering
-  hPut handle hs
-  rlenBS <- hGet handle 1
-  let rlen = fromIntegral $ (unpack rlenBS) !! 0
-  hGet handle rlen
-
--- sendMsg :: Peer -> Handle -> PeerMsg -> IO ()
+  h <- connectTo ip (PortNumber (fromIntegral port))
+  hSetBuffering h LineBuffering
+  hPut h hs
+  rlenBS <- hGet h (length (unpack hs))
+  putStrLn $ "got handshake from peer: " ++ show rlenBS
+  return h
+
+instance Binary PeerMsg where
+  put msg = case msg of
+             KeepAliveMsg -> putWord32be 0
+             ChokeMsg -> do putWord32be 1
+                            putWord8 0
+             UnChokeMsg -> do putWord32be 1
+                              putWord8 1
+             InterestedMsg -> do putWord32be 1
+                                 putWord8 2
+             NotInterestedMsg -> do putWord32be 1
+                                    putWord8 3
+             HaveMsg i -> do putWord32be 5
+                             putWord8 4
+                             putWord32be (fromIntegral i)
+             BitFieldMsg bf -> do putWord32be $ fromIntegral (1 + bfListLen)
+                                  putWord8 5
+                                  mapM_ putWord8 bfList
+                                    where bfList = unpack bf
+                                          bfListLen = length bfList
+             RequestMsg i o l -> do putWord32be 13
+                                    putWord8 6
+                                    putWord32be (fromIntegral i)
+                                    putWord32be (fromIntegral o)
+                                    putWord32be (fromIntegral l)
+             PieceMsg i o b -> do putWord32be $ fromIntegral (9 + blocklen)
+                                  putWord8 7
+                                  putWord32be (fromIntegral i)
+                                  putWord32be (fromIntegral o)
+                                  mapM_ putWord8 blockList
+                                    where blockList = unpack b
+                                          blocklen = length blockList
+             CancelMsg i o l -> do putWord32be 13
+                                   putWord8 8
+                                   putWord32be (fromIntegral i)
+                                   putWord32be (fromIntegral o)
+                                   putWord32be (fromIntegral l)
+             PortMsg p -> do putWord32be 3
+                             putWord8 9
+                             putWord16be (fromIntegral p)
+  get = do
+    l <- getWord32be
+    msgid <- getWord8
+    case msgid of
+     0 -> return ChokeMsg
+     1 -> return UnChokeMsg
+     2 -> return InterestedMsg
+     3 -> return NotInterestedMsg
+     4 -> liftM (HaveMsg . fromIntegral) getWord32be
+     5 -> liftM (BitFieldMsg . pack) (replicateM (fromIntegral l - 1) getWord8)
+     6 -> liftA3 RequestMsg getInteger getInteger getInteger
+       where getInteger = fromIntegral <$> getWord32be
+     7 -> liftA3 PieceMsg getInteger getInteger (pack  <$> replicateM (fromIntegral l - 9) getWord8)
+       where getInteger = fromIntegral <$> getWord32be
+     8 -> liftA3 CancelMsg getInteger getInteger getInteger
+       where getInteger = fromIntegral <$> getWord32be
+     9 -> liftM (PortMsg . fromIntegral) getWord16be
+     _ -> error ("unknown message ID: " ++ show msgid)
+
+getMsg :: Handle -> IO PeerMsg
+getMsg h = do
+  lBS <- hGet h 4
+  let l = bsToInt lBS
+  if l == 0
+    then return KeepAliveMsg
+    else do
+    msg <- hGet h l
+    return $ decode $ fromStrict $ concat [lBS, msg]
+
+
+bsToInt :: ByteString -> Int
+bsToInt x = fromIntegral (runGet getWord32be (fromChunks (return x)))
+
+bitfieldToList :: [Word8] -> [Integer]
+bitfieldToList bs = go bs 0
+  where go [] _ = []
+        go (b:bs') pos =
+          let setBits = [pos*8 + (toInteger i) | i <- [0..8], testBit b i]
+          in
+           setBits ++ (go bs' (pos + 1))
+
+-- downloadPiece :: Integer -> Handle -> IO ()
+
+createDummyFile :: FilePath -> Int -> IO ()
+createDummyFile path size = do
+  writeFile path (BC.replicate size '\0')
+
+-- loop1 :: shake hands with all peers, find out the pieces they have, form PieceData.
 -- recvMsg :: Peer -> Handle -> Msg
+msgLoop :: Handle -> ByteString -> IO ()
+msgLoop h pieceHash =
+  let numPieces = (toInteger . (`quot` 20) . BC.length) pieceHash
+  in
+   forever $ do
+     msg <- getMsg h
+     putStrLn $ "got a " ++ show msg
+     case msg of
+      BitFieldMsg bss -> do
+        let pieceList = bitfieldToList (unpack bss)
+        putStrLn (show pieceList)
+        -- download each of the piece in order
+      _ -> putStrLn (show msg)
index b8166508d20980df85480c8047478388fa265b99..425b5d43ec5172e6dedc5a7b4f009295793c6aff 100644 (file)
@@ -1,9 +1,8 @@
 {-# LANGUAGE OverloadedStrings #-}
 module FuncTorrent.Tracker
     (TrackerResponse(..),
-     tracker,
      mkArgs,
-     mkTrackerResponse,
+     getTrackerResponse,
      urlEncodeHash
     ) where
 
@@ -17,7 +16,7 @@ import Data.Map as M (lookup)
 import Network.HTTP.Base (urlEncode)
 import qualified Data.ByteString.Base16 as B16 (encode)
 
-import FuncTorrent.Bencode (BVal(..))
+import FuncTorrent.Bencode (BVal(..), decode)
 import FuncTorrent.Metainfo (Info(..), Metainfo(..))
 import FuncTorrent.Network (get)
 import FuncTorrent.Peer (Peer(..))
@@ -69,6 +68,13 @@ mkTrackerResponse resp =
 tracker :: Metainfo -> String -> IO ByteString
 tracker m peer_id = get (head . announceList $ m) $ mkArgs m peer_id
 
+getTrackerResponse :: Metainfo -> String -> IO (Either ByteString TrackerResponse)
+getTrackerResponse m peerId = do
+  resp <- tracker m peerId
+  case decode resp of
+   Right trackerInfo -> return $ mkTrackerResponse trackerInfo
+   Left e -> return $ Left (pack (show e))
+
 --- | URL encode hash as per RFC1738
 --- TODO: Add tests
 --- REVIEW: Why is this not written in terms of `Network.HTTP.Base.urlEncode` or
index 65e2dd7cb194321305b3028e88ee1dbe7e7a71fa..7ba6d96c3bbe5884df4aab5b4de3e3a44278d700 100644 (file)
@@ -1,21 +1,20 @@
 {-# LANGUAGE OverloadedStrings #-}
 module Main where
 
-import Prelude hiding (log, length, readFile, writeFile)
-import Data.ByteString.Char8 (ByteString, readFile, writeFile, unpack)
+import Prelude hiding (log, length, readFile)
+import Data.ByteString.Char8 (ByteString, readFile, unpack)
 import System.Environment (getArgs)
 import System.Exit (exitSuccess)
 import System.Directory (doesFileExist)
-import Text.ParserCombinators.Parsec (ParseError)
 
 import FuncTorrent.Bencode (decode)
 import FuncTorrent.Logger (initLogger, logMessage, logStop)
 import FuncTorrent.Metainfo (Info(..), Metainfo(..), mkMetaInfo)
-import FuncTorrent.Peer (handShake)
-import FuncTorrent.Tracker (tracker, peers, mkTrackerResponse)
+import FuncTorrent.Peer (handShake, msgLoop)
+import FuncTorrent.Tracker (peers, getTrackerResponse)
 
-logError :: ParseError -> (String -> IO ()) -> IO ()
-logError e logMsg = logMsg $ "parse error: \n" ++ show e
+logError :: String -> (String -> IO ()) -> IO ()
+logError e logMsg = logMsg $ "parse error: \n" ++ e
 
 peerId :: String
 peerId = "-HS0001-*-*-20150215"
@@ -35,40 +34,37 @@ parse [a] = do
     else error "file does not exist"
 parse _ = exit
 
+torrentToMetaInfo :: ByteString -> Either String Metainfo
+torrentToMetaInfo s =
+  case (decode s) of
+   Right d ->
+     mkMetaInfo d
+   Left e ->
+     Left $ show e
+
 main :: IO ()
 main = do
     args <- getArgs
     logR <- initLogger
     let log = logMessage logR
     log "Starting up functorrent"
-    log $ "Parsing input file " ++ concat args
+    log $ "Parsing arguments " ++ concat args
     torrentStr <- parse args
-    case decode torrentStr of
-      Right d ->
-          case mkMetaInfo d of
-            Nothing -> log "Unable to make meta info file"
-            Just m -> do
-              log "Input File OK"
-              log $ "Downloading file : " ++ name (info m)
-              log "Trying to fetch peers"
-
-              log $ "Trackers: " ++ head (announceList m)
-              response <- tracker m peerId
-
-              -- TODO: Write to ~/.functorrent/caches
-              writeFile (name (info m) ++ ".cache") response
-
-              case decode response of
-                Right trackerInfo ->
-                    case mkTrackerResponse trackerInfo of
-                      Right peerResp -> do
-                          log $ "Peers List : " ++ (show . peers $ peerResp)
-                          let p1 = head (peers peerResp)
-                          msg <- handShake p1 (infoHash m) peerId
-                          log $ "handshake: " ++ (show msg)
-                          return ()
-                      Left e -> log $ "Error" ++ unpack e
-                Left e -> logError e log
+    case (torrentToMetaInfo torrentStr) of
+     Right m -> do
+       log "Input File OK"
+       log $ "Downloading file : " ++ name (info m)
+       log "Trying to fetch peers"
 
-      Left e -> logError e log
+       log $ "Trackers: " ++ head (announceList m)
+       trackerResp <- getTrackerResponse m peerId
+       case  trackerResp of
+        Right peerList -> do
+          log $ "Peers List : " ++ (show . peers $ peerList)
+          let p1 = head (peers peerList)
+          h <- handShake p1 (infoHash m) peerId
+          log $ "handshake"
+          msgLoop h (pieces (info m))
+        Left e -> log $ "Error" ++ unpack e
+     Left e -> logError e log
     logStop logR
diff --git a/stack.yaml b/stack.yaml
new file mode 100644 (file)
index 0000000..ba74732
--- /dev/null
@@ -0,0 +1,5 @@
+flags: {}
+packages:
+- '.'
+extra-deps: []
+resolver: lts-2.16