summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoe Crayne <joe@jerkface.net>2020-01-09 14:04:37 -0500
committerJoe Crayne <joe@jerkface.net>2020-01-09 14:04:37 -0500
commit778114bb6c644c496859e8281e96d5e44661e183 (patch)
tree0f49cabcef5712f799149c5422f33c43a97910af
parentfb8196cde5a56337a0e028f837a34ef1bdbcc94f (diff)
Support for binding UDP "fake" port to simulate TCP-only connections.
-rw-r--r--dht/examples/dhtd.hs11
-rw-r--r--dht/src/Network/BitTorrent/MainlineDHT.hs7
-rw-r--r--dht/src/Network/Tox.hs13
-rw-r--r--server/server.cabal15
-rw-r--r--server/src/Network/Bind.hs36
-rw-r--r--server/src/Network/QueryResponse.hs9
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
38import Data.Data 38import Data.Data
39import Data.Dependent.Sum 39import Data.Dependent.Sum
40import Data.Function 40import Data.Function
41import Data.Functor
41import Data.Functor.Identity 42import Data.Functor.Identity
42import Data.Hashable 43import Data.Hashable
43import Data.List 44import Data.List
@@ -71,6 +72,7 @@ import qualified Data.Tox.DHT.Multi as Multi
71import DebugUtil 72import DebugUtil
72import Network.UPNP as UPNP 73import Network.UPNP as UPNP
73import Network.Address hiding (NodeId, NodeInfo(..)) 74import Network.Address hiding (NodeId, NodeInfo(..))
75import Network.Bind as Bind
74import Network.QueryResponse 76import Network.QueryResponse
75import qualified Network.QueryResponse.TCP as TCP 77import qualified Network.QueryResponse.TCP as TCP
76import Network.StreamServer 78import 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
548newClient :: SwarmsDatabase -> SockAddr 548newClient :: 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 )
555newClient swarms addr = do 557newClient 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
36import Data.Data 36import Data.Data
37import qualified Data.Dependent.Map as DMap 37import qualified Data.Dependent.Map as DMap
38import Data.Dependent.Sum 38import Data.Dependent.Sum
39import Data.Functor
39import Data.Functor.Identity 40import Data.Functor.Identity
40import Data.Functor.Contravariant 41import Data.Functor.Contravariant
41import Data.Maybe 42import Data.Maybe
@@ -56,6 +57,7 @@ import qualified Data.Word64Map (empty)
56 ;import Data.Word64Map (fitsInInt) 57 ;import Data.Word64Map (fitsInInt)
57import qualified Data.Wrapper.PSQ as PSQ 58import qualified Data.Wrapper.PSQ as PSQ
58import Network.Address (IP, WantIP (..), getBindAddress) 59import Network.Address (IP, WantIP (..), getBindAddress)
60import Network.Bind as Bind
59import Network.BitTorrent.DHT.Token as Token 61import Network.BitTorrent.DHT.Token as Token
60import Network.Kademlia.Bootstrap (bootstrap, forkPollForRefresh) 62import Network.Kademlia.Bootstrap (bootstrap, forkPollForRefresh)
61import qualified Network.Kademlia.Routing as R 63import 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)
264newTox keydb bindspecs onsess crypto usetcp = do 266newTox 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
33library 33library
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 @@
1module Network.Bind where
2
3import Data.ByteString (ByteString)
4import Network.Socket
5import System.IO.Error
6
7import Network.Address (getBindAddress)
8import 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.
20udpTransport' :: Show err => Bool -> [String] -> IO (Maybe (Transport err SockAddr ByteString, Socket))
21udpTransport' 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'.
35udpTransport :: Show err => Bool -> [String] -> IO (Maybe (Transport err SockAddr ByteString))
36udpTransport 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
82type Transport err addr x = TransportA err addr x x 82type Transport err addr x = TransportA err addr x x
83 83
84nullTransport :: TransportA err addr x y
85nullTransport = Transport
86 { awaitMessage = \_ -> retry
87 , sendMessage = \_ _ -> return ()
88 , setActive = \_ -> return ()
89 }
90
84closeTransport :: TransportA err addr x y -> IO () 91closeTransport :: TransportA err addr x y -> IO ()
85closeTransport tr = setActive tr False 92closeTransport 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.
609udpTransport' :: Show err => SockAddr -> IO (Transport err SockAddr ByteString, Socket) 618udpTransport' :: Show err => SockAddr -> IO (Transport err SockAddr ByteString, Socket)
610udpTransport' bind_address = do 619udpTransport' bind_address = do
611 let family = sockAddrFamily bind_address 620 let family = sockAddrFamily bind_address