summaryrefslogtreecommitdiff
path: root/src/Network/BitTorrent
diff options
context:
space:
mode:
Diffstat (limited to 'src/Network/BitTorrent')
-rw-r--r--src/Network/BitTorrent/DHT/ContactInfo.hs59
-rw-r--r--src/Network/BitTorrent/DHT/Session.hs22
-rw-r--r--src/Network/BitTorrent/Tracker/RPC/HTTP.hs2
3 files changed, 69 insertions, 14 deletions
diff --git a/src/Network/BitTorrent/DHT/ContactInfo.hs b/src/Network/BitTorrent/DHT/ContactInfo.hs
index 4302288c..117325fc 100644
--- a/src/Network/BitTorrent/DHT/ContactInfo.hs
+++ b/src/Network/BitTorrent/DHT/ContactInfo.hs
@@ -15,6 +15,8 @@ import Data.Serialize
15import Data.PSQueue as PSQ 15import Data.PSQueue as PSQ
16import Data.Time.Clock.POSIX 16import Data.Time.Clock.POSIX
17import Data.ByteString (ByteString) 17import Data.ByteString (ByteString)
18import Data.Word
19import Network.Socket (SockAddr(..))
18 20
19import Data.Torrent 21import Data.Torrent
20import Network.BitTorrent.Address 22import Network.BitTorrent.Address
@@ -122,6 +124,40 @@ data SwarmData ip = SwarmData
122 , name :: Maybe ByteString 124 , name :: Maybe ByteString
123 } 125 }
124 126
127
128newtype SerializeAddress a = SerializeAddress { unserializeAddress :: a }
129
130instance Address a => Serialize (SerializeAddress a) where
131 get = SerializeAddress <$> do
132 c <- get
133 case (c::Word8) of
134 0x34 -> do ip4 <- get
135 return $ fromJust $ fromAddr (ip4::IPv4)
136 0x36 -> do ip6 <- get
137 return $ fromJust $ fromAddr (ip6::IPv6)
138 _ -> return $ error "cannot deserialize non-IP SerializeAddress"
139 put (SerializeAddress a)
140 | Just ip4 <- fromAddr a
141 = put (0x34::Word8) >> put (ip4::IPv4)
142 | Just ip6 <- fromAddr a
143 = put (0x36::Word8) >> put (ip6::IPv6)
144 | otherwise = return $ error "cannot serialize non-IP SerializeAddress"
145
146
147instance (Ord ip, Address ip) => Serialize (SwarmData ip) where
148 get = flip SwarmData <$> get
149 <*> ( PSQ.fromList . L.map parseAddr <$> get )
150 where
151 parseAddr addr = (unserializeAddress <$> addr)
152 :-> 0
153
154 put SwarmData{..} = do
155 put name
156 put $ L.map (\(addr :-> _) -> (SerializeAddress <$> addr))
157 -- XXX: should we serialize the timestamp?
158 $ PSQ.toList peers
159
160
125knownSwarms :: PeerStore ip -> [ (InfoHash, Int, Maybe ByteString) ] 161knownSwarms :: PeerStore ip -> [ (InfoHash, Int, Maybe ByteString) ]
126knownSwarms (PeerStore m) = L.map (\(ih,SwarmData q n) -> (ih,PSQ.size q,n)) $ HM.toList m 162knownSwarms (PeerStore m) = L.map (\(ih,SwarmData q n) -> (ih,PSQ.size q,n)) $ HM.toList m
127 163
@@ -136,26 +172,27 @@ swarmInsert old new = SwarmData
136 , name = name new <|> name old -- TODO: decodeUtf8' check 172 , name = name new <|> name old -- TODO: decodeUtf8' check
137 } 173 }
138 174
175isSwarmOccupied SwarmData{..} = not $ PSQ.null peers
139 176
140-- | Empty store. 177-- | Empty store.
141instance Default (PeerStore a) where 178instance Default (PeerStore a) where
142 def = PeerStore HM.empty 179 def = PeerStore HM.empty
143 {-# INLINE def #-} 180 {-# INLINE def #-}
144 181
145-- -- | Monoid under union operation. 182-- | Monoid under union operation.
146-- instance Eq a => Monoid (PeerStore a) where 183instance Ord a => Monoid (PeerStore a) where
147-- mempty = def 184 mempty = def
148-- {-# INLINE mempty #-} 185 {-# INLINE mempty #-}
149-- 186
150-- mappend (PeerStore a) (PeerStore b) = 187 mappend (PeerStore a) (PeerStore b) =
151-- PeerStore (HM.unionWith L.union a b) 188 PeerStore (HM.unionWith swarmInsert a b)
152-- {-# INLINE mappend #-} 189 {-# INLINE mappend #-}
153 190
154-- | Can be used to store peers between invocations of the client 191-- | Can be used to store peers between invocations of the client
155-- software. 192-- software.
156instance Serialize (PeerStore a) where 193instance (Ord a, Address a) => Serialize (PeerStore a) where
157 get = undefined 194 get = PeerStore . HM.fromList <$> get
158 put = undefined 195 put (PeerStore m) = put (L.filter (isSwarmOccupied . snd) $ HM.toList m)
159 196
160-- | Returns all peers associated with a given info hash. 197-- | Returns all peers associated with a given info hash.
161lookup :: Ord a => InfoHash -> PeerStore a -> [PeerAddr a] 198lookup :: Ord a => InfoHash -> PeerStore a -> [PeerAddr a]
diff --git a/src/Network/BitTorrent/DHT/Session.hs b/src/Network/BitTorrent/DHT/Session.hs
index bc9fda91..c08021c7 100644
--- a/src/Network/BitTorrent/DHT/Session.hs
+++ b/src/Network/BitTorrent/DHT/Session.hs
@@ -54,14 +54,16 @@ module Network.BitTorrent.DHT.Session
54 -- ** Routing table 54 -- ** Routing table
55 , getTable 55 , getTable
56 , getClosest 56 , getClosest
57 , getSwarms
58 , allPeers
59 57
60 -- ** Peer storage 58 -- ** Peer storage
61 , insertPeer 59 , insertPeer
62 , getPeerList 60 , getPeerList
63 , insertTopic 61 , insertTopic
64 , deleteTopic 62 , deleteTopic
63 , getSwarms
64 , savePeerStore
65 , mergeSavedPeers
66 , allPeers
65 67
66 -- ** Messaging 68 -- ** Messaging
67 , queryParallel 69 , queryParallel
@@ -84,6 +86,7 @@ import Data.Fixed
84import Data.Hashable 86import Data.Hashable
85import Data.List as L 87import Data.List as L
86import Data.Maybe 88import Data.Maybe
89import Data.Monoid
87import Data.Set as S 90import Data.Set as S
88import Data.Time 91import Data.Time
89import Network (PortNumber) 92import Network (PortNumber)
@@ -91,6 +94,7 @@ import System.Random (randomIO)
91import Data.Time.Clock.POSIX 94import Data.Time.Clock.POSIX
92import Data.Text as Text 95import Data.Text as Text
93import Text.PrettyPrint.HughesPJClass hiding ((<>),($$)) 96import Text.PrettyPrint.HughesPJClass hiding ((<>),($$))
97import Data.Serialize as S
94 98
95 99
96import Data.Torrent as Torrent 100import Data.Torrent as Torrent
@@ -409,6 +413,20 @@ getSwarms = do
409 store <- asks contactInfo >>= liftIO . atomically . readTVar 413 store <- asks contactInfo >>= liftIO . atomically . readTVar
410 return $ P.knownSwarms store 414 return $ P.knownSwarms store
411 415
416savePeerStore :: (Ord ip, Address ip) => DHT ip ByteString
417savePeerStore = do
418 var <- asks contactInfo
419 peers <- liftIO $ atomically $ readTVar var
420 return $ S.encode peers
421
422mergeSavedPeers :: (Ord ip, Address ip) => ByteString -> DHT ip ()
423mergeSavedPeers bs = do
424 var <- asks contactInfo
425 case S.decode bs of
426 Right newbies -> liftIO $ atomically $ modifyTVar' var (<> newbies)
427 Left _ -> return ()
428
429
412allPeers :: Ord ip => InfoHash -> DHT ip [ PeerAddr ip ] 430allPeers :: Ord ip => InfoHash -> DHT ip [ PeerAddr ip ]
413allPeers ih = do 431allPeers ih = do
414 store <- asks contactInfo >>= liftIO . atomically . readTVar 432 store <- asks contactInfo >>= liftIO . atomically . readTVar
diff --git a/src/Network/BitTorrent/Tracker/RPC/HTTP.hs b/src/Network/BitTorrent/Tracker/RPC/HTTP.hs
index de3fc5f5..bc52bddd 100644
--- a/src/Network/BitTorrent/Tracker/RPC/HTTP.hs
+++ b/src/Network/BitTorrent/Tracker/RPC/HTTP.hs
@@ -129,7 +129,7 @@ fillRequest Options {..} q r = r
129 129
130httpTracker :: BEncode a => Manager -> URI -> SimpleQuery -> IO a 130httpTracker :: BEncode a => Manager -> URI -> SimpleQuery -> IO a
131httpTracker Manager {..} uri q = packHttpException $ do 131httpTracker Manager {..} uri q = packHttpException $ do
132 request <- fillRequest options q <$> setUri def uri 132 request <- fillRequest options q <$> setUri def {- http-client instance for Request -} uri
133 response <- runResourceT $ httpLbs request httpMgr 133 response <- runResourceT $ httpLbs request httpMgr
134 case BE.decode $ BL.toStrict $ responseBody response of 134 case BE.decode $ BL.toStrict $ responseBody response of
135 Left msg -> throwIO (ParserFailure msg) 135 Left msg -> throwIO (ParserFailure msg)