summaryrefslogtreecommitdiff
path: root/dht/HandshakeCache.hs
diff options
context:
space:
mode:
authorJames Crayne <jim.crayne@gmail.com>2019-09-28 13:43:29 -0400
committerJoe Crayne <joe@jerkface.net>2020-01-01 19:27:53 -0500
commit11987749fc6e6d3e53ea737d46d5ab13a16faeb8 (patch)
tree5716463275c2d3e902889db619908ded2a73971c /dht/HandshakeCache.hs
parentadd2c76bced51fde5e9917e7449ef52be70faf87 (diff)
Factor out some new libraries
word64-map: Data.Word64Map network-addr: Network.Address tox-crypto: Crypto.Tox lifted-concurrent: Control.Concurrent.Lifted.Instrument Control.Concurrent.Async.Lifted.Instrument psq-wrap: Data.Wrapper.PSQInt Data.Wrapper.PSQ minmax-psq: Data.MinMaxPSQ tasks: Control.Concurrent.Tasks kad: Network.Kademlia Network.Kademlia.Bootstrap Network.Kademlia.Routing Network.Kademlia.CommonAPI Network.Kademlia.Persistence Network.Kademlia.Search
Diffstat (limited to 'dht/HandshakeCache.hs')
-rw-r--r--dht/HandshakeCache.hs132
1 files changed, 132 insertions, 0 deletions
diff --git a/dht/HandshakeCache.hs b/dht/HandshakeCache.hs
new file mode 100644
index 00000000..61735e8a
--- /dev/null
+++ b/dht/HandshakeCache.hs
@@ -0,0 +1,132 @@
1module HandshakeCache where
2
3import Control.Concurrent.STM
4import Control.Monad
5import Data.Functor.Identity
6import qualified Data.Map.Strict as Map
7 ;import Data.Map.Strict (Map)
8import Data.Time.Clock.POSIX
9import Network.Socket
10import Data.Bool
11
12import Crypto.Hash
13
14import Crypto.Tox
15import qualified Data.MinMaxPSQ as MM
16 ;import Data.MinMaxPSQ (MinMaxPSQ')
17import DPut
18import DebugTag
19import Network.Tox.Crypto.Transport (Handshake, HandshakeData (..))
20import Network.Tox.DHT.Handlers (createCookieSTM)
21import Network.Tox.DHT.Transport (Cookie (..), CookieData (..), NodeInfo,
22 key2id, nodeInfo)
23import Network.Tox.Handshake
24
25data HandshakeCache = HandshakeCache
26 { -- Note that currently we are storing sent handshakes keyed by the
27 -- locally issued cookie nonce.
28 hscTable :: TVar (MinMaxPSQ' Nonce24 POSIXTime (SecretKey,HandshakeData))
29 , hscSend :: SockAddr -> Handshake Encrypted -> IO ()
30 , hscCrypto :: TransportCrypto
31 , hscPendingCookies :: TVar (Map (PublicKey,PublicKey) ())
32 }
33
34
35newHandshakeCache :: TransportCrypto -> (SockAddr -> Handshake Encrypted -> IO ()) -> IO HandshakeCache
36newHandshakeCache crypto send = atomically $ do
37 tbl <- newTVar MM.empty
38 pcs <- newTVar Map.empty
39 return HandshakeCache
40 { hscTable = tbl
41 , hscSend = send
42 , hscCrypto = crypto
43 , hscPendingCookies = pcs
44 }
45
46getSentHandshake :: HandshakeCache
47 -> SecretKey
48 -> SockAddr
49 -> Cookie Identity -- locally issued
50 -> Cookie Encrypted -- remotely issued
51 -> IO (Maybe (SecretKey, HandshakeData))
52getSentHandshake hscache me their_addr (Cookie n24 (Identity cd)) ecookie = do
53 now <- getPOSIXTime
54 io <- atomically $ do
55 m <- checkExpiry now . MM.lookup' n24 <$> readTVar (hscTable hscache)
56 case m of
57 Just s -> return $ return $ Just s
58 Nothing -> do
59 let them = longTermKey cd
60 case nodeInfo (key2id $ dhtKey cd) their_addr of
61 Left _ -> return $ return Nothing -- Non-internet address.
62 Right their_node -> do
63 (s,hs) <- cacheHandshakeSTM hscache me them their_node ecookie now
64 return $ do
65 dput XNetCrypto $ "getSentHandshake sending new handshake."
66 hscSend hscache their_addr hs
67 return $ Just s
68 r <- io
69 dput XNetCrypto $ "getSentHandshake me="++show (key2id $ toPublic me)++" their_addr="++show their_addr++" --> " ++ show r
70 return r
71
72
73checkExpiry :: POSIXTime -> Maybe (POSIXTime,r) -> Maybe r
74checkExpiry now m = do
75 (tm,s) <- m
76 guard $ tm + 5 {- seconds -} > now
77 return s
78
79hashCookie :: HashAlgorithm a => Cookie Encrypted -> Digest a
80hashCookie (Cookie n24 encrypted)
81 = hashFinalize $ hashUpdate (hashUpdate hashInit n24) encrypted
82
83cacheHandshakeSTM :: HandshakeCache
84 -> SecretKey -- ^ my ToxID key
85 -> PublicKey -- ^ them
86 -> NodeInfo -- ^ their DHT node
87 -> Cookie Encrypted -- ^ issued to me by them
88 -> POSIXTime -- ^ current time
89 -> STM ((SecretKey,HandshakeData), Handshake Encrypted)
90cacheHandshakeSTM hscache me them their_node ecookie timestamp = do
91 newsession <- transportNewKey (hscCrypto hscache)
92 freshCookie <- createCookieSTM timestamp (hscCrypto hscache) their_node them
93 n24 <- transportNewNonce (hscCrypto hscache)
94 let hsdata = HandshakeData
95 { baseNonce = n24
96 , sessionKey = toPublic newsession
97 , cookieHash = hashCookie ecookie
98 , otherCookie = freshCookie
99 }
100 hs <- encodeHandshake timestamp (hscCrypto hscache) me them ecookie hsdata
101 let Cookie cnonce _ = freshCookie
102 modifyTVar' (hscTable hscache) $ MM.insertTake' 20 cnonce (newsession,hsdata) timestamp
103 return ((newsession,hsdata),hs)
104
105cacheHandshake :: HandshakeCache
106 -> SecretKey
107 -> PublicKey
108 -> NodeInfo
109 -> Cookie Encrypted
110 -> IO (Handshake Encrypted)
111cacheHandshake hscache me them their_node ecookie = do
112 timestamp <- getPOSIXTime
113 dput XNetCrypto $ "cacheHandshake " ++ show (key2id them,ecookie)
114 atomically $ snd <$> cacheHandshakeSTM hscache me them their_node ecookie timestamp
115
116haveCachedCookie :: HandshakeCache
117 -> PublicKey
118 -> PublicKey
119 -> STM Bool
120haveCachedCookie hscache me them = do
121 m <- Map.lookup (me,them) <$> readTVar (hscPendingCookies hscache)
122 return $ maybe True (const False) m
123
124
125setPendingCookie :: HandshakeCache
126 -> PublicKey
127 -> PublicKey
128 -> Bool
129 -> STM ()
130setPendingCookie hscache me them pending = do
131 modifyTVar' (hscPendingCookies hscache) $ Map.alter (const $ bool Nothing (Just ()) pending)
132 (me,them)