From 82bea85b66304a550df074e700078c0c0c5d602a Mon Sep 17 00:00:00 2001 From: Sam T Date: Wed, 24 Apr 2013 23:52:42 +0400 Subject: + Add handshake pprint. Move Peer to separated module since otherwise we have recursive module dependencies. --- network-bittorrent.cabal | 3 ++ src/Network/BitTorrent.hs | 4 +- src/Network/BitTorrent/Peer.hs | 56 ++++++++++++++++++++++++++++ src/Network/BitTorrent/PeerID.hs | 50 +++---------------------- src/Network/BitTorrent/PeerWire/Handshake.hs | 40 +++++++++++++++----- src/Network/BitTorrent/Tracker.hs | 1 + 6 files changed, 100 insertions(+), 54 deletions(-) create mode 100644 src/Network/BitTorrent/Peer.hs diff --git a/network-bittorrent.cabal b/network-bittorrent.cabal index b408620b..98423512 100644 --- a/network-bittorrent.cabal +++ b/network-bittorrent.cabal @@ -24,9 +24,12 @@ library exposed-modules: Data.Torrent , Data.Torrent.InfoHash , Network.BitTorrent + , Network.BitTorrent.Peer , Network.BitTorrent.PeerID + , Network.BitTorrent.Tracker , Network.BitTorrent.Tracker.Scrape + , Network.BitTorrent.PeerWire , Network.BitTorrent.PeerWire.ClientInfo , Network.BitTorrent.PeerWire.Block diff --git a/src/Network/BitTorrent.hs b/src/Network/BitTorrent.hs index 9c1977d4..97efbbda 100644 --- a/src/Network/BitTorrent.hs +++ b/src/Network/BitTorrent.hs @@ -1,9 +1,11 @@ module Network.BitTorrent - ( module Network.BitTorrent.PeerID + ( module Network.BitTorrent.Peer + , module Network.BitTorrent.PeerID , module Network.BitTorrent.Tracker , module Network.BitTorrent.PeerWire ) where +import Network.BitTorrent.Peer import Network.BitTorrent.PeerID import Network.BitTorrent.Tracker import Network.BitTorrent.PeerWire diff --git a/src/Network/BitTorrent/Peer.hs b/src/Network/BitTorrent/Peer.hs new file mode 100644 index 00000000..e16329d2 --- /dev/null +++ b/src/Network/BitTorrent/Peer.hs @@ -0,0 +1,56 @@ +-- | +-- Copyright : (c) Sam T. 2013 +-- License : MIT +-- Maintainer : pxqr.sta@gmail.com +-- Stability : experimental +-- Portability : non-portable +-- +module Network.BitTorrent.Peer + ( Peer(..) + , peerSockAddr, connectToPeer + , ppPeer + ) where + +import Control.Applicative +import Data.Word +import Data.Bits +import Network +import Network.Socket + +import Network.BitTorrent.PeerID +import Network.BitTorrent.PeerWire.ClientInfo + + +data Peer = Peer { + peerID :: Maybe PeerID + , peerIP :: HostAddress + , peerPort :: PortNumber + } deriving Show + +-- TODO make platform independent, clarify htonl +-- | Convert peer info from tracker response to socket address. +-- Used for establish connection between peers. +-- +peerSockAddr :: Peer -> SockAddr +peerSockAddr = SockAddrInet <$> (g . peerPort) <*> (htonl . peerIP) + where + htonl :: Word32 -> Word32 + htonl d = + ((d .&. 0xff) `shiftL` 24) .|. + (((d `shiftR` 8 ) .&. 0xff) `shiftL` 16) .|. + (((d `shiftR` 16) .&. 0xff) `shiftL` 8) .|. + ((d `shiftR` 24) .&. 0xff) + + g :: PortNumber -> PortNumber + g = id + +-- | Tries to connect to peer using reasonable default parameters. +connectToPeer :: Peer -> IO Socket +connectToPeer p = do + sock <- socket AF_INET Stream Network.Socket.defaultProtocol + connect sock (peerSockAddr p) + return sock + +ppPeer :: Peer -> String +ppPeer p = maybe "" (++ " at ") ((ppClientInfo . clientInfo) <$> peerID p) + ++ show (peerSockAddr p) diff --git a/src/Network/BitTorrent/PeerID.hs b/src/Network/BitTorrent/PeerID.hs index cef1fa58..2c8818fe 100644 --- a/src/Network/BitTorrent/PeerID.hs +++ b/src/Network/BitTorrent/PeerID.hs @@ -8,17 +8,14 @@ -- -- This module provides 'Peer' and 'PeerID' datatypes and all related -- operations. +-- -- Recommended method for generation of the peer ID's is 'newPeerID', -- though this module exports some other goodies for custom generation. -- {-# LANGUAGE OverloadedStrings, GeneralizedNewtypeDeriving #-} module Network.BitTorrent.PeerID - ( -- * Peer addr - Peer(..) - , peerSockAddr, connectToPeer - - -- * Peer identification - , PeerID (getPeerID) + ( -- * Peer identification + PeerID (getPeerID), ppPeerID -- ** Encoding styles , azureusStyle, shadowStyle @@ -34,8 +31,6 @@ module Network.BitTorrent.PeerID ) where import Control.Applicative -import Data.Word -import Data.Bits import Data.BEncode import Data.ByteString (ByteString) import qualified Data.ByteString as B @@ -50,8 +45,6 @@ import Data.Version (Version(Version), versionBranch) import Data.Time.Clock (getCurrentTime) import Data.Time.Format (formatTime) import System.Locale (defaultTimeLocale) -import Network -import Network.Socket -- TODO we have linker error here, so manual hardcoded version for a while. @@ -60,40 +53,6 @@ version :: Version version = Version [0, 10, 0, 0] [] - -data Peer = Peer { - peerID :: Maybe PeerID - , peerIP :: HostAddress - , peerPort :: PortNumber - } deriving Show - --- TODO make platform independent, clarify htonl --- | Convert peer info from tracker response to socket address. --- Used for establish connection between peers. --- -peerSockAddr :: Peer -> SockAddr -peerSockAddr = SockAddrInet <$> (g . peerPort) <*> (htonl . peerIP) - where - htonl :: Word32 -> Word32 - htonl d = - ((d .&. 0xff) `shiftL` 24) .|. - (((d `shiftR` 8 ) .&. 0xff) `shiftL` 16) .|. - (((d `shiftR` 16) .&. 0xff) `shiftL` 8) .|. - ((d `shiftR` 24) .&. 0xff) - - g :: PortNumber -> PortNumber - g = id - --- ipv6 extension --- | Tries to connect to peer using reasonable default parameters. --- -connectToPeer :: Peer -> IO Socket -connectToPeer p = do - sock <- socket AF_INET Stream Network.Socket.defaultProtocol - connect sock (peerSockAddr p) - return sock - - -- | Peer identifier is exactly 20 bytes long bytestring. newtype PeerID = PeerID { getPeerID :: ByteString } deriving (Show, Eq, Ord, BEncodable) @@ -105,6 +64,9 @@ instance Serialize PeerID where instance URLShow PeerID where urlShow = BC.unpack . getPeerID +ppPeerID :: PeerID -> String +ppPeerID = BC.unpack . getPeerID + -- | Azureus-style encoding have the following layout: -- diff --git a/src/Network/BitTorrent/PeerWire/Handshake.hs b/src/Network/BitTorrent/PeerWire/Handshake.hs index 6ce37887..a80728aa 100644 --- a/src/Network/BitTorrent/PeerWire/Handshake.hs +++ b/src/Network/BitTorrent/PeerWire/Handshake.hs @@ -11,30 +11,47 @@ module Network.BitTorrent.PeerWire.Handshake , handshakeMaxSize , defaultBTProtocol, defaultReserved, defaultHandshake , handshake + , ppHandshake ) where import Control.Applicative import Data.Word import Data.ByteString (ByteString) import qualified Data.ByteString as B +import qualified Data.ByteString.Char8 as BC import Data.Serialize as S import Data.Torrent.InfoHash import Network import Network.Socket.ByteString import Network.BitTorrent.PeerID +import Network.BitTorrent.PeerWire.ClientInfo --- | In order to establish the connection between peers we should send 'Handshake' --- message. The 'Handshake' is a required message and must be the first message --- transmitted by the peer to the another peer. +-- | In order to establish the connection between peers we should send +-- 'Handshake' message. The 'Handshake' is a required message and +-- must be the first message transmitted by the peer to the another +-- peer. +-- data Handshake = Handshake { - hsProtocol :: ByteString -- ^ Identifier of the protocol. - , hsReserved :: Word64 -- ^ Reserved bytes, rarely used. - , hsInfoHash :: InfoHash -- ^ Hash from the metainfo file. - -- This /should be/ same hash that is transmitted in tracker requests. - , hsPeerID :: PeerID -- ^ Peer id of the initiator. - -- This is /usually the same peer id that is transmitted in tracker requests. + -- ^ Identifier of the protocol. + hsProtocol :: ByteString + + -- ^ Reserved bytes used to specify supported BEP's. + , hsReserved :: Word64 + + -- ^ Info hash of the info part of the metainfo file. that is + -- transmitted in tracker requests. Info hash of the initiator + -- handshake and response handshake should match, otherwise + -- initiator should break the connection. + -- + , hsInfoHash :: InfoHash + + -- ^ Peer id of the initiator. This is usually the same peer id + -- that is transmitted in tracker requests. + -- + , hsPeerID :: PeerID + } deriving (Show, Eq) instance Serialize Handshake where @@ -52,6 +69,11 @@ instance Serialize Handshake where <*> get <*> get +-- TODO add reserved bits info +ppHandshake :: Handshake -> String +ppHandshake hs = BC.unpack (hsProtocol hs) ++ " " + ++ ppClientInfo (clientInfo (hsPeerID hs)) + -- | Maximum size of handshake message in bytes. handshakeMaxSize :: Int handshakeMaxSize = 1 + 256 + 8 + 20 + 20 diff --git a/src/Network/BitTorrent/Tracker.hs b/src/Network/BitTorrent/Tracker.hs index 643aca16..99ffc280 100644 --- a/src/Network/BitTorrent/Tracker.hs +++ b/src/Network/BitTorrent/Tracker.hs @@ -46,6 +46,7 @@ import Network.Socket import Network.HTTP import Network.URI +import Network.BitTorrent.Peer import Network.BitTorrent.PeerID import Network.BitTorrent.Tracker.Scrape -- cgit v1.2.3