diff options
author | Joe Crayne <joe@jerkface.net> | 2020-01-09 14:04:37 -0500 |
---|---|---|
committer | Joe Crayne <joe@jerkface.net> | 2020-01-09 14:04:37 -0500 |
commit | 778114bb6c644c496859e8281e96d5e44661e183 (patch) | |
tree | 0f49cabcef5712f799149c5422f33c43a97910af | |
parent | fb8196cde5a56337a0e028f837a34ef1bdbcc94f (diff) |
Support for binding UDP "fake" port to simulate TCP-only connections.
-rw-r--r-- | dht/examples/dhtd.hs | 11 | ||||
-rw-r--r-- | dht/src/Network/BitTorrent/MainlineDHT.hs | 7 | ||||
-rw-r--r-- | dht/src/Network/Tox.hs | 13 | ||||
-rw-r--r-- | server/server.cabal | 15 | ||||
-rw-r--r-- | server/src/Network/Bind.hs | 36 | ||||
-rw-r--r-- | server/src/Network/QueryResponse.hs | 9 |
6 files changed, 78 insertions, 13 deletions
diff --git a/dht/examples/dhtd.hs b/dht/examples/dhtd.hs index 2f39303c..ed0feacb 100644 --- a/dht/examples/dhtd.hs +++ b/dht/examples/dhtd.hs | |||
@@ -38,6 +38,7 @@ import qualified Data.Conduit.List as C | |||
38 | import Data.Data | 38 | import Data.Data |
39 | import Data.Dependent.Sum | 39 | import Data.Dependent.Sum |
40 | import Data.Function | 40 | import Data.Function |
41 | import Data.Functor | ||
41 | import Data.Functor.Identity | 42 | import Data.Functor.Identity |
42 | import Data.Hashable | 43 | import Data.Hashable |
43 | import Data.List | 44 | import Data.List |
@@ -71,6 +72,7 @@ import qualified Data.Tox.DHT.Multi as Multi | |||
71 | import DebugUtil | 72 | import DebugUtil |
72 | import Network.UPNP as UPNP | 73 | import Network.UPNP as UPNP |
73 | import Network.Address hiding (NodeId, NodeInfo(..)) | 74 | import Network.Address hiding (NodeId, NodeInfo(..)) |
75 | import Network.Bind as Bind | ||
74 | import Network.QueryResponse | 76 | import Network.QueryResponse |
75 | import qualified Network.QueryResponse.TCP as TCP | 77 | import qualified Network.QueryResponse.TCP as TCP |
76 | import Network.StreamServer | 78 | import Network.StreamServer |
@@ -1771,8 +1773,13 @@ main = do | |||
1771 | (quitBt,btdhts,btips,baddrs) <- case portbt opts of | 1773 | (quitBt,btdhts,btips,baddrs) <- case portbt opts of |
1772 | "" -> return (return (), Map.empty,return [],[]) | 1774 | "" -> return (return (), Map.empty,return [],[]) |
1773 | p -> do | 1775 | p -> do |
1774 | addr <- getBindAddress p (ip6bt opts) | 1776 | msock <- Bind.udpTransport' (ip6bt opts) [p,"0"] |
1775 | (bt,btR,btBootstrap4, btBootstrap6,quitBtClient) <- Mainline.newClient swarms addr | 1777 | let bail = do |
1778 | dput XMisc $ "Bittorrent DHT disabled. Unable to bind bittorrent dht port: " ++ p | ||
1779 | return (return (), Map.empty, return [], []) | ||
1780 | fromMaybe bail $ msock <&> \(udp,sock) -> do | ||
1781 | addr <- getSocketName sock | ||
1782 | (bt,btR,btBootstrap4, btBootstrap6,quitBtClient) <- Mainline.newClient swarms addr udp | ||
1776 | quitBt <- forkListener "bt" (clientNet bt) | 1783 | quitBt <- forkListener "bt" (clientNet bt) |
1777 | mainlineSearches <- atomically $ newTVar Map.empty | 1784 | mainlineSearches <- atomically $ newTVar Map.empty |
1778 | peerPort <- atomically $ newTVar 6881 -- BitTorrent client TCP port. | 1785 | peerPort <- atomically $ newTVar 6881 -- BitTorrent client TCP port. |
diff --git a/dht/src/Network/BitTorrent/MainlineDHT.hs b/dht/src/Network/BitTorrent/MainlineDHT.hs index d3904c40..a83cf740 100644 --- a/dht/src/Network/BitTorrent/MainlineDHT.hs +++ b/dht/src/Network/BitTorrent/MainlineDHT.hs | |||
@@ -545,15 +545,16 @@ mkNodeInfo nid addr = NodeInfo | |||
545 | , nodePort = fromMaybe 0 $ sockAddrPort addr | 545 | , nodePort = fromMaybe 0 $ sockAddrPort addr |
546 | } | 546 | } |
547 | 547 | ||
548 | newClient :: SwarmsDatabase -> SockAddr | 548 | newClient :: SwarmsDatabase |
549 | -> SockAddr -- ^ Tentative IP address for this node (the bind address is suitable). | ||
550 | -> Transport String SockAddr ByteString -- ^ UDP transport | ||
549 | -> IO ( MainlineClient | 551 | -> IO ( MainlineClient |
550 | , Routing | 552 | , Routing |
551 | , [NodeInfo] -> [NodeInfo] -> IO () | 553 | , [NodeInfo] -> [NodeInfo] -> IO () |
552 | , [NodeInfo] -> [NodeInfo] -> IO () | 554 | , [NodeInfo] -> [NodeInfo] -> IO () |
553 | , IO () | 555 | , IO () |
554 | ) | 556 | ) |
555 | newClient swarms addr = do | 557 | newClient swarms addr udp = do |
556 | udp <- udpTransport addr | ||
557 | nid <- NodeId <$> getRandomBytes 20 | 558 | nid <- NodeId <$> getRandomBytes 20 |
558 | let tentative_info = mkNodeInfo nid addr | 559 | let tentative_info = mkNodeInfo nid addr |
559 | tentative_info6 <- | 560 | tentative_info6 <- |
diff --git a/dht/src/Network/Tox.hs b/dht/src/Network/Tox.hs index 4aed1c43..270a9036 100644 --- a/dht/src/Network/Tox.hs +++ b/dht/src/Network/Tox.hs | |||
@@ -36,6 +36,7 @@ import qualified Data.ByteString.Char8 as C8 | |||
36 | import Data.Data | 36 | import Data.Data |
37 | import qualified Data.Dependent.Map as DMap | 37 | import qualified Data.Dependent.Map as DMap |
38 | import Data.Dependent.Sum | 38 | import Data.Dependent.Sum |
39 | import Data.Functor | ||
39 | import Data.Functor.Identity | 40 | import Data.Functor.Identity |
40 | import Data.Functor.Contravariant | 41 | import Data.Functor.Contravariant |
41 | import Data.Maybe | 42 | import Data.Maybe |
@@ -56,6 +57,7 @@ import qualified Data.Word64Map (empty) | |||
56 | ;import Data.Word64Map (fitsInInt) | 57 | ;import Data.Word64Map (fitsInInt) |
57 | import qualified Data.Wrapper.PSQ as PSQ | 58 | import qualified Data.Wrapper.PSQ as PSQ |
58 | import Network.Address (IP, WantIP (..), getBindAddress) | 59 | import Network.Address (IP, WantIP (..), getBindAddress) |
60 | import Network.Bind as Bind | ||
59 | import Network.BitTorrent.DHT.Token as Token | 61 | import Network.BitTorrent.DHT.Token as Token |
60 | import Network.Kademlia.Bootstrap (bootstrap, forkPollForRefresh) | 62 | import Network.Kademlia.Bootstrap (bootstrap, forkPollForRefresh) |
61 | import qualified Network.Kademlia.Routing as R | 63 | import qualified Network.Kademlia.Routing as R |
@@ -262,14 +264,11 @@ newTox :: TVar Onion.AnnouncedKeys -- ^ Store of announced keys we are a rende | |||
262 | -- ( Int -> Onion.OnionMessage Encrypted -> IO () ) -- ^ TCP-bound onion responses. XXX ignored | 264 | -- ( Int -> Onion.OnionMessage Encrypted -> IO () ) -- ^ TCP-bound onion responses. XXX ignored |
263 | -> IO (Tox extra) | 265 | -> IO (Tox extra) |
264 | newTox keydb bindspecs onsess crypto usetcp = do | 266 | newTox keydb bindspecs onsess crypto usetcp = do |
265 | addrs <- mapM (`getBindAddress` True) bindspecs | 267 | msock <- Bind.udpTransport' True bindspecs |
266 | let tryBind addr next _ = udpTransport' addr `catchIOError` (next . Just) | 268 | let failedBind = do |
267 | failedBind mbe = do | 269 | dput XDHT $ "tox udp bind error: " ++ show bindspecs |
268 | forM_ mbe $ \e -> do | ||
269 | dput XDHT $ "tox udp bind error: " ++ show addrs ++ " " ++ show e | ||
270 | throwIO e | ||
271 | throwIO $ userError "Tox UDP listen port?" | 270 | throwIO $ userError "Tox UDP listen port?" |
272 | (udp,sock) <- foldr tryBind failedBind addrs Nothing | 271 | fromMaybe failedBind $ msock <&> \(udp,sock) -> do |
273 | addr <- getSocketName sock | 272 | addr <- getSocketName sock |
274 | dput XOnion $ "UDP bind address: " ++ show addr | 273 | dput XOnion $ "UDP bind address: " ++ show addr |
275 | (relay,sendTCP) <- | 274 | (relay,sendTCP) <- |
diff --git a/server/server.cabal b/server/server.cabal index 44441ef1..b5a36f91 100644 --- a/server/server.cabal +++ b/server/server.cabal | |||
@@ -31,7 +31,20 @@ flag new-network-bsd | |||
31 | 31 | ||
32 | 32 | ||
33 | library | 33 | library |
34 | exposed-modules: Network.QueryResponse, Network.StreamServer, Network.SocketLike, Network.QueryResponse.TCP, Data.TableMethods, Connection.Tcp, Control.Concurrent.Delay, DNSCache, GetHostByAddr, ControlMaybe, SockAddr, Control.Concurrent.PingMachine, Connection | 34 | exposed-modules: Network.QueryResponse |
35 | , Network.StreamServer | ||
36 | , Network.SocketLike | ||
37 | , Network.QueryResponse.TCP | ||
38 | , Network.Bind | ||
39 | , Data.TableMethods | ||
40 | , Connection.Tcp | ||
41 | , Control.Concurrent.Delay | ||
42 | , DNSCache | ||
43 | , GetHostByAddr | ||
44 | , ControlMaybe | ||
45 | , SockAddr | ||
46 | , Control.Concurrent.PingMachine | ||
47 | , Connection | ||
35 | other-modules: ForkLabeled, DebugTag | 48 | other-modules: ForkLabeled, DebugTag |
36 | other-extensions: CPP, GADTs, LambdaCase, PartialTypeSignatures, RankNTypes, ScopedTypeVariables, TupleSections, TypeFamilies, TypeOperators, OverloadedStrings, GeneralizedNewtypeDeriving, DoAndIfThenElse, FlexibleInstances, StandaloneDeriving | 49 | other-extensions: CPP, GADTs, LambdaCase, PartialTypeSignatures, RankNTypes, ScopedTypeVariables, TupleSections, TypeFamilies, TypeOperators, OverloadedStrings, GeneralizedNewtypeDeriving, DoAndIfThenElse, FlexibleInstances, StandaloneDeriving |
37 | build-depends: base, stm, bytestring, dependent-map, dependent-sum, contravariant, containers, time, cpu, dput-hslogger, directory, lifted-base, hashable, conduit, text, psq-wrap, minmax-psq, lifted-concurrent, word64-map, network-addr | 50 | build-depends: base, stm, bytestring, dependent-map, dependent-sum, contravariant, containers, time, cpu, dput-hslogger, directory, lifted-base, hashable, conduit, text, psq-wrap, minmax-psq, lifted-concurrent, word64-map, network-addr |
diff --git a/server/src/Network/Bind.hs b/server/src/Network/Bind.hs new file mode 100644 index 00000000..d2442c82 --- /dev/null +++ b/server/src/Network/Bind.hs | |||
@@ -0,0 +1,36 @@ | |||
1 | module Network.Bind where | ||
2 | |||
3 | import Data.ByteString (ByteString) | ||
4 | import Network.Socket | ||
5 | import System.IO.Error | ||
6 | |||
7 | import Network.Address (getBindAddress) | ||
8 | import qualified Network.QueryResponse as QR | ||
9 | ;import Network.QueryResponse hiding (udpTransport, udpTransport') | ||
10 | |||
11 | -- | Try (in order) a list of port numbers to bind a socket on and return a | ||
12 | -- 'Transport' on the first success. | ||
13 | -- | ||
14 | -- Port numbers may be specified symbolically (for example, "domain" for port | ||
15 | -- 53) and additionally, for testing convenience, the port "fake" will pretend | ||
16 | -- to bind a port but instead return a null transport. | ||
17 | -- | ||
18 | -- The Bool argument should be 'True' if you want a dual-socket that supports | ||
19 | -- both IPv4 and IPv6. Otherwise, IPv4 only will be assumed. | ||
20 | udpTransport' :: Show err => Bool -> [String] -> IO (Maybe (Transport err SockAddr ByteString, Socket)) | ||
21 | udpTransport' want6 ports = do | ||
22 | let tryBind "fake" _ = do | ||
23 | dummysock <- socket (if want6 then AF_INET6 else AF_INET) Datagram defaultProtocol | ||
24 | return $ Just (QR.nullTransport, dummysock) | ||
25 | tryBind port next = do | ||
26 | addr <- getBindAddress port want6 | ||
27 | (udp,sock) <- QR.udpTransport' addr | ||
28 | return $ Just (udp,sock) | ||
29 | `catchIOError` \e -> do | ||
30 | -- warn $ "bind-error: " <> bshow addr <> " " <> bshow e | ||
31 | next | ||
32 | foldr tryBind (return Nothing) ports | ||
33 | |||
34 | -- | Like "udpTransport\'" except that it does not return the bound 'Socket'. | ||
35 | udpTransport :: Show err => Bool -> [String] -> IO (Maybe (Transport err SockAddr ByteString)) | ||
36 | udpTransport want6 ports = fmap fst <$> udpTransport' want6 ports | ||
diff --git a/server/src/Network/QueryResponse.hs b/server/src/Network/QueryResponse.hs index 94eb4796..470b7ce7 100644 --- a/server/src/Network/QueryResponse.hs +++ b/server/src/Network/QueryResponse.hs | |||
@@ -81,6 +81,13 @@ data TransportA err addr x y = Transport | |||
81 | 81 | ||
82 | type Transport err addr x = TransportA err addr x x | 82 | type Transport err addr x = TransportA err addr x x |
83 | 83 | ||
84 | nullTransport :: TransportA err addr x y | ||
85 | nullTransport = Transport | ||
86 | { awaitMessage = \_ -> retry | ||
87 | , sendMessage = \_ _ -> return () | ||
88 | , setActive = \_ -> return () | ||
89 | } | ||
90 | |||
84 | closeTransport :: TransportA err addr x y -> IO () | 91 | closeTransport :: TransportA err addr x y -> IO () |
85 | closeTransport tr = setActive tr False | 92 | closeTransport tr = setActive tr False |
86 | 93 | ||
@@ -606,6 +613,8 @@ saferSendTo sock bs saddr = void (B.sendTo sock bs saddr) | |||
606 | else throw e | 613 | else throw e |
607 | 614 | ||
608 | -- | Like 'udpTransport' except also returns the raw socket (for broadcast use). | 615 | -- | Like 'udpTransport' except also returns the raw socket (for broadcast use). |
616 | -- | ||
617 | -- Note: Throws an exception if unable to bind. | ||
609 | udpTransport' :: Show err => SockAddr -> IO (Transport err SockAddr ByteString, Socket) | 618 | udpTransport' :: Show err => SockAddr -> IO (Transport err SockAddr ByteString, Socket) |
610 | udpTransport' bind_address = do | 619 | udpTransport' bind_address = do |
611 | let family = sockAddrFamily bind_address | 620 | let family = sockAddrFamily bind_address |