30bf12ec35415dd234e2a101ff534599d9f0fbf6
[ghc-hetmet.git] / ghc / lib / misc / Socket.lhs
1 %
2 % (c) The GRASP/AQUA Project, Glasgow University, 1995-98
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, recvFrom, sendTo )
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 PortNumber         -- 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) = do
77     proto       <- getProtocolNumber "tcp"
78     sock        <- socket AF_INET Stream proto
79     port        <- getServicePortNumber serv
80     he          <- getHostByName hostname
81     connect sock (SockAddrInet port (hostAddress he))
82     socketToHandle sock ReadWriteMode
83
84 connectTo hostname (PortNumber port) = do
85     proto       <- getProtocolNumber "tcp"
86     sock        <- socket AF_INET Stream proto
87     he          <- getHostByName hostname
88     connect sock (SockAddrInet port (hostAddress he))
89     socketToHandle sock ReadWriteMode
90
91 #ifndef cygwin32_TARGET_OS
92 connectTo _ (UnixSocket path) = do
93     sock    <- socket AF_UNIX Datagram 0
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) = do
108     proto   <- getProtocolNumber "tcp"
109     sock    <- socket AF_INET Stream proto
110     port    <- getServicePortNumber serv
111     bindSocket sock (SockAddrInet port iNADDR_ANY)
112     listen sock maxListenQueue
113     return sock
114
115 listenOn (PortNumber port) = do
116     proto <- getProtocolNumber "tcp"
117     sock  <- socket AF_INET Stream proto
118     bindSocket sock (SockAddrInet port iNADDR_ANY)
119     listen sock maxListenQueue
120     return sock
121
122 #ifndef cygwin32_TARGET_OS
123 listenOn (UnixSocket path) = do
124     sock <- socket AF_UNIX Datagram 0
125     bindSocket sock (SockAddrUnix path)
126     return sock
127 #endif
128 \end{code}
129
130 \begin{code}
131 accept :: Socket                -- Listening Socket
132        -> IO (Handle,           -- StdIO Handle for read/write
133               HostName)         -- HostName of Peer socket
134 accept sock = do
135  ~(sock', (SockAddrInet _ haddr)) <- SocketPrim.accept sock
136  (HostEntry peer _ _ _)           <- getHostByAddr AF_INET haddr
137  handle                           <- socketToHandle sock' ReadWriteMode
138  return (handle, peer)
139
140 \end{code}
141
142 Send and recived data from/to the given host and port number.  These
143 should normally only be used where the socket will not be required for
144 further calls.
145
146 Thse are wrappers around socket, bind, and listen.
147
148 \begin{code}
149 sendTo :: Hostname      -- Hostname
150        -> PortID        -- Port Number
151        -> String        -- Message to send
152        -> IO ()
153 sendTo h p msg = do
154   s <- connectTo h p
155   hPutStr s msg
156   hClose s
157
158 recvFrom :: Hostname    -- Hostname
159          -> PortID      -- Port Number
160          -> IO String   -- Received Data
161 recvFrom host port = do
162  s <- listenOn port
163  let 
164   waiting = do
165      ~(s', SockAddrInet _ haddr) <-  SocketPrim.accept s
166      (HostEntry peer _ _ _)      <- getHostByAddr AF_INET haddr
167      if peer /= host 
168       then do
169          sClose s'
170          waiting
171       else do
172         msg <- readSocketAll s'
173         sClose s'
174         return msg
175
176  message <- waiting
177  sClose s
178  return message
179
180 \end{code}
181
182 Access function returning the port type/id of socket.
183
184 \begin{code}
185 socketPort :: Socket -> IO PortID
186 socketPort s = do
187     sockaddr <- getSocketName s
188     return (portID sockaddr)
189   where
190    portID sa =
191     case sa of
192      SockAddrInet port _    -> PortNumber port
193 #ifndef cygwin32_TARGET_OS
194      SockAddrUnix path      -> UnixSocket path
195 #endif
196
197 \end{code}