module Sound.OSC.Transport.FD.UDP where
import Control.Exception
import Control.Monad
import Data.Bifunctor
import qualified Network.Socket as N
import qualified Network.Socket.ByteString as C
import qualified Sound.OSC.Coding.Decode.Binary as Binary
import qualified Sound.OSC.Coding.Encode.Builder as Builder
import qualified Sound.OSC.Packet as Packet
import qualified Sound.OSC.Transport.FD as FD
data UDP = UDP {udpSocket :: N.Socket}
udpPort :: Integral n => UDP -> IO n
udpPort = fmap fromIntegral . N.socketPort . udpSocket
upd_send_packet :: UDP -> Packet.Packet -> IO ()
upd_send_packet (UDP fd) p = void (C.send fd (Builder.encodePacket_strict p))
udp_recv_packet :: UDP -> IO Packet.Packet
udp_recv_packet (UDP fd) = liftM Binary.decodePacket_strict (C.recv fd 8192)
udp_close :: UDP -> IO ()
udp_close (UDP fd) = N.close fd
instance FD.Transport UDP where
sendPacket = upd_send_packet
recvPacket = udp_recv_packet
close = udp_close
with_udp :: IO UDP -> (UDP -> IO t) -> IO t
with_udp u = bracket u udp_close
udp_socket :: (N.Socket -> N.SockAddr -> IO ()) -> String -> Int -> IO UDP
udp_socket f host port = do
fd <- N.socket N.AF_INET N.Datagram 0
i:_ <- N.getAddrInfo Nothing (Just host) (Just (show port))
let sa = N.addrAddress i
f fd sa
return (UDP fd)
set_udp_opt :: N.SocketOption -> Int -> UDP -> IO ()
set_udp_opt k v (UDP s) = N.setSocketOption s k v
get_udp_opt :: N.SocketOption -> UDP -> IO Int
get_udp_opt k (UDP s) = N.getSocketOption s k
openUDP :: String -> Int -> IO UDP
openUDP = udp_socket N.connect
udpServer :: String -> Int -> IO UDP
udpServer = udp_socket N.bind
udp_server :: Int -> IO UDP
udp_server p = do
let hints =
N.defaultHints
{N.addrFlags = [N.AI_PASSIVE,N.AI_NUMERICSERV]
,N.addrSocketType = N.Datagram}
a:_ <- N.getAddrInfo (Just hints) Nothing (Just (show p))
s <- N.socket (N.addrFamily a) (N.addrSocketType a) (N.addrProtocol a)
N.setSocketOption s N.ReuseAddr 1
N.bind s (N.addrAddress a)
return (UDP s)
sendTo :: UDP -> Packet.Packet -> N.SockAddr -> IO ()
sendTo (UDP fd) p = void . C.sendTo fd (Builder.encodePacket_strict p)
recvFrom :: UDP -> IO (Packet.Packet, N.SockAddr)
recvFrom (UDP fd) = fmap (first Binary.decodePacket_strict) (C.recvFrom fd 8192)