diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Data/Word64Map.hs | 62 | ||||
-rw-r--r-- | src/Network/BitTorrent/MainlineDHT.hs | 4 | ||||
-rw-r--r-- | src/Network/QueryResponse.hs | 47 | ||||
-rw-r--r-- | src/Network/Tox.hs | 44 | ||||
-rw-r--r-- | src/Network/Tox/DHT/Handlers.hs | 26 | ||||
-rw-r--r-- | src/Network/Tox/NodeId.hs | 5 | ||||
-rw-r--r-- | src/Network/Tox/Onion/Handlers.hs | 81 | ||||
-rw-r--r-- | src/Network/Tox/Onion/Transport.hs | 61 |
8 files changed, 248 insertions, 82 deletions
diff --git a/src/Data/Word64Map.hs b/src/Data/Word64Map.hs new file mode 100644 index 00000000..9e93c8c8 --- /dev/null +++ b/src/Data/Word64Map.hs | |||
@@ -0,0 +1,62 @@ | |||
1 | {-# LANGUAGE RankNTypes #-} | ||
2 | {-# LANGUAGE ScopedTypeVariables #-} | ||
3 | {-# LANGUAGE UnboxedTuples #-} | ||
4 | module Data.Word64Map where | ||
5 | |||
6 | import Data.Bits | ||
7 | import qualified Data.IntMap as IntMap | ||
8 | ;import Data.IntMap (IntMap) | ||
9 | import Data.Typeable | ||
10 | import Data.Word | ||
11 | |||
12 | -- | Since 'Int' may be 32 or 64 bits, this function is provided as a | ||
13 | -- convenience to test if an integral type, such as 'Data.Word.Word64', can be | ||
14 | -- safely transformed into an 'Int' for use with 'IntMap'. | ||
15 | -- | ||
16 | -- Returns 'True' if the proxied type can be losslessly converted to 'Int' using | ||
17 | -- 'fromIntegral'. | ||
18 | fitsInInt :: forall proxy word. (Bounded word, Integral word) => proxy word -> Bool | ||
19 | fitsInInt proxy = (original == casted) | ||
20 | where | ||
21 | original = div maxBound 2 :: word | ||
22 | casted = fromIntegral (fromIntegral original :: Int) :: word | ||
23 | |||
24 | newtype Word64Map a = Word64Map (IntMap (IntMap a)) | ||
25 | |||
26 | empty :: Word64Map a | ||
27 | empty = Word64Map IntMap.empty | ||
28 | |||
29 | -- Warning: This function assumes an 'Int' is either 64 or 32 bits. | ||
30 | keyFrom64 :: Word64 -> (# Int,Int #) | ||
31 | keyFrom64 w8 = | ||
32 | if fitsInInt (Proxy :: Proxy Word64) | ||
33 | then (# fromIntegral w8 , 0 #) | ||
34 | else (# fromIntegral (w8 `shiftR` 32), fromIntegral w8 #) | ||
35 | {-# INLINE keyFrom64 #-} | ||
36 | |||
37 | lookup :: Word64 -> Word64Map b -> Maybe b | ||
38 | lookup w8 (Word64Map m) | (# hi,lo #) <- keyFrom64 w8 = do | ||
39 | m' <- IntMap.lookup hi m | ||
40 | IntMap.lookup lo m' | ||
41 | {-# INLINE lookup #-} | ||
42 | |||
43 | insert :: Word64 -> b -> Word64Map b -> Word64Map b | ||
44 | insert w8 b (Word64Map m) | (# hi,lo #) <- keyFrom64 w8 | ||
45 | = Word64Map $ IntMap.alter (Just . maybe (IntMap.singleton lo b) | ||
46 | (IntMap.insert lo b)) | ||
47 | hi | ||
48 | m | ||
49 | {-# INLINE insert #-} | ||
50 | |||
51 | delete :: Word64 -> Word64Map b -> Word64Map b | ||
52 | delete w8 (Word64Map m) | (# hi,lo #) <- keyFrom64 w8 | ||
53 | = Word64Map $ IntMap.alter (maybe Nothing | ||
54 | (\m' -> case IntMap.delete lo m' of | ||
55 | m'' | IntMap.null m'' -> Nothing | ||
56 | m'' -> Just m'')) | ||
57 | hi | ||
58 | m | ||
59 | {-# INLINE delete #-} | ||
60 | |||
61 | |||
62 | |||
diff --git a/src/Network/BitTorrent/MainlineDHT.hs b/src/Network/BitTorrent/MainlineDHT.hs index 4566471a..f4ce4019 100644 --- a/src/Network/BitTorrent/MainlineDHT.hs +++ b/src/Network/BitTorrent/MainlineDHT.hs | |||
@@ -584,7 +584,7 @@ newClient swarms addr = do | |||
584 | gen cnt = (TransactionId $ S.encode cnt, cnt+1) | 584 | gen cnt = (TransactionId $ S.encode cnt, cnt+1) |
585 | 585 | ||
586 | client = Client | 586 | client = Client |
587 | { clientNet = addHandler (handleMessage client) net | 587 | { clientNet = addHandler ignoreErrors (handleMessage client) net |
588 | , clientDispatcher = dispatch | 588 | , clientDispatcher = dispatch |
589 | , clientErrorReporter = ignoreErrors -- printErrors stderr | 589 | , clientErrorReporter = ignoreErrors -- printErrors stderr |
590 | , clientPending = map_var | 590 | , clientPending = map_var |
@@ -1002,7 +1002,7 @@ mainlineSend meth unwrap msg client nid addr = do | |||
1002 | return $ join $ either (const Nothing) Just <$> reply | 1002 | return $ join $ either (const Nothing) Just <$> reply |
1003 | where | 1003 | where |
1004 | serializer = MethodSerializer | 1004 | serializer = MethodSerializer |
1005 | { methodTimeout = 5 | 1005 | { methodTimeout = \_ ni -> return (ni, 5000000) |
1006 | , method = meth | 1006 | , method = meth |
1007 | , wrapQuery = encodeQueryPayload meth (isReadonlyClient client) | 1007 | , wrapQuery = encodeQueryPayload meth (isReadonlyClient client) |
1008 | , unwrapResponse = (>>= either (Left . Error GenericError . C8.pack) | 1008 | , unwrapResponse = (>>= either (Left . Error GenericError . C8.pack) |
diff --git a/src/Network/QueryResponse.hs b/src/Network/QueryResponse.hs index 0fa1a05a..70d981e2 100644 --- a/src/Network/QueryResponse.hs +++ b/src/Network/QueryResponse.hs | |||
@@ -108,18 +108,18 @@ partitionTransportM parse encodex tr = do | |||
108 | } | 108 | } |
109 | return (xtr, ytr) | 109 | return (xtr, ytr) |
110 | 110 | ||
111 | addHandler :: (addr -> x -> IO (Maybe (x -> x))) -> Transport err addr x -> Transport err addr x | 111 | addHandler :: ErrorReporter addr x meth tid err -> (addr -> x -> IO (Maybe (x -> x))) -> Transport err addr x -> Transport err addr x |
112 | addHandler f tr = tr | 112 | addHandler err f tr = tr |
113 | { awaitMessage = \kont -> fix $ \eat -> awaitMessage tr $ \m -> do | 113 | { awaitMessage = \kont -> fix $ \eat -> awaitMessage tr $ \m -> do |
114 | case m of | 114 | case m of |
115 | Just (Right (x, addr)) -> f addr x >>= maybe eat (kont . Just . Right . (, addr) . ($ x)) | 115 | Just (Right (x, addr)) -> f addr x >>= maybe eat (kont . Just . Right . (, addr) . ($ x)) |
116 | Just (Left e ) -> kont $ Just (Left e) | 116 | Just (Left e ) -> reportParseError err e >> kont (Just $ Left e) |
117 | Nothing -> kont $ Nothing | 117 | Nothing -> kont $ Nothing |
118 | } | 118 | } |
119 | 119 | ||
120 | -- | Modify a 'Transport' to invoke an action upon every received packet. | 120 | -- | Modify a 'Transport' to invoke an action upon every received packet. |
121 | onInbound :: (addr -> x -> IO ()) -> Transport err addr x -> Transport err addr x | 121 | onInbound :: (addr -> x -> IO ()) -> Transport err addr x -> Transport err addr x |
122 | onInbound f tr = addHandler (\addr x -> f addr x >> return (Just id)) tr | 122 | onInbound f tr = addHandler ignoreErrors (\addr x -> f addr x >> return (Just id)) tr |
123 | 123 | ||
124 | -- * Using a query\/response client. | 124 | -- * Using a query\/response client. |
125 | 125 | ||
@@ -153,16 +153,17 @@ sendQuery :: | |||
153 | -> a -- ^ The outbound query. | 153 | -> a -- ^ The outbound query. |
154 | -> addr -- ^ Destination address of query. | 154 | -> addr -- ^ Destination address of query. |
155 | -> IO (Maybe b) -- ^ The response, or 'Nothing' if it timed out. | 155 | -> IO (Maybe b) -- ^ The response, or 'Nothing' if it timed out. |
156 | sendQuery (Client net d err pending whoami _) meth q addr = do | 156 | sendQuery (Client net d err pending whoami _) meth q addr0 = do |
157 | mvar <- newEmptyMVar | 157 | mvar <- newEmptyMVar |
158 | tid <- atomically $ do | 158 | (tid,addr,expiry) <- atomically $ do |
159 | tbl <- readTVar pending | 159 | tbl <- readTVar pending |
160 | (tid, tbl') <- dispatchRegister (tableMethods d) mvar tbl | 160 | (tid, tbl') <- dispatchRegister (tableMethods d) mvar addr0 tbl |
161 | (addr,expiry) <- methodTimeout meth tid addr0 | ||
161 | writeTVar pending tbl' | 162 | writeTVar pending tbl' |
162 | return tid | 163 | return (tid,addr,expiry) |
163 | self <- whoami (Just addr) | 164 | self <- whoami (Just addr) |
164 | sendMessage net addr (wrapQuery meth tid self addr q) | 165 | sendMessage net addr (wrapQuery meth tid self addr q) |
165 | mres <- timeout (1000000 * methodTimeout meth) $ takeMVar mvar | 166 | mres <- timeout expiry $ takeMVar mvar |
166 | case mres of | 167 | case mres of |
167 | Just x -> return $ Just $ unwrapResponse meth x | 168 | Just x -> return $ Just $ unwrapResponse meth x |
168 | Nothing -> do | 169 | Nothing -> do |
@@ -248,8 +249,10 @@ dispatchQuery (NoReply unwrapQ f) tid self x addr = | |||
248 | -- peer-to-peer algorithm will define a 'MethodSerializer' for every 'MethodHandler' that | 249 | -- peer-to-peer algorithm will define a 'MethodSerializer' for every 'MethodHandler' that |
249 | -- might be returned by 'lookupHandler'. | 250 | -- might be returned by 'lookupHandler'. |
250 | data MethodSerializer tid addr x meth a b = MethodSerializer | 251 | data MethodSerializer tid addr x meth a b = MethodSerializer |
251 | { -- | Seconds to wait for a response. | 252 | { -- | Returns the microseconds to wait for a response to this query being |
252 | methodTimeout :: Int | 253 | -- sent to the given address. The /addr/ may also be modified to add |
254 | -- routing information. | ||
255 | methodTimeout :: tid -> addr -> STM (addr,Int) | ||
253 | -- | A method identifier used for error reporting. This needn't be the | 256 | -- | A method identifier used for error reporting. This needn't be the |
254 | -- same as the /meth/ argument to 'MethodHandler', but it is suggested. | 257 | -- same as the /meth/ argument to 'MethodHandler', but it is suggested. |
255 | , method :: meth | 258 | , method :: meth |
@@ -269,13 +272,13 @@ data MethodSerializer tid addr x meth a b = MethodSerializer | |||
269 | -- | 272 | -- |
270 | -- The type variable /d/ is used to represent the current state of the | 273 | -- The type variable /d/ is used to represent the current state of the |
271 | -- transaction generator and the table of pending transactions. | 274 | -- transaction generator and the table of pending transactions. |
272 | data TransactionMethods d tid x = TransactionMethods | 275 | data TransactionMethods d tid addr x = TransactionMethods |
273 | { | 276 | { |
274 | -- | Before a query is sent, this function stores an 'MVar' to which the | 277 | -- | Before a query is sent, this function stores an 'MVar' to which the |
275 | -- response will be written too. The returned /tid/ is a transaction id | 278 | -- response will be written too. The returned /tid/ is a transaction id |
276 | -- that can be used to forget the 'MVar' if the remote peer is not | 279 | -- that can be used to forget the 'MVar' if the remote peer is not |
277 | -- responding. | 280 | -- responding. |
278 | dispatchRegister :: MVar x -> d -> STM (tid, d) | 281 | dispatchRegister :: MVar x -> addr -> d -> STM (tid, d) |
279 | -- | This method is invoked when an incoming packet /x/ indicates it is | 282 | -- | This method is invoked when an incoming packet /x/ indicates it is |
280 | -- a response to the transaction with id /tid/. The returned IO action | 283 | -- a response to the transaction with id /tid/. The returned IO action |
281 | -- is will write the packet to the correct 'MVar' thus completing the | 284 | -- is will write the packet to the correct 'MVar' thus completing the |
@@ -318,27 +321,15 @@ instance Contravariant (TableMethods t) where | |||
318 | (\k t -> del (f k) t) | 321 | (\k t -> del (f k) t) |
319 | (\k t -> lookup (f k) t) | 322 | (\k t -> lookup (f k) t) |
320 | 323 | ||
321 | -- | Since 'Int' may be 32 or 64 bits, this function is provided as a | ||
322 | -- convenience to test if an integral type, such as 'Data.Word.Word64', can be | ||
323 | -- safely transformed into an 'Int' for use with 'IntMap'. | ||
324 | -- | ||
325 | -- Returns 'True' if the proxied type can be losslessly converted to 'Int' using | ||
326 | -- 'fromIntegral'. | ||
327 | fitsInInt :: forall word. (Bounded word, Integral word) => Proxy word -> Bool | ||
328 | fitsInInt Proxy = (original == casted) | ||
329 | where | ||
330 | original = div maxBound 2 :: word | ||
331 | casted = fromIntegral (fromIntegral original :: Int) :: word | ||
332 | |||
333 | -- | Construct 'TransactionMethods' methods out of 3 lookup table primitives and a | 324 | -- | Construct 'TransactionMethods' methods out of 3 lookup table primitives and a |
334 | -- function for generating unique transaction ids. | 325 | -- function for generating unique transaction ids. |
335 | transactionMethods :: | 326 | transactionMethods :: |
336 | TableMethods t tid -- ^ Table methods to lookup values by /tid/. | 327 | TableMethods t tid -- ^ Table methods to lookup values by /tid/. |
337 | -> (g -> (tid,g)) -- ^ Generate a new unique /tid/ value and update the generator state /g/. | 328 | -> (g -> (tid,g)) -- ^ Generate a new unique /tid/ value and update the generator state /g/. |
338 | -> TransactionMethods (g,t (MVar x)) tid x | 329 | -> TransactionMethods (g,t (MVar x)) tid addr x |
339 | transactionMethods (TableMethods insert delete lookup) generate = TransactionMethods | 330 | transactionMethods (TableMethods insert delete lookup) generate = TransactionMethods |
340 | { dispatchCancel = \tid (g,t) -> return (g, delete tid t) | 331 | { dispatchCancel = \tid (g,t) -> return (g, delete tid t) |
341 | , dispatchRegister = \v (g,t) -> | 332 | , dispatchRegister = \v _ (g,t) -> |
342 | let (tid,g') = generate g | 333 | let (tid,g') = generate g |
343 | t' = insert tid v t | 334 | t' = insert tid v t |
344 | in return ( tid, (g',t') ) | 335 | in return ( tid, (g',t') ) |
@@ -356,7 +347,7 @@ data DispatchMethods tbl err meth tid addr x = DispatchMethods | |||
356 | -- | Lookup the handler for a inbound query. | 347 | -- | Lookup the handler for a inbound query. |
357 | , lookupHandler :: meth -> Maybe (MethodHandler err tid addr x) | 348 | , lookupHandler :: meth -> Maybe (MethodHandler err tid addr x) |
358 | -- | Methods for handling incoming responses. | 349 | -- | Methods for handling incoming responses. |
359 | , tableMethods :: TransactionMethods tbl tid x | 350 | , tableMethods :: TransactionMethods tbl tid addr x |
360 | } | 351 | } |
361 | 352 | ||
362 | -- | These methods indicate what should be done upon various conditions. Write | 353 | -- | These methods indicate what should be done upon various conditions. Write |
diff --git a/src/Network/Tox.hs b/src/Network/Tox.hs index 7814046e..3860d309 100644 --- a/src/Network/Tox.hs +++ b/src/Network/Tox.hs | |||
@@ -21,6 +21,7 @@ import Control.Arrow | |||
21 | import Control.Concurrent (MVar) | 21 | import Control.Concurrent (MVar) |
22 | import Control.Concurrent.STM | 22 | import Control.Concurrent.STM |
23 | import Control.Monad | 23 | import Control.Monad |
24 | import Control.Monad.Fix | ||
24 | import qualified Crypto.Cipher.ChaChaPoly1305 as Symmetric | 25 | import qualified Crypto.Cipher.ChaChaPoly1305 as Symmetric |
25 | import qualified Crypto.Cipher.Salsa as Salsa | 26 | import qualified Crypto.Cipher.Salsa as Salsa |
26 | import qualified Crypto.Cipher.XSalsa as XSalsa | 27 | import qualified Crypto.Cipher.XSalsa as XSalsa |
@@ -94,6 +95,7 @@ import qualified Network.Tox.Onion.Handlers as Onion | |||
94 | import Network.Tox.Crypto.Transport (NetCrypto) | 95 | import Network.Tox.Crypto.Transport (NetCrypto) |
95 | import Text.XXD | 96 | import Text.XXD |
96 | import OnionRouter | 97 | import OnionRouter |
98 | import Data.Word64Map (fitsInInt) | ||
97 | 99 | ||
98 | newCrypto :: IO TransportCrypto | 100 | newCrypto :: IO TransportCrypto |
99 | newCrypto = do | 101 | newCrypto = do |
@@ -158,7 +160,7 @@ newClient :: (DRG g, Show addr, Show meth) => | |||
158 | -> (x -> MessageClass String meth DHT.TransactionId) | 160 | -> (x -> MessageClass String meth DHT.TransactionId) |
159 | -> (Maybe addr -> IO addr) | 161 | -> (Maybe addr -> IO addr) |
160 | -> (meth -> Maybe (MethodHandler String DHT.TransactionId addr x)) | 162 | -> (meth -> Maybe (MethodHandler String DHT.TransactionId addr x)) |
161 | -> (forall d. TransactionMethods d DHT.TransactionId x -> TransactionMethods d DHT.TransactionId x) | 163 | -> (forall d. TransactionMethods d DHT.TransactionId addr x -> TransactionMethods d DHT.TransactionId addr x) |
162 | -> (Client String meth DHT.TransactionId addr x -> Transport String addr x -> Transport String addr x) | 164 | -> (Client String meth DHT.TransactionId addr x -> Transport String addr x -> Transport String addr x) |
163 | -> IO (Client String meth DHT.TransactionId addr x) | 165 | -> IO (Client String meth DHT.TransactionId addr x) |
164 | newClient drg net classify selfAddr handlers modifytbl modifynet = do | 166 | newClient drg net classify selfAddr handlers modifytbl modifynet = do |
@@ -180,11 +182,12 @@ newClient drg net classify selfAddr handlers modifytbl modifynet = do | |||
180 | , lookupHandler = handlers -- var | 182 | , lookupHandler = handlers -- var |
181 | , tableMethods = modifytbl tbl | 183 | , tableMethods = modifytbl tbl |
182 | } | 184 | } |
185 | eprinter = printErrors stderr | ||
183 | mkclient (tbl,var) handlers = | 186 | mkclient (tbl,var) handlers = |
184 | let client = Client | 187 | let client = Client |
185 | { clientNet = addHandler (handleMessage client) $ modifynet client net | 188 | { clientNet = addHandler eprinter (handleMessage client) $ modifynet client net |
186 | , clientDispatcher = dispatch tbl var handlers -- (fmap (contramapAddr (\(ToxPath ni _) -> ni)) . handlers) | 189 | , clientDispatcher = dispatch tbl var handlers -- (fmap (contramapAddr (\(ToxPath ni _) -> ni)) . handlers) |
187 | , clientErrorReporter = (printErrors stderr) { reportTimeout = reportTimeout ignoreErrors } | 190 | , clientErrorReporter = eprinter { reportTimeout = reportTimeout ignoreErrors } |
188 | , clientPending = var | 191 | , clientPending = var |
189 | , clientAddress = selfAddr | 192 | , clientAddress = selfAddr |
190 | , clientResponseId = genNonce24 var | 193 | , clientResponseId = genNonce24 var |
@@ -199,18 +202,22 @@ data Tox = Tox | |||
199 | , toxRouting :: DHT.Routing | 202 | , toxRouting :: DHT.Routing |
200 | , toxTokens :: TVar SessionTokens | 203 | , toxTokens :: TVar SessionTokens |
201 | , toxAnnouncedKeys :: TVar Onion.AnnouncedKeys | 204 | , toxAnnouncedKeys :: TVar Onion.AnnouncedKeys |
205 | , toxOnionRoutes :: OnionRouter | ||
202 | } | 206 | } |
203 | 207 | ||
204 | addVerbosity :: Show addr => Transport err addr ByteString -> Transport err addr ByteString | 208 | isLocalHost (SockAddrInet _ host32) = (fromBE32 host32 == 0x7f000001) |
209 | isLocalHost _ = False | ||
210 | |||
211 | addVerbosity :: Transport err SockAddr ByteString -> Transport err SockAddr ByteString | ||
205 | addVerbosity tr = | 212 | addVerbosity tr = |
206 | tr { awaitMessage = \kont -> awaitMessage tr $ \m -> do | 213 | tr { awaitMessage = \kont -> awaitMessage tr $ \m -> do |
207 | forM_ m $ mapM_ $ \(msg,addr) -> do | 214 | forM_ m $ mapM_ $ \(msg,addr) -> do |
208 | when (not (B.null msg || elem (B.head msg) [0,1,2,4])) $ do | 215 | when (isLocalHost addr || not (B.null msg || elem (B.head msg) [0,1,2,4,0x81,0x82,0x8c,0x8d])) $ do |
209 | mapM_ (\x -> hPutStrLn stderr ( (show addr) ++ " --> " ++ x)) | 216 | mapM_ (\x -> hPutStrLn stderr ( (show addr) ++ " --> " ++ x)) |
210 | $ xxd 0 msg | 217 | $ xxd 0 msg |
211 | kont m | 218 | kont m |
212 | , sendMessage = \addr msg -> do | 219 | , sendMessage = \addr msg -> do |
213 | when (not (B.null msg || elem (B.head msg) [0,1,2,4])) $ do | 220 | when (isLocalHost addr || not (B.null msg || elem (B.head msg) [0,1,2,4,0x81,0x82,0x8c,0x8d])) $ do |
214 | mapM_ (\x -> hPutStrLn stderr ( (show addr) ++ " <-- " ++ x)) | 221 | mapM_ (\x -> hPutStrLn stderr ( (show addr) ++ " <-- " ++ x)) |
215 | $ xxd 0 msg | 222 | $ xxd 0 msg |
216 | sendMessage tr addr msg | 223 | sendMessage tr addr msg |
@@ -226,13 +233,15 @@ newTox keydb addr = do | |||
226 | crypto <- newCrypto | 233 | crypto <- newCrypto |
227 | drg <- drgNew | 234 | drg <- drgNew |
228 | let lookupClose _ = return Nothing | 235 | let lookupClose _ = return Nothing |
229 | routing <- DHT.newRouting addr crypto updateIP updateIP | ||
230 | |||
231 | (dhtcrypt,onioncrypt,cryptonet) <- toxTransport crypto (DHT.orouter routing) lookupClose udp | ||
232 | 236 | ||
237 | routing <- DHT.newRouting addr crypto updateIP updateIP | ||
238 | orouter <- newOnionRouter | ||
239 | (dhtcrypt,onioncrypt,cryptonet) <- toxTransport crypto orouter lookupClose udp | ||
233 | let dhtnet0 = layerTransport (DHT.decrypt crypto) (DHT.encrypt crypto) dhtcrypt | 240 | let dhtnet0 = layerTransport (DHT.decrypt crypto) (DHT.encrypt crypto) dhtcrypt |
234 | dhtclient <- newClient drg dhtnet0 DHT.classify (myAddr routing) (DHT.handlers routing) id | 241 | dhtclient <- newClient drg dhtnet0 DHT.classify (myAddr routing) (DHT.handlers routing) id |
235 | $ \client net -> onInbound (DHT.updateRouting client routing) net | 242 | $ \client net -> onInbound (DHT.updateRouting client routing orouter) net |
243 | |||
244 | orouter <- forkRouteBuilder orouter $ \nid ni -> maybe [] (\(_,ns,_)->ns) <$> DHT.getNodes dhtclient nid ni | ||
236 | 245 | ||
237 | toks <- do | 246 | toks <- do |
238 | nil <- nullSessionTokens | 247 | nil <- nullSessionTokens |
@@ -240,13 +249,14 @@ newTox keydb addr = do | |||
240 | oniondrg <- drgNew | 249 | oniondrg <- drgNew |
241 | let onionnet = layerTransport (Onion.decrypt crypto) (Onion.encrypt crypto) onioncrypt | 250 | let onionnet = layerTransport (Onion.decrypt crypto) (Onion.encrypt crypto) onioncrypt |
242 | onionclient <- newClient oniondrg onionnet Onion.classify | 251 | onionclient <- newClient oniondrg onionnet Onion.classify |
243 | (const $ return | 252 | (const $ atomically |
244 | $ either (const $ error "bad sockaddr") | 253 | $ flip Onion.OnionDestination Nothing |
245 | (flip Onion.OnionDestination Nothing) | 254 | . R.thisNode |
246 | $ nodeInfo zeroID addr) | 255 | <$> readTVar (DHT.routing4 routing)) |
247 | (Onion.handlers onionnet routing toks keydb) | 256 | (Onion.handlers onionnet routing toks keydb) |
248 | (hookQueries (DHT.orouter routing) DHT.transactionKey) | 257 | (hookQueries orouter DHT.transactionKey) |
249 | (const id) | 258 | (const id) |
259 | |||
250 | return Tox | 260 | return Tox |
251 | { toxDHT = dhtclient | 261 | { toxDHT = dhtclient |
252 | , toxOnion = onionclient | 262 | , toxOnion = onionclient |
@@ -254,8 +264,12 @@ newTox keydb addr = do | |||
254 | , toxRouting = routing | 264 | , toxRouting = routing |
255 | , toxTokens = toks | 265 | , toxTokens = toks |
256 | , toxAnnouncedKeys = keydb | 266 | , toxAnnouncedKeys = keydb |
267 | , toxOnionRoutes = orouter | ||
257 | } | 268 | } |
258 | 269 | ||
270 | onionTimeout :: Tox -> DHT.TransactionId -> Onion.OnionDestination RouteId -> STM (Onion.OnionDestination RouteId, Int) | ||
271 | onionTimeout Tox { toxOnionRoutes = or } (DHT.TransactionId n8 _) od = lookupTimeout or n8 od | ||
272 | |||
259 | forkTox :: Tox -> IO (IO ()) | 273 | forkTox :: Tox -> IO (IO ()) |
260 | forkTox tox = do | 274 | forkTox tox = do |
261 | _ <- forkListener "toxCrypto" (toxCrypto tox) | 275 | _ <- forkListener "toxCrypto" (toxCrypto tox) |
diff --git a/src/Network/Tox/DHT/Handlers.hs b/src/Network/Tox/DHT/Handlers.hs index c9adc860..a3f13ac7 100644 --- a/src/Network/Tox/DHT/Handlers.hs +++ b/src/Network/Tox/DHT/Handlers.hs | |||
@@ -105,7 +105,6 @@ data Routing = Routing | |||
105 | , sched6 :: !( TVar (Int.PSQ POSIXTime) ) | 105 | , sched6 :: !( TVar (Int.PSQ POSIXTime) ) |
106 | , routing6 :: !( TVar (R.BucketList NodeInfo) ) | 106 | , routing6 :: !( TVar (R.BucketList NodeInfo) ) |
107 | , committee6 :: TriadCommittee NodeId SockAddr | 107 | , committee6 :: TriadCommittee NodeId SockAddr |
108 | , orouter :: OnionRouter | ||
109 | } | 108 | } |
110 | 109 | ||
111 | newRouting :: SockAddr -> TransportCrypto | 110 | newRouting :: SockAddr -> TransportCrypto |
@@ -124,8 +123,9 @@ newRouting addr crypto update4 update6 = do | |||
124 | tentative_info6 <- | 123 | tentative_info6 <- |
125 | maybe (tentative_info { nodeIP = tentative_ip6 }) | 124 | maybe (tentative_info { nodeIP = tentative_ip6 }) |
126 | (\ip6 -> tentative_info { nodeIP = IPv6 ip6 }) | 125 | (\ip6 -> tentative_info { nodeIP = IPv6 ip6 }) |
127 | <$> global6 | 126 | <$> case addr of |
128 | orouter <- newOnionRouter | 127 | SockAddrInet {} -> return Nothing |
128 | _ -> global6 | ||
129 | atomically $ do | 129 | atomically $ do |
130 | let nobkts = R.defaultBucketCount :: Int | 130 | let nobkts = R.defaultBucketCount :: Int |
131 | tbl4 <- newTVar $ R.nullTable (comparing nodeId) (\s -> hashWithSalt s . nodeId) tentative_info4 nobkts | 131 | tbl4 <- newTVar $ R.nullTable (comparing nodeId) (\s -> hashWithSalt s . nodeId) tentative_info4 nobkts |
@@ -134,7 +134,7 @@ newRouting addr crypto update4 update6 = do | |||
134 | committee6 <- newTriadCommittee (update6 tbl6) -- updateIPVote tbl6 addr6 | 134 | committee6 <- newTriadCommittee (update6 tbl6) -- updateIPVote tbl6 addr6 |
135 | sched4 <- newTVar Int.empty | 135 | sched4 <- newTVar Int.empty |
136 | sched6 <- newTVar Int.empty | 136 | sched6 <- newTVar Int.empty |
137 | return $ Routing tentative_info sched4 tbl4 committee4 sched6 tbl6 committee6 orouter | 137 | return $ Routing tentative_info sched4 tbl4 committee4 sched6 tbl6 committee6 |
138 | 138 | ||
139 | 139 | ||
140 | -- TODO: This should cover more cases | 140 | -- TODO: This should cover more cases |
@@ -200,7 +200,7 @@ serializer :: PacketKind | |||
200 | -> (Message -> Maybe (Assym (Nonce8,pong))) | 200 | -> (Message -> Maybe (Assym (Nonce8,pong))) |
201 | -> MethodSerializer TransactionId NodeInfo Message PacketKind ping (Maybe pong) | 201 | -> MethodSerializer TransactionId NodeInfo Message PacketKind ping (Maybe pong) |
202 | serializer pktkind mkping mkpong = MethodSerializer | 202 | serializer pktkind mkping mkpong = MethodSerializer |
203 | { methodTimeout = 5 | 203 | { methodTimeout = \tid addr -> return (addr, 5000000) |
204 | , method = pktkind | 204 | , method = pktkind |
205 | -- wrapQuery :: tid -> addr -> addr -> qry -> x | 205 | -- wrapQuery :: tid -> addr -> addr -> qry -> x |
206 | , wrapQuery = \tid src dst ping -> mkping $ wrapAssym tid src dst (, ping) | 206 | , wrapQuery = \tid src dst ping -> mkping $ wrapAssym tid src dst (, ping) |
@@ -232,20 +232,20 @@ unwrapNodes (SendNodes ns) = (ns,ns,()) | |||
232 | 232 | ||
233 | getNodes :: Client -> NodeId -> NodeInfo -> IO (Maybe ([NodeInfo],[NodeInfo],())) | 233 | getNodes :: Client -> NodeId -> NodeInfo -> IO (Maybe ([NodeInfo],[NodeInfo],())) |
234 | getNodes client nid addr = do | 234 | getNodes client nid addr = do |
235 | hPutStrLn stderr $ show addr ++ " <-- getnodes " ++ show nid | 235 | -- hPutStrLn stderr $ show addr ++ " <-- getnodes " ++ show nid |
236 | reply <- QR.sendQuery client (serializer GetNodesType DHTGetNodes unsendNodes) (GetNodes nid) addr | 236 | reply <- QR.sendQuery client (serializer GetNodesType DHTGetNodes unsendNodes) (GetNodes nid) addr |
237 | hPutStrLn stderr $ show addr ++ " -sendnodes-> " ++ show reply | 237 | -- hPutStrLn stderr $ show addr ++ " -sendnodes-> " ++ show reply |
238 | return $ fmap unwrapNodes $ join reply | 238 | return $ fmap unwrapNodes $ join reply |
239 | 239 | ||
240 | updateRouting :: Client -> Routing -> NodeInfo -> Message -> IO () | 240 | updateRouting :: Client -> Routing -> OnionRouter -> NodeInfo -> Message -> IO () |
241 | updateRouting client routing naddr msg = do | 241 | updateRouting client routing orouter naddr msg = do |
242 | let typ = fst $ dhtMessageType $ fst $ DHTTransport.encrypt (error "updateRouting") msg naddr | 242 | let typ = fst $ dhtMessageType $ fst $ DHTTransport.encrypt (error "updateRouting") msg naddr |
243 | tid = mapMessage (\n24 (n8,_) -> TransactionId n8 n24) msg | 243 | tid = mapMessage (\n24 (n8,_) -> TransactionId n8 n24) msg |
244 | hPutStrLn stderr $ "updateRouting "++show (typ,tid) | 244 | -- hPutStrLn stderr $ "updateRouting "++show (typ,tid) |
245 | -- TODO: check msg type | 245 | -- TODO: check msg type |
246 | case prefer4or6 naddr Nothing of | 246 | case prefer4or6 naddr Nothing of |
247 | Want_IP4 -> updateTable client naddr (orouter routing) (routing4 routing) (committee4 routing) (sched4 routing) | 247 | Want_IP4 -> updateTable client naddr orouter (routing4 routing) (committee4 routing) (sched4 routing) |
248 | Want_IP6 -> updateTable client naddr (orouter routing) (routing6 routing) (committee6 routing) (sched6 routing) | 248 | Want_IP6 -> updateTable client naddr orouter (routing6 routing) (committee6 routing) (sched6 routing) |
249 | 249 | ||
250 | updateTable :: Client -> NodeInfo -> OnionRouter -> TVar (R.BucketList NodeInfo) -> TriadCommittee NodeId SockAddr -> TVar (Int.PSQ POSIXTime) -> IO () | 250 | updateTable :: Client -> NodeInfo -> OnionRouter -> TVar (R.BucketList NodeInfo) -> TriadCommittee NodeId SockAddr -> TVar (Int.PSQ POSIXTime) -> IO () |
251 | updateTable client naddr orouter tbl committee sched = do | 251 | updateTable client naddr orouter tbl committee sched = do |
@@ -262,7 +262,7 @@ toxKademlia client committee orouter var sched | |||
262 | { tblTransition = \tr -> do | 262 | { tblTransition = \tr -> do |
263 | io1 <- transitionCommittee committee tr | 263 | io1 <- transitionCommittee committee tr |
264 | io2 <- touchBucket toxSpace (15*60) var sched tr | 264 | io2 <- touchBucket toxSpace (15*60) var sched tr |
265 | hookBucketList orouter tr | 265 | hookBucketList toxSpace var orouter tr |
266 | return $ do | 266 | return $ do |
267 | io1 >> io2 | 267 | io1 >> io2 |
268 | {- | 268 | {- |
diff --git a/src/Network/Tox/NodeId.hs b/src/Network/Tox/NodeId.hs index 959d689c..d0c57416 100644 --- a/src/Network/Tox/NodeId.hs +++ b/src/Network/Tox/NodeId.hs | |||
@@ -223,7 +223,10 @@ instance Sized NodeInfo where | |||
223 | instance S.Serialize NodeInfo where | 223 | instance S.Serialize NodeInfo where |
224 | get = do | 224 | get = do |
225 | addrfam <- S.get :: S.Get Word8 | 225 | addrfam <- S.get :: S.Get Word8 |
226 | ip <- getIP addrfam | 226 | let fallback = do -- FIXME: Handle unrecognized address families. |
227 | IPv6 <$> S.get | ||
228 | return $ IPv6 (read "::" :: IPv6) | ||
229 | ip <- getIP addrfam <|> fallback | ||
227 | port <- S.get :: S.Get PortNumber | 230 | port <- S.get :: S.Get PortNumber |
228 | nid <- S.get | 231 | nid <- S.get |
229 | return $ NodeInfo nid ip port | 232 | return $ NodeInfo nid ip port |
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 | ||
diff --git a/src/Network/Tox/Onion/Transport.hs b/src/Network/Tox/Onion/Transport.hs index a3c1950f..b5ac748a 100644 --- a/src/Network/Tox/Onion/Transport.hs +++ b/src/Network/Tox/Onion/Transport.hs | |||
@@ -35,6 +35,8 @@ module Network.Tox.Onion.Transport | |||
35 | , peelSymmetric | 35 | , peelSymmetric |
36 | , OnionRoute(..) | 36 | , OnionRoute(..) |
37 | , N3 | 37 | , N3 |
38 | , onionKey | ||
39 | , onionNodeInfo | ||
38 | ) where | 40 | ) where |
39 | 41 | ||
40 | import Network.Address (fromSockAddr,toSockAddr,setPort,either4or6,sockAddrPort) | 42 | import Network.Address (fromSockAddr,toSockAddr,setPort,either4or6,sockAddrPort) |
@@ -42,10 +44,11 @@ import Network.QueryResponse | |||
42 | import Crypto.Tox hiding (encrypt,decrypt) | 44 | import Crypto.Tox hiding (encrypt,decrypt) |
43 | import Network.Tox.NodeId | 45 | import Network.Tox.NodeId |
44 | import qualified Crypto.Tox as ToxCrypto | 46 | import qualified Crypto.Tox as ToxCrypto |
45 | import Network.Tox.DHT.Transport (NodeInfo(..),NodeId(..),SendNodes,nodeInfo,DHTPublicKey,asymNodeInfo) | 47 | import Network.Tox.DHT.Transport (NodeInfo(..),NodeId(..),SendNodes(..),nodeInfo,DHTPublicKey,asymNodeInfo) |
46 | 48 | ||
47 | import Debug.Trace | 49 | import Debug.Trace |
48 | import Control.Arrow | 50 | import Control.Arrow |
51 | import Control.Applicative | ||
49 | import Control.Concurrent.STM | 52 | import Control.Concurrent.STM |
50 | import Control.Monad | 53 | import Control.Monad |
51 | import qualified Data.ByteString as B | 54 | import qualified Data.ByteString as B |
@@ -88,14 +91,23 @@ deriving instance ( Show (f (AnnounceRequest, Nonce8)) | |||
88 | , Show (f DataToRoute) | 91 | , Show (f DataToRoute) |
89 | ) => Show (OnionMessage f) | 92 | ) => Show (OnionMessage f) |
90 | 93 | ||
94 | msgNonce :: OnionMessage f -> Nonce24 | ||
95 | msgNonce (OnionAnnounce a) = assymNonce a | ||
96 | msgNonce (OnionAnnounceResponse _ n24 _) = n24 | ||
97 | msgNonce (OnionToRoute _ a) = assymNonce a | ||
98 | msgNonce (OnionToRouteResponse a) = assymNonce a | ||
99 | |||
91 | data OnionDestination r | 100 | data OnionDestination r |
92 | = OnionToOwner NodeInfo (ReturnPath N3) -- ^ Somebody else's path to us. | 101 | = OnionToOwner NodeInfo (ReturnPath N3) -- ^ Somebody else's path to us. |
93 | | OnionDestination NodeInfo (Maybe r) -- ^ Our own onion-path. | 102 | | OnionDestination NodeInfo (Maybe r) -- ^ Our own onion-path. |
94 | deriving Show | 103 | deriving Show |
95 | 104 | ||
105 | onionNodeInfo :: OnionDestination r -> NodeInfo | ||
106 | onionNodeInfo (OnionToOwner ni _) = ni | ||
107 | onionNodeInfo (OnionDestination ni _) = ni | ||
108 | |||
96 | onionKey :: OnionDestination r -> Maybe PublicKey | 109 | onionKey :: OnionDestination r -> Maybe PublicKey |
97 | onionKey (OnionToOwner ni _) = Just $ id2key (nodeId ni) | 110 | onionKey od = Just $ id2key . nodeId $ onionNodeInfo od |
98 | onionKey (OnionDestination ni _) = Just $ id2key (nodeId ni) | ||
99 | 111 | ||
100 | instance Sized (OnionMessage Encrypted) where | 112 | instance Sized (OnionMessage Encrypted) where |
101 | size = VarSize $ \case | 113 | size = VarSize $ \case |
@@ -176,11 +188,19 @@ encodeOnionAddr :: (NodeInfo -> r -> IO (Maybe OnionRoute)) | |||
176 | encodeOnionAddr _ (msg,OnionToOwner ni p) = | 188 | encodeOnionAddr _ (msg,OnionToOwner ni p) = |
177 | return $ Just ( runPut $ putResponse (OnionResponse p msg) | 189 | return $ Just ( runPut $ putResponse (OnionResponse p msg) |
178 | , nodeAddr ni ) | 190 | , nodeAddr ni ) |
179 | encodeOnionAddr _ (msg,OnionDestination _ Nothing ) = return Nothing | 191 | encodeOnionAddr _ (msg,OnionDestination _ Nothing ) = do |
192 | hPutStrLn stderr $ "ONION encode missing routeid" | ||
193 | return Nothing | ||
180 | encodeOnionAddr getRoute (msg,OnionDestination ni (Just rid)) = do | 194 | encodeOnionAddr getRoute (msg,OnionDestination ni (Just rid)) = do |
181 | let go route = do | 195 | let go route0 = do |
182 | return (runPut $ putRequest $ wrapForRoute msg ni route, nodeAddr ni) | 196 | let route = route0 { routeNonce = msgNonce msg } -- TODO: This necessary? |
183 | getRoute ni rid >>= mapM go | 197 | return ( runPut $ putRequest $ wrapForRoute msg ni route |
198 | , nodeAddr $ routeNodeA route) | ||
199 | mapM' f x = do | ||
200 | hPutStrLn stderr $ "ONION encode sending to " ++ show ni | ||
201 | hPutStrLn stderr $ "ONION encode getRoute -> " ++ show (mapM (\y -> map ($ y) [routeNodeA,routeNodeB,routeNodeC]) x) | ||
202 | mapM f x | ||
203 | getRoute ni rid >>= mapM' go | ||
184 | 204 | ||
185 | 205 | ||
186 | forwardOnions :: TransportCrypto -> UDPTransport -> UDPTransport | 206 | forwardOnions :: TransportCrypto -> UDPTransport -> UDPTransport |
@@ -239,16 +259,19 @@ deriving instance ( Show (Forwarding (ThreeMinus n) (OnionMessage Encrypted)) | |||
239 | instance ( Serialize (Forwarding (ThreeMinus n) (OnionMessage Encrypted)) | 259 | instance ( Serialize (Forwarding (ThreeMinus n) (OnionMessage Encrypted)) |
240 | , Sized (ReturnPath n) | 260 | , Sized (ReturnPath n) |
241 | , Serialize (ReturnPath n) | 261 | , Serialize (ReturnPath n) |
262 | , Typeable n | ||
242 | ) => Serialize (OnionRequest n) where | 263 | ) => Serialize (OnionRequest n) where |
243 | get = do | 264 | get = do |
244 | -- TODO share code with 'getOnionRequest' | 265 | -- TODO share code with 'getOnionRequest' |
245 | n24 <- get | 266 | n24 <- case eqT :: Maybe (n :~: N3) of |
267 | Just Refl -> return $ Nonce24 zeros24 | ||
268 | Nothing -> get | ||
246 | cnt <- remaining | 269 | cnt <- remaining |
247 | let fwdsize = case size :: Size (ReturnPath n) of ConstSize n -> cnt - n | 270 | let fwdsize = case size :: Size (ReturnPath n) of ConstSize n -> cnt - n |
248 | fwd <- isolate fwdsize get | 271 | fwd <- isolate fwdsize get |
249 | rpath <- get | 272 | rpath <- get |
250 | return $ OnionRequest n24 fwd rpath | 273 | return $ OnionRequest n24 fwd rpath |
251 | put (OnionRequest n f p) = put n >> put f >> put p | 274 | put (OnionRequest n f p) = maybe (put n) (\Refl -> return ()) (eqT :: Maybe (n :~: N3)) >> put f >> put p |
252 | 275 | ||
253 | -- getRequest :: _ | 276 | -- getRequest :: _ |
254 | -- getRequest = OnionRequest <$> get <*> get <*> get | 277 | -- getRequest = OnionRequest <$> get <*> get <*> get |
@@ -402,6 +425,7 @@ handleOnionRequest :: forall a proxy n. | |||
402 | ( LessThanThree n | 425 | ( LessThanThree n |
403 | , KnownPeanoNat n | 426 | , KnownPeanoNat n |
404 | , Sized (ReturnPath n) | 427 | , Sized (ReturnPath n) |
428 | , Typeable n | ||
405 | ) => proxy n -> TransportCrypto -> SockAddr -> UDPTransport -> IO a -> OnionRequest n -> IO a | 429 | ) => proxy n -> TransportCrypto -> SockAddr -> UDPTransport -> IO a -> OnionRequest n -> IO a |
406 | handleOnionRequest proxy crypto saddr udp kont (OnionRequest nonce msg rpath) = do | 430 | handleOnionRequest proxy crypto saddr udp kont (OnionRequest nonce msg rpath) = do |
407 | let n = peanoVal rpath | 431 | let n = peanoVal rpath |
@@ -414,7 +438,7 @@ handleOnionRequest proxy crypto saddr udp kont (OnionRequest nonce msg rpath) = | |||
414 | hPutStrLn stderr $ unwords [ "peelOnion:", show n, either show show (either4or6 saddr), e] | 438 | hPutStrLn stderr $ unwords [ "peelOnion:", show n, either show show (either4or6 saddr), e] |
415 | kont | 439 | kont |
416 | Right (Addressed dst msg') -> do | 440 | Right (Addressed dst msg') -> do |
417 | hPutStrLn stderr $ unwords [ "peelOnion:", show n, either show show (either4or6 saddr), "SUCCESS"] | 441 | hPutStrLn stderr $ unwords [ "peelOnion:", show n, either show show (either4or6 saddr), "-->", either show show (either4or6 dst), "SUCCESS"] |
418 | sendMessage udp dst (runPut $ putRequest $ OnionRequest nonce msg' $ wrapSymmetric sym snonce saddr rpath) | 442 | sendMessage udp dst (runPut $ putRequest $ OnionRequest nonce msg' $ wrapSymmetric sym snonce saddr rpath) |
419 | kont | 443 | kont |
420 | 444 | ||
@@ -472,9 +496,13 @@ getOnionRequest = do | |||
472 | path <- get | 496 | path <- get |
473 | return (a,path) | 497 | return (a,path) |
474 | 498 | ||
475 | putRequest :: (KnownPeanoNat n, Serialize (OnionRequest n)) => OnionRequest n -> Put | 499 | putRequest :: ( KnownPeanoNat n |
500 | , Serialize (OnionRequest n) | ||
501 | , Typeable n | ||
502 | ) => OnionRequest n -> Put | ||
476 | putRequest req = do | 503 | putRequest req = do |
477 | putWord8 $ 0x80 + fromIntegral (peanoVal req) | 504 | let tag = 0x80 + fromIntegral (peanoVal req) |
505 | when (tag <= 0x82) (putWord8 tag) | ||
478 | put req | 506 | put req |
479 | 507 | ||
480 | putResponse :: (KnownPeanoNat n, Serialize (OnionResponse n)) => OnionResponse n -> Put | 508 | putResponse :: (KnownPeanoNat n, Serialize (OnionResponse n)) => OnionResponse n -> Put |
@@ -513,9 +541,14 @@ data AnnounceResponse = AnnounceResponse | |||
513 | instance Sized AnnounceResponse where | 541 | instance Sized AnnounceResponse where |
514 | size = contramap is_stored size <> contramap announceNodes size | 542 | size = contramap is_stored size <> contramap announceNodes size |
515 | 543 | ||
544 | getNodeList :: S.Get [NodeInfo] | ||
545 | getNodeList = do | ||
546 | n <- S.get | ||
547 | (:) n <$> (getNodeList <|> pure []) | ||
548 | |||
516 | instance S.Serialize AnnounceResponse where | 549 | instance S.Serialize AnnounceResponse where |
517 | get = AnnounceResponse <$> S.get <*> S.get | 550 | get = AnnounceResponse <$> S.get <*> (SendNodes <$> getNodeList) |
518 | put (AnnounceResponse st ns) = S.put st >> S.put ns | 551 | put (AnnounceResponse st (SendNodes ns)) = S.put st >> mapM_ S.put ns |
519 | 552 | ||
520 | data DataToRoute = DataToRoute | 553 | data DataToRoute = DataToRoute |
521 | { dataFromKey :: PublicKey -- Real public key of sender | 554 | { dataFromKey :: PublicKey -- Real public key of sender |