In the network-multicast Haskell documentation, I see a function
setInterface :: Socket -> HostName -> IO ()
Set the outgoing interface address of the multicast.
How can I use this to specify a source-address in a multicast join? The following code, when ran, produces the given output.. (IP Addresses masked for privacy)
Code
import Network.BSD
import Network.Socket hiding (send, sendTo, recv, recvFrom)
import Network.Socket.ByteString
import Network.Multicast hiding (multicastReceiver)
import Text.Printf
import Data.ByteString as B hiding (putStrLn)
sourceIP = "192.168.MMM.NNN"
mcastIP = "224.0.XXX.YYY"
mcastPort = 32101
mcastLoop :: Socket -> IO ()
mcastLoop sock = do
(msg, addr) <- recvFrom sock 1024
printf "%s-> %s\n" (show addr) (show . B.unpack $ msg)
mcastLoop sock
multicastReceiver :: HostName -> PortNumber -> IO Socket
multicastReceiver host port = do
proto <- getProtocolNumber "udp"
sock <- socket AF_INET Datagram proto
setInterface sock sourceIP
{-# LINE 81 "src/Network/Multicast.hsc" #-}
setInterface sock sourceIP
bindSocket sock $ SockAddrInet port 0
setInterface sock sourceIP
{-# LINE 82 "src/Network/Multicast.hsc" #-}
setInterface sock sourceIP
addMembership sock host
return sock
main :: IO ()
main = withSocketsDo $ do
sock <- multicastReceiver mcastIP mcastPort
dropMembership sock mcastIP
setInterface sock sourceIP
addMembership sock mcastIP
mcastLoop sock
Output
~ - sudo tcpdump -n -nn -i any "host 224.0.XXX.YYY"
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 65535 bytes
08:00:44.463153 IP 10.52.ZZZ.WWW > 224.0.XXX.YYY: igmp v2 report 224.0.XXX.YYY
08:00:52.498722 IP 10.52.ZZZ.WWW > 224.0.XXX.YYY: igmp v2 report 224.0.XXX.YYY
08:00:58.301711 IP 10.52.ZZZ.WWW > 224.0.XXX.YYY: igmp v2 report 224.0.XXX.YYY
08:01:08.408710 IP 10.52.ZZZ.WWW > 224.0.XXX.YYY: igmp v2 report 224.0.XXX.YYY
08:02:04.104707 IP 10.52.ZZZ.WWW > 224.0.XXX.YYY: igmp v2 report 224.0.XXX.YYY
08:03:08.545718 IP 10.52.ZZZ.WWW > 224.0.XXX.YYY: igmp v2 report 224.0.XXX.YYY
08:04:02.634709 IP 10.52.ZZZ.WWW > 224.0.XXX.YYY: igmp v2 report 224.0.XXX.YYY
08:05:03.757718 IP 10.52.ZZZ.WWW > 224.0.XXX.YYY: igmp v2 report 224.0.XXX.YYY
08:06:10.600716 IP 10.52.ZZZ.WWW > 224.0.XXX.YYY: igmp v2 report 224.0.XXX.YYY
08:07:07.248707 IP 10.52.ZZZ.WWW > 224.0.XXX.YYY: igmp v2 report 224.0.XXX.YYY
08:08:10.202708 IP 10.52.ZZZ.WWW > 224.0.XXX.YYY: igmp v2 report 224.0.XXX.YYY
08:09:02.390708 IP 10.52.ZZZ.WWW > 224.0.XXX.YYY: igmp v2 report 224.0.XXX.YYY
This is the comparison of C++/Haskell applications running (as requested by EJP)
~/sandbox - sudo tcpdump -i any "host 192.168.MMM.NNN"
[sudo] password for gresko:
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 65535 bytes
# C++ application started
16:15:55.490156 IP 192.168.MMM.NNN > 224.0.62.108: igmp v2 report 224.0.62.108
# C++ application killed
16:16:04.689342 IP 192.168.MMM.NNN > all-routers.mcast.net: igmp leave 224.0.62.108
# Haskell application started
# Haskell application killed