module Network.Socket.LocalAddress (
localSockAddr',
localSockAddr,
localAddress,
localAddressString) where
import Network.Socket (Socket, Family(..),
SockAddr(..), SocketType(..), HostAddress,
socket, connect,
defaultProtocol,
getSocketName,
sClose,
inet_addr, inet_ntoa)
toIO :: a -> IO a
toIO = return
localSockAddr' :: SockAddr -> IO (SockAddr, Socket)
localSockAddr' remote =
do sock <- socket (af remote) Datagram defaultProtocol
connect sock remote
addr <- getSocketName sock
toIO (addr, sock)
where af (SockAddrInet _ _) = AF_INET
af (SockAddrInet6 _ _ _ _) = AF_INET6
af (SockAddrUnix _) = AF_UNIX
localSockAddr :: SockAddr -> IO SockAddr
localSockAddr remote = do (addr, sock) <- localSockAddr' remote
sClose sock
toIO $ erasePort addr
where erasePort (SockAddrInet _ addr) = SockAddrInet 0 addr
erasePort (SockAddrInet6 _ fi ha si) = SockAddrInet6 0 fi ha si
erasePort sa@(SockAddrUnix _) = sa
localAddress :: HostAddress -> IO (Maybe HostAddress)
localAddress = fmap expect4 . localSockAddr . SockAddrInet 0
where expect4 (SockAddrInet _ addr) = Just addr
expect4 _ = Nothing
localAddressString :: String -> IO (Maybe String)
localAddressString astr =
do remote <- inet_addr astr
local <- localAddress remote
maybe (toIO Nothing) (fmap Just . inet_ntoa) local