diff options
author | joe <joe@jerkface.net> | 2017-10-12 05:41:09 -0400 |
---|---|---|
committer | joe <joe@jerkface.net> | 2017-10-12 05:41:09 -0400 |
commit | 37a7fa4978f89072d9231bcc9bd0848bb52c676c (patch) | |
tree | 48a2a934e5da1c6754915d5ad27417f604cbfd04 /src/Network/Tox/Onion/Handlers.hs | |
parent | 3024b35b05d7f520666af20ced8d1f3080837bb2 (diff) |
WIP Onion routing.
Diffstat (limited to 'src/Network/Tox/Onion/Handlers.hs')
-rw-r--r-- | src/Network/Tox/Onion/Handlers.hs | 81 |
1 files changed, 72 insertions, 9 deletions
diff --git a/src/Network/Tox/Onion/Handlers.hs b/src/Network/Tox/Onion/Handlers.hs index 08f5cabd..91dd843e 100644 --- a/src/Network/Tox/Onion/Handlers.hs +++ b/src/Network/Tox/Onion/Handlers.hs | |||
@@ -1,6 +1,8 @@ | |||
1 | {-# LANGUAGE PatternSynonyms #-} | 1 | {-# LANGUAGE LambdaCase #-} |
2 | {-# LANGUAGE PatternSynonyms #-} | ||
2 | module Network.Tox.Onion.Handlers where | 3 | module Network.Tox.Onion.Handlers where |
3 | 4 | ||
5 | import Network.Kademlia.Search | ||
4 | import Network.Tox.DHT.Transport | 6 | import Network.Tox.DHT.Transport |
5 | import Network.Tox.DHT.Handlers hiding (Message,Client) | 7 | import Network.Tox.DHT.Handlers hiding (Message,Client) |
6 | import Network.Tox.Onion.Transport | 8 | import Network.Tox.Onion.Transport |
@@ -11,9 +13,11 @@ import qualified Data.Wrapper.PSQ as PSQ | |||
11 | ;import Data.Wrapper.PSQ (PSQ) | 13 | ;import Data.Wrapper.PSQ (PSQ) |
12 | import Crypto.Error.Types (CryptoFailable (..), | 14 | import Crypto.Error.Types (CryptoFailable (..), |
13 | throwCryptoError) | 15 | throwCryptoError) |
16 | import Control.Arrow | ||
14 | 17 | ||
15 | import System.IO | 18 | import System.IO |
16 | import qualified Data.ByteArray as BA | 19 | import qualified Data.ByteArray as BA |
20 | import Data.Function | ||
17 | import Data.Serialize as S | 21 | import Data.Serialize as S |
18 | import qualified Data.Wrapper.PSQInt as Int | 22 | import qualified Data.Wrapper.PSQInt as Int |
19 | import Network.Kademlia | 23 | import Network.Kademlia |
@@ -59,23 +63,27 @@ classify msg = go msg | |||
59 | -- The reason for this 20 second timeout in toxcore is that it gives a reasonable | 63 | -- The reason for this 20 second timeout in toxcore is that it gives a reasonable |
60 | -- time (20 to 40 seconds) for a peer to announce himself while taking in count | 64 | -- time (20 to 40 seconds) for a peer to announce himself while taking in count |
61 | -- all the possible delays with some extra seconds. | 65 | -- all the possible delays with some extra seconds. |
66 | -- dhtd: src/Network/Tox/Onion/Handlers.hs:(67,1)-(101,23): Non-exhaustive patterns in function announceH | ||
62 | announceH :: Routing -> TVar SessionTokens -> TVar AnnouncedKeys -> OnionDestination r -> AnnounceRequest -> IO AnnounceResponse | 67 | announceH :: Routing -> TVar SessionTokens -> TVar AnnouncedKeys -> OnionDestination r -> AnnounceRequest -> IO AnnounceResponse |
63 | announceH routing toks keydb (OnionToOwner naddr retpath) req = do | 68 | announceH routing toks keydb oaddr req = do |
64 | case () of | 69 | case () of |
65 | _ | announcePingId req == zeros32 | 70 | _ | announcePingId req == zeros32 |
66 | -> go False | 71 | -> go False |
67 | 72 | ||
68 | _ -> let Nonce32 bs = announcePingId req | 73 | _ -> let Nonce32 bs = announcePingId req |
69 | tok = fromPaddedByteString 32 bs | 74 | tok = fromPaddedByteString 32 bs |
70 | in checkToken toks naddr tok >>= go | 75 | in checkToken toks (onionNodeInfo oaddr) tok >>= go |
71 | `catch` (\(SomeException e) -> hPutStrLn stderr ("announceH Exception! "++show e) >> throw e) | 76 | `catch` (\(SomeException e) -> hPutStrLn stderr ("announceH Exception! "++show e) >> throw e) |
72 | where | 77 | where |
73 | go withTok = do | 78 | go withTok = do |
79 | let naddr = onionNodeInfo oaddr | ||
74 | ns <- getNodesH routing naddr (GetNodes (announceSeeking req)) | 80 | ns <- getNodesH routing naddr (GetNodes (announceSeeking req)) |
75 | tm <- getPOSIXTime | 81 | tm <- getPOSIXTime |
76 | let storing = (nodeId naddr == announceSeeking req) | 82 | let storing = case oaddr of |
83 | OnionToOwner _ pth -> guard (nodeId naddr == announceSeeking req) >> Just pth | ||
84 | _ -> Nothing | ||
77 | record <- atomically $ do | 85 | record <- atomically $ do |
78 | when (withTok && storing) $ do | 86 | forM_ storing $ \retpath -> when withTok $ do |
79 | let toxpath = AnnouncedRoute naddr{ nodeId = announceKey req } retpath | 87 | let toxpath = AnnouncedRoute naddr{ nodeId = announceKey req } retpath |
80 | -- Note: The following distance calculation assumes that | 88 | -- Note: The following distance calculation assumes that |
81 | -- our nodeid doesn't change and is the same for both | 89 | -- our nodeid doesn't change and is the same for both |
@@ -85,12 +93,12 @@ announceH routing toks keydb (OnionToOwner naddr retpath) req = do | |||
85 | modifyTVar' keydb (insertKey tm (announceSeeking req) toxpath d) | 93 | modifyTVar' keydb (insertKey tm (announceSeeking req) toxpath d) |
86 | ks <- readTVar keydb | 94 | ks <- readTVar keydb |
87 | return $ snd . snd <$> MinMaxPSQ.lookup' (announceSeeking req) (keyAssoc ks) | 95 | return $ snd . snd <$> MinMaxPSQ.lookup' (announceSeeking req) (keyAssoc ks) |
88 | newtok <- if storing | 96 | newtok <- maybe (return $ zeros32) |
89 | then Nonce32 . toPaddedByteString 32 <$> grantToken toks naddr | 97 | (const $ Nonce32 . toPaddedByteString 32 <$> grantToken toks naddr) |
90 | else return $ zeros32 | 98 | storing |
91 | let k = case record of | 99 | let k = case record of |
92 | Nothing -> NotStored newtok | 100 | Nothing -> NotStored newtok |
93 | Just _ | storing -> Acknowledged newtok | 101 | Just _ | isJust storing -> Acknowledged newtok |
94 | Just (AnnouncedRoute ni _) -> SendBackKey $ id2key (nodeId ni) | 102 | Just (AnnouncedRoute ni _) -> SendBackKey $ id2key (nodeId ni) |
95 | let response = AnnounceResponse k ns | 103 | let response = AnnounceResponse k ns |
96 | hPutStrLn stderr $ unwords ["Announce:", show req, "-reply->", show response] | 104 | hPutStrLn stderr $ unwords ["Announce:", show req, "-reply->", show response] |
@@ -151,3 +159,58 @@ handlers net routing toks keydb AnnounceType | |||
151 | $ announceH routing toks keydb | 159 | $ announceH routing toks keydb |
152 | handlers net _ _ keydb _ = Just $ NoReply Right $ dataToRouteH keydb net | 160 | handlers net _ _ keydb _ = Just $ NoReply Right $ dataToRouteH keydb net |
153 | 161 | ||
162 | toxidSearch :: (TransactionId -> OnionDestination r -> STM (OnionDestination r, Int)) | ||
163 | -> Client r | ||
164 | -> Search NodeId (IP, PortNumber) (Maybe Nonce32) NodeInfo PublicKey | ||
165 | toxidSearch getTimeout client = Search | ||
166 | { searchSpace = toxSpace | ||
167 | , searchNodeAddress = nodeIP &&& nodePort | ||
168 | , searchQuery = announce getTimeout client | ||
169 | } | ||
170 | |||
171 | announceSerializer :: (TransactionId -> OnionDestination r -> STM (OnionDestination r, Int)) | ||
172 | -> MethodSerializer | ||
173 | TransactionId | ||
174 | (OnionDestination r) | ||
175 | (OnionMessage Identity) | ||
176 | PacketKind | ||
177 | AnnounceRequest | ||
178 | (Maybe AnnounceResponse) | ||
179 | announceSerializer getTimeout = MethodSerializer | ||
180 | { methodTimeout = getTimeout | ||
181 | , method = AnnounceType | ||
182 | , wrapQuery = \(TransactionId n8 n24) src dst req -> | ||
183 | -- :: tid -> addr -> addr -> a -> OnionMessage Identity | ||
184 | OnionAnnounce $ Assym | ||
185 | { -- The public key is our real long term public key if we want to | ||
186 | -- announce ourselves, a temporary one if we are searching for | ||
187 | -- friends. | ||
188 | senderKey = fromJust $ onionKey src -- TODO: FIXME: this should be a temporary alias key | ||
189 | , assymNonce = n24 | ||
190 | , assymData = Identity (req, n8) | ||
191 | } | ||
192 | , unwrapResponse = \case -- :: OnionMessage Identity -> b | ||
193 | OnionAnnounceResponse _ _ resp -> Just $ runIdentity resp | ||
194 | _ -> Nothing | ||
195 | } | ||
196 | |||
197 | unwrapAnnounceResponse :: AnnounceResponse -> ([NodeInfo], [PublicKey], Maybe Nonce32) | ||
198 | unwrapAnnounceResponse (AnnounceResponse is_stored (SendNodes ns)) | ||
199 | = case is_stored of | ||
200 | NotStored n32 -> (ns, [], Just n32) | ||
201 | SendBackKey k -> (ns, [k], Nothing) | ||
202 | Acknowledged n32 -> (ns, [], Just n32) | ||
203 | |||
204 | announce :: (TransactionId -> OnionDestination r -> STM (OnionDestination r, Int)) | ||
205 | -> Client r | ||
206 | -> NodeId | ||
207 | -> NodeInfo | ||
208 | -> IO (Maybe ([NodeInfo],[PublicKey],Maybe Nonce32)) | ||
209 | announce getTimeout client nid ni = | ||
210 | -- Four tries and then we tap out. | ||
211 | flip fix 4 $ \loop n -> do | ||
212 | let oaddr = OnionDestination ni Nothing | ||
213 | mb <- QR.sendQuery client (announceSerializer getTimeout) (AnnounceRequest zeros32 nid zeroID) oaddr | ||
214 | maybe (if n>0 then loop $! n - 1 else return Nothing) | ||
215 | (return . Just . unwrapAnnounceResponse) | ||
216 | $ join mb | ||