Verified Commit ad2a9986 authored by Allele Dev's avatar Allele Dev

core: add simpler socket creation functions

parent 5473cbea
# linear-socket
| linear-socket | 0.3.0.0 |
| linear-socket | 0.3.1.0 |
| ------------- | --------------------------------- |
| Maintainer | Allele Dev ([email protected]) |
| Funding | $0 USD |
......
# 0.3.1.0 (Dec. 2, 2017)
* added socket creation functions that make things easier to use
* tcp4Socket
* tcp6Socket
* tcpUnixSocket
* and UDP versions
# 0.3.0.0 (Dec. 2, 2017)
* made API friendlier for point-free operations
......
......@@ -3,7 +3,7 @@
-- see: https://github.com/sol/hpack
name: linear-socket
version: 0.3.0.0
version: 0.3.1.0
synopsis: Initial project template from stack
description: Please see README.md
license: GPL-3
......
name: linear-socket
version: '0.3.0.0'
version: '0.3.1.0'
synopsis: Initial project template from stack
description: Please see README.md
category: Web
......
......@@ -8,6 +8,13 @@ module Network.Typed.Socket (
ShutdownStatus(..),
socket,
tcp4Socket,
tcp6Socket,
tcpUnixSocket,
udp4Socket,
udp6Socket,
udpUnixSocket,
connect,
bind,
accept,
......@@ -85,6 +92,10 @@ data SockAddr (f :: SocketFamily) where
--------------------------------------------------------------------------------
-- Core operations
--------------------------------------------------------------------------------
----------------------------------------
-- Socket creation
----------------------------------------
socket :: forall f p.
(SockFam f, SockProto p) => IO (SSocket f p 'Unconnected 'Available)
socket =
......@@ -92,10 +103,49 @@ socket =
y = socketProtocol (sockProto1 :: SocketProtocol1 p)
in SSocket <$> (NS.socket x y NS.defaultProtocol)
close :: Closeable s ~ 'True =>
SSocket f p s sh -> IO (SSocket f p 'Closed sh)
close (SSocket s) = NS.close s >> return (SSocket s)
tcp4Socket :: IO (SSocket 'InetV4 'Tcp 'Unconnected 'Available)
tcp4Socket = (socket :: IO (SSocket 'InetV4 'Tcp 'Unconnected 'Available))
tcp6Socket :: IO (SSocket 'InetV6 'Tcp 'Unconnected 'Available)
tcp6Socket = (socket :: IO (SSocket 'InetV6 'Tcp 'Unconnected 'Available))
tcpUnixSocket :: IO (SSocket 'Unix 'Tcp 'Unconnected 'Available)
tcpUnixSocket = (socket :: IO (SSocket 'Unix 'Tcp 'Unconnected 'Available))
udp4Socket :: IO (SSocket 'InetV4 'Udp 'Unconnected 'Available)
udp4Socket = (socket :: IO (SSocket 'InetV4 'Udp 'Unconnected 'Available))
udp6Socket :: IO (SSocket 'InetV6 'Udp 'Unconnected 'Available)
udp6Socket = (socket :: IO (SSocket 'InetV6 'Udp 'Unconnected 'Available))
udpUnixSocket :: IO (SSocket 'Unix 'Udp 'Unconnected 'Available)
udpUnixSocket = (socket :: IO (SSocket 'Unix 'Udp 'Unconnected 'Available))
-- bracketed, typed helpers
withSocket :: (SockFam f, SockProto p) => (SSocket f p 'Unconnected 'Available -> IO a) -> IO a
withSocket = bracket socket close
withTcp4Socket :: (SSocket 'InetV4 'Tcp 'Unconnected 'Available -> IO a) -> IO a
withTcp4Socket = withSocket
withTcp6Socket :: (SSocket 'InetV6 'Tcp 'Unconnected 'Available -> IO a) -> IO a
withTcp6Socket = withSocket
withTcpUnixSocket :: (SSocket 'Unix 'Tcp 'Unconnected 'Available -> IO a) -> IO a
withTcpUnixSocket = withSocket
withUdp4Socket :: (SSocket 'InetV4 'Udp 'Unconnected 'Available -> IO a) -> IO a
withUdp4Socket = withSocket
withUdp6Socket :: (SSocket 'InetV6 'Udp 'Unconnected 'Available -> IO a) -> IO a
withUdp6Socket = withSocket
withUdpUnixSocket :: (SSocket 'Unix 'Udp 'Unconnected 'Available -> IO a) -> IO a
withUdpUnixSocket = withSocket
----------------------------------------
-- Socket ops
----------------------------------------
connect ::
SockAddr f -> SSocket f 'Tcp 'Unconnected sh
-> IO (SSocket f 'Tcp 'Connected 'Available)
......@@ -114,14 +164,21 @@ accept (SSocket s) = do
(s', a) <- NS.accept s
return (SSocket s', a)
send :: CanSend sh ~ 'True
=> ByteString -> SSocket f 'Tcp 'Connected sh -> IO Int
send bs (SSocket s) = NSB.send s bs
----------------------------------------
-- Socket option management
----------------------------------------
setSocketOption :: NS.SocketOption -> Int -> SSocket f p s sh -> IO (SSocket f p s sh)
setSocketOption opt n ss@(SSocket s) = NS.setSocketOption s opt n >> return ss
recv :: CanReceive sh ~ 'True
=> Int -> SSocket f 'Tcp 'Connected sh -> IO ByteString
recv n (SSocket s) = NSB.recv s n
makePortReusable :: SSocket f p s sh -> IO (SSocket f p s sh)
makePortReusable s = setSocketOption NS.ReusePort 0 s >> return s
makeAddrReusable :: SSocket f p s sh -> IO (SSocket f p s sh)
makeAddrReusable s = setSocketOption NS.ReuseAddr 0 s >> return s
----------------------------------------
-- Socket termination
----------------------------------------
shutdownReceive ::
CanShutdownReceive sh ~ 'True =>
SSocket f p s sh
......@@ -143,6 +200,21 @@ shutdownBoth ::
shutdownBoth (SSocket s) =
NS.shutdown s NS.ShutdownBoth >> return (SSocket s)
close :: Closeable s ~ 'True =>
SSocket f p s sh -> IO (SSocket f p 'Closed sh)
close (SSocket s) = NS.close s >> return (SSocket s)
----------------------------------------
-- Reading and writing
----------------------------------------
send :: CanSend sh ~ 'True
=> ByteString -> SSocket f 'Tcp 'Connected sh -> IO Int
send bs (SSocket s) = NSB.send s bs
recv :: CanReceive sh ~ 'True
=> Int -> SSocket f 'Tcp 'Connected sh -> IO ByteString
recv n (SSocket s) = NSB.recv s n
-- simplified assumptions: require connectionless UDP for sendTo/recvFrom
sendTo :: CanSend sh ~ 'True
=> ByteString -> SockAddr f -> SSocket f 'Udp 'Unconnected sh -> IO Int
......@@ -155,37 +227,6 @@ recvFrom n (SSocket s) = do
(bs, sa) <- NSB.recvFrom s n
return (bs, fromNetworkSockAddr sa)
-- bracketed, typed helpers
withSocket :: (SockFam f, SockProto p) => (SSocket f p 'Unconnected 'Available -> IO a) -> IO a
withSocket = bracket socket close
withTcp4Socket :: (SSocket 'InetV4 'Tcp 'Unconnected 'Available -> IO a) -> IO a
withTcp4Socket = withSocket
withTcp6Socket :: (SSocket 'InetV6 'Tcp 'Unconnected 'Available -> IO a) -> IO a
withTcp6Socket = withSocket
withTcpUnixSocket :: (SSocket 'Unix 'Tcp 'Unconnected 'Available -> IO a) -> IO a
withTcpUnixSocket = withSocket
withUdp4Socket :: (SSocket 'InetV4 'Udp 'Unconnected 'Available -> IO a) -> IO a
withUdp4Socket = withSocket
withUdp6Socket :: (SSocket 'InetV6 'Udp 'Unconnected 'Available -> IO a) -> IO a
withUdp6Socket = withSocket
withUdpUnixSocket :: (SSocket 'Unix 'Udp 'Unconnected 'Available -> IO a) -> IO a
withUdpUnixSocket = withSocket
setSocketOption :: NS.SocketOption -> Int -> SSocket f p s sh -> IO (SSocket f p s sh)
setSocketOption opt n ss@(SSocket s) = NS.setSocketOption s opt n >> return ss
makePortReusable :: SSocket f p s sh -> IO (SSocket f p s sh)
makePortReusable s = setSocketOption NS.ReusePort 0 s >> return s
makeAddrReusable :: SSocket f p s sh -> IO (SSocket f p s sh)
makeAddrReusable s = setSocketOption NS.ReuseAddr 0 s >> return s
--------------------------------------------------------------------------------
-- Type machinery to make the above possible
--------------------------------------------------------------------------------
......
......@@ -51,27 +51,27 @@ main = hspec $ do
describe "Network.Typed.Socket" $ do
it "can open and close a tcp4 socket" $ do
(socket :: IO (SSocket 'InetV4 'Tcp 'Unconnected 'Available))
tcp4Socket
>>= close
>> return ()
it "can open and close a tcp6 socket" $ do
(socket :: IO (SSocket 'InetV6 'Tcp 'Unconnected 'Available))
tcp6Socket
>>= close
>> return ()
it "can open and close a udp4 socket" $ do
(socket :: IO (SSocket 'InetV4 'Udp 'Unconnected 'Available))
udp4Socket
>>= close
>> return ()
it "can open and close a udp6 socket" $ do
(socket :: IO (SSocket 'InetV6 'Udp 'Unconnected 'Available))
udp6Socket
>>= close
>> return ()
it "can echo server" $ do
it "can echo server (TCP)" $ do
withTcp4Socket $ \server -> do
withTcp4Socket $ \client -> do
serverWaitLock <- newEmptyMVar
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment