[project @ 1998-02-02 17:27:26 by simonm]
[ghc-hetmet.git] / ghc / lib / misc / Socket.lhs
1 %
2 % (c) The GRASP/AQUA Project, Glasgow University, 1995, 1996
3 %
4 % Last Modified: Fri Jul 21 15:53:32 1995
5 % Darren J Moffat <moffatd@dcs.gla.ac.uk>
6 %
7 % Further hacked on by Sigbjorn Finne <sof@dcs.gla.ac.uk>
8 %
9 \section[Socket]{Haskell 1.3 Socket bindings}
10
11
12 \begin{code}       
13 {-# OPTIONS -#include "cbits/ghcSockets.h" #-}
14
15 #include "config.h"
16
17 module Socket (
18         PortID(..),
19         Hostname,
20
21         connectTo,      -- :: Hostname -> PortID -> IO Handle
22         listenOn,       -- :: PortID -> IO Socket
23         
24         accept,         -- :: Socket -> IO (Handle, HostName)
25
26         sendTo,         -- :: Hostname -> PortID -> String -> IO ()
27         recvFrom,       -- :: Hostname -> PortID -> IO String
28
29         socketPort      -- :: Socket -> IO PortID
30
31        ) where
32
33 import BSD
34 import SocketPrim hiding ( accept, socketPort )
35 import qualified SocketPrim ( accept, socketPort )
36 import IO
37 \end{code} 
38
39 %***************************************************************************
40 %*                                                                         *
41 \subsection[Socket-Setup]{High Level ``Setup'' functions}
42 %*                                                                         *
43 %***************************************************************************
44
45 Calling $connectTo$ creates a client side socket which is
46 connected to the given host and port.  The Protocol and socket type is
47 derived from the given port identifier.  If a port number is given
48 then the result is always an internet family $Stream$ socket. 
49
50 If the $PortID$ specifies a unix family socket and the $Hostname$
51 differs from that returned by $getHostname$ then an error is
52 raised. Alternatively an empty string may be given to $connectTo$
53 signalling that the current hostname applies.
54
55 \begin{code}
56 data PortID = 
57           Service String                -- Service Name eg "ftp"
58         | PortNumber Int                -- User defined Port Number
59 #ifndef cygwin32_TARGET_OS
60         | UnixSocket String             -- Unix family socket in file system
61 #endif
62
63 type Hostname = String
64 -- Maybe consider this alternative.
65 -- data Hostname = Name String | IP Int Int Int Int
66 \end{code}
67    
68 If more control over the socket type is required then $socketPrim$
69 should be used instead.
70
71 \begin{code}
72 connectTo :: Hostname           -- Hostname
73           -> PortID             -- Port Identifier
74           -> IO Handle          -- Connected Socket
75
76 connectTo hostname (Service serv) =
77     getProtocolNumber "tcp"                         >>= \ proto ->
78     socket AF_INET Stream proto                     >>= \ sock ->
79     getServicePortNumber serv                       >>= \ port ->
80     getHostByName hostname                          >>= \ (HostEntry _ _ _ haddrs) ->
81     connect sock (SockAddrInet port (head haddrs))  >>
82     socketToHandle sock ReadWriteMode               >>= \ h ->
83     return h
84 connectTo hostname (PortNumber port) =
85     getProtocolNumber "tcp"                         >>= \ proto ->
86     socket AF_INET Stream proto                     >>= \ sock ->
87     getHostByName hostname                          >>= \ (HostEntry _ _ _ haddrs) ->
88     connect sock (SockAddrInet port (head haddrs))  >>
89     socketToHandle sock ReadWriteMode
90
91 #ifndef cygwin32_TARGET_OS
92 connectTo _ (UnixSocket path) =
93     socket AF_UNIX Datagram 0                       >>= \ sock ->
94     connect sock (SockAddrUnix path)                >>
95     socketToHandle sock ReadWriteMode
96 #endif
97
98 \end{code}
99
100 The dual to the $connectTo$ call. This creates the server side
101 socket which has been bound to the specified port.
102
103 \begin{code}
104 listenOn :: PortID      -- Port Identifier
105          -> IO Socket   -- Connected Socket
106
107 listenOn (Service serv) =
108     getProtocolNumber "tcp"                         >>= \ proto ->
109     socket AF_INET Stream proto                     >>= \ sock ->
110     getServicePortNumber serv                       >>= \ port ->
111     bindSocket sock (SockAddrInet port iNADDR_ANY)  >>
112     listen sock maxListenQueue                      >>
113     return sock
114 listenOn (PortNumber port) =
115     getProtocolNumber "tcp"                         >>= \ proto ->
116     socket AF_INET Stream proto                     >>= \ sock ->
117     bindSocket sock (SockAddrInet port iNADDR_ANY)  >>
118     listen sock maxListenQueue                      >>
119     return sock
120 #ifndef cygwin32_TARGET_OS
121 listenOn (UnixSocket path) =
122     socket AF_UNIX Datagram 0                       >>= \ sock ->
123     bindSocket sock (SockAddrUnix path)             >>
124     return sock
125 #endif
126 \end{code}
127
128 \begin{code}
129 accept :: Socket                -- Listening Socket
130        -> IO (Handle,           -- StdIO Handle for read/write
131               HostName)         -- HostName of Peer socket
132
133 accept sock =
134  SocketPrim.accept sock              >>= \ (sock', (SockAddrInet _ haddr)) ->
135  getHostByAddr AF_INET haddr         >>= \ (HostEntry peer _ _ _) ->
136  socketToHandle sock ReadWriteMode   >>= \ handle ->
137  return (handle, peer)
138 \end{code}
139
140 Send and recived data from/to the given host and port number.  These
141 should normally only be used where the socket will not be required for
142 further calls.
143
144 Thse are wrappers around socket, bind, and listen.
145
146 \begin{code}
147 sendTo :: Hostname      -- Hostname
148        -> PortID        -- Port Number
149        -> String        -- Message to send
150        -> IO ()
151 sendTo h p msg = 
152  connectTo h p  >>= \ s ->
153  hPutStr s msg  >>
154  hClose s
155
156 recvFrom :: Hostname    -- Hostname
157          -> PortID      -- Port Number
158          -> IO String   -- Received Data
159 recvFrom host port =
160  listenOn port          >>= \ s ->
161  let 
162   waiting =
163    SocketPrim.accept s          >>= \ (s', (SockAddrInet _ haddr)) ->
164    getHostByAddr AF_INET haddr          >>= \ (HostEntry peer _ _ _) ->
165    if peer /= host then
166       sClose s'                 >>
167       waiting
168    else
169       readSocketAll s'          >>= \ msg ->
170       sClose s'                 >>
171       return msg
172  in
173  waiting                        >>= \ message ->
174  sClose s                       >>
175  return message
176 \end{code}
177
178 Access function returning the port type/id of socket.
179
180 \begin{code}
181 socketPort :: Socket -> IO PortID
182 socketPort s =
183     getSocketName s                     >>= \ sockaddr ->
184     return (case sockaddr of
185                 SockAddrInet port _     ->
186                     (PortNumber port)
187 #ifndef cygwin32_TARGET_OS
188                 SockAddrUnix path       ->
189                     (UnixSocket path)
190 #endif
191             )
192 \end{code}