2 % (c) The GRASP/AQUA Project, Glasgow University, 1995-1997
4 \section[BSD]{Misc BSD bindings}
6 The @BSD@ module defines Haskell bindings to network programming
7 functionality that is only provided by BSD-style APIs.
10 {-# OPTIONS -#include "cbits/ghcSockets.h" #-}
15 getHostName, -- :: IO HostName
19 getServiceByName, -- :: ServiceName -> ProtocolName -> IO ServiceEntry
20 getServiceByPort, -- :: PortNumber -> ProtocolName -> IO ServiceEntry
21 getServicePortNumber, -- :: ServiceName -> IO PortNumber
22 getServiceEntry, -- :: IO ServiceEntry
23 setServiceEntry, -- :: Bool -> IO ()
24 endServiceEntry, -- :: IO ()
25 getServiceEntries, -- :: Bool -> IO [ServiceEntry]
30 getProtocolByName, -- :: ProtocolName -> IO ProtocolEntry
31 getProtocolByNumber, -- :: ProtocolNumber -> IO ProtcolEntry
32 getProtocolNumber, -- :: ProtocolName -> ProtocolNumber
34 setProtocolEntry, -- :: Bool -> IO ()
35 getProtocolEntry, -- :: IO ProtocolEntry
36 endProtocolEntry, -- :: IO ()
37 getProtocolEntries, -- :: Bool -> IO [ProtocolEntry]
40 mkPortNumber, -- :: Int -> PortNumber
43 getHostByName, -- :: HostName -> IO HostEntry
44 getHostByAddr, -- :: HostAddress -> Family -> IO HostEntry
45 hostAddress, -- :: HostEntry -> HostAddress
47 setHostEntry, -- :: Bool -> IO ()
48 getHostEntry, -- :: IO HostEntry
49 endHostEntry, -- :: IO ()
50 getHostEntries, -- :: Bool -> IO [HostEntry]
55 getNetworkByName, -- :: NetworkName -> IO NetworkEntry
56 getNetworkByAddr, -- :: NetworkAddr -> Family -> IO NetworkEntry
57 setNetworkEntry, -- :: Bool -> IO ()
58 getNetworkEntry, -- :: IO NetworkEntry
59 endNetworkEntry, -- :: IO ()
60 getNetworkEntries -- :: Bool -> IO [NetworkEntry]
66 import PrelIOBase ( IOError (..), IOErrorType(..) )
70 import PackedString ( cByteArrayToPS, unpackPS, unpackCStringIO )
72 import PosixUtil ( unvectorize )
78 %***************************************************************************
80 \subsection[BSD-DBTypes]{Service, Protocol \& Host Database Types}
82 %***************************************************************************
85 type HostName = String
86 type ProtocolName = String
87 type ServiceName = String
91 protoName :: ProtocolName, -- Official Name
92 protoAliases :: [ProtocolName], -- aliases
93 protoNumber :: ProtocolNumber -- Protocol Number
98 serviceName :: ServiceName, -- Official Name
99 serviceAliases :: [ServiceName], -- aliases
100 servicePort :: PortNumber, -- Port Number ( network byte order )
101 serviceProtocol :: ProtocolName -- Protocol
106 hostName :: HostName, -- Official Name
107 hostAliases :: [HostName], -- aliases
108 hostFamily :: Family, -- Host Type (currently AF_INET)
109 hostAddresses :: [HostAddress] -- Set of Network Addresses (in network byte order)
112 -- convenience function:
113 hostAddress :: HostEntry -> HostAddress
114 hostAddress (HostEntry nm _ _ ls) =
116 [] -> error ("BSD.hostAddress: empty network address list for " ++ nm)
121 %***************************************************************************
123 \subsection[BSD-DBAccess]{Service, Protocol Host Database Access}
125 %***************************************************************************
127 Calling @getServiceByName@ for a given service and protocol returns the
128 systems service entry. This should be used to find the port numbers
129 for standard protocols such as SMTP and FTP. The remaining three
130 functions should be used for browsing the service database
133 Calling @setServiceEntry@ with \tr{True} indicates that the service
134 database should be left open between calls to @getServiceEntry@. To
135 close the database a call to @endServiceEntry@ is required. This
136 database file is usually stored in the file /etc/services.
139 getServiceByName :: ServiceName -- Service Name
140 -> ProtocolName -- Protocol Name
141 -> IO ServiceEntry -- Service Entry
142 getServiceByName name proto = do
143 ptr <- _ccall_ getservbyname name proto
145 then fail (IOError Nothing NoSuchThing "no such service entry")
146 else unpackServiceEntry ptr
148 getServiceByPort :: PortNumber
151 getServiceByPort (PNum port) proto = do
152 ptr <- _ccall_ getservbyport port proto
154 then fail (IOError Nothing NoSuchThing "no such service entry")
155 else unpackServiceEntry ptr
157 getServicePortNumber :: ServiceName -> IO PortNumber
158 getServicePortNumber name = do
159 (ServiceEntry _ _ port _) <- getServiceByName name "tcp"
162 getServiceEntry :: IO ServiceEntry
164 ptr <- _ccall_ getservent
166 then fail (IOError Nothing NoSuchThing "no such service entry")
167 else unpackServiceEntry ptr
169 setServiceEntry :: Bool -> IO ()
170 setServiceEntry flg = _ccall_ setservent stayOpen
171 where stayOpen = if flg then 1 else 0
173 endServiceEntry :: IO ()
174 endServiceEntry = _ccall_ endservent
176 getServiceEntries :: Bool -> IO [ServiceEntry]
177 getServiceEntries stayOpen = do
178 setServiceEntry stayOpen
179 getEntries (getServiceEntry) (endServiceEntry)
183 The following relate directly to the corresponding \tr{UNIX} {C} calls for
184 returning the protocol entries. The protocol entry is represented by
185 the Haskell type @ProtocolEntry@.
187 As for @setServiceEntry@ above, calling @setProtocolEntry@.
188 determines whether or not the protocol database file, usually
189 \tr{/etc/protocols}, is to be kept open between calls of
190 @getProtocolEntry@. Similarly,
193 getProtocolByName :: ProtocolName -> IO ProtocolEntry
194 getProtocolByNumber :: ProtocolNumber -> IO ProtocolEntry
195 getProtocolNumber :: ProtocolName -> IO ProtocolNumber
197 setProtocolEntry :: Bool -> IO () -- Keep DB Open ?
198 getProtocolEntry :: IO ProtocolEntry -- Next Protocol Entry from DB
199 endProtocolEntry :: IO ()
200 getProtocolEntries :: Bool -> IO [ProtocolEntry]
204 --getProtocolByName :: ProtocolName -> IO ProtocolEntry
205 getProtocolByName name = do
206 ptr <- _ccall_ getprotobyname name
208 then fail (IOError Nothing NoSuchThing "no such protocol entry")
209 else unpackProtocolEntry ptr
211 --getProtocolByNumber :: ProtocolNumber -> IO ProtocolEntry
212 getProtocolByNumber num = do
213 ptr <- _ccall_ getprotobynumber num
215 then fail (IOError Nothing NoSuchThing "no such protocol entry")
216 else unpackProtocolEntry ptr
218 --getProtocolNumber :: ProtocolName -> IO ProtocolNumber
219 getProtocolNumber proto = do
220 (ProtocolEntry _ _ num) <- getProtocolByName proto
223 --getProtocolEntry :: IO ProtocolEntry -- Next Protocol Entry from DB
224 getProtocolEntry = do
225 ptr <- _ccall_ getprotoent
227 then fail (IOError Nothing NoSuchThing "no such protocol entry")
228 else unpackProtocolEntry ptr
230 --setProtocolEntry :: Bool -> IO () -- Keep DB Open ?
231 setProtocolEntry flg = _ccall_ setprotoent v
232 where v = if flg then 1 else 0
234 --endProtocolEntry :: IO ()
235 endProtocolEntry = _ccall_ endprotoent
237 --getProtocolEntries :: Bool -> IO [ProtocolEntry]
238 getProtocolEntries stayOpen = do
239 setProtocolEntry stayOpen
240 getEntries (getProtocolEntry) (endProtocolEntry)
245 getHostByName :: HostName -> IO HostEntry
246 getHostByName name = do
247 ptr <- _ccall_ gethostbyname name
249 then fail (IOError Nothing NoSuchThing "no such host entry")
250 else unpackHostEntry ptr
252 getHostByAddr :: Family -> HostAddress -> IO HostEntry
253 getHostByAddr family addr = do
254 ptr <- _casm_ ``struct in_addr addr;
256 %r = gethostbyaddr ((char*)&addr, sizeof(struct in_addr), %1);''
260 then fail (IOError Nothing NoSuchThing "no such host entry")
261 else unpackHostEntry ptr
263 getHostEntry :: IO HostEntry
265 ptr <- _ccall_ gethostent
267 then fail (IOError Nothing NoSuchThing "unable to retrieve host entry")
268 else unpackHostEntry ptr
270 setHostEntry :: Bool -> IO ()
271 setHostEntry flg = _ccall_ sethostent v
272 where v = if flg then 1 else 0
274 endHostEntry :: IO ()
275 endHostEntry = _ccall_ endhostent
277 getHostEntries :: Bool -> IO [HostEntry]
278 getHostEntries stayOpen = do
279 setHostEntry stayOpen
280 getEntries (getHostEntry) (endHostEntry)
284 %***************************************************************************
286 \subsection[BSD-Network]{Accessing network information}
288 %***************************************************************************
290 Same set of access functions as for accessing host,protocol and service
291 system info, this time for the types of networks supported.
294 -- network addresses are represented in host byte order.
295 type NetworkAddr = Word
297 type NetworkName = String
301 networkName :: NetworkName, -- official name
302 networkAliases :: [NetworkName], -- aliases
303 networkFamily :: Family, -- type
304 networkAddress :: NetworkAddr
307 getNetworkByName :: NetworkName -> IO NetworkEntry
308 getNetworkByName name = do
309 ptr <- _ccall_ getnetbyname name
311 then fail (IOError Nothing NoSuchThing "no such network entry")
312 else unpackNetworkEntry ptr
314 getNetworkByAddr :: NetworkAddr -> Family -> IO NetworkEntry
315 getNetworkByAddr addr family = do
316 ptr <- _ccall_ getnetbyaddr addr (packFamily family)
318 then fail (IOError Nothing NoSuchThing "no such network entry")
319 else unpackNetworkEntry ptr
321 getNetworkEntry :: IO NetworkEntry
323 ptr <- _ccall_ getnetent
325 then fail (IOError Nothing NoSuchThing "no more network entries")
326 else unpackNetworkEntry ptr
328 setNetworkEntry :: Bool -> IO ()
329 setNetworkEntry flg = _ccall_ setnetent v
330 where v = if flg then 1 else 0
332 endNetworkEntry :: IO ()
333 endNetworkEntry = _ccall_ endnetent
335 getNetworkEntries :: Bool -> IO [NetworkEntry]
336 getNetworkEntries stayOpen = do
337 setNetworkEntry stayOpen
338 getEntries (getNetworkEntry) (endNetworkEntry)
342 %***************************************************************************
344 \subsection[BSD-Misc]{Miscellaneous Functions}
346 %***************************************************************************
348 Calling @getHostName@ returns the standard host name for the current
349 processor, as set at boot time.
352 getHostName :: IO HostName
354 ptr <- stToIO (newCharArray (0,256))
355 rc <- _casm_ ``%r=gethostname(%0, 256);'' ptr
356 ba <- stToIO (unsafeFreezeByteArray ptr)
358 then fail (userError "getHostName: unable to determine host name")
359 else return (unpackPS (cByteArrayToPS ba))
362 Helper function used by the exported functions that provides a
363 Haskellised view of the enumerator functions:
366 getEntries :: IO a -- read
369 getEntries getOne atEnd = loop
372 catch (do { v <- getOne; vs <- loop ; return (v:vs) })
373 (\ _ -> do { atEnd; return [] } )
379 char *s_name; /* official name of service */
380 char **s_aliases; /* alias list */
381 int s_port; /* port service resides at */
382 char *s_proto; /* protocol to use */
385 The members of this structure are:
386 s_name The official name of the service.
387 s_aliases A zero terminated list of alternate
388 names for the service.
389 s_port The port number at which the ser-
390 vice resides. Port numbers are
391 returned in network short byte
393 s_proto The name of the protocol to use
394 when contacting the service.
398 unpackServiceEntry :: Addr -> PrimIO ServiceEntry
399 unpackServiceEntry ptr = do
400 str <- _casm_ ``%r = ((struct servent*)%0)->s_name;'' ptr
401 name <- unpackCStringIO str
402 alias <- _casm_ ``%r = ((struct servent*)%0)->s_aliases;'' ptr
403 aliases <- unvectorize alias 0
404 port <- _casm_ ``%r = (int)(((struct servent*)%0)->s_port);'' ptr
405 str <- _casm_ ``%r = (char *)((struct servent*)%0)->s_proto;'' ptr
406 proto <- unpackCStringIO str
407 return (ServiceEntry name aliases (PNum port) proto)
409 -------------------------------------------------------------------------------
411 unpackProtocolEntry :: Addr -> IO ProtocolEntry
412 unpackProtocolEntry ptr = do
413 str <- _casm_ ``%r = ((struct protoent*)%0)->p_name;'' ptr
414 name <- unpackCStringIO str
415 alias <- _casm_ ``%r = ((struct protoent*)%0)->p_aliases;'' ptr
416 aliases <- unvectorize alias 0
417 proto <- _casm_ ``%r = ((struct protoent*)%0)->p_proto;'' ptr
418 return (ProtocolEntry name aliases proto)
420 -------------------------------------------------------------------------------
422 unpackHostEntry :: Addr -> IO HostEntry
423 unpackHostEntry ptr = do
424 str <- _casm_ ``%r = ((struct hostent*)%0)->h_name;'' ptr
425 name <- unpackCStringIO str
426 alias <- _casm_ ``%r = ((struct hostent*)%0)->h_aliases;'' ptr
427 aliases <- unvectorize alias 0
428 addrList <- unvectorizeHostAddrs ptr 0
429 return (HostEntry name aliases AF_INET addrList)
431 -------------------------------------------------------------------------------
433 unpackNetworkEntry :: Addr -> IO NetworkEntry
434 unpackNetworkEntry ptr = do
435 str <- _casm_ ``%r = ((struct netent*)%0)->n_name;'' ptr
436 name <- unpackCStringIO str
437 alias <- _casm_ ``%r = ((struct netent*)%0)->n_aliases;'' ptr
438 aliases <- unvectorize alias 0
439 fam <- _casm_ ``%r = ((struct netent*)%0)->n_addrtype;'' ptr
440 na <- _casm_ ``%r = ((struct netent*)%0)->n_net;'' ptr
441 return (NetworkEntry name aliases (unpackFamily fam) na)
443 -------------------------------------------------------------------------------
445 unvectorizeHostAddrs :: Addr -> Int -> IO [HostAddress]
446 unvectorizeHostAddrs ptr n = do
447 x <- _casm_ ``{ unsigned long tmp;
448 if ((((struct hostent*)%0)->h_addr_list[(int)%1]) == NULL)
451 tmp = (W_)((struct in_addr *)(((struct hostent*)%0)->h_addr_list[(int)%1]))->s_addr;
454 if x == (W# (int2Word# 0#))
457 xs <- unvectorizeHostAddrs ptr (n+1)