{-# LANGUAGE OverloadedStrings #-}
module FuncTorrent.Peer
(Peer(..),
- handShakeMsg
+ handShake
) where
import Prelude hiding (lookup, concat, replicate, splitAt)
-import Data.ByteString.Char8 (ByteString, pack, concat, replicate)
-import Data.ByteString.Lazy (toChunks)
-import Data.Int (Int8)
-import qualified Data.Binary as Bin (encode)
+import System.IO
+import Data.ByteString (ByteString, unpack, concat, hGet, hPut, singleton)
+import Data.ByteString.Char8 (replicate, pack)
+import Network (connectTo, PortID(..))
-import FuncTorrent.Metainfo (Metainfo(..))
+type ID = String
+type IP = String
+type Port = Integer
--- | Peer is a IP address, port tuple
-data Peer = Peer String Integer
- deriving (Show, Eq)
+data PeerState = PeerState { am_choking :: Bool
+ , am_interested :: Bool
+ , peer_choking :: Bool
+ , peer_interested :: Bool }
-handShakeMsg :: Metainfo -> String -> ByteString
-handShakeMsg m peer_id = concat [pstrlen, pstr, reserved, infoH, peerID]
- where pstrlen = concat $ toChunks $ Bin.encode (19 :: Int8)
- pstr = pack "BitTorrent protocol"
- reserved = replicate 8 '\0'
- infoH = infoHash m
- peerID = pack peer_id
+-- | 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)
+
+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
+
+handShake :: Peer -> ByteString -> String -> IO ByteString
+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 ()
+-- recvMsg :: Peer -> Handle -> Msg
module Main where
import Prelude hiding (log, length, readFile, writeFile)
-import Data.ByteString.Char8 (ByteString, readFile, writeFile, length, unpack)
+import Data.ByteString.Char8 (ByteString, readFile, writeFile, unpack)
import System.Environment (getArgs)
import System.Exit (exitSuccess)
import System.Directory (doesFileExist)
import FuncTorrent.Bencode (decode)
import FuncTorrent.Logger (initLogger, logMessage, logStop)
import FuncTorrent.Metainfo (Info(..), Metainfo(..), mkMetaInfo)
-import FuncTorrent.Peer (handShakeMsg)
+import FuncTorrent.Peer (Peer(..), handShake)
import FuncTorrent.Tracker (tracker, peers, mkTrackerResponse)
logError :: ParseError -> (String -> IO ()) -> IO ()
log $ "Trackers: " ++ head (announceList m)
response <- tracker m peerId
- let hsMsgLen = show $ length $ handShakeMsg m peerId
- log $ "Hand-shake message length : " ++ hsMsgLen
-
-- TODO: Write to ~/.functorrent/caches
writeFile (name (info m) ++ ".cache") response
case decode response of
Right trackerInfo ->
case mkTrackerResponse trackerInfo of
- Right peerResp ->
+ Right peerResp -> do
log $ "Peers List : " ++ (show . peers $ peerResp)
+ let p1 = head (peers peerResp)
+ msg <- handShake (Peer "" "95.188.88.59" 27000) (infoHash m) peerId
+ log $ "handshake: " ++ (show msg)
+ return ()
Left e -> log $ "Error" ++ unpack e
Left e -> logError e log