summaryrefslogtreecommitdiff
path: root/src/Network
diff options
context:
space:
mode:
Diffstat (limited to 'src/Network')
-rw-r--r--src/Network/Tox/Onion/Handlers.hs148
1 files changed, 148 insertions, 0 deletions
diff --git a/src/Network/Tox/Onion/Handlers.hs b/src/Network/Tox/Onion/Handlers.hs
new file mode 100644
index 00000000..f02bac98
--- /dev/null
+++ b/src/Network/Tox/Onion/Handlers.hs
@@ -0,0 +1,148 @@
1{-# LANGUAGE PatternSynonyms #-}
2module Network.Tox.Onion.Handlers where
3
4import Network.Tox.DHT.Transport
5import Network.Tox.DHT.Handlers hiding (Message,Client)
6import Network.Tox.Onion.Transport
7import Network.QueryResponse as QR hiding (Client)
8import qualified Network.QueryResponse as QR (Client)
9import Crypto.Tox
10import qualified Data.Wrapper.PSQ as PSQ
11 ;import Data.Wrapper.PSQ (PSQ)
12import Crypto.Error.Types (CryptoFailable (..),
13 throwCryptoError)
14
15import System.IO
16import qualified Data.ByteArray as BA
17import Data.Serialize as S
18import qualified Data.Wrapper.PSQInt as Int
19import Network.Kademlia
20import Network.Address (WantIP (..), ipFamily, testIdBit)
21import qualified Network.DHT.Routing as R
22import Control.TriadCommittee
23import qualified Data.MinMaxPSQ as MinMaxPSQ
24 ;import Data.MinMaxPSQ (MinMaxPSQ')
25import Network.BitTorrent.DHT.Token as Token
26
27import Control.Exception hiding (Handler)
28import Control.Monad
29import Control.Concurrent.STM
30import Data.Time.Clock.POSIX (POSIXTime, getPOSIXTime)
31import Network.Socket
32import Data.IP
33import Data.Maybe
34import Data.Bits
35import Data.Ord
36import Data.Functor.Identity
37
38type Client = QR.Client String PacketKind TransactionId OnionToOwner Message
39type Message = OnionMessage Identity
40
41classify :: Message -> MessageClass String PacketKind TransactionId
42classify msg = go msg
43 where
44 go (OnionAnnounce announce) = IsQuery AnnounceType
45 $ TransactionId (snd $ runIdentity $ assymData announce)
46 (assymNonce announce)
47 go (OnionAnnounceResponse n8 n24 resp) = IsResponse (TransactionId n8 n24)
48 go (OnionToRoute {}) = IsQuery DataRequestType (TransactionId (Nonce8 0) (Nonce24 zeros24))
49 go (OnionToRouteResponse {}) = IsResponse (TransactionId (Nonce8 0) (Nonce24 zeros24))
50
51-- Toxcore generates `ping_id`s by taking a 32 byte sha hash of the current time,
52-- some secret bytes generated when the instance is created, the current time
53-- divided by a 20 second timeout, the public key of the requester and the source
54-- ip/port that the packet was received from. Since the ip/port that the packet
55-- was received from is in the `ping_id`, the announce packets being sent with a
56-- ping id must be sent using the same path as the packet that we received the
57-- `ping_id` from or announcing will fail.
58--
59-- 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
61-- all the possible delays with some extra seconds.
62announceH :: Routing -> TVar SessionTokens -> TVar AnnouncedKeys -> OnionToOwner -> AnnounceRequest -> IO AnnounceResponse
63announceH routing toks keydb (OnionToOwner naddr retpath) req = do
64 case () of
65 _ | announcePingId req == zeros32
66 -> go False
67
68 _ -> let Nonce32 bs = announcePingId req
69 tok = fromPaddedByteString 32 bs
70 in checkToken toks naddr tok >>= go
71 `catch` (\(SomeException e) -> hPutStrLn stderr ("announceH Exception! "++show e) >> throw e)
72 where
73 go withTok = do
74 ns <- getNodesH routing naddr (GetNodes (announceSeeking req))
75 tm <- getPOSIXTime
76 let storing = (nodeId naddr == announceSeeking req)
77 record <- atomically $ do
78 when (withTok && storing) $ do
79 let toxpath = OnionToOwner naddr{ nodeId = announceKey req } retpath
80 -- Note: The following distance calculation assumes that
81 -- our nodeid doesn't change and is the same for both
82 -- routing4 and routing6.
83 d = xorNodeId (nodeId (tentativeId routing))
84 (announceSeeking req)
85 modifyTVar' keydb (insertKey tm (announceSeeking req) toxpath d)
86 ks <- readTVar keydb
87 return $ snd . snd <$> MinMaxPSQ.lookup' (announceSeeking req) (keyAssoc ks)
88 newtok <- if storing
89 then Nonce32 . toPaddedByteString 32 <$> grantToken toks naddr
90 else return $ zeros32
91 let k = case record of
92 Nothing -> NotStored newtok
93 Just (OnionToOwner {}) | storing -> Acknowledged newtok
94 Just (OnionToOwner ni _) -> SendBackKey $ id2key (nodeId ni)
95 let response = AnnounceResponse k ns
96 hPutStrLn stderr $ unwords ["Announce:", show req, "-reply->", show response]
97 return response
98
99dataToRouteH ::
100 TVar AnnouncedKeys
101 -> Transport err OnionToOwner (OnionMessage f)
102 -> addr
103 -> OnionMessage f
104 -> IO ()
105dataToRouteH keydb udp _ (OnionToRoute pub assym) = do
106 let k = key2id pub
107 mb <- atomically $ do
108 ks <- readTVar keydb
109 forM (MinMaxPSQ.lookup' k (keyAssoc ks)) $ \(p,(cnt,rpath)) -> do
110 writeTVar keydb $ ks { keyAssoc = MinMaxPSQ.insert' k (cnt + 1, rpath) p (keyAssoc ks) }
111 return rpath
112 forM_ mb $ \rpath -> do
113 -- forward
114 sendMessage udp rpath $ OnionToRouteResponse assym
115 hPutStrLn stderr $ "Forwarding data-to-route -->"++show k
116
117type NodeDistance = NodeId
118
119data AnnouncedKeys = AnnouncedKeys
120 { keyByAge :: !(PSQ NodeId (Down POSIXTime)) -- timeout of 300 seconds
121 , keyAssoc :: !(MinMaxPSQ' NodeId NodeDistance (Int,OnionToOwner))
122 }
123
124
125insertKey :: POSIXTime -> NodeId -> OnionToOwner -> NodeDistance -> AnnouncedKeys -> AnnouncedKeys
126insertKey tm pub toxpath d keydb = AnnouncedKeys
127 { keyByAge = PSQ.insert pub (Down tm) (keyByAge keydb)
128 , keyAssoc = case MinMaxPSQ.lookup' pub (keyAssoc keydb) of
129 Just (_,(cnt,_)) -> MinMaxPSQ.insert' pub (cnt,toxpath) d (keyAssoc keydb)
130 Nothing -> MinMaxPSQ.insert' pub (0 ,toxpath) d (keyAssoc keydb)
131 }
132
133areq :: Message -> Either String AnnounceRequest
134areq (OnionAnnounce assym) = Right $ fst $ runIdentity $ assymData assym
135areq _ = Left "Unexpected non-announce OnionMessage"
136
137handlers :: Transport err OnionToOwner Message
138 -> Routing
139 -> TVar SessionTokens
140 -> TVar AnnouncedKeys
141 -> PacketKind
142 -> Maybe (MethodHandler String TransactionId OnionToOwner Message)
143handlers net routing toks keydb AnnounceType
144 = Just
145 $ MethodHandler areq (\(TransactionId n8 n24) src dst -> OnionAnnounceResponse n8 n24 . Identity)
146 $ announceH routing toks keydb
147handlers net _ _ keydb _ = Just $ NoReply Right $ dataToRouteH keydb net
148