Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 590 lines (476 sloc) 20.279 kb
1f4b76e @tibbe Update for GHC 7.0
tibbe authored
1 {-# LANGUAGE CPP, ForeignFunctionInterface #-}
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
2 -----------------------------------------------------------------------------
5a38dbc [project @ 2002-06-20 15:59:01 by simonmar]
simonmar authored
3 -- |
8012aaa [project @ 2002-07-30 17:26:29 by sof]
sof authored
4 -- Module : Network.BSD
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
5 -- Copyright : (c) The University of Glasgow 2001
b95d7ab [project @ 2004-03-27 14:20:13 by panne]
panne authored
6 -- License : BSD-style (see the file libraries/network/LICENSE)
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
7 --
8 -- Maintainer : libraries@haskell.org
9 -- Stability : experimental
f27bd04 [project @ 2002-06-21 13:53:19 by simonmar]
simonmar authored
10 -- Portability : non-portable
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
11 --
146fbb5 @igfoo Update Network.BSD header to not mention symlinks.
igfoo authored
12 -- The "Network.BSD" module defines Haskell bindings to network
13 -- programming functionality provided by BSD Unix derivatives.
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
14 --
15 -----------------------------------------------------------------------------
16
a152aaa [project @ 2003-07-25 13:46:03 by ross]
ross authored
17 #include "HsNet.h"
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
18
3b91231 [project @ 2005-02-07 11:09:27 by simonmar]
simonmar authored
19 -- NOTE: ##, we want this interpreted when compiling the .hs, not by hsc2hs.
f1bb2a9 [project @ 2005-09-20 09:47:48 by ross]
ross authored
20 ##include "Typeable.h"
3b91231 [project @ 2005-02-07 11:09:27 by simonmar]
simonmar authored
21
cbdd620 @tibbe Whitespace changes only: harmonize export lists
tibbe authored
22 module Network.BSD
23 (
f27bd04 [project @ 2002-06-21 13:53:19 by simonmar]
simonmar authored
24 -- * Host names
cbdd620 @tibbe Whitespace changes only: harmonize export lists
tibbe authored
25 HostName
26 , getHostName
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
27
cbdd620 @tibbe Whitespace changes only: harmonize export lists
tibbe authored
28 , HostEntry(..)
29 , getHostByName
30 , getHostByAddr
31 , hostAddress
f27bd04 [project @ 2002-06-21 13:53:19 by simonmar]
simonmar authored
32
dfd451a [project @ 2005-01-28 13:36:34 by simonmar]
simonmar authored
33 #if defined(HAVE_GETHOSTENT) && !defined(cygwin32_HOST_OS) && !defined(mingw32_HOST_OS) && !defined(_WIN32)
cbdd620 @tibbe Whitespace changes only: harmonize export lists
tibbe authored
34 , getHostEntries
35
a0ebccc workaround for non-thread-safety of some functions in Network.BSD
Simon Marlow authored
36 -- ** Low level functionality
cbdd620 @tibbe Whitespace changes only: harmonize export lists
tibbe authored
37 , setHostEntry
38 , getHostEntry
39 , endHostEntry
f27bd04 [project @ 2002-06-21 13:53:19 by simonmar]
simonmar authored
40 #endif
41
42 -- * Service names
cbdd620 @tibbe Whitespace changes only: harmonize export lists
tibbe authored
43 , ServiceEntry(..)
44 , ServiceName
45 , getServiceByName
46 , getServiceByPort
47 , getServicePortNumber
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
48
dfd451a [project @ 2005-01-28 13:36:34 by simonmar]
simonmar authored
49 #if !defined(cygwin32_HOST_OS) && !defined(mingw32_HOST_OS) && !defined(_WIN32)
cbdd620 @tibbe Whitespace changes only: harmonize export lists
tibbe authored
50 , getServiceEntries
51
a0ebccc workaround for non-thread-safety of some functions in Network.BSD
Simon Marlow authored
52 -- ** Low level functionality
cbdd620 @tibbe Whitespace changes only: harmonize export lists
tibbe authored
53 , getServiceEntry
54 , setServiceEntry
55 , endServiceEntry
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
56 #endif
57
f27bd04 [project @ 2002-06-21 13:53:19 by simonmar]
simonmar authored
58 -- * Protocol names
cbdd620 @tibbe Whitespace changes only: harmonize export lists
tibbe authored
59 , ProtocolName
60 , ProtocolNumber
61 , ProtocolEntry(..)
62 , getProtocolByName
63 , getProtocolByNumber
64 , getProtocolNumber
65 , defaultProtocol
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
66
dfd451a [project @ 2005-01-28 13:36:34 by simonmar]
simonmar authored
67 #if !defined(cygwin32_HOST_OS) && !defined(mingw32_HOST_OS) && !defined(_WIN32)
cbdd620 @tibbe Whitespace changes only: harmonize export lists
tibbe authored
68 , getProtocolEntries
a0ebccc workaround for non-thread-safety of some functions in Network.BSD
Simon Marlow authored
69 -- ** Low level functionality
cbdd620 @tibbe Whitespace changes only: harmonize export lists
tibbe authored
70 , setProtocolEntry
71 , getProtocolEntry
72 , endProtocolEntry
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
73 #endif
74
f27bd04 [project @ 2002-06-21 13:53:19 by simonmar]
simonmar authored
75 -- * Port numbers
cbdd620 @tibbe Whitespace changes only: harmonize export lists
tibbe authored
76 , PortNumber
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
77
f27bd04 [project @ 2002-06-21 13:53:19 by simonmar]
simonmar authored
78 -- * Network names
cbdd620 @tibbe Whitespace changes only: harmonize export lists
tibbe authored
79 , NetworkName
80 , NetworkAddr
81 , NetworkEntry(..)
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
82
dfd451a [project @ 2005-01-28 13:36:34 by simonmar]
simonmar authored
83 #if !defined(cygwin32_HOST_OS) && !defined(mingw32_HOST_OS) && !defined(_WIN32)
e054e90 @tibbe Get rid of type signatures in export lists
tibbe authored
84 , getNetworkByName
85 , getNetworkByAddr
86 , getNetworkEntries
a0ebccc workaround for non-thread-safety of some functions in Network.BSD
Simon Marlow authored
87 -- ** Low level functionality
e054e90 @tibbe Get rid of type signatures in export lists
tibbe authored
88 , setNetworkEntry
89 , getNetworkEntry
90 , endNetworkEntry
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
91 #endif
92 ) where
93
ae13bd3 [project @ 2003-02-11 04:38:03 by sof]
sof authored
94 #ifdef __HUGS__
ca025e0 @tibbe Whitespace changes only: make import lists more consistent
tibbe authored
95 import Hugs.Prelude (IOException(..), IOErrorType(..))
ae13bd3 [project @ 2003-02-11 04:38:03 by sof]
sof authored
96 #endif
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
97 import Network.Socket
98
ca025e0 @tibbe Whitespace changes only: make import lists more consistent
tibbe authored
99 import Control.Concurrent (MVar, newMVar, withMVar)
6869949 @tibbe Get rid of deprecated 'catch'
tibbe authored
100 import Control.Exception (catch)
0f2ea9a @kfish Remove unused imports
kfish authored
101 import Foreign.C.String (CString, peekCString, withCString)
102 #if defined(HAVE_WINSOCK2_H) && !defined(cygwin32_HOST_OS)
103 import Foreign.C.Types ( CShort )
104 #endif
2b9c1dd @mvv Fix build with GHC 7.3+
mvv authored
105 #if __GLASGOW_HASKELL__ >= 703
106 import Foreign.C.Types ( CInt(..), CULong(..), CSize(..) )
107 #else
108 import Foreign.C.Types ( CInt, CULong, CSize )
109 #endif
ca025e0 @tibbe Whitespace changes only: make import lists more consistent
tibbe authored
110 import Foreign.Ptr (Ptr, nullPtr)
111 import Foreign.Storable (Storable(..))
112 import Foreign.Marshal.Array (allocaArray0, peekArray0)
113 import Foreign.Marshal.Utils (with, fromBool)
3b91231 [project @ 2005-02-07 11:09:27 by simonmar]
simonmar authored
114 import Data.Typeable
e25f69d @markwright Compatibility with ghc head
markwright authored
115 #if !MIN_VERSION_base(4,6,0)
6869949 @tibbe Get rid of deprecated 'catch'
tibbe authored
116 import Prelude hiding (catch)
e25f69d @markwright Compatibility with ghc head
markwright authored
117 #endif
6869949 @tibbe Get rid of deprecated 'catch'
tibbe authored
118 import System.IO.Error (ioeSetErrorString, mkIOError)
ca025e0 @tibbe Whitespace changes only: make import lists more consistent
tibbe authored
119 import System.IO.Unsafe (unsafePerformIO)
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
120
121 #ifdef __GLASGOW_HASKELL__
cd9c309 @int-e Follow GHC IO library rewrite
int-e authored
122 # if __GLASGOW_HASKELL__ >= 611
123 import GHC.IO.Exception
124 # else
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
125 import GHC.IOBase
cd9c309 @int-e Follow GHC IO library rewrite
int-e authored
126 # endif
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
127 #endif
128
ca025e0 @tibbe Whitespace changes only: make import lists more consistent
tibbe authored
129 import Control.Monad (liftM)
3f3114b [project @ 2003-03-04 15:35:01 by stolz]
stolz authored
130
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
131 -- ---------------------------------------------------------------------------
132 -- Basic Types
133
134 type ProtocolName = String
135
136 -- ---------------------------------------------------------------------------
137 -- Service Database Access
138
139 -- Calling getServiceByName for a given service and protocol returns
140 -- the systems service entry. This should be used to find the port
141 -- numbers for standard protocols such as SMTP and FTP. The remaining
142 -- three functions should be used for browsing the service database
143 -- sequentially.
144
145 -- Calling setServiceEntry with True indicates that the service
146 -- database should be left open between calls to getServiceEntry. To
147 -- close the database a call to endServiceEntry is required. This
148 -- database file is usually stored in the file /etc/services.
149
150 data ServiceEntry =
151 ServiceEntry {
ea57628 @tibbe Tabs -> spaces
tibbe authored
152 serviceName :: ServiceName, -- Official Name
153 serviceAliases :: [ServiceName], -- aliases
154 servicePort :: PortNumber, -- Port Number ( network byte order )
155 serviceProtocol :: ProtocolName -- Protocol
a4ca449 @tibbe Derive Typeable instead of using a CPP macro
tibbe authored
156 } deriving (Show, Typeable)
3b91231 [project @ 2005-02-07 11:09:27 by simonmar]
simonmar authored
157
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
158 instance Storable ServiceEntry where
159 sizeOf _ = #const sizeof(struct servent)
160 alignment _ = alignment (undefined :: CInt) -- ???
161
162 peek p = do
a0ebccc workaround for non-thread-safety of some functions in Network.BSD
Simon Marlow authored
163 s_name <- (#peek struct servent, s_name) p >>= peekCString
164 s_aliases <- (#peek struct servent, s_aliases) p
165 >>= peekArray0 nullPtr
166 >>= mapM peekCString
167 s_port <- (#peek struct servent, s_port) p
168 s_proto <- (#peek struct servent, s_proto) p >>= peekCString
169 return (ServiceEntry {
170 serviceName = s_name,
171 serviceAliases = s_aliases,
ebdaf5d @hreinhardt replace HAVE_WINSOCK_H with HAVE_WINSOCK2_H
hreinhardt authored
172 #if defined(HAVE_WINSOCK2_H) && !defined(cygwin32_HOST_OS)
a0ebccc workaround for non-thread-safety of some functions in Network.BSD
Simon Marlow authored
173 servicePort = PortNum (fromIntegral (s_port :: CShort)),
8cc68f0 [project @ 2003-03-07 22:38:20 by sof]
sof authored
174 #else
a0ebccc workaround for non-thread-safety of some functions in Network.BSD
Simon Marlow authored
175 -- s_port is already in network byte order, but it
176 -- might be the wrong size.
177 servicePort = PortNum (fromIntegral (s_port :: CInt)),
8cc68f0 [project @ 2003-03-07 22:38:20 by sof]
sof authored
178 #endif
a0ebccc workaround for non-thread-safety of some functions in Network.BSD
Simon Marlow authored
179 serviceProtocol = s_proto
180 })
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
181
fa353d8 @kfish Fix warnings for unused variables
kfish authored
182 poke _p = error "Storable.poke(BSD.ServiceEntry) not implemented"
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
183
184
a0ebccc workaround for non-thread-safety of some functions in Network.BSD
Simon Marlow authored
185 -- | Get service by name.
cf32057 @tibbe Whitespace changes only: use spaces consistently in Network.BSD
tibbe authored
186 getServiceByName :: ServiceName -- Service Name
187 -> ProtocolName -- Protocol Name
188 -> IO ServiceEntry -- Service Entry
a0ebccc workaround for non-thread-safety of some functions in Network.BSD
Simon Marlow authored
189 getServiceByName name proto = withLock $ do
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
190 withCString name $ \ cstr_name -> do
191 withCString proto $ \ cstr_proto -> do
3f3114b [project @ 2003-03-04 15:35:01 by stolz]
stolz authored
192 throwNoSuchThingIfNull "getServiceByName" "no such service entry"
ab2a7f0 [project @ 2003-03-07 21:22:28 by sof]
sof authored
193 $ (trySysCall (c_getservbyname cstr_name cstr_proto))
3f3114b [project @ 2003-03-04 15:35:01 by stolz]
stolz authored
194 >>= peek
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
195
21ab09a FIX net001 (Windows): get some calling conventions right
Simon Marlow authored
196 foreign import CALLCONV unsafe "getservbyname"
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
197 c_getservbyname :: CString -> CString -> IO (Ptr ServiceEntry)
198
a0ebccc workaround for non-thread-safety of some functions in Network.BSD
Simon Marlow authored
199 -- | Get the service given a 'PortNumber' and 'ProtocolName'.
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
200 getServiceByPort :: PortNumber -> ProtocolName -> IO ServiceEntry
a0ebccc workaround for non-thread-safety of some functions in Network.BSD
Simon Marlow authored
201 getServiceByPort (PortNum port) proto = withLock $ do
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
202 withCString proto $ \ cstr_proto -> do
3f3114b [project @ 2003-03-04 15:35:01 by stolz]
stolz authored
203 throwNoSuchThingIfNull "getServiceByPort" "no such service entry"
ab2a7f0 [project @ 2003-03-07 21:22:28 by sof]
sof authored
204 $ (trySysCall (c_getservbyport (fromIntegral port) cstr_proto))
3f3114b [project @ 2003-03-04 15:35:01 by stolz]
stolz authored
205 >>= peek
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
206
21ab09a FIX net001 (Windows): get some calling conventions right
Simon Marlow authored
207 foreign import CALLCONV unsafe "getservbyport"
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
208 c_getservbyport :: CInt -> CString -> IO (Ptr ServiceEntry)
209
a0ebccc workaround for non-thread-safety of some functions in Network.BSD
Simon Marlow authored
210 -- | Get the 'PortNumber' corresponding to the 'ServiceName'.
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
211 getServicePortNumber :: ServiceName -> IO PortNumber
212 getServicePortNumber name = do
213 (ServiceEntry _ _ port _) <- getServiceByName name "tcp"
214 return port
215
dfd451a [project @ 2005-01-28 13:36:34 by simonmar]
simonmar authored
216 #if !defined(cygwin32_HOST_OS) && !defined(mingw32_HOST_OS) && !defined(_WIN32)
cf32057 @tibbe Whitespace changes only: use spaces consistently in Network.BSD
tibbe authored
217 getServiceEntry :: IO ServiceEntry
a0ebccc workaround for non-thread-safety of some functions in Network.BSD
Simon Marlow authored
218 getServiceEntry = withLock $ do
3f3114b [project @ 2003-03-04 15:35:01 by stolz]
stolz authored
219 throwNoSuchThingIfNull "getServiceEntry" "no such service entry"
220 $ trySysCall c_getservent
221 >>= peek
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
222
5a38dbc [project @ 2002-06-20 15:59:01 by simonmar]
simonmar authored
223 foreign import ccall unsafe "getservent" c_getservent :: IO (Ptr ServiceEntry)
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
224
cf32057 @tibbe Whitespace changes only: use spaces consistently in Network.BSD
tibbe authored
225 setServiceEntry :: Bool -> IO ()
a0ebccc workaround for non-thread-safety of some functions in Network.BSD
Simon Marlow authored
226 setServiceEntry flg = withLock $ trySysCall $ c_setservent (fromBool flg)
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
227
5a38dbc [project @ 2002-06-20 15:59:01 by simonmar]
simonmar authored
228 foreign import ccall unsafe "setservent" c_setservent :: CInt -> IO ()
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
229
cf32057 @tibbe Whitespace changes only: use spaces consistently in Network.BSD
tibbe authored
230 endServiceEntry :: IO ()
a0ebccc workaround for non-thread-safety of some functions in Network.BSD
Simon Marlow authored
231 endServiceEntry = withLock $ trySysCall $ c_endservent
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
232
5a38dbc [project @ 2002-06-20 15:59:01 by simonmar]
simonmar authored
233 foreign import ccall unsafe "endservent" c_endservent :: IO ()
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
234
235 getServiceEntries :: Bool -> IO [ServiceEntry]
236 getServiceEntries stayOpen = do
237 setServiceEntry stayOpen
238 getEntries (getServiceEntry) (endServiceEntry)
239 #endif
240
241 -- ---------------------------------------------------------------------------
242 -- Protocol Entries
243
244 -- The following relate directly to the corresponding UNIX C
245 -- calls for returning the protocol entries. The protocol entry is
246 -- represented by the Haskell type ProtocolEntry.
247
248 -- As for setServiceEntry above, calling setProtocolEntry.
249 -- determines whether or not the protocol database file, usually
5a38dbc [project @ 2002-06-20 15:59:01 by simonmar]
simonmar authored
250 -- @/etc/protocols@, is to be kept open between calls of
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
251 -- getProtocolEntry. Similarly,
252
253 data ProtocolEntry =
254 ProtocolEntry {
ea57628 @tibbe Tabs -> spaces
tibbe authored
255 protoName :: ProtocolName, -- Official Name
256 protoAliases :: [ProtocolName], -- aliases
257 protoNumber :: ProtocolNumber -- Protocol Number
a4ca449 @tibbe Derive Typeable instead of using a CPP macro
tibbe authored
258 } deriving (Read, Show, Typeable)
3b91231 [project @ 2005-02-07 11:09:27 by simonmar]
simonmar authored
259
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
260 instance Storable ProtocolEntry where
261 sizeOf _ = #const sizeof(struct protoent)
262 alignment _ = alignment (undefined :: CInt) -- ???
263
264 peek p = do
a0ebccc workaround for non-thread-safety of some functions in Network.BSD
Simon Marlow authored
265 p_name <- (#peek struct protoent, p_name) p >>= peekCString
266 p_aliases <- (#peek struct protoent, p_aliases) p
267 >>= peekArray0 nullPtr
268 >>= mapM peekCString
ebdaf5d @hreinhardt replace HAVE_WINSOCK_H with HAVE_WINSOCK2_H
hreinhardt authored
269 #if defined(HAVE_WINSOCK2_H) && !defined(cygwin32_HOST_OS)
ab2a7f0 [project @ 2003-03-07 21:22:28 by sof]
sof authored
270 -- With WinSock, the protocol number is only a short;
a0ebccc workaround for non-thread-safety of some functions in Network.BSD
Simon Marlow authored
271 -- hoist it in as such, but represent it on the Haskell side
272 -- as a CInt.
273 p_proto_short <- (#peek struct protoent, p_proto) p
274 let p_proto = fromIntegral (p_proto_short :: CShort)
ab2a7f0 [project @ 2003-03-07 21:22:28 by sof]
sof authored
275 #else
a0ebccc workaround for non-thread-safety of some functions in Network.BSD
Simon Marlow authored
276 p_proto <- (#peek struct protoent, p_proto) p
ab2a7f0 [project @ 2003-03-07 21:22:28 by sof]
sof authored
277 #endif
a0ebccc workaround for non-thread-safety of some functions in Network.BSD
Simon Marlow authored
278 return (ProtocolEntry {
279 protoName = p_name,
280 protoAliases = p_aliases,
281 protoNumber = p_proto
282 })
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
283
fa353d8 @kfish Fix warnings for unused variables
kfish authored
284 poke _p = error "Storable.poke(BSD.ProtocolEntry) not implemented"
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
285
286 getProtocolByName :: ProtocolName -> IO ProtocolEntry
a0ebccc workaround for non-thread-safety of some functions in Network.BSD
Simon Marlow authored
287 getProtocolByName name = withLock $ do
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
288 withCString name $ \ name_cstr -> do
7908563 [project @ 2005-10-14 14:16:48 by sof]
sof authored
289 throwNoSuchThingIfNull "getProtocolByName" ("no such protocol name: " ++ name)
3f3114b [project @ 2003-03-04 15:35:01 by stolz]
stolz authored
290 $ (trySysCall.c_getprotobyname) name_cstr
291 >>= peek
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
292
21ab09a FIX net001 (Windows): get some calling conventions right
Simon Marlow authored
293 foreign import CALLCONV unsafe "getprotobyname"
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
294 c_getprotobyname :: CString -> IO (Ptr ProtocolEntry)
295
296
297 getProtocolByNumber :: ProtocolNumber -> IO ProtocolEntry
a0ebccc workaround for non-thread-safety of some functions in Network.BSD
Simon Marlow authored
298 getProtocolByNumber num = withLock $ do
7908563 [project @ 2005-10-14 14:16:48 by sof]
sof authored
299 throwNoSuchThingIfNull "getProtocolByNumber" ("no such protocol number: " ++ show num)
3f3114b [project @ 2003-03-04 15:35:01 by stolz]
stolz authored
300 $ (trySysCall.c_getprotobynumber) (fromIntegral num)
301 >>= peek
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
302
21ab09a FIX net001 (Windows): get some calling conventions right
Simon Marlow authored
303 foreign import CALLCONV unsafe "getprotobynumber"
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
304 c_getprotobynumber :: CInt -> IO (Ptr ProtocolEntry)
305
306
307 getProtocolNumber :: ProtocolName -> IO ProtocolNumber
308 getProtocolNumber proto = do
309 (ProtocolEntry _ _ num) <- getProtocolByName proto
310 return num
311
dfd451a [project @ 2005-01-28 13:36:34 by simonmar]
simonmar authored
312 #if !defined(cygwin32_HOST_OS) && !defined(mingw32_HOST_OS) && !defined(_WIN32)
cf32057 @tibbe Whitespace changes only: use spaces consistently in Network.BSD
tibbe authored
313 getProtocolEntry :: IO ProtocolEntry -- Next Protocol Entry from DB
a0ebccc workaround for non-thread-safety of some functions in Network.BSD
Simon Marlow authored
314 getProtocolEntry = withLock $ do
7b08679 [project @ 2003-03-05 09:52:23 by simonmar]
simonmar authored
315 ent <- throwNoSuchThingIfNull "getProtocolEntry" "no such protocol entry"
cf32057 @tibbe Whitespace changes only: use spaces consistently in Network.BSD
tibbe authored
316 $ trySysCall c_getprotoent
7b08679 [project @ 2003-03-05 09:52:23 by simonmar]
simonmar authored
317 peek ent
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
318
5a38dbc [project @ 2002-06-20 15:59:01 by simonmar]
simonmar authored
319 foreign import ccall unsafe "getprotoent" c_getprotoent :: IO (Ptr ProtocolEntry)
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
320
cf32057 @tibbe Whitespace changes only: use spaces consistently in Network.BSD
tibbe authored
321 setProtocolEntry :: Bool -> IO () -- Keep DB Open ?
a0ebccc workaround for non-thread-safety of some functions in Network.BSD
Simon Marlow authored
322 setProtocolEntry flg = withLock $ trySysCall $ c_setprotoent (fromBool flg)
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
323
5a38dbc [project @ 2002-06-20 15:59:01 by simonmar]
simonmar authored
324 foreign import ccall unsafe "setprotoent" c_setprotoent :: CInt -> IO ()
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
325
326 endProtocolEntry :: IO ()
a0ebccc workaround for non-thread-safety of some functions in Network.BSD
Simon Marlow authored
327 endProtocolEntry = withLock $ trySysCall $ c_endprotoent
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
328
5a38dbc [project @ 2002-06-20 15:59:01 by simonmar]
simonmar authored
329 foreign import ccall unsafe "endprotoent" c_endprotoent :: IO ()
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
330
331 getProtocolEntries :: Bool -> IO [ProtocolEntry]
a0ebccc workaround for non-thread-safety of some functions in Network.BSD
Simon Marlow authored
332 getProtocolEntries stayOpen = withLock $ do
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
333 setProtocolEntry stayOpen
334 getEntries (getProtocolEntry) (endProtocolEntry)
335 #endif
336
337 -- ---------------------------------------------------------------------------
338 -- Host lookups
339
340 data HostEntry =
341 HostEntry {
ea57628 @tibbe Tabs -> spaces
tibbe authored
342 hostName :: HostName, -- Official Name
343 hostAliases :: [HostName], -- aliases
344 hostFamily :: Family, -- Host Type (currently AF_INET)
345 hostAddresses :: [HostAddress] -- Set of Network Addresses (in network byte order)
a4ca449 @tibbe Derive Typeable instead of using a CPP macro
tibbe authored
346 } deriving (Read, Show, Typeable)
3b91231 [project @ 2005-02-07 11:09:27 by simonmar]
simonmar authored
347
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
348 instance Storable HostEntry where
349 sizeOf _ = #const sizeof(struct hostent)
350 alignment _ = alignment (undefined :: CInt) -- ???
351
352 peek p = do
a0ebccc workaround for non-thread-safety of some functions in Network.BSD
Simon Marlow authored
353 h_name <- (#peek struct hostent, h_name) p >>= peekCString
354 h_aliases <- (#peek struct hostent, h_aliases) p
355 >>= peekArray0 nullPtr
356 >>= mapM peekCString
357 h_addrtype <- (#peek struct hostent, h_addrtype) p
358 -- h_length <- (#peek struct hostent, h_length) p
359 h_addr_list <- (#peek struct hostent, h_addr_list) p
360 >>= peekArray0 nullPtr
361 >>= mapM peek
362 return (HostEntry {
363 hostName = h_name,
364 hostAliases = h_aliases,
ebdaf5d @hreinhardt replace HAVE_WINSOCK_H with HAVE_WINSOCK2_H
hreinhardt authored
365 #if defined(HAVE_WINSOCK2_H) && !defined(cygwin32_HOST_OS)
d9e10eb @bos Network.Socket.unpackFamily: account for size of h_addrtype on Windows
bos authored
366 hostFamily = unpackFamily (fromIntegral (h_addrtype :: CShort)),
367 #else
a0ebccc workaround for non-thread-safety of some functions in Network.BSD
Simon Marlow authored
368 hostFamily = unpackFamily h_addrtype,
d9e10eb @bos Network.Socket.unpackFamily: account for size of h_addrtype on Windows
bos authored
369 #endif
a0ebccc workaround for non-thread-safety of some functions in Network.BSD
Simon Marlow authored
370 hostAddresses = h_addr_list
371 })
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
372
fa353d8 @kfish Fix warnings for unused variables
kfish authored
373 poke _p = error "Storable.poke(BSD.ServiceEntry) not implemented"
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
374
375
376 -- convenience function:
377 hostAddress :: HostEntry -> HostAddress
378 hostAddress (HostEntry nm _ _ ls) =
379 case ls of
380 [] -> error ("BSD.hostAddress: empty network address list for " ++ nm)
381 (x:_) -> x
382
a0ebccc workaround for non-thread-safety of some functions in Network.BSD
Simon Marlow authored
383 -- getHostByName must use the same lock as the *hostent functions
384 -- may cause problems if called concurrently.
385
386 -- | Resolve a 'HostName' to IPv4 address.
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
387 getHostByName :: HostName -> IO HostEntry
a0ebccc workaround for non-thread-safety of some functions in Network.BSD
Simon Marlow authored
388 getHostByName name = withLock $ do
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
389 withCString name $ \ name_cstr -> do
7b08679 [project @ 2003-03-05 09:52:23 by simonmar]
simonmar authored
390 ent <- throwNoSuchThingIfNull "getHostByName" "no such host entry"
cf32057 @tibbe Whitespace changes only: use spaces consistently in Network.BSD
tibbe authored
391 $ trySysCall $ c_gethostbyname name_cstr
7b08679 [project @ 2003-03-05 09:52:23 by simonmar]
simonmar authored
392 peek ent
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
393
21ab09a FIX net001 (Windows): get some calling conventions right
Simon Marlow authored
394 foreign import CALLCONV safe "gethostbyname"
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
395 c_gethostbyname :: CString -> IO (Ptr HostEntry)
396
a0ebccc workaround for non-thread-safety of some functions in Network.BSD
Simon Marlow authored
397
398 -- The locking of gethostbyaddr is similar to gethostbyname.
399 -- | Get a 'HostEntry' corresponding to the given address and family.
400 -- Note that only IPv4 is currently supported.
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
401 getHostByAddr :: Family -> HostAddress -> IO HostEntry
402 getHostByAddr family addr = do
a0ebccc workaround for non-thread-safety of some functions in Network.BSD
Simon Marlow authored
403 with addr $ \ ptr_addr -> withLock $ do
cf32057 @tibbe Whitespace changes only: use spaces consistently in Network.BSD
tibbe authored
404 throwNoSuchThingIfNull "getHostByAddr" "no such host entry"
3f3114b [project @ 2003-03-04 15:35:01 by stolz]
stolz authored
405 $ trySysCall $ c_gethostbyaddr ptr_addr (fromIntegral (sizeOf addr)) (packFamily family)
406 >>= peek
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
407
21ab09a FIX net001 (Windows): get some calling conventions right
Simon Marlow authored
408 foreign import CALLCONV safe "gethostbyaddr"
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
409 c_gethostbyaddr :: Ptr HostAddress -> CInt -> CInt -> IO (Ptr HostEntry)
410
dfd451a [project @ 2005-01-28 13:36:34 by simonmar]
simonmar authored
411 #if defined(HAVE_GETHOSTENT) && !defined(cygwin32_HOST_OS) && !defined(mingw32_HOST_OS) && !defined(_WIN32)
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
412 getHostEntry :: IO HostEntry
a0ebccc workaround for non-thread-safety of some functions in Network.BSD
Simon Marlow authored
413 getHostEntry = withLock $ do
cf32057 @tibbe Whitespace changes only: use spaces consistently in Network.BSD
tibbe authored
414 throwNoSuchThingIfNull "getHostEntry" "unable to retrieve host entry"
3f3114b [project @ 2003-03-04 15:35:01 by stolz]
stolz authored
415 $ trySysCall $ c_gethostent
416 >>= peek
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
417
5a38dbc [project @ 2002-06-20 15:59:01 by simonmar]
simonmar authored
418 foreign import ccall unsafe "gethostent" c_gethostent :: IO (Ptr HostEntry)
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
419
420 setHostEntry :: Bool -> IO ()
a0ebccc workaround for non-thread-safety of some functions in Network.BSD
Simon Marlow authored
421 setHostEntry flg = withLock $ trySysCall $ c_sethostent (fromBool flg)
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
422
5a38dbc [project @ 2002-06-20 15:59:01 by simonmar]
simonmar authored
423 foreign import ccall unsafe "sethostent" c_sethostent :: CInt -> IO ()
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
424
425 endHostEntry :: IO ()
a0ebccc workaround for non-thread-safety of some functions in Network.BSD
Simon Marlow authored
426 endHostEntry = withLock $ c_endhostent
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
427
5a38dbc [project @ 2002-06-20 15:59:01 by simonmar]
simonmar authored
428 foreign import ccall unsafe "endhostent" c_endhostent :: IO ()
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
429
430 getHostEntries :: Bool -> IO [HostEntry]
431 getHostEntries stayOpen = do
432 setHostEntry stayOpen
433 getEntries (getHostEntry) (endHostEntry)
434 #endif
435
436 -- ---------------------------------------------------------------------------
437 -- Accessing network information
438
439 -- Same set of access functions as for accessing host,protocol and
440 -- service system info, this time for the types of networks supported.
441
442 -- network addresses are represented in host byte order.
443 type NetworkAddr = CULong
444
445 type NetworkName = String
446
447 data NetworkEntry =
448 NetworkEntry {
ea57628 @tibbe Tabs -> spaces
tibbe authored
449 networkName :: NetworkName, -- official name
450 networkAliases :: [NetworkName], -- aliases
451 networkFamily :: Family, -- type
452 networkAddress :: NetworkAddr
a4ca449 @tibbe Derive Typeable instead of using a CPP macro
tibbe authored
453 } deriving (Read, Show, Typeable)
3b91231 [project @ 2005-02-07 11:09:27 by simonmar]
simonmar authored
454
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
455 instance Storable NetworkEntry where
456 sizeOf _ = #const sizeof(struct hostent)
457 alignment _ = alignment (undefined :: CInt) -- ???
458
459 peek p = do
a0ebccc workaround for non-thread-safety of some functions in Network.BSD
Simon Marlow authored
460 n_name <- (#peek struct netent, n_name) p >>= peekCString
461 n_aliases <- (#peek struct netent, n_aliases) p
462 >>= peekArray0 nullPtr
463 >>= mapM peekCString
464 n_addrtype <- (#peek struct netent, n_addrtype) p
465 n_net <- (#peek struct netent, n_net) p
466 return (NetworkEntry {
467 networkName = n_name,
468 networkAliases = n_aliases,
469 networkFamily = unpackFamily (fromIntegral
470 (n_addrtype :: CInt)),
471 networkAddress = n_net
472 })
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
473
fa353d8 @kfish Fix warnings for unused variables
kfish authored
474 poke _p = error "Storable.poke(BSD.NetEntry) not implemented"
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
475
476
dfd451a [project @ 2005-01-28 13:36:34 by simonmar]
simonmar authored
477 #if !defined(cygwin32_HOST_OS) && !defined(mingw32_HOST_OS) && !defined(_WIN32)
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
478 getNetworkByName :: NetworkName -> IO NetworkEntry
a0ebccc workaround for non-thread-safety of some functions in Network.BSD
Simon Marlow authored
479 getNetworkByName name = withLock $ do
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
480 withCString name $ \ name_cstr -> do
3f3114b [project @ 2003-03-04 15:35:01 by stolz]
stolz authored
481 throwNoSuchThingIfNull "getNetworkByName" "no such network entry"
482 $ trySysCall $ c_getnetbyname name_cstr
483 >>= peek
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
484
5a38dbc [project @ 2002-06-20 15:59:01 by simonmar]
simonmar authored
485 foreign import ccall unsafe "getnetbyname"
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
486 c_getnetbyname :: CString -> IO (Ptr NetworkEntry)
487
488 getNetworkByAddr :: NetworkAddr -> Family -> IO NetworkEntry
a0ebccc workaround for non-thread-safety of some functions in Network.BSD
Simon Marlow authored
489 getNetworkByAddr addr family = withLock $ do
3f3114b [project @ 2003-03-04 15:35:01 by stolz]
stolz authored
490 throwNoSuchThingIfNull "getNetworkByAddr" "no such network entry"
491 $ trySysCall $ c_getnetbyaddr addr (packFamily family)
492 >>= peek
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
493
5a38dbc [project @ 2002-06-20 15:59:01 by simonmar]
simonmar authored
494 foreign import ccall unsafe "getnetbyaddr"
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
495 c_getnetbyaddr :: NetworkAddr -> CInt -> IO (Ptr NetworkEntry)
496
497 getNetworkEntry :: IO NetworkEntry
a0ebccc workaround for non-thread-safety of some functions in Network.BSD
Simon Marlow authored
498 getNetworkEntry = withLock $ do
3f3114b [project @ 2003-03-04 15:35:01 by stolz]
stolz authored
499 throwNoSuchThingIfNull "getNetworkEntry" "no more network entries"
500 $ trySysCall $ c_getnetent
501 >>= peek
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
502
5a38dbc [project @ 2002-06-20 15:59:01 by simonmar]
simonmar authored
503 foreign import ccall unsafe "getnetent" c_getnetent :: IO (Ptr NetworkEntry)
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
504
a0ebccc workaround for non-thread-safety of some functions in Network.BSD
Simon Marlow authored
505 -- | Open the network name database. The parameter specifies
506 -- whether a connection is maintained open between various
507 -- networkEntry calls
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
508 setNetworkEntry :: Bool -> IO ()
a0ebccc workaround for non-thread-safety of some functions in Network.BSD
Simon Marlow authored
509 setNetworkEntry flg = withLock $ trySysCall $ c_setnetent (fromBool flg)
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
510
5a38dbc [project @ 2002-06-20 15:59:01 by simonmar]
simonmar authored
511 foreign import ccall unsafe "setnetent" c_setnetent :: CInt -> IO ()
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
512
a0ebccc workaround for non-thread-safety of some functions in Network.BSD
Simon Marlow authored
513 -- | Close the connection to the network name database.
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
514 endNetworkEntry :: IO ()
a0ebccc workaround for non-thread-safety of some functions in Network.BSD
Simon Marlow authored
515 endNetworkEntry = withLock $ trySysCall $ c_endnetent
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
516
5a38dbc [project @ 2002-06-20 15:59:01 by simonmar]
simonmar authored
517 foreign import ccall unsafe "endnetent" c_endnetent :: IO ()
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
518
a0ebccc workaround for non-thread-safety of some functions in Network.BSD
Simon Marlow authored
519 -- | Get the list of network entries.
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
520 getNetworkEntries :: Bool -> IO [NetworkEntry]
521 getNetworkEntries stayOpen = do
522 setNetworkEntry stayOpen
523 getEntries (getNetworkEntry) (endNetworkEntry)
524 #endif
525
a0ebccc workaround for non-thread-safety of some functions in Network.BSD
Simon Marlow authored
526 -- Mutex for name service lockdown
527
528 {-# NOINLINE lock #-}
529 lock :: MVar ()
530 lock = unsafePerformIO $ newMVar ()
531
532 withLock :: IO a -> IO a
533 withLock act = withMVar lock (\_ -> act)
534
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
535 -- ---------------------------------------------------------------------------
536 -- Miscellaneous Functions
537
a0ebccc workaround for non-thread-safety of some functions in Network.BSD
Simon Marlow authored
538 -- | Calling getHostName returns the standard host name for the current
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
539 -- processor, as set at boot time.
540
541 getHostName :: IO HostName
542 getHostName = do
543 let size = 256
544 allocaArray0 size $ \ cstr -> do
fa47dbd [project @ 2003-03-04 02:55:24 by sof]
sof authored
545 throwSocketErrorIfMinus1_ "getHostName" $ c_gethostname cstr (fromIntegral size)
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
546 peekCString cstr
547
21ab09a FIX net001 (Windows): get some calling conventions right
Simon Marlow authored
548 foreign import CALLCONV unsafe "gethostname"
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
549 c_gethostname :: CString -> CSize -> IO CInt
550
551 -- Helper function used by the exported functions that provides a
552 -- Haskellised view of the enumerator functions:
553
554 getEntries :: IO a -- read
555 -> IO () -- at end
cf32057 @tibbe Whitespace changes only: use spaces consistently in Network.BSD
tibbe authored
556 -> IO [a]
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
557 getEntries getOne atEnd = loop
558 where
3f3114b [project @ 2003-03-04 15:35:01 by stolz]
stolz authored
559 loop = do
6869949 @tibbe Get rid of deprecated 'catch'
tibbe authored
560 vv <- catch (liftM Just getOne)
561 (\ e -> let _types = e :: IOException in return Nothing)
3f3114b [project @ 2003-03-04 15:35:01 by stolz]
stolz authored
562 case vv of
563 Nothing -> return []
564 Just v -> loop >>= \ vs -> atEnd >> return (v:vs)
efb0e79 [project @ 2001-08-01 13:33:27 by simonmar]
simonmar authored
565
566
567 -- ---------------------------------------------------------------------------
fa47dbd [project @ 2003-03-04 02:55:24 by sof]
sof authored
568 -- Winsock only:
569 -- The BSD API networking calls made locally return NULL upon failure.
570 -- That failure may very well be due to WinSock not being initialised,
571 -- so if NULL is seen try init'ing and repeat the call.
dfd451a [project @ 2005-01-28 13:36:34 by simonmar]
simonmar authored
572 #if !defined(mingw32_HOST_OS) && !defined(_WIN32)
0961a08 @kfish Add missing type signatures
kfish authored
573 trySysCall :: IO a -> IO a
fa47dbd [project @ 2003-03-04 02:55:24 by sof]
sof authored
574 trySysCall act = act
575 #else
0961a08 @kfish Add missing type signatures
kfish authored
576 trySysCall :: IO (Ptr a) -> IO (Ptr a)
fa47dbd [project @ 2003-03-04 02:55:24 by sof]
sof authored
577 trySysCall act = do
578 ptr <- act
579 if (ptr == nullPtr)
580 then withSocketsDo act
581 else return ptr
582 #endif
3f3114b [project @ 2003-03-04 15:35:01 by stolz]
stolz authored
583
584 throwNoSuchThingIfNull :: String -> String -> IO (Ptr a) -> IO (Ptr a)
585 throwNoSuchThingIfNull loc desc act = do
586 ptr <- act
587 if (ptr == nullPtr)
122b1f3 @igfoo Avoid using IOError internals
igfoo authored
588 then ioError (ioeSetErrorString (mkIOError NoSuchThing loc Nothing Nothing) desc)
3f3114b [project @ 2003-03-04 15:35:01 by stolz]
stolz authored
589 else return ptr
Something went wrong with that request. Please try again.