4

I have the following to try and connect to a server:

testAddress :: HostName -> Int -> IO (Maybe Handle)
testAddress host iPort = do
 let port = PortNumber $ fromIntegral iPort
 putStrLn $ "Testing - Host: " ++ host ++ ", Port: " ++ show iPort
 result <- try $ connectTo host port
 case result of
 Left (SomeException e) -> return Nothing
 Right h -> do
 putStrLn $ "Connected to " ++ host
 return $ Just h

I made the exception to catch "SomeException", but I know that's not the proper way to do it; as it will catch everything, and you can't handle individual cases. I can't find the names of specific network exceptions though. There doesn't appear to be any documentation for the Network package, and a every example I can find on google just uses "SomeException". If I try and connect to a random host and port, and I don't attempt to catch anything, I get the error: "* Exception: connect: failed (Connection timed out (WSAETIMEDOUT))" But it doesn't seem to give me the exact name of the exception to try and catch. I thought it might be "WSAETIMEOUT", but when I tried catching that, I got a compilation error saying that it couldn't find the constructor for "WSAETIMEOUT". What should I do. I don't want to just catch everything and treat it the same, because then I don't know whats going on.

Thank you

asked Jul 24, 2014 at 1:54
11
  • 1
    @Ptharien's Flame Control .Exception. It returns an IO Either. Commented Jul 24, 2014 at 13:20
  • 1
    And I found the documentation here: hackage.haskell.org/package/network-2.5.0.0/docs/Network.html but it's very bare. Nothing about exceptions, even though it throws them. Commented Jul 24, 2014 at 14:04
  • 1
    Thank you, and good luck. I'm fairly good with Google, and I can't find anything. The only thing left (that I literally just realized) was that I remember hearing that Haskell's Network module is basically just a port from a different language, and I haven't checked it's documentation yet. It's in a different language though, so I can't imagine the exception handling will be the same across the board. Commented Jul 24, 2014 at 15:02
  • 1
    I'll find the SO post. Someone was asking for network's documentation, and someone directed them elsewhere. Should be easy to find again. 2 seconds. Commented Jul 24, 2014 at 15:04
  • 1
    Maybe it's not a different language. I don't know what the "Berkeley Socket API" is from. stackoverflow.com/questions/3406998/… Commented Jul 24, 2014 at 15:05

2 Answers 2

3

You can pattern-match on a specific exception type like this:

testAddress :: HostName -> Int -> IO (Maybe Handle)
testAddress host iPort = do
 let port = PortNumber $ fromIntegral iPort
 putStrLn $ "Testing - Host: " ++ host ++ ", Port: " ++ show iPort
 result <- try $ connectTo host port
 case result of
 Left (e :: MyExceptionType) -> return Nothing
 Right h -> do
 putStrLn $ "Connected to " ++ host
 return $ Just h

This will actually cause Haskell to infer that the type of result is Either MyExceptionType Handle, and try will therefore only catch exceptions of MyExceptionType, propagating all others unchanged.

As for the particular exception types used by the network package, I couldn't find any documentation on them either, but since Typeable is a superclass of Exception, you should be able to print out the type of any exception you catch, which should be useful.

answered Jul 24, 2014 at 15:55
2
  • 1
    Thanks. See my answer above. I'd like any feedback on how this could be made cleaner/safer. I'll accept your answer though, as there's no point in accepting mine. Commented Jul 24, 2014 at 16:14
  • 1
    pastebin.com/VNwrSAr3 All of it, although it won't compile as I don't have time to fill the cases. Thanks again. Commented Jul 24, 2014 at 16:34
1

After jumping through hoops, this is my end solution (far from perfect):

data NetException = NetNoException | NetTimeOut | NetRefused | NetHostUnreach
 | NetANotAvail
 deriving (Show, Eq)
diffExcept :: Either SomeException Handle -> Either NetException Handle
diffExcept (Right h) = Right h
diffExcept (Left (SomeException m))
 | err == "WSAETIMEDOUT" = Left NetTimeOut
 | err == "WSAECONNREFUSED" = Left NetRefused
 | err == "WSAEHOSTUNREACH" = Left NetHostUnreach
 | err == "WSAEADDRNOTAVAIL" = Left NetANotAvail
 | otherwise = error $ show m
 where
 err = reverse . dropWhile (== ')') . reverse . dropWhile (/='W') $ show m

So the error will have to be passed to diffExcept, then the result of that can be pattern matched against.

Note that this isn't that safe in it's current form. It's assuming that every error will start with a 'W' (all net errors seem to so far), and the message will end in only ')''s. Anyone using this should probably fix it up prior, but it gives the general idea.

answered Jul 24, 2014 at 16:12

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.