{-# LANGUAGE Strict #-} module Foreign.Erlang.NodeData ( DistributionVersion(..) , matchDistributionVersion , DistributionFlag(..) , DistributionFlags(..) , NodeType(..) , NodeProtocol(..) , NodeData(..) ) where import qualified Data.ByteString as BS import Data.Binary import Data.Binary.Put import Data.Binary.Get import Data.Bits import Data.Ix import Util.Binary -------------------------------------------------------------------------------- data DistributionVersion = Zero | R4 | NeverUsed | R5C | R6 | R6B deriving (Eq, Show, Enum, Bounded, Ord, Ix) instance Binary DistributionVersion where put = putWord16be . fromIntegral . fromEnum get = do c <- getWord16be return $ toEnum $ fromIntegral c -------------------------------------------------------------------------------- matchDistributionVersion :: NodeData -> NodeData -> Maybe DistributionVersion matchDistributionVersion NodeData{protocol = localProto,hiVer = localHi,loVer = localLo} NodeData{protocol = remoteProto,hiVer = remoteHi,loVer = remoteLo} | localProto /= remoteProto = Nothing | localHi < remoteLo = Nothing | localLo > remoteHi = Nothing | otherwise = Just (max localHi remoteHi) -------------------------------------------------------------------------------- data DistributionFlag = PUBLISHED -- The node should be published and part of the global namespace | ATOM_CACHE -- The node implements an atom cache (obsolete) | EXTENDED_REFERENCES -- The node implements extended (3 * 32 bits) references. This is required today. If not present connection will be refused. | DIST_MONITOR -- The node implements distributed process monitoring. | FUN_TAGS -- The node uses separate tag for fun's (lambdas) in the distribution protocol. | DIST_MONITOR_NAME -- The node implements distributed named process monitoring. | HIDDEN_ATOM_CACHE -- The (hidden) node implements atom cache (obsolete) | NEW_FUN_TAGS -- The node understand new fun-tags | EXTENDED_PIDS_PORTS -- The node is capable of handling extended pids and ports. This is required today. If not present connection will be refused. | EXPORT_PTR_TAG | BIT_BINARIES | NEW_FLOATS -- The node understands new float format | UNICODE_IO | DIST_HDR_ATOM_CACHE -- The node implements atom cache in distribution header. | SMALL_ATOM_TAGS -- The node understand the SMALL_ATOM_EXT tag | UTF8_ATOMS -- The node understand UTF-8 encoded atoms deriving (Eq, Show, Enum, Bounded, Ord) newtype DistributionFlags = DistributionFlags [DistributionFlag] deriving (Eq, Show) instance Binary DistributionFlags where put (DistributionFlags flags) = do putWord32be $ toBits flags where toBits :: [DistributionFlag] -> Word32 toBits = foldl (flip $ (.|.) . toBit) 0 get = do (DistributionFlags . fromBits) <$> getWord32be where fromBits :: Word32 -> [DistributionFlag] fromBits bits = [ flag | flag <- [minBound .. maxBound] , bits .&. toBit flag /= 0 ] toBit :: DistributionFlag -> Word32 toBit PUBLISHED = 0x00001 toBit ATOM_CACHE = 0x00002 toBit EXTENDED_REFERENCES = 0x00004 toBit DIST_MONITOR = 0x00008 toBit FUN_TAGS = 0x00010 toBit DIST_MONITOR_NAME = 0x00020 -- NOT USED toBit HIDDEN_ATOM_CACHE = 0x00040 -- NOT SUPPORTED toBit NEW_FUN_TAGS = 0x00080 toBit EXTENDED_PIDS_PORTS = 0x00100 toBit EXPORT_PTR_TAG = 0x00200 -- NOT SUPPORTED toBit BIT_BINARIES = 0x00400 toBit NEW_FLOATS = 0x00800 toBit UNICODE_IO = 0x01000 toBit DIST_HDR_ATOM_CACHE = 0x02000 toBit SMALL_ATOM_TAGS = 0x04000 toBit UTF8_ATOMS = 0x10000 -------------------------------------------------------------------------------- data NodeType = NormalNode | HiddenNode deriving (Eq, Show, Enum, Bounded) instance Binary NodeType where put NormalNode = putWord8 77 put HiddenNode = putWord8 72 get = do nodeType <- getWord8 case nodeType of 77 -> return NormalNode 72 -> return HiddenNode _ -> fail $ "Bad node type: " ++ show nodeType -------------------------------------------------------------------------------- data NodeProtocol = TcpIpV4 deriving (Eq, Show, Enum, Bounded) instance Binary NodeProtocol where put = putWord8 . fromIntegral . fromEnum get = do c <- getWord8 return $ toEnum $ fromIntegral c -------------------------------------------------------------------------------- data NodeData = NodeData { portNo :: Word16 , nodeType :: NodeType , protocol :: NodeProtocol , hiVer :: DistributionVersion , loVer :: DistributionVersion , aliveName :: BS.ByteString , extra :: BS.ByteString } deriving (Eq, Show) -------------------------------------------------------------------------------- instance Binary NodeData where put NodeData{portNo,nodeType,protocol,hiVer,loVer,aliveName,extra} = do putWord16be portNo put nodeType put protocol put hiVer put loVer putLength16beByteString aliveName putLength16beByteString extra get = do NodeData <$> getWord16be <*> get <*> get <*> get <*> get <*> getLength16beByteString <*> getLength16beByteString