{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE OverloadedStrings #-} module Snap.Internal.Http.Server.Address ( getHostAddr , getSockAddr , getAddress ) where ------------------------------------------------------------------------------ import Control.Exception import Control.Monad import Data.ByteString (ByteString) import qualified Data.ByteString as S import Data.ByteString.Char8 () import Data.ByteString.Internal (c2w, w2c) import Data.Maybe import Data.Typeable import Network.Socket ------------------------------------------------------------------------------ data AddressNotSupportedException = AddressNotSupportedException String deriving (Typeable) instance Show AddressNotSupportedException where show (AddressNotSupportedException x) = "Address not supported: " ++ x instance Exception AddressNotSupportedException ------------------------------------------------------------------------------ getHostAddr :: SockAddr -> IO String getHostAddr addr = (fromMaybe "" . fst) `liftM` getNameInfo [NI_NUMERICHOST] True False addr ------------------------------------------------------------------------------ getAddress :: SockAddr -> IO (Int, ByteString) getAddress addr = do port <- case addr of SockAddrInet p _ -> return p SockAddrInet6 p _ _ _ -> return p x -> throwIO $ AddressNotSupportedException $ show x host <- getHostAddr addr return (fromIntegral port, S.pack $ map c2w host) ------------------------------------------------------------------------------ getSockAddr :: Int -> ByteString -> IO (Family, SockAddr) getSockAddr p s | s == "*" = return $! ( AF_INET , SockAddrInet (fromIntegral p) iNADDR_ANY ) getSockAddr p s | s == "::" = return $! ( AF_INET6 , SockAddrInet6 (fromIntegral p) 0 iN6ADDR_ANY 0 ) getSockAddr p s = do let hints = defaultHints { addrFlags = [AI_NUMERICSERV] } ais <- getAddrInfo (Just hints) (Just $ map w2c $ S.unpack s) (Just $ show p) if null ais then throwIO $ AddressNotSupportedException $ show s else do let ai = head ais let fm = addrFamily ai let sa = addrAddress ai return (fm, sa)