1 | |
module Network.UCSPI where
|
| 1 |
module Network.UCSPI
|
| 2 |
( UCSPIOptions(..)
|
| 3 |
, ucspiClient
|
| 4 |
, ucspiServer
|
| 5 |
) where
|
2 | 6 |
|
3 | 7 |
import Control.Arrow (first)
|
4 | 8 |
import Data.List (stripPrefix)
|
5 | |
import System.IO (Handle, hPutStrLn, stderr)
|
| 9 |
import System.IO (Handle, hClose, hPutStrLn, stderr)
|
6 | 10 |
import System.Posix.IO (fdToHandle)
|
7 | 11 |
import System.Posix.Types (Fd(..))
|
8 | 12 |
import System.Environment (getEnvironment)
|
9 | 13 |
|
| 14 |
-- | The @UCSPI@ spec indicates that applications will receive information
|
| 15 |
-- about their connection through environment variables. A 'UCSPIOptions'
|
| 16 |
-- value will contains all the relevant values filtered out. As most of
|
| 17 |
-- these (save for the protocol name) are prefixed with both the protocol
|
| 18 |
-- name and either @LOCAL@ or @REMOTE@, those values are stripped before
|
| 19 |
-- they are added to the respective lists: for example, if a @UCSPI@
|
| 20 |
-- application for the @TCP@ protocol passes in an environment variable
|
| 21 |
-- @TCPREMOTEPORT=7777@, then the value of 'ucspiProtocol' will be
|
| 22 |
-- @TCP@ and 'ucspiRemoteVars' will contain a pair @(\"PORT\","7777")@.
|
10 | 23 |
data UCSPIOptions = UCSPIOptions
|
11 | 24 |
{ ucspiProtocol :: String
|
12 | 25 |
, ucspiLocalVars :: [(String,String)]
|
|
29 | 42 |
}
|
30 | 43 |
|
31 | 44 |
|
| 45 |
-- | A @UCSPI@ client is passed an options value, a handle which corresponds
|
| 46 |
-- to the reading end of a socket, and a handle which corresponds to the
|
| 47 |
-- writing end of a socket. For example, a sample @UCSPI@ client which
|
| 48 |
-- connects to a server, writes a line, and reads something back, regardless
|
| 49 |
-- of the underlying transport mechanism, would look like
|
| 50 |
--
|
| 51 |
-- > main :: IO ()
|
| 52 |
-- > main = ucspiClient $ \_ rdH wrH -> do
|
| 53 |
-- > hPutStrLn wrH "hello"
|
| 54 |
-- > ln <- hGetLine rdH
|
| 55 |
-- > putStrLn ln
|
32 | 56 |
ucspiClient :: (UCSPIOptions -> Handle -> Handle -> IO ()) -> IO ()
|
33 | 57 |
ucspiClient client = do
|
34 | 58 |
opts <- gatherOptions `fmap` getEnvironment
|
|
38 | 62 |
rdH <- fdToHandle (Fd 6)
|
39 | 63 |
wrH <- fdToHandle (Fd 7)
|
40 | 64 |
client opts' rdH wrH
|
| 65 |
hClose rdH
|
| 66 |
hClose wrH
|
41 | 67 |
|
| 68 |
-- | A @UCSPI@ server is passed only an options value. In order to read from or
|
| 69 |
-- write to the connection, it just uses @stdin@ and @stdout@, which means that
|
| 70 |
-- a server which reads a single line from a client and echoes it back would
|
| 71 |
-- look like
|
| 72 |
--
|
| 73 |
-- > main :: IO ()
|
| 74 |
-- > main = ucspiServer $ \_ -> getLine >>= putStrLn
|
42 | 75 |
ucspiServer :: (UCSPIOptions -> IO ()) -> IO ()
|
43 | 76 |
ucspiServer server = do
|
44 | 77 |
opts <- gatherOptions `fmap` getEnvironment
|