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 /server/src | |
parent | fb8196cde5a56337a0e028f837a34ef1bdbcc94f (diff) |
Support for binding UDP "fake" port to simulate TCP-only connections.
Diffstat (limited to 'server/src')
-rw-r--r-- | server/src/Network/Bind.hs | 36 | ||||
-rw-r--r-- | server/src/Network/QueryResponse.hs | 9 |
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 @@ | |||
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 |