| 1 | |
|---|
| 2 | New patches: |
|---|
| 3 | |
|---|
| 4 | [Add IPv6 support. |
|---|
| 5 | Bryan O'Sullivan <bos@serpentine.com>**20070403065512 |
|---|
| 6 | |
|---|
| 7 | The only public API changes are to Network.Socket, which has the following |
|---|
| 8 | exported names added (no existing names have been removed): |
|---|
| 9 | |
|---|
| 10 | -- IPv6 address components |
|---|
| 11 | HostAddress6 |
|---|
| 12 | FlowInfo |
|---|
| 13 | ScopeID |
|---|
| 14 | |
|---|
| 15 | -- Name -> address lookup |
|---|
| 16 | getAddrInfo |
|---|
| 17 | AddrInfo |
|---|
| 18 | AddrInfoFlag |
|---|
| 19 | defaultHints |
|---|
| 20 | |
|---|
| 21 | -- Address -> name lookup |
|---|
| 22 | getNameInfo |
|---|
| 23 | NameInfoFlag |
|---|
| 24 | |
|---|
| 25 | The SockAddr type acquires a new branch, SockAddr6. (This could cause |
|---|
| 26 | new "non-exhaustive matches" warnings when compiling pre-existing client |
|---|
| 27 | code that pattern-matches on SockAddr values. However, it will not |
|---|
| 28 | cause runtime pattern failure errors in clients using the pre-existing |
|---|
| 29 | IPv4 entry points, as they will never see IPv6 addresses.) |
|---|
| 30 | |
|---|
| 31 | This change moves a few type names from Network.BSD to Network.Socket: |
|---|
| 32 | |
|---|
| 33 | HostName |
|---|
| 34 | ServiceName |
|---|
| 35 | |
|---|
| 36 | These names are still re-exported from Network.BSD, so pre-existing code |
|---|
| 37 | should not be affected. |
|---|
| 38 | ] { |
|---|
| 39 | hunk ./Network/BSD.hsc 117 |
|---|
| 40 | -type HostName = String |
|---|
| 41 | hunk ./Network/BSD.hsc 118 |
|---|
| 42 | -type ServiceName = String |
|---|
| 43 | hunk ./Network/BSD.hsc 299 |
|---|
| 44 | --- | This is the default protocol for the given service. |
|---|
| 45 | -defaultProtocol :: ProtocolNumber |
|---|
| 46 | -defaultProtocol = 0 |
|---|
| 47 | - |
|---|
| 48 | hunk ./Network/Socket.hsc 54 |
|---|
| 49 | +#if defined(IPV6_SOCKET_SUPPORT) |
|---|
| 50 | + HostAddress6, |
|---|
| 51 | + FlowInfo, |
|---|
| 52 | + ScopeID, |
|---|
| 53 | +#endif |
|---|
| 54 | hunk ./Network/Socket.hsc 65 |
|---|
| 55 | + -- * Address operations |
|---|
| 56 | + |
|---|
| 57 | +#if defined(IPV6_SOCKET_SUPPORT) |
|---|
| 58 | + AddrInfo(..), |
|---|
| 59 | + |
|---|
| 60 | + AddrInfoFlag(..), |
|---|
| 61 | + |
|---|
| 62 | + HostName, |
|---|
| 63 | + ServiceName, |
|---|
| 64 | + |
|---|
| 65 | + defaultHints, -- :: AddrInfo |
|---|
| 66 | + defaultProtocol, -- :: ProtocolNumber |
|---|
| 67 | + |
|---|
| 68 | + getAddrInfo, -- :: Maybe AddrInfo -> Maybe HostName -> Maybe ServiceName -> IO [AddrInfo] |
|---|
| 69 | + |
|---|
| 70 | + NameInfoFlag(..), |
|---|
| 71 | + |
|---|
| 72 | + getNameInfo, -- :: [NameInfoFlag] -> Bool -> Bool -> SockAddr -> IO (Maybe HostName, Maybe ServiceName) |
|---|
| 73 | +#endif |
|---|
| 74 | + |
|---|
| 75 | hunk ./Network/Socket.hsc 148 |
|---|
| 76 | +#if defined(IPV6_SOCKET_SUPPORT) |
|---|
| 77 | + iN6ADDR_ANY, -- :: HostAddress6 |
|---|
| 78 | +#endif |
|---|
| 79 | hunk ./Network/Socket.hsc 194 |
|---|
| 80 | +import Data.Bits |
|---|
| 81 | +import Data.List (foldl') |
|---|
| 82 | hunk ./Network/Socket.hsc 197 |
|---|
| 83 | -import Foreign.Ptr ( Ptr, castPtr, plusPtr ) |
|---|
| 84 | +import Foreign.Ptr ( Ptr, castPtr, nullPtr, plusPtr ) |
|---|
| 85 | hunk ./Network/Socket.hsc 200 |
|---|
| 86 | -import Foreign.C.String ( withCString, peekCString, peekCStringLen, castCharToCChar ) |
|---|
| 87 | +import Foreign.C.String ( CString, withCString, peekCString, peekCStringLen, castCharToCChar ) |
|---|
| 88 | hunk ./Network/Socket.hsc 204 |
|---|
| 89 | -import Foreign.Marshal.Utils ( with ) |
|---|
| 90 | +import Foreign.Marshal.Utils ( maybeWith, with ) |
|---|
| 91 | hunk ./Network/Socket.hsc 227 |
|---|
| 92 | +type HostName = String |
|---|
| 93 | +type ServiceName = String |
|---|
| 94 | + |
|---|
| 95 | hunk ./Network/Socket.hsc 291 |
|---|
| 96 | +-- | This is the default protocol for a given service. |
|---|
| 97 | +defaultProtocol :: ProtocolNumber |
|---|
| 98 | +defaultProtocol = 0 |
|---|
| 99 | + |
|---|
| 100 | hunk ./Network/Socket.hsc 300 |
|---|
| 101 | +#if defined(IPV6_SOCKET_SUPPORT) |
|---|
| 102 | +type HostAddress6 = (Word32, Word32, Word32, Word32) |
|---|
| 103 | +#endif |
|---|
| 104 | + |
|---|
| 105 | hunk ./Network/Socket.hsc 374 |
|---|
| 106 | --- families. Currently only Unix domain sockets and the Internet family |
|---|
| 107 | --- are supported. |
|---|
| 108 | +-- families. Currently only Unix domain sockets and the Internet |
|---|
| 109 | +-- families are supported. |
|---|
| 110 | + |
|---|
| 111 | +#if defined(IPV6_SOCKET_SUPPORT) |
|---|
| 112 | +type FlowInfo = Word32 |
|---|
| 113 | +type ScopeID = Word32 |
|---|
| 114 | +#endif |
|---|
| 115 | hunk ./Network/Socket.hsc 386 |
|---|
| 116 | +#if defined(IPV6_SOCKET_SUPPORT) |
|---|
| 117 | + | SockAddrInet6 |
|---|
| 118 | + PortNumber -- sin6_port (network byte order) |
|---|
| 119 | + FlowInfo -- sin6_flowinfo (ditto) |
|---|
| 120 | + HostAddress6 -- sin6_addr (ditto) |
|---|
| 121 | + ScopeID -- sin6_scope_id (ditto) |
|---|
| 122 | +#endif |
|---|
| 123 | hunk ./Network/Socket.hsc 417 |
|---|
| 124 | +#if defined(IPV6_SOCKET_SUPPORT) |
|---|
| 125 | + showsPrec _ addr@(SockAddrInet6 port _ _ _) |
|---|
| 126 | + = showChar '[' |
|---|
| 127 | + . showString (unsafePerformIO $ |
|---|
| 128 | + fst `liftM` getNameInfo [NI_NUMERICHOST] True False addr >>= |
|---|
| 129 | + maybe (fail "showsPrec: impossible internal error") return) |
|---|
| 130 | + . showString "]:" |
|---|
| 131 | + . shows port |
|---|
| 132 | + |
|---|
| 133 | +instance Storable HostAddress6 where |
|---|
| 134 | + sizeOf _ = (#const sizeof(struct in6_addr)) |
|---|
| 135 | + alignment _ = alignment (undefined :: CInt) |
|---|
| 136 | + |
|---|
| 137 | + peek p = do |
|---|
| 138 | + a <- (#peek struct in6_addr, s6_addr32[0]) p |
|---|
| 139 | + b <- (#peek struct in6_addr, s6_addr32[1]) p |
|---|
| 140 | + c <- (#peek struct in6_addr, s6_addr32[2]) p |
|---|
| 141 | + d <- (#peek struct in6_addr, s6_addr32[3]) p |
|---|
| 142 | + return (a, b, c, d) |
|---|
| 143 | + |
|---|
| 144 | + poke p (a, b, c, d) = do |
|---|
| 145 | + (#poke struct in6_addr, s6_addr32[0]) p a |
|---|
| 146 | + (#poke struct in6_addr, s6_addr32[1]) p b |
|---|
| 147 | + (#poke struct in6_addr, s6_addr32[2]) p c |
|---|
| 148 | + (#poke struct in6_addr, s6_addr32[3]) p d |
|---|
| 149 | +#endif |
|---|
| 150 | hunk ./Network/Socket.hsc 464 |
|---|
| 151 | +#if defined(IPV6_SOCKET_SUPPORT) |
|---|
| 152 | +pokeSockAddr p (SockAddrInet6 (PortNum port) flow addr scope) = do |
|---|
| 153 | +#if defined(darwin_TARGET_OS) |
|---|
| 154 | + zeroMemory p (#const sizeof(struct sockaddr_in6)) |
|---|
| 155 | +#endif |
|---|
| 156 | + (#poke struct sockaddr_in6, sin6_family) p ((#const AF_INET6) :: CSaFamily) |
|---|
| 157 | + (#poke struct sockaddr_in6, sin6_port) p port |
|---|
| 158 | + (#poke struct sockaddr_in6, sin6_flowinfo) p flow |
|---|
| 159 | + (#poke struct sockaddr_in6, sin6_addr) p addr |
|---|
| 160 | + (#poke struct sockaddr_in6, sin6_scope_id) p scope |
|---|
| 161 | +#endif |
|---|
| 162 | + |
|---|
| 163 | +peekSockAddr :: Ptr SockAddr -> IO SockAddr |
|---|
| 164 | hunk ./Network/Socket.hsc 490 |
|---|
| 165 | +#if defined(IPV6_SOCKET_SUPPORT) |
|---|
| 166 | + (#const AF_INET6) -> do |
|---|
| 167 | + port <- (#peek struct sockaddr_in6, sin6_port) p |
|---|
| 168 | + flow <- (#peek struct sockaddr_in6, sin6_flowinfo) p |
|---|
| 169 | + addr <- (#peek struct sockaddr_in6, sin6_addr) p |
|---|
| 170 | + scope <- (#peek struct sockaddr_in6, sin6_scope_id) p |
|---|
| 171 | + return (SockAddrInet6 (PortNum port) flow addr scope) |
|---|
| 172 | +#endif |
|---|
| 173 | hunk ./Network/Socket.hsc 515 |
|---|
| 174 | +#if defined(IPV6_SOCKET_SUPPORT) |
|---|
| 175 | +sizeOfSockAddr (SockAddrInet6 _ _ _ _) = #const sizeof(struct sockaddr_in6) |
|---|
| 176 | +#endif |
|---|
| 177 | hunk ./Network/Socket.hsc 901 |
|---|
| 178 | +#if defined(IPV6_SOCKET_SUPPORT) |
|---|
| 179 | +socketPort sock@(MkSocket _ AF_INET6 _ _ _) = do |
|---|
| 180 | + (SockAddrInet6 port _ _ _) <- getSocketName sock |
|---|
| 181 | + return port |
|---|
| 182 | +#endif |
|---|
| 183 | hunk ./Network/Socket.hsc 1243 |
|---|
| 184 | +unpackSocketType:: CInt -> SocketType |
|---|
| 185 | hunk ./Network/Socket.hsc 1886 |
|---|
| 186 | +unpackSocketType t = case t of |
|---|
| 187 | + 0 -> NoSocketType |
|---|
| 188 | +#ifdef SOCK_STREAM |
|---|
| 189 | + (#const SOCK_STREAM) -> Stream |
|---|
| 190 | +#endif |
|---|
| 191 | +#ifdef SOCK_DGRAM |
|---|
| 192 | + (#const SOCK_DGRAM) -> Datagram |
|---|
| 193 | +#endif |
|---|
| 194 | +#ifdef SOCK_RAW |
|---|
| 195 | + (#const SOCK_RAW) -> Raw |
|---|
| 196 | +#endif |
|---|
| 197 | +#ifdef SOCK_RDM |
|---|
| 198 | + (#const SOCK_RDM) -> RDM |
|---|
| 199 | +#endif |
|---|
| 200 | +#ifdef SOCK_SEQPACKET |
|---|
| 201 | + (#const SOCK_SEQPACKET) -> SeqPacket |
|---|
| 202 | +#endif |
|---|
| 203 | + |
|---|
| 204 | hunk ./Network/Socket.hsc 1910 |
|---|
| 205 | +-- | The IPv4 wild card address. |
|---|
| 206 | + |
|---|
| 207 | hunk ./Network/Socket.hsc 1915 |
|---|
| 208 | +#if defined(IPV6_SOCKET_SUPPORT) |
|---|
| 209 | +-- | The IPv6 wild card address. |
|---|
| 210 | + |
|---|
| 211 | +iN6ADDR_ANY :: HostAddress6 |
|---|
| 212 | +iN6ADDR_ANY = (0, 0, 0, 0) |
|---|
| 213 | +#endif |
|---|
| 214 | + |
|---|
| 215 | hunk ./Network/Socket.hsc 2047 |
|---|
| 216 | + |
|---|
| 217 | +-- | Pack a list of values into a bitmask. The possible mappings from |
|---|
| 218 | +-- value to bit-to-set are given as the first argument. We assume |
|---|
| 219 | +-- that each value can cause exactly one bit to be set; unpackBits will |
|---|
| 220 | +-- break if this property is not true. |
|---|
| 221 | + |
|---|
| 222 | +packBits :: (Eq a, Bits b) => [(a, b)] -> [a] -> b |
|---|
| 223 | + |
|---|
| 224 | +packBits mapping xs = foldl' pack 0 mapping |
|---|
| 225 | + where pack acc (k, v) | k `elem` xs = acc .|. v |
|---|
| 226 | + | otherwise = acc |
|---|
| 227 | + |
|---|
| 228 | +-- | Unpack a bitmask into a list of values. |
|---|
| 229 | + |
|---|
| 230 | +unpackBits :: Bits b => [(a, b)] -> b -> [a] |
|---|
| 231 | + |
|---|
| 232 | +unpackBits [] 0 = [] |
|---|
| 233 | +unpackBits [] r = error ("unpackBits: unhandled bits set: " ++ show r) |
|---|
| 234 | +unpackBits ((k,v):xs) r |
|---|
| 235 | + | r .&. v /= 0 = k : unpackBits xs (r .&. complement v) |
|---|
| 236 | + | otherwise = unpackBits xs r |
|---|
| 237 | + |
|---|
| 238 | +----------------------------------------------------------------------------- |
|---|
| 239 | +-- Address and service lookups |
|---|
| 240 | + |
|---|
| 241 | +#if defined(IPV6_SOCKET_SUPPORT) |
|---|
| 242 | + |
|---|
| 243 | +-- | Flags that control the querying behaviour of 'getAddrInfo'. |
|---|
| 244 | +data AddrInfoFlag |
|---|
| 245 | + = AI_ADDRCONFIG |
|---|
| 246 | + | AI_CANONNAME |
|---|
| 247 | + | AI_NUMERICHOST |
|---|
| 248 | + | AI_PASSIVE |
|---|
| 249 | + deriving (Eq, Read, Show) |
|---|
| 250 | + |
|---|
| 251 | +INSTANCE_TYPEABLE0(AddrInfoFlag,addrInfoFlagTc,"AddrInfoFlag") |
|---|
| 252 | + |
|---|
| 253 | +aiFlagMapping :: [(AddrInfoFlag, CInt)] |
|---|
| 254 | + |
|---|
| 255 | +aiFlagMapping = |
|---|
| 256 | + [(AI_ADDRCONFIG, #const AI_ADDRCONFIG), |
|---|
| 257 | + (AI_CANONNAME, #const AI_CANONNAME), |
|---|
| 258 | + (AI_NUMERICHOST, #const AI_NUMERICHOST), |
|---|
| 259 | + (AI_PASSIVE, #const AI_PASSIVE)] |
|---|
| 260 | + |
|---|
| 261 | +data AddrInfo = |
|---|
| 262 | + AddrInfo { |
|---|
| 263 | + addrFlags :: [AddrInfoFlag], |
|---|
| 264 | + addrFamily :: Family, |
|---|
| 265 | + addrSocketType :: SocketType, |
|---|
| 266 | + addrProtocol :: ProtocolNumber, |
|---|
| 267 | + addrAddress :: SockAddr, |
|---|
| 268 | + addrCanonName :: Maybe String |
|---|
| 269 | + } |
|---|
| 270 | + deriving (Eq, Show) |
|---|
| 271 | + |
|---|
| 272 | +INSTANCE_TYPEABLE0(AddrInfo,addrInfoTc,"AddrInfo") |
|---|
| 273 | + |
|---|
| 274 | +instance Storable AddrInfo where |
|---|
| 275 | + sizeOf _ = #const sizeof(struct addrinfo) |
|---|
| 276 | + alignment _ = alignment (undefined :: CInt) |
|---|
| 277 | + |
|---|
| 278 | + peek p = do |
|---|
| 279 | + ai_flags <- (#peek struct addrinfo, ai_flags) p |
|---|
| 280 | + ai_family <- (#peek struct addrinfo, ai_family) p |
|---|
| 281 | + ai_socktype <- (#peek struct addrinfo, ai_socktype) p |
|---|
| 282 | + ai_protocol <- (#peek struct addrinfo, ai_protocol) p |
|---|
| 283 | + ai_addr <- (#peek struct addrinfo, ai_addr) p >>= peekSockAddr |
|---|
| 284 | + ai_canonname_ptr <- (#peek struct addrinfo, ai_canonname) p |
|---|
| 285 | + |
|---|
| 286 | + ai_canonname <- if ai_canonname_ptr == nullPtr |
|---|
| 287 | + then return Nothing |
|---|
| 288 | + else liftM Just $ peekCString ai_canonname_ptr |
|---|
| 289 | + |
|---|
| 290 | + return (AddrInfo |
|---|
| 291 | + { |
|---|
| 292 | + addrFlags = unpackBits aiFlagMapping ai_flags, |
|---|
| 293 | + addrFamily = unpackFamily ai_family, |
|---|
| 294 | + addrSocketType = unpackSocketType ai_socktype, |
|---|
| 295 | + addrProtocol = ai_protocol, |
|---|
| 296 | + addrAddress = ai_addr, |
|---|
| 297 | + addrCanonName = ai_canonname |
|---|
| 298 | + }) |
|---|
| 299 | + |
|---|
| 300 | + poke p (AddrInfo flags family socketType protocol _ _) = do |
|---|
| 301 | + (#poke struct addrinfo, ai_flags) p (packBits aiFlagMapping flags) |
|---|
| 302 | + (#poke struct addrinfo, ai_family) p (packFamily family) |
|---|
| 303 | + (#poke struct addrinfo, ai_socktype) p (packSocketType socketType) |
|---|
| 304 | + (#poke struct addrinfo, ai_protocol) p protocol |
|---|
| 305 | + |
|---|
| 306 | + -- stuff below is probably not needed, but let's zero it for safety |
|---|
| 307 | + |
|---|
| 308 | + (#poke struct addrinfo, ai_addrlen) p (0::CSize) |
|---|
| 309 | + (#poke struct addrinfo, ai_addr) p nullPtr |
|---|
| 310 | + (#poke struct addrinfo, ai_canonname) p nullPtr |
|---|
| 311 | + (#poke struct addrinfo, ai_next) p nullPtr |
|---|
| 312 | + |
|---|
| 313 | +data NameInfoFlag |
|---|
| 314 | + = NI_DGRAM |
|---|
| 315 | + | NI_NAMEREQD |
|---|
| 316 | + | NI_NOFQDN |
|---|
| 317 | + | NI_NUMERICHOST |
|---|
| 318 | + | NI_NUMERICSERV |
|---|
| 319 | + deriving (Eq, Read, Show) |
|---|
| 320 | + |
|---|
| 321 | +INSTANCE_TYPEABLE0(NameInfoFlag,nameInfoFlagTc,"NameInfoFlag") |
|---|
| 322 | + |
|---|
| 323 | +niFlagMapping :: [(NameInfoFlag, CInt)] |
|---|
| 324 | + |
|---|
| 325 | +niFlagMapping = [(NI_DGRAM, #const NI_DGRAM), |
|---|
| 326 | + (NI_NAMEREQD, #const NI_NAMEREQD), |
|---|
| 327 | + (NI_NOFQDN, #const NI_NOFQDN), |
|---|
| 328 | + (NI_NUMERICHOST, #const NI_NUMERICHOST), |
|---|
| 329 | + (NI_NUMERICSERV, #const NI_NUMERICSERV)] |
|---|
| 330 | + |
|---|
| 331 | +-- | Default hints for address lookup with 'getAddrInfo'. The values |
|---|
| 332 | +-- of the 'addrAddress' and 'addrCanonName' fields are 'undefined', |
|---|
| 333 | +-- and are never inspected by 'getAddrInfo'. |
|---|
| 334 | + |
|---|
| 335 | +defaultHints :: AddrInfo |
|---|
| 336 | + |
|---|
| 337 | +defaultHints = AddrInfo { |
|---|
| 338 | + addrFlags = [], |
|---|
| 339 | + addrFamily = AF_UNSPEC, |
|---|
| 340 | + addrSocketType = NoSocketType, |
|---|
| 341 | + addrProtocol = defaultProtocol, |
|---|
| 342 | + addrAddress = undefined, |
|---|
| 343 | + addrCanonName = undefined |
|---|
| 344 | + } |
|---|
| 345 | + |
|---|
| 346 | +-- | Resolve a host or service name to one or more addresses. |
|---|
| 347 | +-- The 'AddrInfo' values that this function returns contain 'SockAddr' |
|---|
| 348 | +-- values that you can pass directly to 'connect' or |
|---|
| 349 | +-- 'bindSocket'. |
|---|
| 350 | +-- |
|---|
| 351 | +-- This function is protocol independent. It can return both IPv4 and |
|---|
| 352 | +-- IPv6 address information. |
|---|
| 353 | +-- |
|---|
| 354 | +-- The 'AddrInfo' argument specifies the preferred query behaviour, |
|---|
| 355 | +-- socket options, or protocol. You can override these conveniently |
|---|
| 356 | +-- using Haskell's record update syntax on 'defaultHints', for example |
|---|
| 357 | +-- as follows: |
|---|
| 358 | +-- |
|---|
| 359 | +-- @ |
|---|
| 360 | +-- myHints = defaultHints { addrFlags = aI_ADDRCONFIG + aI_CANONNAME } |
|---|
| 361 | +-- @ |
|---|
| 362 | +-- |
|---|
| 363 | +-- Values for 'addrFlags' control query behaviour. The supported |
|---|
| 364 | +-- flags are as follows: |
|---|
| 365 | +-- |
|---|
| 366 | +-- [@AI_PASSIVE@] If no 'HostName' value is provided, the network |
|---|
| 367 | +-- address in each 'SockAddr' |
|---|
| 368 | +-- will be left as a "wild card", i.e. as either 'iNADDR_ANY' |
|---|
| 369 | +-- or 'iN6ADDR_ANY'. This is useful for server applications that |
|---|
| 370 | +-- will accept connections from any client. |
|---|
| 371 | +-- |
|---|
| 372 | +-- [@AI_CANONNAME@] The 'addrCanonName' field of the first returned |
|---|
| 373 | +-- 'AddrInfo' will contain the "canonical name" of the host. |
|---|
| 374 | +-- |
|---|
| 375 | +-- [@AI_NUMERICHOST@] The 'HostName' argument /must/ be a numeric |
|---|
| 376 | +-- address in string form, and network name lookups will not be |
|---|
| 377 | +-- attempted. |
|---|
| 378 | +-- |
|---|
| 379 | +-- [@AI_ADDRCONFIG@] The list of returned 'AddrInfo' values will only |
|---|
| 380 | +-- contain IPv4 addresses if the local system has at least one |
|---|
| 381 | +-- IPv4 interface configured, and likewise for IPv6. |
|---|
| 382 | +-- |
|---|
| 383 | +-- You must provide a 'Just' value for at least one of the 'HostName' |
|---|
| 384 | +-- or 'ServiceName' arguments. 'HostName' can be either a numeric |
|---|
| 385 | +-- network address (dotted quad for IPv4, colon-separated hex for |
|---|
| 386 | +-- IPv6) or a hostname. In the latter case, its addresses will be |
|---|
| 387 | +-- looked up unless 'AI_NUMERICHOST' is specified as a hint. If you |
|---|
| 388 | +-- do not provide a 'HostName' value /and/ do not set 'AI_PASSIVE' as |
|---|
| 389 | +-- a hint, network addresses in the result will contain the address of |
|---|
| 390 | +-- the loopback interface. |
|---|
| 391 | +-- |
|---|
| 392 | +-- If the query fails, this function throws an IO exception instead of |
|---|
| 393 | +-- returning an empty list. Otherwise, it returns a non-empty list |
|---|
| 394 | +-- of 'AddrInfo' values. |
|---|
| 395 | +-- |
|---|
| 396 | +-- There are several reasons why a query might result in several |
|---|
| 397 | +-- values. For example, the queried-for host could be multihomed, or |
|---|
| 398 | +-- the service might be available via several protocols. |
|---|
| 399 | +-- |
|---|
| 400 | +-- Note: the order of arguments is slightly different to that defined |
|---|
| 401 | +-- for @getaddrinfo@ in RFC 2553. The 'AddrInfo' parameter comes first |
|---|
| 402 | +-- to make partial application easier. |
|---|
| 403 | +-- |
|---|
| 404 | +-- Example: |
|---|
| 405 | +-- @ |
|---|
| 406 | +-- let hints = defaultHints { addrFlags = [AI_ADDRCONFIG, AI_CANONNAME] } |
|---|
| 407 | +-- addrs <- getAddrInfo (Just hints) (Just "www.haskell.org") (Just "http") |
|---|
| 408 | +-- let addr = head addrs |
|---|
| 409 | +-- sock <- socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr) |
|---|
| 410 | +-- connect sock (addrAddress addr) |
|---|
| 411 | +-- @ |
|---|
| 412 | + |
|---|
| 413 | +getAddrInfo :: Maybe AddrInfo -- ^ preferred socket type or protocol |
|---|
| 414 | + -> Maybe HostName -- ^ host name to look up |
|---|
| 415 | + -> Maybe ServiceName -- ^ service name to look up |
|---|
| 416 | + -> IO [AddrInfo] -- ^ resolved addresses, with "best" first |
|---|
| 417 | + |
|---|
| 418 | +getAddrInfo hints node service = |
|---|
| 419 | + maybeWith withCString node $ \c_node -> |
|---|
| 420 | + maybeWith withCString service $ \c_service -> |
|---|
| 421 | + maybeWith with hints $ \c_hints -> |
|---|
| 422 | + alloca $ \ptr_ptr_addrs -> do |
|---|
| 423 | + ret <- c_getaddrinfo c_node c_service c_hints ptr_ptr_addrs |
|---|
| 424 | + case ret of |
|---|
| 425 | + 0 -> do ptr_addrs <- peek ptr_ptr_addrs |
|---|
| 426 | + ais <- followAddrInfo ptr_addrs |
|---|
| 427 | + c_freeaddrinfo ptr_addrs |
|---|
| 428 | + return ais |
|---|
| 429 | + _ -> do err <- gai_strerror ret |
|---|
| 430 | + ioError (IOError Nothing NoSuchThing "getAddrInfo" err |
|---|
| 431 | + Nothing) |
|---|
| 432 | + |
|---|
| 433 | +followAddrInfo :: Ptr AddrInfo -> IO [AddrInfo] |
|---|
| 434 | + |
|---|
| 435 | +followAddrInfo ptr_ai | ptr_ai == nullPtr = return [] |
|---|
| 436 | + | otherwise = do |
|---|
| 437 | + a <- peek ptr_ai |
|---|
| 438 | + as <- (#peek struct addrinfo, ai_next) ptr_ai >>= followAddrInfo |
|---|
| 439 | + return (a:as) |
|---|
| 440 | + |
|---|
| 441 | +foreign import ccall safe "getaddrinfo" |
|---|
| 442 | + c_getaddrinfo :: CString -> CString -> Ptr AddrInfo -> Ptr (Ptr AddrInfo) |
|---|
| 443 | + -> IO CInt |
|---|
| 444 | + |
|---|
| 445 | +foreign import ccall safe "freeaddrinfo" |
|---|
| 446 | + c_freeaddrinfo :: Ptr AddrInfo -> IO () |
|---|
| 447 | + |
|---|
| 448 | +gai_strerror :: CInt -> IO String |
|---|
| 449 | + |
|---|
| 450 | +gai_strerror n = c_gai_strerror n >>= peekCString |
|---|
| 451 | + |
|---|
| 452 | +foreign import ccall safe "gai_strerror" |
|---|
| 453 | + c_gai_strerror :: CInt -> IO CString |
|---|
| 454 | + |
|---|
| 455 | +withCStringIf :: Bool -> Int -> (CSize -> CString -> IO a) -> IO a |
|---|
| 456 | +withCStringIf False _ f = f 0 nullPtr |
|---|
| 457 | +withCStringIf True n f = allocaBytes n (f (fromIntegral n)) |
|---|
| 458 | + |
|---|
| 459 | +-- | Resolve an address to a host or service name. |
|---|
| 460 | +-- This function is protocol independent. |
|---|
| 461 | +-- |
|---|
| 462 | +-- The list of 'NameInfoFlag' values controls query behaviour. The |
|---|
| 463 | +-- supported flags are as follows: |
|---|
| 464 | +-- |
|---|
| 465 | +-- [@NI_NOFQDN@] If a host is local, return only the |
|---|
| 466 | +-- hostname part of the FQDN. |
|---|
| 467 | +-- |
|---|
| 468 | +-- [@NI_NUMERICHOST@] The name of the host is not |
|---|
| 469 | +-- looked up. Instead, a numeric representation of the host's |
|---|
| 470 | +-- address is returned. |
|---|
| 471 | +-- |
|---|
| 472 | +-- [@NI_NUMERICSERV@] The name of the service is not |
|---|
| 473 | +-- looked up. Instead, a numeric representation of the |
|---|
| 474 | +-- service is returned. |
|---|
| 475 | +-- |
|---|
| 476 | +-- [@NI_NAMEREQD@] If the hostname cannot be looked up, an IO error |
|---|
| 477 | +-- is thrown. |
|---|
| 478 | +-- |
|---|
| 479 | +-- [@NI_DGRAM@] Resolve a datagram-based service name. This is |
|---|
| 480 | +-- required for the few protocols that have different port numbers |
|---|
| 481 | +-- for their datagram-based versions than for their stream-based |
|---|
| 482 | +-- versions. |
|---|
| 483 | +-- |
|---|
| 484 | +-- Hostname and service name lookups can be expensive. You can |
|---|
| 485 | +-- specify which lookups to perform via the two 'Bool' arguments. If |
|---|
| 486 | +-- one of these is 'False', the corresponding value in the returned |
|---|
| 487 | +-- tuple will be 'Nothing', and no lookup will be performed. |
|---|
| 488 | +-- |
|---|
| 489 | +-- If a host or service's name cannot be looked up, then the numeric |
|---|
| 490 | +-- form of the address or service will be returned. |
|---|
| 491 | +-- |
|---|
| 492 | +-- If the query fails, this function throws an IO exception. |
|---|
| 493 | + |
|---|
| 494 | +getNameInfo :: [NameInfoFlag] -- ^ flags to control lookup behaviour |
|---|
| 495 | + -> Bool -- ^ whether to look up a hostname |
|---|
| 496 | + -> Bool -- ^ whether to look up a service name |
|---|
| 497 | + -> SockAddr -- ^ the address to look up |
|---|
| 498 | + -> IO (Maybe HostName, Maybe ServiceName) |
|---|
| 499 | + |
|---|
| 500 | +getNameInfo flags doHost doService addr = |
|---|
| 501 | + withCStringIf doHost (#const NI_MAXHOST) $ \c_hostlen c_host -> |
|---|
| 502 | + withCStringIf doService (#const NI_MAXSERV) $ \c_servlen c_serv -> do |
|---|
| 503 | + withSockAddr addr $ \ptr_addr sz -> do |
|---|
| 504 | + ret <- c_getnameinfo ptr_addr (fromIntegral sz) c_host c_hostlen |
|---|
| 505 | + c_serv c_servlen (packBits niFlagMapping flags) |
|---|
| 506 | + case ret of |
|---|
| 507 | + 0 -> do |
|---|
| 508 | + let peekIf doIf c_val = if doIf |
|---|
| 509 | + then liftM Just $ peekCString c_val |
|---|
| 510 | + else return Nothing |
|---|
| 511 | + host <- peekIf doHost c_host |
|---|
| 512 | + serv <- peekIf doService c_serv |
|---|
| 513 | + return (host, serv) |
|---|
| 514 | + _ -> do err <- gai_strerror ret |
|---|
| 515 | + ioError (IOError Nothing NoSuchThing "getNameInfo" err |
|---|
| 516 | + Nothing) |
|---|
| 517 | + |
|---|
| 518 | +foreign import ccall safe "getnameinfo" |
|---|
| 519 | + c_getnameinfo :: Ptr SockAddr -> CInt{-CSockLen???-} -> CString -> CSize -> CString |
|---|
| 520 | + -> CSize -> CInt -> IO CInt |
|---|
| 521 | +#endif |
|---|
| 522 | hunk ./configure.ac 37 |
|---|
| 523 | +dnl -------------------------------------------------- |
|---|
| 524 | +dnl * test for in6_addr as proxy for IPv6 support |
|---|
| 525 | +dnl -------------------------------------------------- |
|---|
| 526 | +AC_MSG_CHECKING(for in6_addr in netinet/in.h) |
|---|
| 527 | +AC_EGREP_HEADER(in6_addr, netinet/in.h, |
|---|
| 528 | + [ AC_DEFINE([HAVE_IN6_ADDR], [1], [Define to 1 if in6_addr is available.]) AC_MSG_RESULT(yes) ], |
|---|
| 529 | + AC_MSG_RESULT(no)) |
|---|
| 530 | + |
|---|
| 531 | hunk ./include/HsNet.h 28 |
|---|
| 532 | + |
|---|
| 533 | +#ifdef HAVE_IN6_ADDR |
|---|
| 534 | +# define IPV6_SOCKET_SUPPORT 1 |
|---|
| 535 | +#else |
|---|
| 536 | +# undef IPV6_SOCKET_SUPPORT |
|---|
| 537 | +#endif |
|---|
| 538 | } |
|---|
| 539 | |
|---|
| 540 | Context: |
|---|
| 541 | |
|---|
| 542 | [apply changes from patch "make this test deterministic on a multiprocessor" in testsuite |
|---|
| 543 | Simon Marlow <simonmar@microsoft.com>**20070221142822] |
|---|
| 544 | [tests for use with GHC's test framework, moved from the testsuite |
|---|
| 545 | Simon Marlow <simonmar@microsoft.com>**20070221142258] |
|---|
| 546 | [README about building from darcs |
|---|
| 547 | Ross Paterson <ross@soi.city.ac.uk>**20070218110201] |
|---|
| 548 | [don't install Typeable.h, fixes #1106 |
|---|
| 549 | Simon Marlow <simonmar@microsoft.com>**20070201125821] |
|---|
| 550 | [network doesn't really need the html package |
|---|
| 551 | Ian Lynagh <igloo@earth.li>**20070111122348] |
|---|
| 552 | [includes -> install-includes |
|---|
| 553 | Ross Paterson <ross@soi.city.ac.uk>**20060829123744] |
|---|
| 554 | [change title to Haskell Hierarchical Libraries |
|---|
| 555 | Ross Paterson <ross@soi.city.ac.uk>**20060827131348] |
|---|
| 556 | [exclude Setup.hs from build |
|---|
| 557 | Ross Paterson <ross@soi.city.ac.uk>**20060824183533] |
|---|
| 558 | [add boilerplate Setup.hs |
|---|
| 559 | Ross Paterson <ross@soi.city.ac.uk>**20060824115019] |
|---|
| 560 | [Update Network.BSD header to not mention symlinks. |
|---|
| 561 | Ian Lynagh <igloo@earth.li>**20060823184314] |
|---|
| 562 | [Removed Network.CGI from the network package. A backwards-compatible new Network.CGI is available in the cgi package. |
|---|
| 563 | bringert@cs.chalmers.se**20060814095652] |
|---|
| 564 | [remove deprecated Network.BSD.{readlink,symlink} |
|---|
| 565 | Simon Marlow <simonmar@microsoft.com>**20060811153755] |
|---|
| 566 | [bump version to 2.0 |
|---|
| 567 | Simon Marlow <simonmar@microsoft.com>**20060811152554] |
|---|
| 568 | [depend on html (for the time being) |
|---|
| 569 | Simon Marlow <simonmar@microsoft.com>**20060810121424] |
|---|
| 570 | [initWinSock(): have defn match proto |
|---|
| 571 | sof@galois.com**20060613224903] |
|---|
| 572 | [only GHC has rtsSupportsBoundThreads |
|---|
| 573 | Ross Paterson <ross@soi.city.ac.uk>**20060531200123] |
|---|
| 574 | [add files used by configure |
|---|
| 575 | Ross Paterson <ross@soi.city.ac.uk>**20060518174356] |
|---|
| 576 | [Import unsafePerformIO |
|---|
| 577 | Sven Panne <sven.panne@aedion.de>**20060507171832] |
|---|
| 578 | [Import MVar type |
|---|
| 579 | Sven Panne <sven.panne@aedion.de>**20060507170308] |
|---|
| 580 | [Add various address families |
|---|
| 581 | Simon Marlow <simonmar@microsoft.com>**20060503081915] |
|---|
| 582 | [Fix for #265, build problem on AIX |
|---|
| 583 | Simon Marlow <simonmar@microsoft.com>**20060316143337 |
|---|
| 584 | Not the fix from the ticket, but this one at least doesn't require |
|---|
| 585 | modifying the configure script. |
|---|
| 586 | ] |
|---|
| 587 | [workaround for non-thread-safety of some functions in Network.BSD |
|---|
| 588 | Simon Marlow <simonmar@microsoft.com>**20060126153014 |
|---|
| 589 | Various functions in Network.BSD are non-thread-safe, |
|---|
| 590 | eg. getHostByName, because the underlying gethostbyname() provided by |
|---|
| 591 | the C library uses static storage. The workaround here is to use a |
|---|
| 592 | giant lock around these functions. |
|---|
| 593 | |
|---|
| 594 | In some cases, even the API we provide is itself unsafe, relying on |
|---|
| 595 | implicit state (eg. getHostEntry), but this commit makes no attempt to |
|---|
| 596 | fix that. We should deprecate this library in favour of a complete |
|---|
| 597 | replacement at some point (before 6.6 would be nice). |
|---|
| 598 | |
|---|
| 599 | Thanks to Einar Kartunnen for the patch. |
|---|
| 600 | ] |
|---|
| 601 | [Fix Ticket 647, Socket bug on Mac OS X |
|---|
| 602 | wolfgang.thaller@gmx.net**20060121050509 |
|---|
| 603 | Patch kindly provided by Greg Wright |
|---|
| 604 | ] |
|---|
| 605 | [TAG Initial conversion from CVS complete |
|---|
| 606 | John Goerzen <jgoerzen@complete.org>**20060112154134] |
|---|
| 607 | Patch bundle hash: |
|---|
| 608 | 5ea614c8eadaf4f27ea7d0cb4a95a7268ecf8cac |
|---|