diff options
Diffstat (limited to 'src/Network/BitTorrent/DHT.hs')
-rw-r--r-- | src/Network/BitTorrent/DHT.hs | 61 |
1 files changed, 33 insertions, 28 deletions
diff --git a/src/Network/BitTorrent/DHT.hs b/src/Network/BitTorrent/DHT.hs index 1c62a0e0..3867d182 100644 --- a/src/Network/BitTorrent/DHT.hs +++ b/src/Network/BitTorrent/DHT.hs | |||
@@ -33,7 +33,6 @@ module Network.BitTorrent.DHT | |||
33 | 33 | ||
34 | -- * Initialization | 34 | -- * Initialization |
35 | , snapshot | 35 | , snapshot |
36 | , restore | ||
37 | 36 | ||
38 | -- * Operations | 37 | -- * Operations |
39 | , Network.BitTorrent.DHT.lookup | 38 | , Network.BitTorrent.DHT.lookup |
@@ -162,24 +161,39 @@ resolveHostName NodeAddr {..} = do | |||
162 | -- | 161 | -- |
163 | -- This operation do block, use | 162 | -- This operation do block, use |
164 | -- 'Control.Concurrent.Async.Lifted.async' if needed. | 163 | -- 'Control.Concurrent.Async.Lifted.async' if needed. |
165 | bootstrap :: Address ip => [NodeAddr ip] -> DHT ip () | 164 | bootstrap :: Address ip => Maybe BS.ByteString -> [NodeAddr ip] -> DHT ip () |
166 | bootstrap startNodes = do | 165 | bootstrap mbs startNodes = do |
166 | restored <- | ||
167 | case decode <$> mbs of | ||
168 | Just (Right tbl) -> return (T.toList tbl) | ||
169 | Just (Left e) -> do $(logWarnS) "restore" (Text.pack e) | ||
170 | return [] | ||
171 | Nothing -> return [] | ||
172 | |||
167 | $(logInfoS) "bootstrap" "Start node bootstrapping" | 173 | $(logInfoS) "bootstrap" "Start node bootstrapping" |
168 | nid <- asks thisNodeId | 174 | let searchAll aliveNodes = do |
169 | let searchAll aliveNodes | 175 | nid <- myNodeIdAccordingTo (error "FIXME") |
170 | = C.sourceList [aliveNodes] $= search nid (findNodeQ nid) $$ C.consume | 176 | C.sourceList [aliveNodes] $= search nid (findNodeQ nid) $$ C.consume |
177 | input_nodes <- (restored ++) . T.toList <$> getTable | ||
171 | -- Step 1: Use iterative searches to flesh out the table.. | 178 | -- Step 1: Use iterative searches to flesh out the table.. |
172 | do knowns <- map (map $ nodeAddr . fst) . T.toList <$> getTable | 179 | do let knowns = map (map $ nodeAddr . fst) input_nodes |
173 | alive_knowns <- queryParallel (pingQ <$> concat knowns) | 180 | -- Below, we reverse the nodes since the table serialization puts the |
174 | nss <- searchAll alive_knowns | 181 | -- nearest nodes last and we want to choose a similar node id to bootstrap |
175 | -- We only use the supplied bootstrap nodes when we don't know of any | 182 | -- faster. |
176 | -- others to try. | 183 | (alive_knowns,_) <- unzip <$> queryParallel (pingQ <$> reverse (concat knowns)) |
177 | when (null nss) $ do | 184 | b <- isBootstrapped |
178 | -- TODO filter duplicated in startNodes list | 185 | -- If our cached nodes are alive and our IP address did not change, it's possible |
179 | -- TODO retransmissions for startNodes | 186 | -- we are already bootsrapped, so no need to do any searches. |
180 | aliveNodes <- queryParallel (pingQ <$> startNodes) | 187 | when (not b) $ do |
181 | _ <- searchAll aliveNodes | 188 | nss <- searchAll $ take 2 alive_knowns |
182 | return () | 189 | -- We only use the supplied bootstrap nodes when we don't know of any |
190 | -- others to try. | ||
191 | when (null nss) $ do | ||
192 | -- TODO filter duplicated in startNodes list | ||
193 | -- TODO retransmissions for startNodes | ||
194 | (aliveNodes,_) <- unzip <$> queryParallel (pingQ <$> startNodes) | ||
195 | _ <- searchAll $ take 2 aliveNodes | ||
196 | return () | ||
183 | -- Step 2: Repeatedly refresh incomplete buckets until the table is full. | 197 | -- Step 2: Repeatedly refresh incomplete buckets until the table is full. |
184 | maxbuckets <- asks $ optBucketCount . options | 198 | maxbuckets <- asks $ optBucketCount . options |
185 | flip fix 0 $ \loop icnt -> do | 199 | flip fix 0 $ \loop icnt -> do |
@@ -195,6 +209,7 @@ bootstrap startNodes = do | |||
195 | p:ps -> p:unfull ps | 209 | p:ps -> p:unfull ps |
196 | [] -> [] | 210 | [] -> [] |
197 | forM_ us $ \(is_last,(index,_)) -> do | 211 | forM_ us $ \(is_last,(index,_)) -> do |
212 | nid <- myNodeIdAccordingTo (error "FIXME") | ||
198 | sample <- liftIO $ genBucketSample nid (bucketRange index is_last) | 213 | sample <- liftIO $ genBucketSample nid (bucketRange index is_last) |
199 | $(logDebugS) "bootstrapping" | 214 | $(logDebugS) "bootstrapping" |
200 | $ "BOOTSTRAP sample" | 215 | $ "BOOTSTRAP sample" |
@@ -213,23 +228,13 @@ bootstrap startNodes = do | |||
213 | -- | 228 | -- |
214 | -- This operation do not block. | 229 | -- This operation do not block. |
215 | -- | 230 | -- |
216 | isBootstrapped :: DHT ip Bool | 231 | isBootstrapped :: Eq ip => DHT ip Bool |
217 | isBootstrapped = T.full <$> getTable | 232 | isBootstrapped = T.full <$> getTable |
218 | 233 | ||
219 | {----------------------------------------------------------------------- | 234 | {----------------------------------------------------------------------- |
220 | -- Initialization | 235 | -- Initialization |
221 | -----------------------------------------------------------------------} | 236 | -----------------------------------------------------------------------} |
222 | 237 | ||
223 | -- | Load previous session. (corrupted - exception/ignore ?) | ||
224 | -- | ||
225 | -- This is blocking operation, use | ||
226 | -- 'Control.Concurrent.Async.Lifted.async' if needed. | ||
227 | restore :: Address ip => BS.ByteString -> DHT ip () | ||
228 | restore bs = do | ||
229 | case decode bs of | ||
230 | Right tbl -> restoreTable tbl | ||
231 | Left e -> $(logWarnS) "restore" (Text.pack e) | ||
232 | |||
233 | -- | Serialize current DHT session to byte string. | 238 | -- | Serialize current DHT session to byte string. |
234 | -- | 239 | -- |
235 | -- This is blocking operation, use | 240 | -- This is blocking operation, use |