summaryrefslogtreecommitdiff
path: root/examples/dhtd.hs
diff options
context:
space:
mode:
Diffstat (limited to 'examples/dhtd.hs')
-rw-r--r--examples/dhtd.hs118
1 files changed, 95 insertions, 23 deletions
diff --git a/examples/dhtd.hs b/examples/dhtd.hs
index bd9b9e09..f9dce3bc 100644
--- a/examples/dhtd.hs
+++ b/examples/dhtd.hs
@@ -112,10 +112,11 @@ data DHTQuery nid ni = forall addr r tok.
112 , Typeable tok 112 , Typeable tok
113 , Typeable ni 113 , Typeable ni
114 ) => DHTQuery 114 ) => DHTQuery
115 { qsearch :: Search nid addr tok ni r 115 { qsearch :: Search nid addr tok ni r
116 , qhandler :: ni -> nid -> IO ([ni], [r], tok) -- ^ Invoked on local node, when there is no query destination. 116 , qhandler :: ni -> nid -> IO ([ni], [r], tok) -- ^ Invoked on local node, when there is no query destination.
117 , qshowR :: r -> String 117 , qshowR :: r -> String
118 , qshowTok :: tok -> Maybe String 118 , qshowTok :: tok -> Maybe String
119 , qresultAddr :: r -> nid
119 } 120 }
120 121
121data DHTAnnouncable = forall dta tok ni r. 122data DHTAnnouncable = forall dta tok ni r.
@@ -129,6 +130,7 @@ data DHTAnnouncable = forall dta tok ni r.
129 , announceParseToken :: dta -> String -> Either String tok 130 , announceParseToken :: dta -> String -> Either String tok
130 , announceParseAddress :: String -> Either String ni 131 , announceParseAddress :: String -> Either String ni
131 , announceSendData :: dta -> tok -> Maybe ni -> IO (Maybe r) 132 , announceSendData :: dta -> tok -> Maybe ni -> IO (Maybe r)
133 , announceInterval :: POSIXTime
132 } 134 }
133 135
134data DHTLink = forall status linkid params. 136data DHTLink = forall status linkid params.
@@ -616,15 +618,19 @@ clientSession s@Session{..} sock cnum h = do
616 matchingResult _ _ = liftA3 (\a b c -> (a,b,c)) eqT eqT eqT 618 matchingResult _ _ = liftA3 (\a b c -> (a,b,c)) eqT eqT eqT
617 mameth = do 619 mameth = do
618 DHTAnnouncable { announceSendData 620 DHTAnnouncable { announceSendData
619 , announceParseData } <- a 621 , announceParseData
620 DHTQuery { qsearch } <- q 622 , announceInterval } <- a
623 DHTQuery { qsearch
624 , qresultAddr } <- q
621 (Refl,Refl,nr@Refl) <- matchingResult qsearch announceSendData 625 (Refl,Refl,nr@Refl) <- matchingResult qsearch announceSendData
622 dta <- either (const Nothing) Just $ announceParseData dtastr 626 dta <- either (const Nothing) Just $ announceParseData dtastr
623 return $ do 627 return $ do
624 akey <- atomically $ packAnnounceKey announcer (method ++ ":" ++ dtastr) 628 akey <- atomically $ packAnnounceKey announcer (method ++ ":" ++ dtastr)
625 doit op nr announcer 629 doit op nr announcer
626 akey 630 akey
627 (AnnounceMethod qsearch announceSendData) 631 (AnnounceMethod qsearch announceSendData dhtBuckets
632 (qresultAddr dta)
633 announceInterval)
628 dta 634 dta
629 fromMaybe (hPutClient h "error.") mameth 635 fromMaybe (hPutClient h "error.") mameth
630 636
@@ -824,19 +830,25 @@ main = do
824 , pingShowResult = show 830 , pingShowResult = show
825 } 831 }
826 , dhtQuery = Map.fromList 832 , dhtQuery = Map.fromList
827 [ ("node", DHTQuery (Mainline.nodeSearch bt) 833 [ ("node", DHTQuery
828 (\ni -> fmap Mainline.unwrapNodes 834 { qsearch = (Mainline.nodeSearch bt)
835 , qhandler = (\ni -> fmap Mainline.unwrapNodes
829 . Mainline.findNodeH btR ni 836 . Mainline.findNodeH btR ni
830 . flip Mainline.FindNode (Just Want_Both)) 837 . flip Mainline.FindNode (Just Want_Both))
831 show 838 , qshowR = show
832 (const Nothing)) 839 , qshowTok = (const Nothing)
833 , ("peer", DHTQuery (Mainline.peerSearch bt) 840 , qresultAddr = Mainline.nodeId
834 (\ni -> fmap Mainline.unwrapPeers 841 })
842 , ("peer", DHTQuery
843 { qsearch = (Mainline.peerSearch bt)
844 , qhandler = (\ni -> fmap Mainline.unwrapPeers
835 . Mainline.getPeersH btR swarms ni 845 . Mainline.getPeersH btR swarms ni
836 . flip Mainline.GetPeers (Just Want_Both) 846 . flip Mainline.GetPeers (Just Want_Both)
837 . (read . show)) -- TODO: InfoHash -> NodeId 847 . (read . show)) -- TODO: InfoHash -> NodeId
838 (show . pPrint) 848 , qshowR = (show . pPrint)
839 (Just . show)) 849 , qshowTok = (Just . show)
850 , qresultAddr = (read . show) -- TODO: InfoHash -> NodeId
851 })
840 ] 852 ]
841 , dhtParseId = readEither :: String -> Either String Mainline.NodeId 853 , dhtParseId = readEither :: String -> Either String Mainline.NodeId
842 , dhtSearches = mainlineSearches 854 , dhtSearches = mainlineSearches
@@ -851,6 +863,7 @@ main = do
851 , announceParseAddress = readEither 863 , announceParseAddress = readEither
852 , announceParseData = readEither 864 , announceParseData = readEither
853 , announceParseToken = const $ readEither 865 , announceParseToken = const $ readEither
866 , announceInterval = 60 -- TODO: Is one minute good?
854 }) 867 })
855 , ("port", DHTAnnouncable { announceParseData = readEither 868 , ("port", DHTAnnouncable { announceParseData = readEither
856 , announceParseToken = \_ _ -> return () 869 , announceParseToken = \_ _ -> return ()
@@ -859,6 +872,8 @@ main = do
859 Nothing -> do atomically $ writeTVar peerPort (dta :: PortNumber) 872 Nothing -> do atomically $ writeTVar peerPort (dta :: PortNumber)
860 return $ Just dta 873 return $ Just dta
861 Just _ -> return Nothing 874 Just _ -> return Nothing
875 , announceInterval = 0 -- TODO: The "port" setting should probably
876 -- be a command rather than an announcement.
862 })] 877 })]
863 878
864 , dhtLinks = Map.fromList 879 , dhtLinks = Map.fromList
@@ -908,16 +923,20 @@ main = do
908 , pingShowResult = show 923 , pingShowResult = show
909 })] 924 })]
910 , dhtQuery = Map.fromList 925 , dhtQuery = Map.fromList
911 [ ("node", DHTQuery (Tox.nodeSearch $ Tox.toxDHT tox) 926 [ ("node", DHTQuery
912 (\ni -> fmap Tox.unwrapNodes 927 { qsearch = (Tox.nodeSearch $ Tox.toxDHT tox)
928 , qhandler = (\ni -> fmap Tox.unwrapNodes
913 . Tox.getNodesH (Tox.toxRouting tox) ni 929 . Tox.getNodesH (Tox.toxRouting tox) ni
914 . Tox.GetNodes) 930 . Tox.GetNodes)
915 show -- NodeInfo 931 , qshowR = show -- NodeInfo
916 (const Nothing)) 932 , qshowTok = (const Nothing)
917 , ("toxid", DHTQuery (Tox.toxidSearch (Tox.onionTimeout tox) 933 , qresultAddr = Tox.nodeId
934 })
935 , ("toxid", DHTQuery
936 { qsearch = (Tox.toxidSearch (Tox.onionTimeout tox)
918 (Tox.toxCryptoKeys tox) 937 (Tox.toxCryptoKeys tox)
919 (Tox.toxOnion tox)) 938 (Tox.toxOnion tox))
920 -- qhandler :: ni -> nid -> IO ([ni], [r], tok) 939 , qhandler = -- qhandler :: ni -> nid -> IO ([ni], [r], tok)
921 (\ni nid -> 940 (\ni nid ->
922 Tox.unwrapAnnounceResponse Nothing 941 Tox.unwrapAnnounceResponse Nothing
923 <$> clientAddress (Tox.toxDHT tox) Nothing 942 <$> clientAddress (Tox.toxDHT tox) Nothing
@@ -926,8 +945,10 @@ main = do
926 (Tox.toxAnnouncedKeys tox) 945 (Tox.toxAnnouncedKeys tox)
927 (Tox.OnionDestination Tox.SearchingAlias ni Nothing) 946 (Tox.OnionDestination Tox.SearchingAlias ni Nothing)
928 (Tox.AnnounceRequest zeros32 nid Tox.zeroID)) 947 (Tox.AnnounceRequest zeros32 nid Tox.zeroID))
929 show -- PublicKey 948 , qshowR = show -- Rendezvous
930 (fmap show)) 949 , qshowTok = (fmap show) -- Nonce32
950 , qresultAddr = Tox.key2id . Tox.rendezvousKey
951 })
931 ] 952 ]
932 , dhtParseId = readEither :: String -> Either String Tox.NodeId 953 , dhtParseId = readEither :: String -> Either String Tox.NodeId
933 , dhtSearches = toxSearches 954 , dhtSearches = toxSearches
@@ -946,6 +967,21 @@ main = do
946 , announceParseAddress = readEither 967 , announceParseAddress = readEither
947 , announceParseToken = const $ readEither 968 , announceParseToken = const $ readEither
948 , announceParseData = fmap Tox.id2key . readEither 969 , announceParseData = fmap Tox.id2key . readEither
970
971 -- For peers we are announcing ourselves to, if we are not
972 -- announced to them toxcore tries every 3 seconds to
973 -- announce ourselves to them until they return that we
974 -- have announced ourselves to, then toxcore sends an
975 -- announce request packet every 15 seconds to see if we
976 -- are still announced and re announce ourselves at the
977 -- same time. The timeout of 15 seconds means a `ping_id`
978 -- received in the last packet will not have had time to
979 -- expire (20 second minimum timeout) before it is resent
980 -- 15 seconds later. Toxcore sends every announce packet
981 -- with the `ping_id` previously received from that peer
982 -- with the same path (if possible).
983 , announceInterval = 15
984
949 }) 985 })
950 , ("dhtkey", DHTAnnouncable { announceSendData = \pubkey () -> \case 986 , ("dhtkey", DHTAnnouncable { announceSendData = \pubkey () -> \case
951 Just addr -> do 987 Just addr -> do
@@ -959,6 +995,23 @@ main = do
959 , announceParseAddress = readEither 995 , announceParseAddress = readEither
960 , announceParseToken = \_ _ -> return () 996 , announceParseToken = \_ _ -> return ()
961 , announceParseData = fmap Tox.id2key . readEither 997 , announceParseData = fmap Tox.id2key . readEither
998
999 -- We send this packet every 30 seconds if there is more
1000 -- than one peer (in the 8) that says they our friend is
1001 -- announced on them. This packet can also be sent through
1002 -- the DHT module as a DHT request packet (see DHT) if we
1003 -- know the DHT public key of the friend and are looking
1004 -- for them in the DHT but have not connected to them yet.
1005 -- 30 second is a reasonable timeout to not flood the
1006 -- network with too many packets while making sure the
1007 -- other will eventually receive the packet. Since packets
1008 -- are sent through every peer that knows the friend,
1009 -- resending it right away without waiting has a high
1010 -- likelihood of failure as the chances of packet loss
1011 -- happening to all (up to to 8) packets sent is low.
1012 --
1013 , announceInterval = 30
1014
962 }) 1015 })
963 , ("friend", DHTAnnouncable { announceSendData = \pubkey nospam -> \case 1016 , ("friend", DHTAnnouncable { announceSendData = \pubkey nospam -> \case
964 Just addr -> do 1017 Just addr -> do
@@ -979,6 +1032,25 @@ main = do
979 (Tox.verifyChecksum pubkey) 1032 (Tox.verifyChecksum pubkey)
980 chksum 1033 chksum
981 return nospam 1034 return nospam
1035
1036 -- Friend requests are sent with exponentially increasing
1037 -- interval of 2 seconds, 4 seconds, 8 seconds, etc... in
1038 -- toxcore. This is so friend requests get resent but
1039 -- eventually get resent in intervals that are so big that
1040 -- they essentially expire. The sender has no way of
1041 -- knowing if a peer refuses a friend requests which is why
1042 -- friend requests need to expire in some way. Note that
1043 -- the interval is the minimum timeout, if toxcore cannot
1044 -- send that friend request it will try again until it
1045 -- manages to send it. One reason for not being able to
1046 -- send the friend request would be that the onion has not
1047 -- found the friend in the onion and so cannot send an
1048 -- onion data packet to them.
1049 --
1050 -- TODO: Support exponential backoff behavior. For now, setting
1051 -- interval to 8 seconds.
1052
1053 , announceInterval = 8
982 })] 1054 })]
983 , dhtLinks = Map.fromList 1055 , dhtLinks = Map.fromList
984 [ {- TODO -} 1056 [ {- TODO -}