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" #-}
17 getHostName, -- :: IO HostName
21 getServiceByName, -- :: ServiceName -> ProtocolName -> IO ServiceEntry
22 getServiceByPort, -- :: PortNumber -> ProtocolName -> IO ServiceEntry
23 getServicePortNumber, -- :: ServiceName -> IO PortNumber
25 #ifndef cygwin32_TARGET_OS
26 getServiceEntry, -- :: IO ServiceEntry
27 setServiceEntry, -- :: Bool -> IO ()
28 endServiceEntry, -- :: IO ()
29 getServiceEntries, -- :: Bool -> IO [ServiceEntry]
35 getProtocolByName, -- :: ProtocolName -> IO ProtocolEntry
36 getProtocolByNumber, -- :: ProtocolNumber -> IO ProtcolEntry
37 getProtocolNumber, -- :: ProtocolName -> ProtocolNumber
39 #ifndef cygwin32_TARGET_OS
40 setProtocolEntry, -- :: Bool -> IO ()
41 getProtocolEntry, -- :: IO ProtocolEntry
42 endProtocolEntry, -- :: IO ()
43 getProtocolEntries, -- :: Bool -> IO [ProtocolEntry]
47 mkPortNumber, -- :: Int -> PortNumber
50 getHostByName, -- :: HostName -> IO HostEntry
51 getHostByAddr, -- :: HostAddress -> Family -> IO HostEntry
52 hostAddress, -- :: HostEntry -> HostAddress
54 #ifndef cygwin32_TARGET_OS
55 setHostEntry, -- :: Bool -> IO ()
56 getHostEntry, -- :: IO HostEntry
57 endHostEntry, -- :: IO ()
58 getHostEntries, -- :: Bool -> IO [HostEntry]
64 #ifndef cygwin32_TARGET_OS
65 getNetworkByName, -- :: NetworkName -> IO NetworkEntry
66 getNetworkByAddr, -- :: NetworkAddr -> Family -> IO NetworkEntry
67 setNetworkEntry, -- :: Bool -> IO ()
68 getNetworkEntry, -- :: IO NetworkEntry
69 endNetworkEntry, -- :: IO ()
70 getNetworkEntries -- :: Bool -> IO [NetworkEntry]
76 import PrelIOBase ( IOError (..), IOErrorType(..) )
80 import CString ( unpackCStringIO, unpackCStringBA, unvectorize )
86 %***************************************************************************
88 \subsection[BSD-DBTypes]{Service, Protocol \& Host Database Types}
90 %***************************************************************************
93 type HostName = String
94 type ProtocolName = String
95 type ServiceName = String
99 protoName :: ProtocolName, -- Official Name
100 protoAliases :: [ProtocolName], -- aliases
101 protoNumber :: ProtocolNumber -- Protocol Number
106 serviceName :: ServiceName, -- Official Name
107 serviceAliases :: [ServiceName], -- aliases
108 servicePort :: PortNumber, -- Port Number ( network byte order )
109 serviceProtocol :: ProtocolName -- Protocol
114 hostName :: HostName, -- Official Name
115 hostAliases :: [HostName], -- aliases
116 hostFamily :: Family, -- Host Type (currently AF_INET)
117 hostAddresses :: [HostAddress] -- Set of Network Addresses (in network byte order)
120 -- convenience function:
121 hostAddress :: HostEntry -> HostAddress
122 hostAddress (HostEntry nm _ _ ls) =
124 [] -> error ("BSD.hostAddress: empty network address list for " ++ nm)
129 %***************************************************************************
131 \subsection[BSD-DBAccess]{Service, Protocol Host Database Access}
133 %***************************************************************************
135 Calling @getServiceByName@ for a given service and protocol returns the
136 systems service entry. This should be used to find the port numbers
137 for standard protocols such as SMTP and FTP. The remaining three
138 functions should be used for browsing the service database
141 Calling @setServiceEntry@ with \tr{True} indicates that the service
142 database should be left open between calls to @getServiceEntry@. To
143 close the database a call to @endServiceEntry@ is required. This
144 database file is usually stored in the file /etc/services.
147 getServiceByName :: ServiceName -- Service Name
148 -> ProtocolName -- Protocol Name
149 -> IO ServiceEntry -- Service Entry
150 getServiceByName name proto = do
151 ptr <- _ccall_ getservbyname name proto
153 then fail (IOError Nothing NoSuchThing "getServiceByName" "no such service entry")
154 else unpackServiceEntry ptr
156 getServiceByPort :: PortNumber
159 getServiceByPort (PNum port) proto = do
160 ptr <- _ccall_ getservbyport port proto
162 then fail (IOError Nothing NoSuchThing "getServiceByPort" "no such service entry")
163 else unpackServiceEntry ptr
165 getServicePortNumber :: ServiceName -> IO PortNumber
166 getServicePortNumber name = do
167 (ServiceEntry _ _ port _) <- getServiceByName name "tcp"
170 #ifndef cygwin32_TARGET_OS
171 getServiceEntry :: IO ServiceEntry
173 ptr <- _ccall_ getservent
175 then fail (IOError Nothing NoSuchThing "getServiceEntry" "no such service entry")
176 else unpackServiceEntry ptr
178 setServiceEntry :: Bool -> IO ()
179 setServiceEntry flg = _ccall_ setservent stayOpen
180 where stayOpen = if flg then 1 else 0
182 endServiceEntry :: IO ()
183 endServiceEntry = _ccall_ endservent
185 getServiceEntries :: Bool -> IO [ServiceEntry]
186 getServiceEntries stayOpen = do
187 setServiceEntry stayOpen
188 getEntries (getServiceEntry) (endServiceEntry)
192 The following relate directly to the corresponding \tr{UNIX} {C} calls for
193 returning the protocol entries. The protocol entry is represented by
194 the Haskell type @ProtocolEntry@.
196 As for @setServiceEntry@ above, calling @setProtocolEntry@.
197 determines whether or not the protocol database file, usually
198 \tr{/etc/protocols}, is to be kept open between calls of
199 @getProtocolEntry@. Similarly,
202 getProtocolByName :: ProtocolName -> IO ProtocolEntry
203 getProtocolByNumber :: ProtocolNumber -> IO ProtocolEntry
204 getProtocolNumber :: ProtocolName -> IO ProtocolNumber
206 #ifndef cygwin32_TARGET_OS
207 setProtocolEntry :: Bool -> IO () -- Keep DB Open ?
208 getProtocolEntry :: IO ProtocolEntry -- Next Protocol Entry from DB
209 endProtocolEntry :: IO ()
210 getProtocolEntries :: Bool -> IO [ProtocolEntry]
215 --getProtocolByName :: ProtocolName -> IO ProtocolEntry
216 getProtocolByName name = do
217 ptr <- _ccall_ getprotobyname name
219 then fail (IOError Nothing NoSuchThing "getProtocolByName" "no such protocol entry")
220 else unpackProtocolEntry ptr
222 --getProtocolByNumber :: ProtocolNumber -> IO ProtocolEntry
223 getProtocolByNumber num = do
224 ptr <- _ccall_ getprotobynumber num
226 then fail (IOError Nothing NoSuchThing "getProtocolByNumber" "no such protocol entry")
227 else unpackProtocolEntry ptr
229 --getProtocolNumber :: ProtocolName -> IO ProtocolNumber
230 getProtocolNumber proto = do
231 (ProtocolEntry _ _ num) <- getProtocolByName proto
234 #ifndef cygwin32_TARGET_OS
235 --getProtocolEntry :: IO ProtocolEntry -- Next Protocol Entry from DB
236 getProtocolEntry = do
237 ptr <- _ccall_ getprotoent
239 then fail (IOError Nothing NoSuchThing "getProtocolEntry" "no such protocol entry")
240 else unpackProtocolEntry ptr
242 --setProtocolEntry :: Bool -> IO () -- Keep DB Open ?
243 setProtocolEntry flg = _ccall_ setprotoent v
244 where v = if flg then 1 else 0
246 --endProtocolEntry :: IO ()
247 endProtocolEntry = _ccall_ endprotoent
249 --getProtocolEntries :: Bool -> IO [ProtocolEntry]
250 getProtocolEntries stayOpen = do
251 setProtocolEntry stayOpen
252 getEntries (getProtocolEntry) (endProtocolEntry)
258 getHostByName :: HostName -> IO HostEntry
259 getHostByName name = do
260 ptr <- _ccall_ gethostbyname name
262 then fail (IOError Nothing NoSuchThing "getHostByName" "no such host entry")
263 else unpackHostEntry ptr
265 getHostByAddr :: Family -> HostAddress -> IO HostEntry
266 getHostByAddr family addr = do
267 ptr <- _casm_ ``struct in_addr addr;
269 %r = gethostbyaddr ((char*)&addr, sizeof(struct in_addr), %1);''
273 then fail (IOError Nothing NoSuchThing "getHostByAddr" "no such host entry")
274 else unpackHostEntry ptr
276 #ifndef cygwin32_TARGET_OS
277 getHostEntry :: IO HostEntry
279 ptr <- _ccall_ gethostent
281 then fail (IOError Nothing NoSuchThing "getHostEntry" "unable to retrieve host entry")
282 else unpackHostEntry ptr
284 setHostEntry :: Bool -> IO ()
285 setHostEntry flg = _ccall_ sethostent v
286 where v = if flg then 1 else 0
288 endHostEntry :: IO ()
289 endHostEntry = _ccall_ endhostent
291 getHostEntries :: Bool -> IO [HostEntry]
292 getHostEntries stayOpen = do
293 setHostEntry stayOpen
294 getEntries (getHostEntry) (endHostEntry)
298 %***************************************************************************
300 \subsection[BSD-Network]{Accessing network information}
302 %***************************************************************************
304 Same set of access functions as for accessing host,protocol and service
305 system info, this time for the types of networks supported.
308 -- network addresses are represented in host byte order.
309 type NetworkAddr = Word
311 type NetworkName = String
315 networkName :: NetworkName, -- official name
316 networkAliases :: [NetworkName], -- aliases
317 networkFamily :: Family, -- type
318 networkAddress :: NetworkAddr
320 #ifndef cygwin32_TARGET_OS
321 getNetworkByName :: NetworkName -> IO NetworkEntry
322 getNetworkByName name = do
323 ptr <- _ccall_ getnetbyname name
325 then fail (IOError Nothing NoSuchThing "getNetworkByName" "no such network entry")
326 else unpackNetworkEntry ptr
328 getNetworkByAddr :: NetworkAddr -> Family -> IO NetworkEntry
329 getNetworkByAddr addr family = do
330 ptr <- _ccall_ getnetbyaddr addr (packFamily family)
332 then fail (IOError Nothing NoSuchThing "getNetworkByAddr" "no such network entry")
333 else unpackNetworkEntry ptr
335 getNetworkEntry :: IO NetworkEntry
337 ptr <- _ccall_ getnetent
339 then fail (IOError Nothing NoSuchThing "getNetworkEntry" "no more network entries")
340 else unpackNetworkEntry ptr
342 setNetworkEntry :: Bool -> IO ()
343 setNetworkEntry flg = _ccall_ setnetent v
344 where v = if flg then 1 else 0
346 endNetworkEntry :: IO ()
347 endNetworkEntry = _ccall_ endnetent
349 getNetworkEntries :: Bool -> IO [NetworkEntry]
350 getNetworkEntries stayOpen = do
351 setNetworkEntry stayOpen
352 getEntries (getNetworkEntry) (endNetworkEntry)
357 %***************************************************************************
359 \subsection[BSD-Misc]{Miscellaneous Functions}
361 %***************************************************************************
363 Calling @getHostName@ returns the standard host name for the current
364 processor, as set at boot time.
367 getHostName :: IO HostName
369 ptr <- stToIO (newCharArray (0,256))
370 rc <- _casm_ ``%r=gethostname(%0, 256);'' ptr
371 ba <- stToIO (unsafeFreezeByteArray ptr)
373 then fail (userError "getHostName: unable to determine host name")
375 return (unpackCStringBA ba)
378 Helper function used by the exported functions that provides a
379 Haskellised view of the enumerator functions:
382 getEntries :: IO a -- read
385 getEntries getOne atEnd = loop
388 catch (do { v <- getOne; vs <- loop ; return (v:vs) })
389 (\ _ -> do { atEnd; return [] } )
395 char *s_name; /* official name of service */
396 char **s_aliases; /* alias list */
397 int s_port; /* port service resides at */
398 char *s_proto; /* protocol to use */
401 The members of this structure are:
402 s_name The official name of the service.
403 s_aliases A zero terminated list of alternate
404 names for the service.
405 s_port The port number at which the ser-
406 vice resides. Port numbers are
407 returned in network short byte
409 s_proto The name of the protocol to use
410 when contacting the service.
414 unpackServiceEntry :: Addr -> PrimIO ServiceEntry
415 unpackServiceEntry ptr = do
416 str <- _casm_ ``%r = ((struct servent*)%0)->s_name;'' ptr
417 name <- unpackCStringIO str
418 alias <- _casm_ ``%r = ((struct servent*)%0)->s_aliases;'' ptr
419 aliases <- unvectorize alias 0
420 port <- _casm_ ``%r = (int)(((struct servent*)%0)->s_port);'' ptr
421 str <- _casm_ ``%r = (char *)((struct servent*)%0)->s_proto;'' ptr
422 proto <- unpackCStringIO str
423 return (ServiceEntry name aliases (PNum port) proto)
425 -------------------------------------------------------------------------------
427 unpackProtocolEntry :: Addr -> IO ProtocolEntry
428 unpackProtocolEntry ptr = do
429 str <- _casm_ ``%r = ((struct protoent*)%0)->p_name;'' ptr
430 name <- unpackCStringIO str
431 alias <- _casm_ ``%r = ((struct protoent*)%0)->p_aliases;'' ptr
432 aliases <- unvectorize alias 0
433 proto <- _casm_ ``%r = ((struct protoent*)%0)->p_proto;'' ptr
434 return (ProtocolEntry name aliases proto)
436 -------------------------------------------------------------------------------
438 unpackHostEntry :: Addr -> IO HostEntry
439 unpackHostEntry ptr = do
440 str <- _casm_ ``%r = ((struct hostent*)%0)->h_name;'' ptr
441 name <- unpackCStringIO str
442 alias <- _casm_ ``%r = ((struct hostent*)%0)->h_aliases;'' ptr
443 aliases <- unvectorize alias 0
444 addrList <- unvectorizeHostAddrs ptr 0
445 return (HostEntry name aliases AF_INET addrList)
447 -------------------------------------------------------------------------------
449 unpackNetworkEntry :: Addr -> IO NetworkEntry
450 unpackNetworkEntry ptr = do
451 str <- _casm_ ``%r = ((struct netent*)%0)->n_name;'' ptr
452 name <- unpackCStringIO str
453 alias <- _casm_ ``%r = ((struct netent*)%0)->n_aliases;'' ptr
454 aliases <- unvectorize alias 0
455 fam <- _casm_ ``%r = ((struct netent*)%0)->n_addrtype;'' ptr
456 na <- _casm_ ``%r = ((struct netent*)%0)->n_net;'' ptr
457 return (NetworkEntry name aliases (unpackFamily fam) na)
459 -------------------------------------------------------------------------------
461 unvectorizeHostAddrs :: Addr -> Int -> IO [HostAddress]
462 unvectorizeHostAddrs ptr n = do
463 x <- _casm_ ``{ unsigned long tmp;
464 if ((((struct hostent*)%0)->h_addr_list[(int)%1]) == NULL)
467 tmp = (W_)((struct in_addr *)(((struct hostent*)%0)->h_addr_list[(int)%1]))->s_addr;
470 if x == (W# (int2Word# 0#))
473 xs <- unvectorizeHostAddrs ptr (n+1)