summaryrefslogtreecommitdiff
path: root/server
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 /server
parentfb8196cde5a56337a0e028f837a34ef1bdbcc94f (diff)
Support for binding UDP "fake" port to simulate TCP-only connections.
Diffstat (limited to 'server')
-rw-r--r--server/server.cabal15
-rw-r--r--server/src/Network/Bind.hs36
-rw-r--r--server/src/Network/QueryResponse.hs9
3 files changed, 59 insertions, 1 deletions
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