diff options
Diffstat (limited to 'examples/dhtd.hs')
-rw-r--r-- | examples/dhtd.hs | 118 |
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 | ||
121 | data DHTAnnouncable = forall dta tok ni r. | 122 | data 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 | ||
134 | data DHTLink = forall status linkid params. | 136 | data 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 -} |