module Network.QUIC.Socket (
    serverSocket,
    clientSocket,
    natRebinding,
) where

import qualified Control.Exception as E
import Data.IP (IP, toSockAddr)
import qualified Data.List.NonEmpty as NE
import Network.Socket

natRebinding :: SockAddr -> IO Socket
natRebinding :: SockAddr -> IO Socket
natRebinding SockAddr
sa = IO Socket
-> (Socket -> IO ()) -> (Socket -> IO Socket) -> IO Socket
forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
E.bracketOnError IO Socket
open Socket -> IO ()
close Socket -> IO Socket
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return
  where
    family :: Family
family = SockAddr -> Family
sockAddrFamily SockAddr
sa
    open :: IO Socket
open = Family -> SocketType -> ProtocolNumber -> IO Socket
socket Family
family SocketType
Datagram ProtocolNumber
defaultProtocol

sockAddrFamily :: SockAddr -> Family
sockAddrFamily :: SockAddr -> Family
sockAddrFamily SockAddrInet{} = Family
AF_INET
sockAddrFamily SockAddrInet6{} = Family
AF_INET6
sockAddrFamily SockAddr
_ = [Char] -> Family
forall a. HasCallStack => [Char] -> a
error [Char]
"sockAddrFamily"

clientSocket :: HostName -> ServiceName -> IO (Socket, SockAddr)
clientSocket :: [Char] -> [Char] -> IO (Socket, SockAddr)
clientSocket [Char]
host [Char]
port = do
    AddrInfo
addr <- NonEmpty AddrInfo -> AddrInfo
forall a. NonEmpty a -> a
NE.head (NonEmpty AddrInfo -> AddrInfo)
-> IO (NonEmpty AddrInfo) -> IO AddrInfo
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe AddrInfo
-> Maybe [Char] -> Maybe [Char] -> IO (NonEmpty AddrInfo)
forall (t :: * -> *).
GetAddrInfo t =>
Maybe AddrInfo -> Maybe [Char] -> Maybe [Char] -> IO (t AddrInfo)
getAddrInfo (AddrInfo -> Maybe AddrInfo
forall a. a -> Maybe a
Just AddrInfo
hints) ([Char] -> Maybe [Char]
forall a. a -> Maybe a
Just [Char]
host) ([Char] -> Maybe [Char]
forall a. a -> Maybe a
Just [Char]
port)
    IO Socket
-> (Socket -> IO ())
-> (Socket -> IO (Socket, SockAddr))
-> IO (Socket, SockAddr)
forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
E.bracketOnError (AddrInfo -> IO Socket
openSocket AddrInfo
addr) Socket -> IO ()
close ((Socket -> IO (Socket, SockAddr)) -> IO (Socket, SockAddr))
-> (Socket -> IO (Socket, SockAddr)) -> IO (Socket, SockAddr)
forall a b. (a -> b) -> a -> b
$ \Socket
s -> (Socket, SockAddr) -> IO (Socket, SockAddr)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Socket
s, AddrInfo -> SockAddr
addrAddress AddrInfo
addr)
  where
    hints :: AddrInfo
hints = AddrInfo
defaultHints{addrSocketType = Datagram, addrFlags = [AI_ADDRCONFIG]}

serverSocket :: (IP, PortNumber) -> IO Socket
serverSocket :: (IP, PortNumber) -> IO Socket
serverSocket (IP, PortNumber)
ip = IO Socket
-> (Socket -> IO ()) -> (Socket -> IO Socket) -> IO Socket
forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
E.bracketOnError IO Socket
open Socket -> IO ()
close ((Socket -> IO Socket) -> IO Socket)
-> (Socket -> IO Socket) -> IO Socket
forall a b. (a -> b) -> a -> b
$ \Socket
s -> do
    Socket -> SocketOption -> Int -> IO ()
setSocketOption Socket
s SocketOption
ReuseAddr Int
1
    Socket -> (ProtocolNumber -> IO ()) -> IO ()
forall r. Socket -> (ProtocolNumber -> IO r) -> IO r
withFdSocket Socket
s ProtocolNumber -> IO ()
setCloseOnExecIfNeeded
    Socket -> SockAddr -> IO ()
bind Socket
s SockAddr
sa
    Socket -> IO Socket
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Socket
s
  where
    sa :: SockAddr
sa = (IP, PortNumber) -> SockAddr
toSockAddr (IP, PortNumber)
ip
    family :: Family
family = SockAddr -> Family
sockAddrFamily SockAddr
sa
    open :: IO Socket
open = Family -> SocketType -> ProtocolNumber -> IO Socket
socket Family
family SocketType
Datagram ProtocolNumber
defaultProtocol