summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoe Crayne <joe@jerkface.net>2020-01-03 17:12:14 -0500
committerJoe Crayne <joe@jerkface.net>2020-01-03 17:26:06 -0500
commit5181c77ce7dd73d622ff3921b90bf2741bedb646 (patch)
tree16ba93b83ad0c137a013e47f593d7d40ace68ce6
parent31b799222cb76cd0002d9a3cc5b340a7b6fed139 (diff)
QueryResponse: Use three-way sum to distinguish Canceled and Timedout.
-rw-r--r--dht/src/Network/BitTorrent/MainlineDHT.hs21
-rw-r--r--dht/src/Network/Tox/DHT/Handlers.hs8
-rw-r--r--dht/src/Network/Tox/Onion/Handlers.hs2
-rw-r--r--dht/src/Network/Tox/Onion/Routes.hs2
-rw-r--r--dht/src/Network/Tox/TCP.hs10
-rw-r--r--server/src/Network/QueryResponse.hs35
6 files changed, 46 insertions, 32 deletions
diff --git a/dht/src/Network/BitTorrent/MainlineDHT.hs b/dht/src/Network/BitTorrent/MainlineDHT.hs
index bb556bc6..e604f5e5 100644
--- a/dht/src/Network/BitTorrent/MainlineDHT.hs
+++ b/dht/src/Network/BitTorrent/MainlineDHT.hs
@@ -1033,21 +1033,22 @@ announceH (SwarmsDatabase peers toks _) naddr announcement = do
1033isReadonlyClient :: MainlineClient -> Bool 1033isReadonlyClient :: MainlineClient -> Bool
1034isReadonlyClient client = False -- TODO 1034isReadonlyClient client = False -- TODO
1035 1035
1036mainlineSend :: ( BEncode a 1036mainlineSend :: ( BEncode xqry
1037 , BEncode a2 1037 , BEncode xrsp
1038 ) => Method 1038 ) => Method
1039 -> (a2 -> b) 1039 -> (xrsp -> rsp)
1040 -> (t -> a) 1040 -> (qry -> xqry)
1041 -> MainlineClient 1041 -> MainlineClient
1042 -> t 1042 -> qry
1043 -> NodeInfo 1043 -> NodeInfo
1044 -> IO (Maybe b) 1044 -> IO (Maybe rsp)
1045mainlineSend meth unwrap msg client nid addr = do 1045mainlineSend meth unwrap msg client nid addr = do
1046 reply <- sendQuery client serializer (msg nid) addr 1046 reply <- sendQuery client serializer (msg nid) addr
1047 -- sendQuery will return (Just (Left _)) on a parse error. We're going to 1047 return $ case reply of
1048 -- blow it away with the join-either sequence. 1048 Success (Right x) -> Just x
1049 -- TODO: Do something with parse errors. 1049 Success (Left e) -> Nothing -- TODO: Do something with parse errors.
1050 return $ join $ either (const Nothing) Just <$> reply 1050 Canceled -> Nothing
1051 TimedOut -> Nothing
1051 where 1052 where
1052 serializer = MethodSerializer 1053 serializer = MethodSerializer
1053 { methodTimeout = \ni -> return (ni, 5000000) 1054 { methodTimeout = \ni -> return (ni, 5000000)
diff --git a/dht/src/Network/Tox/DHT/Handlers.hs b/dht/src/Network/Tox/DHT/Handlers.hs
index 7806da78..dc4ca5fa 100644
--- a/dht/src/Network/Tox/DHT/Handlers.hs
+++ b/dht/src/Network/Tox/DHT/Handlers.hs
@@ -353,7 +353,7 @@ ping client addr = do
353 dput XPing $ show addr ++ " <-- ping" 353 dput XPing $ show addr ++ " <-- ping"
354 reply <- QR.sendQuery client (serializer PingType DHTPing unpong) Ping addr 354 reply <- QR.sendQuery client (serializer PingType DHTPing unpong) Ping addr
355 dput XPing $ show addr ++ " -pong-> " ++ show reply 355 dput XPing $ show addr ++ " -pong-> " ++ show reply
356 maybe (return False) (\Pong -> return True) $ join reply 356 maybe (return False) (\Pong -> return True) $ join $ resultToMaybe reply
357 357
358 358
359saveCookieKey :: TVar [(SockAddr, (Int, PublicKey))] -> SockAddr -> PublicKey -> STM () 359saveCookieKey :: TVar [(SockAddr, (Int, PublicKey))] -> SockAddr -> PublicKey -> STM ()
@@ -396,7 +396,7 @@ cookieRequest crypto client localUserKey addr = do
396 reply <- QR.sendQuery client cookieSerializer cookieRequest addr 396 reply <- QR.sendQuery client cookieSerializer cookieRequest addr
397 runlast 397 runlast
398 dput XNetCrypto $ show addr ++ " -cookieResponse-> " ++ show reply 398 dput XNetCrypto $ show addr ++ " -cookieResponse-> " ++ show reply
399 return $ join reply 399 return $ join $ resultToMaybe reply
400 400
401unCookie :: DHTMessage t -> Maybe (t (Cookie Encrypted)) 401unCookie :: DHTMessage t -> Maybe (t (Cookie Encrypted))
402unCookie (DHTCookie n24 fcookie) = Just fcookie 402unCookie (DHTCookie n24 fcookie) = Just fcookie
@@ -415,7 +415,7 @@ getNodes client cbvar nid addr = do
415 -- dput XMisc $ show addr ++ " <-- getnodes " ++ show nid 415 -- dput XMisc $ show addr ++ " <-- getnodes " ++ show nid
416 reply <- QR.sendQuery client (serializer GetNodesType DHTGetNodes unsendNodes) (GetNodes nid) addr 416 reply <- QR.sendQuery client (serializer GetNodesType DHTGetNodes unsendNodes) (GetNodes nid) addr
417 -- dput XMisc $ show addr ++ " -sendnodes-> " ++ show reply 417 -- dput XMisc $ show addr ++ " -sendnodes-> " ++ show reply
418 forM_ (join reply) $ \(SendNodes ns) -> 418 forM_ (join $ resultToMaybe reply) $ \(SendNodes ns) ->
419 forM_ ns $ \n -> do 419 forM_ ns $ \n -> do
420 now <- getPOSIXTime 420 now <- getPOSIXTime
421 atomically $ do 421 atomically $ do
@@ -423,7 +423,7 @@ getNodes client cbvar nid addr = do
423 forM_ mcbs $ \cbs -> do 423 forM_ mcbs $ \cbs -> do
424 forM_ cbs $ \cb -> do 424 forM_ cbs $ \cb -> do
425 rumoredAddress cb now addr (udpNodeInfo n) 425 rumoredAddress cb now addr (udpNodeInfo n)
426 return $ fmap unwrapNodes $ join reply 426 return $ fmap unwrapNodes $ join $ resultToMaybe reply
427 427
428getNodesUDP :: Client -> TVar (HashMap NodeId [NodeInfoCallback]) -> NodeId -> NodeInfo -> IO (Maybe ([NodeInfo],[NodeInfo],Maybe ())) 428getNodesUDP :: Client -> TVar (HashMap NodeId [NodeInfoCallback]) -> NodeId -> NodeInfo -> IO (Maybe ([NodeInfo],[NodeInfo],Maybe ()))
429getNodesUDP client cbvar nid addr = getNodes client cbvar nid (Multi.UDP ==> addr) 429getNodesUDP client cbvar nid addr = getNodes client cbvar nid (Multi.UDP ==> addr)
diff --git a/dht/src/Network/Tox/Onion/Handlers.hs b/dht/src/Network/Tox/Onion/Handlers.hs
index 65ec846c..fa7bc83c 100644
--- a/dht/src/Network/Tox/Onion/Handlers.hs
+++ b/dht/src/Network/Tox/Onion/Handlers.hs
@@ -285,7 +285,7 @@ sendOnion getTimeout client req oaddr unwrap =
285 forM_ mb $ \r -> dput XAnnounce $ show (onionNodeInfo oaddr) ++ " sent response: " ++ show r 285 forM_ mb $ \r -> dput XAnnounce $ show (onionNodeInfo oaddr) ++ " sent response: " ++ show r
286 maybe (if n>0 then loop $! n - 1 else return Nothing) 286 maybe (if n>0 then loop $! n - 1 else return Nothing)
287 (return . Just . unwrap (onionNodeInfo oaddr)) 287 (return . Just . unwrap (onionNodeInfo oaddr))
288 $ join mb 288 $ join $ resultToMaybe mb
289 289
290 290
291-- | Lookup the secret counterpart for a given alias key. 291-- | Lookup the secret counterpart for a given alias key.
diff --git a/dht/src/Network/Tox/Onion/Routes.hs b/dht/src/Network/Tox/Onion/Routes.hs
index b20ad7dd..7c11227a 100644
--- a/dht/src/Network/Tox/Onion/Routes.hs
+++ b/dht/src/Network/Tox/Onion/Routes.hs
@@ -171,7 +171,7 @@ newOnionRouter crypto perror tcp_enabled = do
171 ((tbl,(tcptbl,tcpcons,relaynet,onionnet)),tcp) <- do 171 ((tbl,(tcptbl,tcpcons,relaynet,onionnet)),tcp) <- do
172 (tcptbl, client) <- TCP.newClient crypto 172 (tcptbl, client) <- TCP.newClient crypto
173 id 173 id
174 (. (Just . (,) False)) 174 (. (Success . (,) False))
175 (lookupSender' pq rlog) 175 (lookupSender' pq rlog)
176 (\_ (RouteId rid) -> atomically $ fmap storedRoute <$> readArray rm rid) 176 (\_ (RouteId rid) -> atomically $ fmap storedRoute <$> readArray rm rid)
177 177
diff --git a/dht/src/Network/Tox/TCP.hs b/dht/src/Network/Tox/TCP.hs
index 9f0af976..0850ce51 100644
--- a/dht/src/Network/Tox/TCP.hs
+++ b/dht/src/Network/Tox/TCP.hs
@@ -46,7 +46,7 @@ import DPut
46import Network.Address (setPort,PortNumber,localhost4,fromSockAddr,nullAddress4) 46import Network.Address (setPort,PortNumber,localhost4,fromSockAddr,nullAddress4)
47import Network.Kademlia.Routing 47import Network.Kademlia.Routing
48import Network.Kademlia.Search hiding (sendQuery) 48import Network.Kademlia.Search hiding (sendQuery)
49import Network.QueryResponse 49import Network.QueryResponse as QR
50import Network.QueryResponse.TCP 50import Network.QueryResponse.TCP
51import Network.Tox.TCP.NodeId () 51import Network.Tox.TCP.NodeId ()
52import Network.Tox.DHT.Transport (toxSpace) 52import Network.Tox.DHT.Transport (toxSpace)
@@ -226,7 +226,7 @@ getUDPNodes tcp seeking dst = fmap fst <$> getUDPNodes' tcp seeking dst
226getUDPNodes' :: TCPClient err Nonce8 -> NodeId -> UDP.NodeInfo -> IO (Maybe (([UDP.NodeInfo], [UDP.NodeInfo], Maybe ()), NodeInfo)) 226getUDPNodes' :: TCPClient err Nonce8 -> NodeId -> UDP.NodeInfo -> IO (Maybe (([UDP.NodeInfo], [UDP.NodeInfo], Maybe ()), NodeInfo))
227getUDPNodes' tcp seeking dst0 = do 227getUDPNodes' tcp seeking dst0 = do
228 mgateway <- atomically $ tcpGetGateway tcp dst0 228 mgateway <- atomically $ tcpGetGateway tcp dst0
229 fmap join $ forM mgateway $ \gateway -> do 229 fmap (join . fmap resultToMaybe) $ forM mgateway $ \gateway -> do
230 (b,c,n24) <- atomically $ do 230 (b,c,n24) <- atomically $ do
231 b <- transportNewKey (tcpCrypto tcp) 231 b <- transportNewKey (tcpCrypto tcp)
232 c <- transportNewKey (tcpCrypto tcp) 232 c <- transportNewKey (tcpCrypto tcp)
@@ -284,7 +284,7 @@ handle2route o src dst = do
284tcpPing :: Show addr => Client err PacketNumber Nonce8 addr (Bool,RelayPacket) -> addr -> IO (Maybe ()) 284tcpPing :: Show addr => Client err PacketNumber Nonce8 addr (Bool,RelayPacket) -> addr -> IO (Maybe ())
285tcpPing client dst = do 285tcpPing client dst = do
286 dput XTCP $ "tcpPing " ++ show dst 286 dput XTCP $ "tcpPing " ++ show dst
287 sendQuery client meth () dst 287 resultToMaybe <$> sendQuery client meth () dst
288 where meth = MethodSerializer 288 where meth = MethodSerializer
289 { wrapQuery = \n8 src dst () -> (True,RelayPing n8) 289 { wrapQuery = \n8 src dst () -> (True,RelayPing n8)
290 , unwrapResponse = \_ -> () 290 , unwrapResponse = \_ -> ()
@@ -295,7 +295,7 @@ tcpPing client dst = do
295tcpConnectionRequest_ :: Client err PacketNumber tid addr (Bool, RelayPacket) 295tcpConnectionRequest_ :: Client err PacketNumber tid addr (Bool, RelayPacket)
296 -> PublicKey -> addr -> IO (Maybe ConId) 296 -> PublicKey -> addr -> IO (Maybe ConId)
297tcpConnectionRequest_ client pubkey ni = do 297tcpConnectionRequest_ client pubkey ni = do
298 sendQuery client meth pubkey ni 298 resultToMaybe <$> sendQuery client meth pubkey ni
299 where 299 where
300 meth = MethodSerializer 300 meth = MethodSerializer
301 { wrapQuery = \n8 src dst pubkey -> (True,RoutingRequest pubkey) 301 { wrapQuery = \n8 src dst pubkey -> (True,RoutingRequest pubkey)
@@ -319,7 +319,7 @@ type RelayCache = TCPCache (SessionProtocol (SessionData,RelayPacket) RelayPacke
319-- defaults are 'id' and 'tryPutMVar'. The resulting customized table state 319-- defaults are 'id' and 'tryPutMVar'. The resulting customized table state
320-- will be returned to the caller along with the new client. 320-- will be returned to the caller along with the new client.
321newClient :: TransportCrypto 321newClient :: TransportCrypto
322 -> ((Maybe (Bool,RelayPacket) -> IO ()) -> a) -- ^ store mvar for relay query 322 -> ((QR.Result (Bool,RelayPacket) -> IO ()) -> a) -- ^ store mvar for relay query
323 -> (a -> RelayPacket -> IO void) -- ^ load mvar for relay query 323 -> (a -> RelayPacket -> IO void) -- ^ load mvar for relay query
324 -> (SockAddr -> Nonce8 -> IO (Maybe (OnionDestination RouteId))) -- ^ lookup sender of onion query 324 -> (SockAddr -> Nonce8 -> IO (Maybe (OnionDestination RouteId))) -- ^ lookup sender of onion query
325 -> (UDP.NodeInfo -> RouteId -> IO (Maybe OnionRoute)) -- ^ lookup OnionRoute by id 325 -> (UDP.NodeInfo -> RouteId -> IO (Maybe OnionRoute)) -- ^ lookup OnionRoute by id
diff --git a/server/src/Network/QueryResponse.hs b/server/src/Network/QueryResponse.hs
index 20e7ecf0..cb65eb47 100644
--- a/server/src/Network/QueryResponse.hs
+++ b/server/src/Network/QueryResponse.hs
@@ -2,6 +2,9 @@
2-- with Kademlia implementations in mind. 2-- with Kademlia implementations in mind.
3 3
4{-# LANGUAGE CPP #-} 4{-# LANGUAGE CPP #-}
5{-# LANGUAGE DeriveFoldable #-}
6{-# LANGUAGE DeriveFunctor #-}
7{-# LANGUAGE DeriveTraversable #-}
5{-# LANGUAGE GADTs #-} 8{-# LANGUAGE GADTs #-}
6{-# LANGUAGE LambdaCase #-} 9{-# LANGUAGE LambdaCase #-}
7{-# LANGUAGE PartialTypeSignatures #-} 10{-# LANGUAGE PartialTypeSignatures #-}
@@ -32,6 +35,7 @@ import qualified Data.IntMap.Strict as IntMap
32import qualified Data.Map.Strict as Map 35import qualified Data.Map.Strict as Map
33 ;import Data.Map.Strict (Map) 36 ;import Data.Map.Strict (Map)
34import Data.Time.Clock.POSIX 37import Data.Time.Clock.POSIX
38import Data.Traversable (Traversable)
35import qualified Data.Word64Map as W64Map 39import qualified Data.Word64Map as W64Map
36 ;import Data.Word64Map (Word64Map) 40 ;import Data.Word64Map (Word64Map)
37import Data.Word 41import Data.Word
@@ -49,6 +53,15 @@ import DPut
49import DebugTag 53import DebugTag
50import Data.TableMethods 54import Data.TableMethods
51 55
56-- | The reply to a query to a remote server or the result of some other IO
57-- process that can timeout or be canceled.
58data Result a = Success a | TimedOut | Canceled
59 deriving (Functor, Foldable, Traversable, Eq, Ord, Show)
60
61resultToMaybe :: Result a -> Maybe a
62resultToMaybe (Success a) = Just a
63resultToMaybe _ = Nothing
64
52-- | An inbound packet or condition raised while monitoring a connection. 65-- | An inbound packet or condition raised while monitoring a connection.
53data Arrival err addr x 66data Arrival err addr x
54 = Terminated -- ^ Virtual message that signals EOF. 67 = Terminated -- ^ Virtual message that signals EOF.
@@ -310,7 +323,7 @@ data TransactionMethods d qid addr x = TransactionMethods
310 -- that can be used to forget the 'MVar' if the remote peer is not 323 -- that can be used to forget the 'MVar' if the remote peer is not
311 -- responding. 324 -- responding.
312 dispatchRegister :: POSIXTime -- time of expiry 325 dispatchRegister :: POSIXTime -- time of expiry
313 -> (Maybe x -> IO ()) -- callback upon response (or timeout) 326 -> (Result x -> IO ()) -- callback upon response (or timeout)
314 -> addr 327 -> addr
315 -> d 328 -> d
316 -> STM (qid, d) 329 -> STM (qid, d)
@@ -394,7 +407,7 @@ asyncQuery_ :: Client err meth tid addr x
394 -> MethodSerializer tid addr x meth a b 407 -> MethodSerializer tid addr x meth a b
395 -> a 408 -> a
396 -> addr 409 -> addr
397 -> (Maybe b -> IO ()) 410 -> (Result b -> IO ())
398 -> IO (tid,POSIXTime,Int) 411 -> IO (tid,POSIXTime,Int)
399asyncQuery_ (Client net d err pending whoami _) meth q addr0 withResponse = do 412asyncQuery_ (Client net d err pending whoami _) meth q addr0 withResponse = do
400 now <- getPOSIXTime 413 now <- getPOSIXTime
@@ -419,14 +432,14 @@ asyncQuery :: Show meth => Client err meth tid addr x
419 -> MethodSerializer tid addr x meth a b 432 -> MethodSerializer tid addr x meth a b
420 -> a 433 -> a
421 -> addr 434 -> addr
422 -> (Maybe b -> IO ()) 435 -> (Result b -> IO ())
423 -> IO () 436 -> IO ()
424asyncQuery client meth q addr withResponse0 = do 437asyncQuery client meth q addr withResponse0 = do
425 tm <- getSystemTimerManager 438 tm <- getSystemTimerManager
426 tidvar <- newEmptyMVar 439 tidvar <- newEmptyMVar
427 timedout <- registerTimeout tm 1000000 $ do 440 timedout <- registerTimeout tm 1000000 $ do
428 dput XMisc $ "async TIMEDOUT " ++ show (method meth) 441 dput XMisc $ "async TIMEDOUT " ++ show (method meth)
429 withResponse0 Nothing 442 withResponse0 TimedOut
430 tid <- takeMVar tidvar 443 tid <- takeMVar tidvar
431 dput XMisc $ "async TIMEDOUT mvar " ++ show (method meth) 444 dput XMisc $ "async TIMEDOUT mvar " ++ show (method meth)
432 case client of 445 case client of
@@ -448,16 +461,16 @@ sendQuery ::
448 -> MethodSerializer tid addr x meth a b -- ^ Information for marshaling the query. 461 -> MethodSerializer tid addr x meth a b -- ^ Information for marshaling the query.
449 -> a -- ^ The outbound query. 462 -> a -- ^ The outbound query.
450 -> addr -- ^ Destination address of query. 463 -> addr -- ^ Destination address of query.
451 -> IO (Maybe b) -- ^ The response, or 'Nothing' if it timed out. 464 -> IO (Result b) -- ^ The response or failure condition.
452sendQuery c@(Client net d err pending whoami _) meth q addr0 = do 465sendQuery c@(Client net d err pending whoami _) meth q addr0 = do
453 mvar <- newEmptyMVar 466 mvar <- newEmptyMVar
454 (tid,now,expiry) <- asyncQuery_ c meth q addr0 $ mapM_ (putMVar mvar) 467 (tid,now,expiry) <- asyncQuery_ c meth q addr0 $ mapM_ (putMVar mvar)
455 mres <- timeout expiry $ takeMVar mvar 468 mres <- timeout expiry $ takeMVar mvar
456 case mres of 469 case mres of
457 Just b -> return $ Just b 470 Just b -> return $ Success b
458 Nothing -> do 471 Nothing -> do
459 atomically $ readTVar pending >>= dispatchCancel (tableMethods d) tid >>= writeTVar pending 472 atomically $ readTVar pending >>= dispatchCancel (tableMethods d) tid >>= writeTVar pending
460 return Nothing 473 return TimedOut
461 474
462contramapAddr :: (a -> b) -> MethodHandler err tid b x -> MethodHandler err tid a x 475contramapAddr :: (a -> b) -> MethodHandler err tid b x -> MethodHandler err tid a x
463contramapAddr f (MethodHandler p s a) 476contramapAddr f (MethodHandler p s a)
@@ -495,8 +508,8 @@ dispatchQuery (NoReply unwrapQ f) tid self x addr =
495-- table of pending transactions. This also enables multiple 'Client's to 508-- table of pending transactions. This also enables multiple 'Client's to
496-- share a single transaction table. 509-- share a single transaction table.
497transactionMethods' :: 510transactionMethods' ::
498 ((Maybe x -> IO ()) -> a) -- ^ store MVar into table entry 511 ((Result x -> IO ()) -> a) -- ^ store MVar into table entry
499 -> (a -> Maybe x -> IO void) -- ^ load MVar from table entry 512 -> (a -> Result x -> IO void) -- ^ load MVar from table entry
500 -> TableMethods t tid -- ^ Table methods to lookup values by /tid/. 513 -> TableMethods t tid -- ^ Table methods to lookup values by /tid/.
501 -> (g -> (tid,g)) -- ^ Generate a new unique /tid/ value and update the generator state /g/. 514 -> (g -> (tid,g)) -- ^ Generate a new unique /tid/ value and update the generator state /g/.
502 -> TransactionMethods (g,t a) tid addr x 515 -> TransactionMethods (g,t a) tid addr x
@@ -509,7 +522,7 @@ transactionMethods' store load (TableMethods insert delete lookup) generate = Tr
509 , dispatchResponse = \tid x (g,t) -> 522 , dispatchResponse = \tid x (g,t) ->
510 case lookup tid t of 523 case lookup tid t of
511 Just v -> let t' = delete tid t 524 Just v -> let t' = delete tid t
512 in return ((g,t'),void $ load v $ Just x) 525 in return ((g,t'),void $ load v $ Success x)
513 Nothing -> return ((g,t), return ()) 526 Nothing -> return ((g,t), return ())
514 } 527 }
515 528
@@ -518,7 +531,7 @@ transactionMethods' store load (TableMethods insert delete lookup) generate = Tr
518transactionMethods :: 531transactionMethods ::
519 TableMethods t tid -- ^ Table methods to lookup values by /tid/. 532 TableMethods t tid -- ^ Table methods to lookup values by /tid/.
520 -> (g -> (tid,g)) -- ^ Generate a new unique /tid/ value and update the generator state /g/. 533 -> (g -> (tid,g)) -- ^ Generate a new unique /tid/ value and update the generator state /g/.
521 -> TransactionMethods (g,t (Maybe x -> IO ())) tid addr x 534 -> TransactionMethods (g,t (Result x -> IO ())) tid addr x
522transactionMethods methods generate = transactionMethods' id id methods generate 535transactionMethods methods generate = transactionMethods' id id methods generate
523 536
524-- | Handle a single inbound packet and then invoke the given continuation. 537-- | Handle a single inbound packet and then invoke the given continuation.