diff options
Diffstat (limited to 'dht/src/Network/Tox')
-rw-r--r-- | dht/src/Network/Tox/RelayPinger.hs | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/dht/src/Network/Tox/RelayPinger.hs b/dht/src/Network/Tox/RelayPinger.hs new file mode 100644 index 00000000..00c6f65a --- /dev/null +++ b/dht/src/Network/Tox/RelayPinger.hs | |||
@@ -0,0 +1,99 @@ | |||
1 | {-# LANGUAGE NamedFieldPuns #-} | ||
2 | {-# LANGUAGE PatternSynonyms #-} | ||
3 | module Network.Tox.RelayPinger where | ||
4 | |||
5 | import Announcer | ||
6 | import Control.Arrow | ||
7 | import Control.Concurrent.STM | ||
8 | import Control.Concurrent.ThreadUtil | ||
9 | import Control.Monad | ||
10 | import Data.Ord | ||
11 | import qualified Data.Serialize as S | ||
12 | import Data.Time.Clock (NominalDiffTime) | ||
13 | import Data.Time.Clock.POSIX | ||
14 | import qualified Data.Wrapper.PSQ as PSQ | ||
15 | ;import Data.Wrapper.PSQ (pattern (:->), PSQ) | ||
16 | import Network.Kademlia.Routing | ||
17 | import Network.QueryResponse | ||
18 | import Network.Tox.TCP as TCP | ||
19 | |||
20 | data RelayPriority = RelayPriority | ||
21 | { tcpPortRank :: Int | ||
22 | , xorDeltaDistance :: NodeId | ||
23 | } | ||
24 | deriving (Eq,Ord) | ||
25 | |||
26 | data RelayPinger = RelayPinger | ||
27 | { relayAnnouncer :: Announcer | ||
28 | , relayKademliaSpace :: KademliaSpace NodeId NodeInfo | ||
29 | , relayClient :: RelayClient | ||
30 | , relayQueue :: TVar (Int, PSQ NodeInfo (Down RelayPriority)) | ||
31 | , relaySelf :: NodeId | ||
32 | } | ||
33 | |||
34 | forkRelayPinger :: KademliaSpace NodeId NodeInfo -> RelayClient -> IO RelayPinger | ||
35 | forkRelayPinger kad cli = do | ||
36 | a <- forkAnnouncer | ||
37 | q <- newTVarIO (0,PSQ.empty) | ||
38 | self <- kademliaLocation kad <$> clientAddress cli Nothing | ||
39 | return RelayPinger | ||
40 | { relayAnnouncer = a | ||
41 | , relayKademliaSpace = kad | ||
42 | , relayClient = cli | ||
43 | , relayQueue = q | ||
44 | , relaySelf = self | ||
45 | } | ||
46 | |||
47 | pinginterval :: NominalDiffTime | ||
48 | pinginterval = 120.0 -- 2 minutes | ||
49 | |||
50 | |||
51 | rankTCPPort :: NodeInfo -> Int | ||
52 | rankTCPPort NodeInfo{tcpPort = 443} = 1 | ||
53 | rankTCPPort NodeInfo{tcpPort = 80} = 1 | ||
54 | rankTCPPort NodeInfo{tcpPort = 3389} = 2 | ||
55 | rankTCPPort _ = 3 | ||
56 | |||
57 | addRelay :: RelayPinger -> TCP.NodeInfo -> STM () | ||
58 | addRelay (RelayPinger a kad cli que self) ni = do | ||
59 | let nid = kademliaLocation kad ni | ||
60 | nidk = decodeAnnounceKey a $ S.encode nid | ||
61 | pingit = ScheduledItem $ \a nidk tm -> do | ||
62 | scheduleRel a nidk pingit pinginterval -- Reschedule the next ping. | ||
63 | return $ do | ||
64 | _ <- tcpPing cli ni | ||
65 | -- TODO: Remove after ping timeout? | ||
66 | return () | ||
67 | modifyTVar' que $ \(n,q) -> | ||
68 | ( (,) $! (if PSQ.member ni q then n else n+1) ) | ||
69 | $ PSQ.insert | ||
70 | ni | ||
71 | (Down $ RelayPriority (rankTCPPort ni) (kademliaXor kad self nid)) | ||
72 | q | ||
73 | scheduleRel a nidk pingit pinginterval | ||
74 | |||
75 | delRelay :: RelayPinger -> TCP.NodeInfo -> STM () | ||
76 | delRelay (RelayPinger a kad _ que _) ni = do | ||
77 | let nid = kademliaLocation kad ni | ||
78 | nidk = decodeAnnounceKey a $ S.encode nid | ||
79 | (n,q) <- readTVar que | ||
80 | writeTVar que $ ( (,) $! (if PSQ.member ni q then n - 1 else n) ) | ||
81 | $ PSQ.delete ni q | ||
82 | unschedule a nidk | ||
83 | |||
84 | bumpRelay :: RelayPinger -> TCP.NodeInfo -> STM () | ||
85 | bumpRelay rp@(RelayPinger a kad cli que self) ni = do | ||
86 | let nid = kademliaLocation kad ni | ||
87 | (cnt,q) <- readTVar que | ||
88 | if cnt < 4 | ||
89 | then addRelay rp ni | ||
90 | else case PSQ.minView q of | ||
91 | Nothing -> addRelay rp ni | ||
92 | Just (r :-> Down p, q') | ||
93 | | let pnew = RelayPriority (rankTCPPort ni) (kademliaXor kad self nid) | ||
94 | , pnew < p | ||
95 | -> delRelay rp r >> addRelay rp ni | ||
96 | _ -> return () | ||
97 | |||
98 | currentRelays :: RelayPinger -> STM (Int,[TCP.NodeInfo]) | ||
99 | currentRelays rp = second PSQ.keys <$> readTVar (relayQueue rp) | ||