zre-0.1.0.2: src/Network/ZRE/Beacon.hs
{-# LANGUAGE OverloadedStrings #-}
module Network.ZRE.Beacon (beacon, beaconRecv) where
import Control.Monad
import Control.Exception
import Control.Concurrent
import Control.Concurrent.STM
import Network.Socket hiding (accept, send, sendTo, recv, recvFrom)
import Network.Socket.ByteString
import Network.SockAddr
import Network.Multicast
import Data.Maybe
import Data.UUID
import Data.Time.Clock
import qualified Data.Map as M
import qualified Data.ByteString.Char8 as B
import Data.ZRE
import Network.ZRE.Peer
import Network.ZRE.Types
import System.ZMQ4.Endpoint
beaconRecv :: TVar ZREState -> Endpoint -> IO b
beaconRecv s e = do
sock <- multicastReceiver (B.unpack $ endpointAddr e) (fromIntegral $ fromJust $ endpointPort e)
forever $ do
(msg, addr) <- recvFrom sock 22
case parseBeacon msg of
Left err -> print err
Right (_lead, _ver, uuid, port) -> do
case addr of
x@(SockAddrInet _hisport _host) -> do
beaconHandle s (showSockAddrBS x) uuid (fromIntegral port)
x@(SockAddrInet6 _hisport _ _host _) -> do
beaconHandle s (showSockAddrBS x) uuid (fromIntegral port)
_ -> return ()
-- handle messages received on beacon
-- creates new peers
-- updates peers last heard
beaconHandle :: TVar ZREState -> B.ByteString -> UUID -> Int -> IO ()
beaconHandle s addr uuid port = do
st <- atomically $ readTVar s
if uuid == zreUUID st
then return () -- our own message
else do
case M.lookup uuid $ zrePeers st of
(Just peer) -> do
now <- getCurrentTime
atomically $ updateLastHeard peer now
Nothing -> do
-- B.putStrLn $ B.concat ["New peer from beacon ", B.pack $ show uuid, " (", addr, ":", B.pack $ show port , ")"]
void $ makePeer s uuid $ newPeerFromBeacon addr port
return ()
-- sends udp multicast beacons
beacon :: AddrInfo -> B.ByteString -> Port -> IO a
beacon addrInfo uuid port = do
withSocketsDo $ do
bracket (getSocket addrInfo) close (talk (addrAddress addrInfo) (zreBeacon uuid port))
where
getSocket addr = do
s <- socket (addrFamily addr) Datagram defaultProtocol
mapM_ (\x -> setSocketOption s x 1) [Broadcast, ReuseAddr, ReusePort]
bind s (addrAddress addr)
return s
talk addr msg s =
forever $ do
void $ sendTo s msg addr
threadDelay zreBeaconMs