summaryrefslogtreecommitdiff
path: root/dht/src/Network
diff options
context:
space:
mode:
authorJoe Crayne <joe@jerkface.net>2019-12-07 22:38:40 -0500
committerJoe Crayne <joe@jerkface.net>2020-01-01 23:25:05 -0500
commit6326b4f674b4093c28a8760e53f5a81ad5747a50 (patch)
tree1372e54ca19d800a772318a5b5e5f2265de7748b /dht/src/Network
parentaf60f0551f7ed51669422234ad0916c71ba42e71 (diff)
Network.Tox.RelayPinger
Diffstat (limited to 'dht/src/Network')
-rw-r--r--dht/src/Network/Tox/RelayPinger.hs99
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 #-}
3module Network.Tox.RelayPinger where
4
5import Announcer
6import Control.Arrow
7import Control.Concurrent.STM
8import Control.Concurrent.ThreadUtil
9import Control.Monad
10import Data.Ord
11import qualified Data.Serialize as S
12import Data.Time.Clock (NominalDiffTime)
13import Data.Time.Clock.POSIX
14import qualified Data.Wrapper.PSQ as PSQ
15 ;import Data.Wrapper.PSQ (pattern (:->), PSQ)
16import Network.Kademlia.Routing
17import Network.QueryResponse
18import Network.Tox.TCP as TCP
19
20data RelayPriority = RelayPriority
21 { tcpPortRank :: Int
22 , xorDeltaDistance :: NodeId
23 }
24 deriving (Eq,Ord)
25
26data 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
34forkRelayPinger :: KademliaSpace NodeId NodeInfo -> RelayClient -> IO RelayPinger
35forkRelayPinger 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
47pinginterval :: NominalDiffTime
48pinginterval = 120.0 -- 2 minutes
49
50
51rankTCPPort :: NodeInfo -> Int
52rankTCPPort NodeInfo{tcpPort = 443} = 1
53rankTCPPort NodeInfo{tcpPort = 80} = 1
54rankTCPPort NodeInfo{tcpPort = 3389} = 2
55rankTCPPort _ = 3
56
57addRelay :: RelayPinger -> TCP.NodeInfo -> STM ()
58addRelay (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
75delRelay :: RelayPinger -> TCP.NodeInfo -> STM ()
76delRelay (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
84bumpRelay :: RelayPinger -> TCP.NodeInfo -> STM ()
85bumpRelay 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
98currentRelays :: RelayPinger -> STM (Int,[TCP.NodeInfo])
99currentRelays rp = second PSQ.keys <$> readTVar (relayQueue rp)