{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric #-}
module Netcode.IO.Address where

--------------------------------------------------------------------------------

import Data.Data             (Data)
import Data.Typeable         (Typeable)
import Data.Word             (Word8, Word16)
import Control.Monad         (unless)
import Foreign.C.String      (withCString, peekCString)
import Foreign.ForeignPtr    (ForeignPtr, withForeignPtr, mallocForeignPtr)
import Foreign.Marshal.Alloc (allocaBytes)
import Foreign.Storable      (peek, poke)
import GHC.Generics          (Generic)

import Bindings.Netcode.IO

--------------------------------------------------------------------------------

-- | An opaque type that encapsulates an address that can be used with
-- @netcode.io@. The address may be stored in memory in different ways (for
-- example with encryption), and therefore needs the IO monad to interact with
-- it.
--
-- <https://github.com/Mokosha/netcode-io/issues/1 TODO>: Use a high-level
-- representation here to enable a more pure interface.
newtype Address = Address (ForeignPtr C'netcode_address_t)
                deriving (Int -> Address -> ShowS
[Address] -> ShowS
Address -> String
(Int -> Address -> ShowS)
-> (Address -> String) -> ([Address] -> ShowS) -> Show Address
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Address] -> ShowS
$cshowList :: [Address] -> ShowS
show :: Address -> String
$cshow :: Address -> String
showsPrec :: Int -> Address -> ShowS
$cshowsPrec :: Int -> Address -> ShowS
Show)

-- | The address mode based on how the address is represented. Usually a
-- consequence of how it was parsed.
data AddressMode
  = AddressMode'Unknown  -- ^ Usually when address is stored encrypted.
  | AddressMode'IPv4
  | AddressMode'IPv6
    deriving (AddressMode -> AddressMode -> Bool
(AddressMode -> AddressMode -> Bool)
-> (AddressMode -> AddressMode -> Bool) -> Eq AddressMode
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: AddressMode -> AddressMode -> Bool
$c/= :: AddressMode -> AddressMode -> Bool
== :: AddressMode -> AddressMode -> Bool
$c== :: AddressMode -> AddressMode -> Bool
Eq, Eq AddressMode
Eq AddressMode
-> (AddressMode -> AddressMode -> Ordering)
-> (AddressMode -> AddressMode -> Bool)
-> (AddressMode -> AddressMode -> Bool)
-> (AddressMode -> AddressMode -> Bool)
-> (AddressMode -> AddressMode -> Bool)
-> (AddressMode -> AddressMode -> AddressMode)
-> (AddressMode -> AddressMode -> AddressMode)
-> Ord AddressMode
AddressMode -> AddressMode -> Bool
AddressMode -> AddressMode -> Ordering
AddressMode -> AddressMode -> AddressMode
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: AddressMode -> AddressMode -> AddressMode
$cmin :: AddressMode -> AddressMode -> AddressMode
max :: AddressMode -> AddressMode -> AddressMode
$cmax :: AddressMode -> AddressMode -> AddressMode
>= :: AddressMode -> AddressMode -> Bool
$c>= :: AddressMode -> AddressMode -> Bool
> :: AddressMode -> AddressMode -> Bool
$c> :: AddressMode -> AddressMode -> Bool
<= :: AddressMode -> AddressMode -> Bool
$c<= :: AddressMode -> AddressMode -> Bool
< :: AddressMode -> AddressMode -> Bool
$c< :: AddressMode -> AddressMode -> Bool
compare :: AddressMode -> AddressMode -> Ordering
$ccompare :: AddressMode -> AddressMode -> Ordering
$cp1Ord :: Eq AddressMode
Ord, Int -> AddressMode -> ShowS
[AddressMode] -> ShowS
AddressMode -> String
(Int -> AddressMode -> ShowS)
-> (AddressMode -> String)
-> ([AddressMode] -> ShowS)
-> Show AddressMode
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [AddressMode] -> ShowS
$cshowList :: [AddressMode] -> ShowS
show :: AddressMode -> String
$cshow :: AddressMode -> String
showsPrec :: Int -> AddressMode -> ShowS
$cshowsPrec :: Int -> AddressMode -> ShowS
Show, ReadPrec [AddressMode]
ReadPrec AddressMode
Int -> ReadS AddressMode
ReadS [AddressMode]
(Int -> ReadS AddressMode)
-> ReadS [AddressMode]
-> ReadPrec AddressMode
-> ReadPrec [AddressMode]
-> Read AddressMode
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [AddressMode]
$creadListPrec :: ReadPrec [AddressMode]
readPrec :: ReadPrec AddressMode
$creadPrec :: ReadPrec AddressMode
readList :: ReadS [AddressMode]
$creadList :: ReadS [AddressMode]
readsPrec :: Int -> ReadS AddressMode
$creadsPrec :: Int -> ReadS AddressMode
Read, Int -> AddressMode
AddressMode -> Int
AddressMode -> [AddressMode]
AddressMode -> AddressMode
AddressMode -> AddressMode -> [AddressMode]
AddressMode -> AddressMode -> AddressMode -> [AddressMode]
(AddressMode -> AddressMode)
-> (AddressMode -> AddressMode)
-> (Int -> AddressMode)
-> (AddressMode -> Int)
-> (AddressMode -> [AddressMode])
-> (AddressMode -> AddressMode -> [AddressMode])
-> (AddressMode -> AddressMode -> [AddressMode])
-> (AddressMode -> AddressMode -> AddressMode -> [AddressMode])
-> Enum AddressMode
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
enumFromThenTo :: AddressMode -> AddressMode -> AddressMode -> [AddressMode]
$cenumFromThenTo :: AddressMode -> AddressMode -> AddressMode -> [AddressMode]
enumFromTo :: AddressMode -> AddressMode -> [AddressMode]
$cenumFromTo :: AddressMode -> AddressMode -> [AddressMode]
enumFromThen :: AddressMode -> AddressMode -> [AddressMode]
$cenumFromThen :: AddressMode -> AddressMode -> [AddressMode]
enumFrom :: AddressMode -> [AddressMode]
$cenumFrom :: AddressMode -> [AddressMode]
fromEnum :: AddressMode -> Int
$cfromEnum :: AddressMode -> Int
toEnum :: Int -> AddressMode
$ctoEnum :: Int -> AddressMode
pred :: AddressMode -> AddressMode
$cpred :: AddressMode -> AddressMode
succ :: AddressMode -> AddressMode
$csucc :: AddressMode -> AddressMode
Enum, AddressMode
AddressMode -> AddressMode -> Bounded AddressMode
forall a. a -> a -> Bounded a
maxBound :: AddressMode
$cmaxBound :: AddressMode
minBound :: AddressMode
$cminBound :: AddressMode
Bounded, Typeable AddressMode
DataType
Constr
Typeable AddressMode
-> (forall (c :: * -> *).
    (forall d b. Data d => c (d -> b) -> d -> c b)
    -> (forall g. g -> c g) -> AddressMode -> c AddressMode)
-> (forall (c :: * -> *).
    (forall b r. Data b => c (b -> r) -> c r)
    -> (forall r. r -> c r) -> Constr -> c AddressMode)
-> (AddressMode -> Constr)
-> (AddressMode -> DataType)
-> (forall (t :: * -> *) (c :: * -> *).
    Typeable t =>
    (forall d. Data d => c (t d)) -> Maybe (c AddressMode))
-> (forall (t :: * -> * -> *) (c :: * -> *).
    Typeable t =>
    (forall d e. (Data d, Data e) => c (t d e))
    -> Maybe (c AddressMode))
-> ((forall b. Data b => b -> b) -> AddressMode -> AddressMode)
-> (forall r r'.
    (r -> r' -> r)
    -> r -> (forall d. Data d => d -> r') -> AddressMode -> r)
-> (forall r r'.
    (r' -> r -> r)
    -> r -> (forall d. Data d => d -> r') -> AddressMode -> r)
-> (forall u. (forall d. Data d => d -> u) -> AddressMode -> [u])
-> (forall u.
    Int -> (forall d. Data d => d -> u) -> AddressMode -> u)
-> (forall (m :: * -> *).
    Monad m =>
    (forall d. Data d => d -> m d) -> AddressMode -> m AddressMode)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> AddressMode -> m AddressMode)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> AddressMode -> m AddressMode)
-> Data AddressMode
AddressMode -> DataType
AddressMode -> Constr
(forall b. Data b => b -> b) -> AddressMode -> AddressMode
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> AddressMode -> c AddressMode
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c AddressMode
forall a.
Typeable a
-> (forall (c :: * -> *).
    (forall d b. Data d => c (d -> b) -> d -> c b)
    -> (forall g. g -> c g) -> a -> c a)
-> (forall (c :: * -> *).
    (forall b r. Data b => c (b -> r) -> c r)
    -> (forall r. r -> c r) -> Constr -> c a)
-> (a -> Constr)
-> (a -> DataType)
-> (forall (t :: * -> *) (c :: * -> *).
    Typeable t =>
    (forall d. Data d => c (t d)) -> Maybe (c a))
-> (forall (t :: * -> * -> *) (c :: * -> *).
    Typeable t =>
    (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c a))
-> ((forall b. Data b => b -> b) -> a -> a)
-> (forall r r'.
    (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall r r'.
    (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall u. (forall d. Data d => d -> u) -> a -> [u])
-> (forall u. Int -> (forall d. Data d => d -> u) -> a -> u)
-> (forall (m :: * -> *).
    Monad m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> Data a
forall u. Int -> (forall d. Data d => d -> u) -> AddressMode -> u
forall u. (forall d. Data d => d -> u) -> AddressMode -> [u]
forall r r'.
(r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> AddressMode -> r
forall r r'.
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> AddressMode -> r
forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d) -> AddressMode -> m AddressMode
forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> AddressMode -> m AddressMode
forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c AddressMode
forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> AddressMode -> c AddressMode
forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c AddressMode)
forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e))
-> Maybe (c AddressMode)
$cAddressMode'IPv6 :: Constr
$cAddressMode'IPv4 :: Constr
$cAddressMode'Unknown :: Constr
$tAddressMode :: DataType
gmapMo :: (forall d. Data d => d -> m d) -> AddressMode -> m AddressMode
$cgmapMo :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> AddressMode -> m AddressMode
gmapMp :: (forall d. Data d => d -> m d) -> AddressMode -> m AddressMode
$cgmapMp :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> AddressMode -> m AddressMode
gmapM :: (forall d. Data d => d -> m d) -> AddressMode -> m AddressMode
$cgmapM :: forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d) -> AddressMode -> m AddressMode
gmapQi :: Int -> (forall d. Data d => d -> u) -> AddressMode -> u
$cgmapQi :: forall u. Int -> (forall d. Data d => d -> u) -> AddressMode -> u
gmapQ :: (forall d. Data d => d -> u) -> AddressMode -> [u]
$cgmapQ :: forall u. (forall d. Data d => d -> u) -> AddressMode -> [u]
gmapQr :: (r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> AddressMode -> r
$cgmapQr :: forall r r'.
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> AddressMode -> r
gmapQl :: (r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> AddressMode -> r
$cgmapQl :: forall r r'.
(r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> AddressMode -> r
gmapT :: (forall b. Data b => b -> b) -> AddressMode -> AddressMode
$cgmapT :: (forall b. Data b => b -> b) -> AddressMode -> AddressMode
dataCast2 :: (forall d e. (Data d, Data e) => c (t d e))
-> Maybe (c AddressMode)
$cdataCast2 :: forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e))
-> Maybe (c AddressMode)
dataCast1 :: (forall d. Data d => c (t d)) -> Maybe (c AddressMode)
$cdataCast1 :: forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c AddressMode)
dataTypeOf :: AddressMode -> DataType
$cdataTypeOf :: AddressMode -> DataType
toConstr :: AddressMode -> Constr
$ctoConstr :: AddressMode -> Constr
gunfold :: (forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c AddressMode
$cgunfold :: forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c AddressMode
gfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> AddressMode -> c AddressMode
$cgfoldl :: forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> AddressMode -> c AddressMode
$cp1Data :: Typeable AddressMode
Data, Typeable, (forall x. AddressMode -> Rep AddressMode x)
-> (forall x. Rep AddressMode x -> AddressMode)
-> Generic AddressMode
forall x. Rep AddressMode x -> AddressMode
forall x. AddressMode -> Rep AddressMode x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep AddressMode x -> AddressMode
$cfrom :: forall x. AddressMode -> Rep AddressMode x
Generic)

typedAddressMode :: Word8 -> AddressMode
typedAddressMode :: Word8 -> AddressMode
typedAddressMode Word8
m
  | Word8
m Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
forall a. Num a => a
c'NETCODE_ADDRESS_NONE = AddressMode
AddressMode'Unknown
  | Word8
m Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
forall a. Num a => a
c'NETCODE_ADDRESS_IPV4 = AddressMode
AddressMode'IPv4
  | Word8
m Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
forall a. Num a => a
c'NETCODE_ADDRESS_IPV6 = AddressMode
AddressMode'IPv6
  | Bool
otherwise = String -> AddressMode
forall a. HasCallStack => String -> a
error String
"Unknown address mode!"

rawAddressMode :: AddressMode -> Word8
rawAddressMode :: AddressMode -> Word8
rawAddressMode AddressMode
AddressMode'Unknown = Word8
forall a. Num a => a
c'NETCODE_ADDRESS_NONE
rawAddressMode AddressMode
AddressMode'IPv4    = Word8
forall a. Num a => a
c'NETCODE_ADDRESS_IPV4
rawAddressMode AddressMode
AddressMode'IPv6    = Word8
forall a. Num a => a
c'NETCODE_ADDRESS_IPV6

-- | Returns the address mode for the given address. Note, this address may be
-- stored in memory in different ways, so we must inspect the memory contents
-- in order to retreive the addressing mode.
addressMode :: Address -> IO AddressMode
addressMode :: Address -> IO AddressMode
addressMode (Address ForeignPtr C'netcode_address_t
addr) = ForeignPtr C'netcode_address_t
-> (Ptr C'netcode_address_t -> IO AddressMode) -> IO AddressMode
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr C'netcode_address_t
addr ((Ptr C'netcode_address_t -> IO AddressMode) -> IO AddressMode)
-> (Ptr C'netcode_address_t -> IO AddressMode) -> IO AddressMode
forall a b. (a -> b) -> a -> b
$
  (C'netcode_address_t -> AddressMode)
-> IO C'netcode_address_t -> IO AddressMode
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Word8 -> AddressMode
typedAddressMode (Word8 -> AddressMode)
-> (C'netcode_address_t -> Word8)
-> C'netcode_address_t
-> AddressMode
forall b c a. (b -> c) -> (a -> b) -> a -> c
. C'netcode_address_t -> Word8
c'netcode_address_t'type) (IO C'netcode_address_t -> IO AddressMode)
-> (Ptr C'netcode_address_t -> IO C'netcode_address_t)
-> Ptr C'netcode_address_t
-> IO AddressMode
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Ptr C'netcode_address_t -> IO C'netcode_address_t
forall a. Storable a => Ptr a -> IO a
peek

-- | Returns the port associated with this address.
addressPort :: Address -> IO Word16
addressPort :: Address -> IO Word16
addressPort (Address ForeignPtr C'netcode_address_t
addr) = ForeignPtr C'netcode_address_t
-> (Ptr C'netcode_address_t -> IO Word16) -> IO Word16
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr C'netcode_address_t
addr ((Ptr C'netcode_address_t -> IO Word16) -> IO Word16)
-> (Ptr C'netcode_address_t -> IO Word16) -> IO Word16
forall a b. (a -> b) -> a -> b
$
  (C'netcode_address_t -> Word16)
-> IO C'netcode_address_t -> IO Word16
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap C'netcode_address_t -> Word16
c'netcode_address_t'port (IO C'netcode_address_t -> IO Word16)
-> (Ptr C'netcode_address_t -> IO C'netcode_address_t)
-> Ptr C'netcode_address_t
-> IO Word16
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Ptr C'netcode_address_t -> IO C'netcode_address_t
forall a. Storable a => Ptr a -> IO a
peek

-- | Returns the address as a sequence of values in its human readable format.
-- For example:
--
-- >>> parseAddress "123.231.132.213" >>= addressValues
-- [123, 231, 132, 213]
--
-- The length of the list is either 4 or 8 depending on the address mode. If
-- the address mode is unknown, 'addressValues' returns the empty list.
addressValues :: Address -> IO [Word16]
addressValues :: Address -> IO [Word16]
addressValues (Address ForeignPtr C'netcode_address_t
fptr) = ForeignPtr C'netcode_address_t
-> (Ptr C'netcode_address_t -> IO [Word16]) -> IO [Word16]
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr C'netcode_address_t
fptr ((Ptr C'netcode_address_t -> IO [Word16]) -> IO [Word16])
-> (Ptr C'netcode_address_t -> IO [Word16]) -> IO [Word16]
forall a b. (a -> b) -> a -> b
$ \Ptr C'netcode_address_t
aptr -> do
  C'netcode_address_t
addr <- Ptr C'netcode_address_t -> IO C'netcode_address_t
forall a. Storable a => Ptr a -> IO a
peek Ptr C'netcode_address_t
aptr
  case (Word8 -> AddressMode
typedAddressMode (Word8 -> AddressMode) -> Word8 -> AddressMode
forall a b. (a -> b) -> a -> b
$ C'netcode_address_t -> Word8
c'netcode_address_t'type C'netcode_address_t
addr) of
    AddressMode
AddressMode'IPv4 ->
      [Word16] -> IO [Word16]
forall (m :: * -> *) a. Monad m => a -> m a
return ([Word16] -> IO [Word16]) -> [Word16] -> IO [Word16]
forall a b. (a -> b) -> a -> b
$ (Word8 -> Word16) -> [Word8] -> [Word16]
forall a b. (a -> b) -> [a] -> [b]
map Word8 -> Word16
forall a b. (Integral a, Num b) => a -> b
fromIntegral ([Word8] -> [Word16]) -> [Word8] -> [Word16]
forall a b. (a -> b) -> a -> b
$ C'netcode_address_t -> [Word8]
c'netcode_address_t'data'ipv4 C'netcode_address_t
addr
    AddressMode
AddressMode'IPv6 ->  [Word16] -> IO [Word16]
forall (m :: * -> *) a. Monad m => a -> m a
return ([Word16] -> IO [Word16]) -> [Word16] -> IO [Word16]
forall a b. (a -> b) -> a -> b
$ C'netcode_address_t -> [Word16]
c'netcode_address_t'data'ipv6 C'netcode_address_t
addr
    AddressMode
_                ->  [Word16] -> IO [Word16]
forall (m :: * -> *) a. Monad m => a -> m a
return []

-- | Returns an address with the given values interpreted using the given mode.
-- For IPv4 addresses, only the bottom 8 bits of each 16-bit word will be used.
-- The list will be zero padded to contain enough values to fill the address as
-- needed.
constructAddress :: AddressMode
                 -> Word16       -- ^ Port
                 -> [Word16]
                 -> IO Address
constructAddress :: AddressMode -> Word16 -> [Word16] -> IO Address
constructAddress AddressMode
mode Word16
port [Word16]
vals =
  let ipv4Vals :: [Word8]
ipv4Vals = Int -> [Word8] -> [Word8]
forall a. Int -> [a] -> [a]
take Int
4 ([Word8] -> [Word8]) -> [Word8] -> [Word8]
forall a b. (a -> b) -> a -> b
$ (Word16 -> Word8) -> [Word16] -> [Word8]
forall a b. (a -> b) -> [a] -> [b]
map Word16 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral ([Word16] -> [Word8]) -> [Word16] -> [Word8]
forall a b. (a -> b) -> a -> b
$ [Word16]
vals [Word16] -> [Word16] -> [Word16]
forall a. Semigroup a => a -> a -> a
<> Word16 -> [Word16]
forall a. a -> [a]
repeat Word16
0
      ipv6Vals :: [Word16]
ipv6Vals = Int -> [Word16] -> [Word16]
forall a. Int -> [a] -> [a]
take Int
8 ([Word16] -> [Word16]) -> [Word16] -> [Word16]
forall a b. (a -> b) -> a -> b
$ [Word16]
vals [Word16] -> [Word16] -> [Word16]
forall a. Semigroup a => a -> a -> a
<> Word16 -> [Word16]
forall a. a -> [a]
repeat Word16
0
   in do
    ForeignPtr C'netcode_address_t
address <- IO (ForeignPtr C'netcode_address_t)
forall a. Storable a => IO (ForeignPtr a)
mallocForeignPtr
    ForeignPtr C'netcode_address_t
-> (Ptr C'netcode_address_t -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr C'netcode_address_t
address ((Ptr C'netcode_address_t -> IO ()) -> IO ())
-> (Ptr C'netcode_address_t -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr C'netcode_address_t
ptr -> do
      C'netcode_address_t
addrVal <- Ptr C'netcode_address_t -> IO C'netcode_address_t
forall a. Storable a => Ptr a -> IO a
peek Ptr C'netcode_address_t
ptr
      case AddressMode
mode of
        AddressMode
AddressMode'IPv4 -> Ptr C'netcode_address_t -> C'netcode_address_t -> IO ()
forall a. Storable a => Ptr a -> a -> IO ()
poke Ptr C'netcode_address_t
ptr (C'netcode_address_t -> IO ()) -> C'netcode_address_t -> IO ()
forall a b. (a -> b) -> a -> b
$ C'netcode_address_t
addrVal {
            c'netcode_address_t'data'ipv4 :: [Word8]
c'netcode_address_t'data'ipv4 = [Word8]
ipv4Vals
          , c'netcode_address_t'port :: Word16
c'netcode_address_t'port = Word16
port
          , c'netcode_address_t'type :: Word8
c'netcode_address_t'type = Word8
forall a. Num a => a
c'NETCODE_ADDRESS_IPV4
          }
        AddressMode
AddressMode'IPv6 -> Ptr C'netcode_address_t -> C'netcode_address_t -> IO ()
forall a. Storable a => Ptr a -> a -> IO ()
poke Ptr C'netcode_address_t
ptr (C'netcode_address_t -> IO ()) -> C'netcode_address_t -> IO ()
forall a b. (a -> b) -> a -> b
$ C'netcode_address_t
addrVal {
            c'netcode_address_t'data'ipv6 :: [Word16]
c'netcode_address_t'data'ipv6 = [Word16]
ipv6Vals
          , c'netcode_address_t'port :: Word16
c'netcode_address_t'port = Word16
port
          , c'netcode_address_t'type :: Word8
c'netcode_address_t'type = Word8
forall a. Num a => a
c'NETCODE_ADDRESS_IPV6
          }
        AddressMode
_ -> String -> IO ()
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Cannot construct address with unknown address mode"
    Address -> IO Address
forall (m :: * -> *) a. Monad m => a -> m a
return (Address -> IO Address) -> Address -> IO Address
forall a b. (a -> b) -> a -> b
$ ForeignPtr C'netcode_address_t -> Address
Address ForeignPtr C'netcode_address_t
address

-- | Takes a 'String' and parses it to create an 'Address'. The string should
-- be formatted as either a valid IPv4 or IPv6 address. It does not, however,
-- support dual address modes.
parseAddress :: String -> IO Address
parseAddress :: String -> IO Address
parseAddress String
addrStr = do
    ForeignPtr C'netcode_address_t
address <- IO (ForeignPtr C'netcode_address_t)
forall a. Storable a => IO (ForeignPtr a)
mallocForeignPtr
    CInt
retVal <- ForeignPtr C'netcode_address_t
-> (Ptr C'netcode_address_t -> IO CInt) -> IO CInt
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr C'netcode_address_t
address ((Ptr C'netcode_address_t -> IO CInt) -> IO CInt)
-> (Ptr C'netcode_address_t -> IO CInt) -> IO CInt
forall a b. (a -> b) -> a -> b
$ \Ptr C'netcode_address_t
addressPtr ->
                String -> (CString -> IO CInt) -> IO CInt
forall a. String -> (CString -> IO a) -> IO a
withCString String
addrStr (CString -> Ptr C'netcode_address_t -> IO CInt
`c'netcode_parse_address` Ptr C'netcode_address_t
addressPtr)
    Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (CInt
retVal CInt -> CInt -> Bool
forall a. Eq a => a -> a -> Bool
== CInt
forall a. Num a => a
c'NETCODE_OK) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ String -> IO ()
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Unable to parse address"
    Address -> IO Address
forall (m :: * -> *) a. Monad m => a -> m a
return (Address -> IO Address) -> Address -> IO Address
forall a b. (a -> b) -> a -> b
$ ForeignPtr C'netcode_address_t -> Address
Address ForeignPtr C'netcode_address_t
address

-- | Returns a string that represents the given 'Address'.
addressToString :: Address -> IO String
addressToString :: Address -> IO String
addressToString (Address ForeignPtr C'netcode_address_t
addrPtr) =
    let maxAddrStringLen :: Int
maxAddrStringLen = Int
256
     in Int -> (CString -> IO String) -> IO String
forall a b. Int -> (Ptr a -> IO b) -> IO b
allocaBytes Int
maxAddrStringLen ((CString -> IO String) -> IO String)
-> (CString -> IO String) -> IO String
forall a b. (a -> b) -> a -> b
$ \CString
addrStr -> do
         CString
_ <- ForeignPtr C'netcode_address_t
-> (Ptr C'netcode_address_t -> IO CString) -> IO CString
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr C'netcode_address_t
addrPtr (Ptr C'netcode_address_t -> CString -> IO CString
`c'netcode_address_to_string` CString
addrStr)
         CString -> IO String
peekCString CString
addrStr

-- | Returns True if two addresses are equal by examining their memory contents.
addressEqual :: Address -> Address -> IO Bool
addressEqual :: Address -> Address -> IO Bool
addressEqual (Address ForeignPtr C'netcode_address_t
addrPtrA) (Address ForeignPtr C'netcode_address_t
addrPtrB) =
    ForeignPtr C'netcode_address_t
-> (Ptr C'netcode_address_t -> IO Bool) -> IO Bool
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr C'netcode_address_t
addrPtrA ((Ptr C'netcode_address_t -> IO Bool) -> IO Bool)
-> (Ptr C'netcode_address_t -> IO Bool) -> IO Bool
forall a b. (a -> b) -> a -> b
$ \Ptr C'netcode_address_t
ptrA ->
        ForeignPtr C'netcode_address_t
-> (Ptr C'netcode_address_t -> IO Bool) -> IO Bool
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr C'netcode_address_t
addrPtrB ((Ptr C'netcode_address_t -> IO Bool) -> IO Bool)
-> (Ptr C'netcode_address_t -> IO Bool) -> IO Bool
forall a b. (a -> b) -> a -> b
$ \Ptr C'netcode_address_t
ptrB ->
            (CInt -> CInt -> Bool
forall a. Eq a => a -> a -> Bool
/= CInt
0) (CInt -> Bool) -> IO CInt -> IO Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Ptr C'netcode_address_t -> Ptr C'netcode_address_t -> IO CInt
c'netcode_address_equal Ptr C'netcode_address_t
ptrA Ptr C'netcode_address_t
ptrB