summaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorjoe <joe@jerkface.net>2017-09-14 20:29:47 -0400
committerjoe <joe@jerkface.net>2017-09-14 20:29:47 -0400
commitf9ca5de790ea7d430b70471f476ad7b1823b8c0a (patch)
tree49a0b2143755e917a0b801bdeefce88716d0e93c /examples
parent7e44a19fae9bc9f90c38641cbc5cf8af9c540ecb (diff)
Switched to the 3-transports (DHT,Onion,Crypto) Tox design.
Diffstat (limited to 'examples')
-rw-r--r--examples/dhtd.hs311
1 files changed, 205 insertions, 106 deletions
diff --git a/examples/dhtd.hs b/examples/dhtd.hs
index 232abd6e..f651ba1b 100644
--- a/examples/dhtd.hs
+++ b/examples/dhtd.hs
@@ -14,6 +14,7 @@
14{-# LANGUAGE ScopedTypeVariables #-} 14{-# LANGUAGE ScopedTypeVariables #-}
15{-# LANGUAGE TupleSections #-} 15{-# LANGUAGE TupleSections #-}
16{-# LANGUAGE TypeFamilies #-} 16{-# LANGUAGE TypeFamilies #-}
17{-# LANGUAGE TypeOperators #-}
17 18
18import Control.Arrow 19import Control.Arrow
19import Control.Concurrent.STM 20import Control.Concurrent.STM
@@ -64,6 +65,10 @@ import Data.Wrapper.PSQ as PSQ (pattern (:->))
64import qualified Data.Wrapper.PSQ as PSQ 65import qualified Data.Wrapper.PSQ as PSQ
65import Data.Ord 66import Data.Ord
66import Data.Time.Clock.POSIX 67import Data.Time.Clock.POSIX
68import qualified DHTTransport as Tox
69import qualified DHTHandlers as Tox
70import qualified OnionHandlers as Tox
71import Data.Typeable
67 72
68showReport :: [(String,String)] -> String 73showReport :: [(String,String)] -> String
69showReport kvs = showColumns $ map (\(x,y)->[x,y]) kvs 74showReport kvs = showColumns $ map (\(x,y)->[x,y]) kvs
@@ -88,7 +93,10 @@ hPutClient h s = hPutStr h ('.' : marshalForClient s)
88hPutClientChunk :: Handle -> String -> IO () 93hPutClientChunk :: Handle -> String -> IO ()
89hPutClientChunk h s = hPutStr h (' ' : marshalForClient s) 94hPutClientChunk h s = hPutStr h (' ' : marshalForClient s)
90 95
91data DHTQuery nid ni = forall addr r tok. Ord addr => DHTQuery 96data DHTQuery nid ni = forall addr r tok.
97 ( Ord addr
98 , Typeable r
99 )=> DHTQuery
92 { qsearch :: Search nid addr tok ni r 100 { qsearch :: Search nid addr tok ni r
93 , qhandler :: ni -> nid -> IO ([ni], [r], tok) 101 , qhandler :: ni -> nid -> IO ([ni], [r], tok)
94 , qshowR :: r -> String 102 , qshowR :: r -> String
@@ -111,13 +119,16 @@ data DHT = forall nid ni. ( Show ni
111 , Show nid 119 , Show nid
112 , Ord nid 120 , Ord nid
113 , Hashable nid 121 , Hashable nid
122 , Typeable ni
123 , S.Serialize nid
114 ) => 124 ) =>
115 DHT 125 DHT
116 { dhtBuckets :: TVar (BucketList ni) 126 { dhtBuckets :: TVar (BucketList ni)
117 , dhtPing :: ni -> IO Bool 127 , dhtPing :: ni -> IO Bool
118 , dhtQuery :: Map.Map String (DHTQuery nid ni) 128 , dhtQuery :: Map.Map String (DHTQuery nid ni)
119 , dhtParseId :: String -> Either String nid 129 , dhtParseId :: String -> Either String nid
120 , dhtSearches :: TVar (Map.Map (String,nid) (DHTSearch nid ni)) 130 , dhtSearches :: TVar (Map.Map (String,nid) (DHTSearch nid ni))
131 , dhtFallbackNodes :: IO [ni]
121 } 132 }
122 133
123nodesFileName :: String -> String 134nodesFileName :: String -> String
@@ -459,140 +470,228 @@ clientSession s@Session{..} sock cnum h = do
459 _ -> cmd0 $ hPutClient h "error." 470 _ -> cmd0 $ hPutClient h "error."
460 471
461 472
462readExternals :: [TVar (BucketList Mainline.NodeInfo)] -> IO [SockAddr] 473readExternals :: (ni -> SockAddr) -> [TVar (BucketList ni)] -> IO [SockAddr]
463readExternals vars = do 474readExternals nodeAddr vars = do
464 as <- atomically $ mapM (fmap (Mainline.nodeAddr . selfNode) . readTVar) vars 475 as <- atomically $ mapM (fmap (nodeAddr . selfNode) . readTVar) vars
465 let unspecified (SockAddrInet _ 0) = True 476 let unspecified (SockAddrInet _ 0) = True
466 unspecified (SockAddrInet6 _ _ (0,0,0,0) _) = True 477 unspecified (SockAddrInet6 _ _ (0,0,0,0) _) = True
467 unspecified _ = False 478 unspecified _ = False
468 -- TODO: Filter to only global addresses? 479 -- TODO: Filter to only global addresses?
469 return $ filter (not . unspecified) as 480 return $ filter (not . unspecified) as
470 481
471defaultPort :: String 482data Options = Options
472defaultPort = "6881" 483 { portbt :: String
484 , porttox :: String
485 , ip6bt :: Bool
486 , ip6tox :: Bool
487 }
488 deriving (Eq,Show)
489
490sensibleDefaults :: Options
491sensibleDefaults = Options
492 { portbt = "6881"
493 , porttox = "33445"
494 , ip6bt = True
495 , ip6tox = True
496 }
497
498-- bt=<port>,tox=<port>
499-- -4
500parseArgs :: [String] -> Options -> Options
501parseArgs [] opts = opts
502parseArgs ("-4":args) opts = parseArgs args opts
503 { ip6bt = False
504 , ip6tox = False }
505parseArgs (arg:args) opts = parseArgs args opts
506 { portbt = fromMaybe (portbt opts) $ Prelude.lookup "bt" ports
507 , porttox = fromMaybe (porttox opts) $ Prelude.lookup "tox" ports }
508 where
509 ports = map ( (dropWhile (==',') *** dropWhile (=='='))
510 . break (=='=') )
511 $ groupBy (const (/= ',')) arg
512
473 513
474main :: IO () 514main :: IO ()
475main = do 515main = do
476 args <- getArgs 516 args <- getArgs
477 p <- case take 2 (dropWhile (/="-p") args) of 517 let opts = parseArgs args sensibleDefaults
478 ["-p",port] | not ("-" `isPrefixOf` port) -> return port 518 print opts
479 ("-p":_) -> error "Port not specified! (-p PORT)"
480 _ -> return defaultPort
481 addr <- getBindAddress p True{- ipv6 -}
482
483 (bt,btR,swarms) <- Mainline.newClient addr
484 519
520 swarms <- Mainline.newSwarmsDatabase
485 -- Restore peer database before forking the listener thread. 521 -- Restore peer database before forking the listener thread.
486 peerdb <- left show <$> tryIOError (L.readFile "bt-peers.dat") 522 peerdb <- left show <$> tryIOError (L.readFile "bt-peers.dat")
487 either (hPutStrLn stderr . ("bt-peers.dat: "++)) 523 either (hPutStrLn stderr . ("bt-peers.dat: "++))
488 (atomically . writeTVar (Mainline.contactInfo swarms)) 524 (atomically . writeTVar (Mainline.contactInfo swarms))
489 (peerdb >>= S.decodeLazy) 525 (peerdb >>= S.decodeLazy)
490 526
491 quitBt <- forkListener (clientNet bt) 527 (quitBt,btdhts,btips) <- case portbt opts of
492 528 "" -> return (return (), Map.empty,return [])
493 let toxport = succ $ fromMaybe 33445 (fromIntegral <$> sockAddrPort addr) 529 p -> do
494 addrTox <- getBindAddress (show toxport) True 530 addr <- getBindAddress p (ip6bt opts)
495 (tox,toxR,toxkeys) <- Tox.newClient addrTox 531 (bt,btR) <- Mainline.newClient swarms addr
496 532 quitBt <- forkListener "bt" (clientNet bt)
497 quitTox <- forkListener (clientNet tox) 533 mainlineSearches <- atomically $ newTVar Map.empty
498 534 let mainlineDHT bkts wantip = DHT
499 mainlineSearches <- atomically $ newTVar Map.empty 535 { dhtBuckets = bkts btR
500 toxSearches <- atomically $ newTVar Map.empty 536 , dhtPing = Mainline.ping bt
501 537 , dhtQuery = Map.fromList
502 let mainlineDHT bkts = DHT 538 [ ("node", DHTQuery (Mainline.nodeSearch bt)
503 { dhtBuckets = bkts btR 539 (\ni -> fmap Mainline.unwrapNodes
504 , dhtPing = Mainline.ping bt 540 . Mainline.findNodeH btR ni
505 , dhtQuery = Map.fromList 541 . flip Mainline.FindNode (Just Want_Both))
506 [ ("node", DHTQuery (Mainline.nodeSearch bt) 542 show
507 (\ni -> fmap Mainline.unwrapNodes 543 (const Nothing))
508 . Mainline.findNodeH btR ni 544 , ("peer", DHTQuery (Mainline.peerSearch bt)
509 . flip Mainline.FindNode (Just Want_Both)) 545 (\ni -> fmap Mainline.unwrapPeers
510 show 546 . Mainline.getPeersH btR swarms ni
511 (const Nothing)) 547 . flip Mainline.GetPeers (Just Want_Both)
512 , ("peer", DHTQuery (Mainline.peerSearch bt) 548 . (read . show)) -- TODO: InfoHash -> NodeId
513 (\ni -> fmap Mainline.unwrapPeers 549 (show . pPrint)
514 . Mainline.getPeersH btR swarms ni 550 (Just . show))
515 . flip Mainline.GetPeers (Just Want_Both) 551 ]
516 . (read . show)) -- TODO: InfoHash -> NodeId 552 , dhtParseId = readEither :: String -> Either String Mainline.NodeId
517 (show . pPrint) 553 , dhtSearches = mainlineSearches
518 (Just . show)) 554 , dhtFallbackNodes = Mainline.bootstrapNodes wantip
519 ] 555 }
520 , dhtParseId = readEither :: String -> Either String Mainline.NodeId 556 dhts = Map.fromList $
521 , dhtSearches = mainlineSearches 557 ("bt4", mainlineDHT Mainline.routing4 Want_IP4)
522 } 558 : if ip6bt opts
523 toxDHT bkts = DHT 559 then [ ("bt6", mainlineDHT Mainline.routing6 Want_IP6) ]
524 { dhtBuckets = bkts toxR 560 else []
525 , dhtPing = Tox.ping tox 561 ips :: IO [SockAddr]
526 , dhtQuery = Map.fromList 562 ips = readExternals Mainline.nodeAddr
527 [ ("node", DHTQuery (Tox.nodeSearch tox) 563 [ Mainline.routing4 btR
528 (\ni -> fmap Tox.unwrapNodes 564 , Mainline.routing6 btR
529 . Tox.getNodesH toxR ni 565 ]
530 . Tox.GetNodes) 566 return (quitBt,dhts,ips)
531 show 567
532 (const Nothing)) 568 keysdb <- Tox.newKeysDatabase
533 ] 569
534 , dhtParseId = readEither :: String -> Either String Tox.NodeId 570 (quitTox,toxdhts,toxips) <- case porttox opts of
535 , dhtSearches = toxSearches 571 "" -> return (return (), Map.empty, return [])
536 } 572 toxport -> do
537 dhts = Map.fromList 573 addrTox <- getBindAddress toxport (ip6tox opts)
538 [ ("bt4", mainlineDHT Mainline.routing4) 574 tox <- Tox.newTox keysdb addrTox
539 , ("bt6", mainlineDHT Mainline.routing6) 575 quitTox <- Tox.forkTox tox
540 , ("tox4", toxDHT Tox.routing4) 576
541 , ("tox6", toxDHT Tox.routing6) 577 toxSearches <- atomically $ newTVar Map.empty
542 ] 578
579 let toxDHT bkts = DHT
580 { dhtBuckets = bkts (Tox.toxRouting tox)
581 , dhtPing = Tox.ping (Tox.toxDHT tox)
582 , dhtQuery = Map.fromList
583 [ ("node", DHTQuery (Tox.nodeSearch $ Tox.toxDHT tox)
584 (\ni -> fmap Tox.unwrapNodes
585 . Tox.getNodesH (Tox.toxRouting tox) ni
586 . Tox.GetNodes)
587 show
588 (const Nothing))
589 ]
590 , dhtParseId = readEither :: String -> Either String Tox.NodeId
591 , dhtSearches = toxSearches
592 , dhtFallbackNodes = return []
593 }
594 dhts = Map.fromList $
595 ("tox4", toxDHT Tox.routing4)
596 : if ip6tox opts
597 then [ ("tox6", toxDHT Tox.routing6) ]
598 else []
599 ips :: IO [SockAddr]
600 ips = readExternals Tox.nodeAddr [ Tox.routing4 $ Tox.toxRouting tox
601 , Tox.routing6 $ Tox.toxRouting tox ]
602 return (quitTox, dhts, ips)
603
604 let dhts = Map.union btdhts toxdhts
543 605
544 waitForSignal <- do 606 waitForSignal <- do
545 signalQuit <- newEmptyMVar 607 signalQuit <- newEmptyMVar
546 let session = clientSession $ Session 608 let session = clientSession $ Session
547 { netname = "bt4" -- initial default DHT 609 { netname = concat $ take 1 $ Map.keys dhts -- initial default DHT
548 , dhts = dhts -- all DHTs 610 , dhts = dhts -- all DHTs
549 , signalQuit = signalQuit 611 , signalQuit = signalQuit
550 , swarms = swarms 612 , swarms = swarms
551 , toxkeys = toxkeys 613 , toxkeys = keysdb
552 , externalAddresses = readExternals 614 , externalAddresses = liftM2 (++) btips toxips
553 [ Mainline.routing4 btR
554 , Mainline.routing6 btR
555 ]
556 } 615 }
557 srv <- streamServer (withSession session) (SockAddrUnix "dht.sock") 616 srv <- streamServer (withSession session) (SockAddrUnix "dht.sock")
558 return $ do 617 return $ do
559 () <- takeMVar signalQuit 618 () <- takeMVar signalQuit
560 quitListening srv 619 quitListening srv
561 620
621
622 forM_ (Map.toList dhts)
623 $ \(netname, dht@DHT { dhtBuckets = bkts
624 , dhtQuery = qrys
625 , dhtPing = ping
626 , dhtFallbackNodes = getBootstrapNodes }) -> do
627 btSaved <- loadNodes netname -- :: IO [Mainline.NodeInfo]
628 putStrLn $ "Loaded "++show (length btSaved)++" nodes for "++netname++"."
629 fallbackNodes <- getBootstrapNodes
630 let isNodesSearch :: ni :~: r -> Search nid addr tok ni r -> Search nid addr tok ni ni
631 isNodesSearch Refl sch = sch
632 fork $ do
633 myThreadId >>= flip labelThread ("bootstrap."++netname)
634 case Map.lookup "node" qrys of
635 Just DHTQuery { qsearch = srch } -> do
636 case eqT of
637 Just witness -> bootstrap (isNodesSearch witness srch) bkts ping btSaved fallbackNodes
638 _ -> error $ "Missing node-search for "++netname++"."
639 saveNodes netname dht
640 Nothing -> return ()
641 return ()
642
643 {-
562 let bkts4 = Mainline.routing4 btR 644 let bkts4 = Mainline.routing4 btR
563 btSaved4 <- loadNodes "bt4" :: IO [Mainline.NodeInfo] 645 (fallbackNodes4,fallbackNodes6) <- case portbt opts of
564 putStrLn $ "Loaded "++show (length btSaved4)++" nodes for bt4." 646 [] -> return ([],[])
565 fallbackNodes4 <- Mainline.bootstrapNodes Want_IP4 647 _ -> do
566 fork $ do 648 btSaved4 <- loadNodes "bt4" :: IO [Mainline.NodeInfo]
567 myThreadId >>= flip labelThread "bootstrap.Mainline4" 649 putStrLn $ "Loaded "++show (length btSaved4)++" nodes for bt4."
568 bootstrap (Mainline.nodeSearch bt) bkts4 (Mainline.ping bt) btSaved4 fallbackNodes4 650 fallbackNodes4 <- Mainline.bootstrapNodes Want_IP4
569 saveNodes "bt4" (dhts Map.! "bt4") 651 fork $ do
570 652 myThreadId >>= flip labelThread "bootstrap.Mainline4"
571 btSaved6 <- loadNodes "bt6" 653 bootstrap (Mainline.nodeSearch bt) bkts4 (Mainline.ping bt) btSaved4 fallbackNodes4
572 putStrLn $ "Loaded "++show (length btSaved6)++" nodes for bt6." 654 saveNodes "bt4" (dhts Map.! "bt4")
573 let bkts6 = Mainline.routing6 btR 655
574 fallbackNodes6 <- Mainline.bootstrapNodes Want_IP6 656 fallbackNodes6 <- case ip6bt opts of
575 fork $ do 657 True -> do
576 myThreadId >>= flip labelThread "bootstrap.Mainline6" 658 btSaved6 <- loadNodes "bt6"
577 bootstrap (Mainline.nodeSearch bt) bkts6 (Mainline.ping bt) btSaved6 fallbackNodes6 659 putStrLn $ "Loaded "++show (length btSaved6)++" nodes for bt6."
578 saveNodes "bt6" (dhts Map.! "bt6") 660 let bkts6 = Mainline.routing6 btR
579 661 fallbackNodes6 <- Mainline.bootstrapNodes Want_IP6
580 toxSaved4 <- loadNodes "tox4" 662 fork $ do
581 putStrLn $ "Loaded "++show (length toxSaved4)++" nodes for tox4" 663 myThreadId >>= flip labelThread "bootstrap.Mainline6"
582 fork $ do 664 bootstrap (Mainline.nodeSearch bt) bkts6 (Mainline.ping bt) btSaved6 fallbackNodes6
583 myThreadId >>= flip labelThread "bootstrap.Tox4" 665 saveNodes "bt6" (dhts Map.! "bt6")
584 bootstrap (Tox.nodeSearch tox) (Tox.routing4 toxR) (Tox.ping tox) toxSaved4 [] 666 return fallbackNodes6
585 saveNodes "tox4" (dhts Map.! "tox4") 667 False -> return []
586 668 return (fallbackNodes4,fallbackNodes6)
587 toxSaved6 <- loadNodes "tox6" 669
588 putStrLn $ "Loaded "++show (length toxSaved6)++" nodes for tox6" 670 (toxSaved4, toxSaved6) <- case porttox opts of
589 fork $ do 671 [] -> return ([],[])
590 myThreadId >>= flip labelThread "bootstrap.Tox6" 672 _ -> do
591 bootstrap (Tox.nodeSearch tox) (Tox.routing6 toxR) (Tox.ping tox) toxSaved6 [] 673 toxSaved4 <- loadNodes "tox4"
592 saveNodes "tox6" (dhts Map.! "tox6") 674 putStrLn $ "Loaded "++show (length toxSaved4)++" nodes for tox4"
675 fork $ do
676 myThreadId >>= flip labelThread "bootstrap.Tox4"
677 bootstrap (Tox.nodeSearch $ Tox.toxDHT tox) (Tox.routing4 (Tox.toxRouting tox)) (Tox.ping $ Tox.toxDHT tox) toxSaved4 []
678 saveNodes "tox4" (dhts Map.! "tox4")
679
680 toxSaved6 <- case ip6tox opts of
681 True -> do
682 toxSaved6 <- loadNodes "tox6"
683 putStrLn $ "Loaded "++show (length toxSaved6)++" nodes for tox6"
684 fork $ do
685 myThreadId >>= flip labelThread "bootstrap.Tox6"
686 bootstrap (Tox.nodeSearch $ Tox.toxDHT tox) (Tox.routing6 (Tox.toxRouting tox)) (Tox.ping $ Tox.toxDHT tox) toxSaved6 []
687 saveNodes "tox6" (dhts Map.! "tox6")
688 return toxSaved6
689 False -> return []
690 return (toxSaved4,toxSaved6)
593 691
594 hPutStr stderr $ showReport $ map (("bootstrap (IPv4)",) . show) fallbackNodes4 692 hPutStr stderr $ showReport $ map (("bootstrap (IPv4)",) . show) fallbackNodes4
595 ++ map (("bootstrap (IPv6)",) . show) fallbackNodes6 693 ++ map (("bootstrap (IPv6)",) . show) fallbackNodes6
694 -}
596 695
597 waitForSignal 696 waitForSignal
598 697