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