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 | |
parent | fb8196cde5a56337a0e028f837a34ef1bdbcc94f (diff) |
Support for binding UDP "fake" port to simulate TCP-only connections.
Diffstat (limited to 'server')
-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 |
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 | ||
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 |