In Network 2.8, it is difficult to create a new socket of the same shape as an existing socket due to missing interfaces. In C, I can do this via:
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
typedef int SOCKET; /* Unix */
#define INVALID_SOCKET ((SOCKET)-1);
SOCKET cloneSocket(SOCKET s)
{
struct sockaddr_storage saddr;
struct sockaddr *sa = (struct sockaddr *)&saddr;
socklen_t len;
SOCKET s2 = INVALID_SOCKET;
int stype;
int sproto;
len = sizeof(stype);
if (getsockopt(s, SOL_SOCKET, SO_TYPE, &stype, &len) == -1 ||
getsockopt(s, SOL_SOCKET, SO_PROTOCOL, &sproto, &len) == -1)
return s2;
len = sizeof(saddr);
memset(&saddr, 0, len);
if (getsockname(s, sa, &len) != -1)
s2 = socket(sa->sa_family, stype, sproto);
return s2;
}
But Network.Socket does not export a way to recover the address family of a socket other than case matching the constructor, and no way to map the integer returned from (getSocketOption sock Type) back to a SocketType that can be used to create a new socket, and SO_PROTOCOL is missing entirely, so one can simply hope that defaultProtocol is good enough.
As systems evolve and new values for some of these fields are added, the "sum type" representation of these fields creates constant compatibility issues. These could in some cases be much better handled via PatternSynonyms than fixed sum types. Something like the below suitably refined (e.g. Perhaps SocketFamily can be 8 bits on BSD and 16 bits on Linux, with some Haskell type defined accordingly to match the platform's sa_family_t)
{-# LANGUAGE CPP #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
#include <sys/param.h>
#include <sys/socket.h>
module Network.Socket.Types
( AddressFamily
( AF_INET
, AF_INET6
, AF_UNIX
)
) where
import Data.Word
newtype AddressFamily = AddressFamily { packAddressFamily :: Word16 }
deriving (Eq)
#ifdef AF_INET
pattern AF_INET :: AddressFamily
pattern AF_INET = AddressFamily (#const AF_INET)
#else
pattern AF_INET = AddressFamily 0
#endif
#ifdef AF_INET6
pattern AF_INET6 :: AddressFamily
pattern AF_INET6 = AddressFamily (#const AF_INET6)
#else
pattern AF_INET6 = AddressFamily 0
#endif
#ifdef AF_UNIX
pattern AF_UNIX :: AddressFamily
pattern AF_UNIX = AddressFamily (#const AF_UNIX)
#else
pattern AF_UNIX = AddressFamily 0
#endif
instance Show AddressFamily where
show AF_INET = "inet"
show AF_INET6 = "inet6"
show AF_UNIX = "unix"
show (AddressFamily n) = "<family" ++ show n ++ ">"
and so on for various similar cases.
In Network 2.8, it is difficult to create a new socket of the same shape as an existing socket due to missing interfaces. In C, I can do this via:
But
Network.Socketdoes not export a way to recover the address family of a socket other than case matching the constructor, and no way to map the integer returned from(getSocketOption sock Type)back to aSocketTypethat can be used to create a new socket, andSO_PROTOCOLis missing entirely, so one can simply hope thatdefaultProtocolis good enough.As systems evolve and new values for some of these fields are added, the "sum type" representation of these fields creates constant compatibility issues. These could in some cases be much better handled via
PatternSynonymsthan fixed sum types. Something like the below suitably refined (e.g. Perhaps SocketFamily can be 8 bits on BSD and 16 bits on Linux, with some Haskell type defined accordingly to match the platform'ssa_family_t){-# LANGUAGE CPP #-} {-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} #include <sys/param.h> #include <sys/socket.h> module Network.Socket.Types ( AddressFamily ( AF_INET , AF_INET6 , AF_UNIX ) ) where import Data.Word newtype AddressFamily = AddressFamily { packAddressFamily :: Word16 } deriving (Eq) #ifdef AF_INET pattern AF_INET :: AddressFamily pattern AF_INET = AddressFamily (#const AF_INET) #else pattern AF_INET = AddressFamily 0 #endif #ifdef AF_INET6 pattern AF_INET6 :: AddressFamily pattern AF_INET6 = AddressFamily (#const AF_INET6) #else pattern AF_INET6 = AddressFamily 0 #endif #ifdef AF_UNIX pattern AF_UNIX :: AddressFamily pattern AF_UNIX = AddressFamily (#const AF_UNIX) #else pattern AF_UNIX = AddressFamily 0 #endif instance Show AddressFamily where show AF_INET = "inet" show AF_INET6 = "inet6" show AF_UNIX = "unix" show (AddressFamily n) = "<family" ++ show n ++ ">"and so on for various similar cases.