summaryrefslogtreecommitdiff
path: root/src/Network/SocketLike.hs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Network/SocketLike.hs')
-rw-r--r--src/Network/SocketLike.hs104
1 files changed, 104 insertions, 0 deletions
diff --git a/src/Network/SocketLike.hs b/src/Network/SocketLike.hs
new file mode 100644
index 00000000..2aa78e3e
--- /dev/null
+++ b/src/Network/SocketLike.hs
@@ -0,0 +1,104 @@
1{-# LANGUAGE GeneralizedNewtypeDeriving #-}
2-- |
3--
4-- A socket could be used indirectly via a 'System.IO.Handle' or a conduit from
5-- Michael Snoyman's conduit package. But doing so presents an encapsulation
6-- problem. Do we allow access to the underlying socket and trust that it wont
7-- be used in an unsafe way? Or do we protect it at the higher level and deny
8-- access to various state information?
9--
10-- The 'SocketLike' class enables the approach that provides a safe wrapper to
11-- the underlying socket and gives access to various state information without
12-- enabling direct reads or writes.
13module Network.SocketLike
14 ( SocketLike(..)
15 , RestrictedSocket
16 , restrictSocket
17 , restrictHandleSocket
18 -- * Re-exports
19 --
20 -- | To make the 'SocketLike' methods less awkward to use, the types
21 -- 'CUInt', 'SockAddr', and 'PortNumber' are re-exported.
22 , CUInt
23 , PortNumber
24 , SockAddr(..)
25 ) where
26
27import Network.Socket
28 ( PortNumber
29 , SockAddr
30 )
31import Foreign.C.Types ( CUInt )
32
33import qualified Network.Socket as NS
34import System.IO (Handle,hClose,hIsOpen)
35
36-- | A safe (mostly read-only) interface to a 'NS.Socket'. Note that despite
37-- how this class is named, it provides no access to typical 'NS.Socket' uses
38-- like sending or receiving network packets.
39class SocketLike sock where
40 -- | See 'NS.getSocketName'
41 getSocketName :: sock -> IO SockAddr
42 -- | See 'NS.getPeerName'
43 getPeerName :: sock -> IO SockAddr
44 -- | See 'NS.getPeerCred'
45 getPeerCred :: sock -> IO (CUInt, CUInt, CUInt)
46 -- | See 'NS.socketPort'
47 socketPort :: sock -> IO PortNumber
48 -- | See 'NS.sIsConnected'
49 --
50 -- __Warning__: Don't rely on this method if it's possible the socket was
51 -- converted into a 'Handle'.
52 sIsConnected :: sock -> IO Bool
53 -- | See 'NS.sIsBound'
54 sIsBound :: sock -> IO Bool
55 -- | See 'NS.sIsListening'
56 sIsListening :: sock -> IO Bool
57 -- | See 'NS.sIsReadable'
58 sIsReadable :: sock -> IO Bool
59 -- | See 'NS.sIsWritable'
60 sIsWritable :: sock -> IO Bool
61
62 -- | This is the only exposed write-access method to the
63 -- underlying state. Usually implemented by 'NS.close'
64 sClose :: sock -> IO ()
65
66instance SocketLike NS.Socket where
67 getSocketName = NS.getSocketName
68 getPeerName = NS.getPeerName
69 getPeerCred = NS.getPeerCred
70 socketPort = NS.socketPort
71 sIsConnected = NS.sIsConnected -- warning: this is always False if the socket
72 -- was converted to a Handle
73 sIsBound = NS.sIsBound
74 sIsListening = NS.sIsListening
75 sIsReadable = NS.sIsReadable
76 sIsWritable = NS.sIsWritable
77
78 sClose = NS.sClose
79
80-- | An encapsulated socket. Data reads and writes are not possible.
81data RestrictedSocket = Restricted (Maybe Handle) NS.Socket deriving Show
82
83instance SocketLike RestrictedSocket where
84 getSocketName (Restricted mb sock) = NS.getSocketName sock
85 getPeerName (Restricted mb sock) = NS.getPeerName sock
86 getPeerCred (Restricted mb sock) = NS.getPeerCred sock
87 socketPort (Restricted mb sock) = NS.socketPort sock
88 sIsConnected (Restricted mb sock) = maybe (NS.sIsConnected sock) (hIsOpen) mb
89 sIsBound (Restricted mb sock) = NS.sIsBound sock
90 sIsListening (Restricted mb sock) = NS.sIsListening sock
91 sIsReadable (Restricted mb sock) = NS.sIsReadable sock
92 sIsWritable (Restricted mb sock) = NS.sIsWritable sock
93 sClose (Restricted mb sock) = maybe (NS.sClose sock) (\h -> hClose h >> NS.sClose sock) mb
94
95-- | Create a 'RestrictedSocket' that explicitly disallows sending or
96-- receiving data.
97restrictSocket :: NS.Socket -> RestrictedSocket
98restrictSocket socket = Restricted Nothing socket
99
100-- | Build a 'RestrictedSocket' for which 'sClose' will close the given
101-- 'Handle'. It is intended that this 'Handle' was obtained via
102-- 'NS.socketToHandle'.
103restrictHandleSocket :: Handle -> NS.Socket -> RestrictedSocket
104restrictHandleSocket h socket = Restricted (Just h) socket