Network Connect Timeouts

I'd like a configurable network connect timeout. Has anyone solved this reasonably? *System.Timeout.timeout* times out connections, but works on the granularity of the life of the connection. Is there a reasonable way to configure a timeout around just establishing the connection? Maybe something like a conditional timeout that enables an action to disable the timeout once it expires? As a workaround, I'm spinning trying to successfully connect first before trying to connect for real: -- | Try the TCP connection and see if you can connect... -- tryTCPClient :: Int -> ClientSettings -> IO () tryTCPClient microseconds settings = do ok <- newIORef False void $ timeout microseconds $ runTCPClient settings $ const $ writeIORef ok True ok' <- readIORef ok unless ok' $ tryTCPClient microseconds settings -- | Wrap runTCPClient with a connect timeout. -- -- Tries the TCP connection first, and the runs the regular runTCPClient. -- Of course, this only enforces a TCP connect timeout on the first connect. -- The second TCP connect has no timeout :( -- runTCPClient' :: Int -> ClientSettings -> (AppData -> IO a) -> IO a runTCPClient' microseconds settings action = do tryTCPClient microseconds settings runTCPClient settings action I've also tried running the *tryTCPClient* in its own thread concurrently with *runTCPClient* and throwing an exception if it can't connect in *microseconds*. None of these offer an actual true connection establishment timeout. Has anyone found a way to solve this? Thanks! Mark

I do not have an answer to your actual question, just a side node on your workaround: Am 14.10.2017 um 04:14 schrieb Mark Fine:
As a workaround, I'm spinning trying to successfully connect first before trying to connect for real:
This does not give you the effect you want out of it. Nowadays, middleboxes and servers keep track of past connections, for various reasons - mostly it's NAT in things like cable modems, and intrusion detection systems (IDSes) in servers or close-to-server middleboxes. Cable modems and similar tend to operate under memory-constrained conditions. If you open two connections, this may be the final straw that breaks the cable modem, causing all kinds of weird behaviour (the better ones will drop the longest-unused connections, but I have seen some that will start exhibiting all kinds of bugs). This failure mode is particularly important if you plan to open many connections from a client at the user's home; otherwise it is less relevant. IDSes will notice that you quickly opened and closed connections, and potentially flag this as suspicious. The usual solution is to open the connection, and retry a few times. (Failed connection attempts tend to be not remembered by middleboxes.) If retrying fails, either ask the user if the program should retry connecting (not telling the user that there were retries already, they don't care and wouldn't understand), or if it's a server, do the retries with an exponential standoff and log the situation once it becomes severe enough. Neither solution is really doable at the network connection layer, so maybe it's actually okay if there is no answer to your original question :-) Regards, Jo

Hi Mark,
What networking library are you using?
There should be a lower level interface which allows for managing the
lifetime of a connection by hand.
Chris
On Oct 14, 2017 15:17, "Mark Fine"
I'd like a configurable network connect timeout. Has anyone solved this reasonably?
*System.Timeout.timeout* times out connections, but works on the granularity of the life of the connection. Is there a reasonable way to configure a timeout around just establishing the connection? Maybe something like a conditional timeout that enables an action to disable the timeout once it expires?
As a workaround, I'm spinning trying to successfully connect first before trying to connect for real:
-- | Try the TCP connection and see if you can connect... -- tryTCPClient :: Int -> ClientSettings -> IO () tryTCPClient microseconds settings = do ok <- newIORef False void $ timeout microseconds $ runTCPClient settings $ const $ writeIORef ok True ok' <- readIORef ok unless ok' $ tryTCPClient microseconds settings
-- | Wrap runTCPClient with a connect timeout. -- -- Tries the TCP connection first, and the runs the regular runTCPClient. -- Of course, this only enforces a TCP connect timeout on the first connect. -- The second TCP connect has no timeout :( -- runTCPClient' :: Int -> ClientSettings -> (AppData -> IO a) -> IO a runTCPClient' microseconds settings action = do tryTCPClient microseconds settings runTCPClient settings action
I've also tried running the *tryTCPClient* in its own thread concurrently with *runTCPClient* and throwing an exception if it can't connect in *microseconds*. None of these offer an actual true connection establishment timeout.
Has anyone found a way to solve this? Thanks!
Mark
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.
participants (3)
-
Chris Wong
-
Joachim Durchholz
-
Mark Fine