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

11
  • 1
    @Ptharien's Flame Control .Exception. It returns an IO Either. 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. 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. 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. 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/… 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.

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. 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. 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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.