Skip to content

Commit 1dc8708

Browse files
committed
Support Wasm/WASI
1 parent ca0a569 commit 1dc8708

File tree

15 files changed

+216
-20
lines changed

15 files changed

+216
-20
lines changed

Network/Socket/Buffer.hsc

+25-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{-# LANGUAGE CPP #-}
22

3+
#include "HsNet.h"
34
##include "HsNetDef.h"
45
#if defined(mingw32_HOST_OS)
56
# include "windows.h"
@@ -57,6 +58,7 @@ sendBufTo :: SocketAddress sa =>
5758
-> Int -- Data to send
5859
-> sa
5960
-> IO Int -- Number of Bytes sent
61+
#ifdef HAVE_SENDTO
6062
sendBufTo s ptr nbytes sa =
6163
withSocketAddress sa $ \p_sa siz -> fromIntegral <$> do
6264
withFdSocket s $ \fd -> do
@@ -65,6 +67,10 @@ sendBufTo s ptr nbytes sa =
6567
flags = 0
6668
throwSocketErrorWaitWrite s "Network.Socket.sendBufTo" $
6769
c_sendto fd ptr n flags p_sa sz
70+
#else
71+
sendBufTo _ _ _ _ = unsupported "sendBufTo"
72+
{-# WARNING sendBufTo "operation will throw 'IOError' \"unsupported operation\"" #-}
73+
#endif
6874

6975
#if defined(mingw32_HOST_OS)
7076
socket2FD :: Socket -> IO FD
@@ -112,6 +118,7 @@ sendBuf s str len = fromIntegral <$> do
112118
-- NOTE: blocking on Windows unless you compile with -threaded (see
113119
-- GHC ticket #1129)
114120
recvBufFrom :: SocketAddress sa => Socket -> Ptr a -> Int -> IO (Int, sa)
121+
#ifdef HAVE_RECVFROM
115122
recvBufFrom s ptr nbytes
116123
| nbytes <= 0 = ioError (mkInvalidRecvArgError "Network.Socket.recvBufFrom")
117124
| otherwise = withNewSocketAddress $ \ptr_sa sz -> alloca $ \ptr_len ->
@@ -124,6 +131,10 @@ recvBufFrom s ptr nbytes
124131
sockaddr <- peekSocketAddress ptr_sa
125132
`catchIOError` \_ -> getPeerName s
126133
return (fromIntegral len, sockaddr)
134+
#else
135+
recvBufFrom _ _ _ = unsupported "recvBufFrom"
136+
{-# WARNING recvBufFrom "operation will throw 'IOError' \"unsupported operation\"" #-}
137+
#endif
127138

128139
-- | Receive data from the socket. The socket must be in a connected
129140
-- state. This function may return fewer bytes than specified. If the
@@ -204,6 +215,7 @@ sendBufMsg :: SocketAddress sa
204215
-> [Cmsg] -- ^ Control messages
205216
-> MsgFlag -- ^ Message flags
206217
-> IO Int -- ^ The length actually sent
218+
#ifdef HAVE_STRUCT_CMSGHDR
207219
sendBufMsg s sa bufsizs cmsgs flags = do
208220
sz <- withSocketAddress sa $ \addrPtr addrSize ->
209221
#if !defined(mingw32_HOST_OS)
@@ -237,6 +249,10 @@ sendBufMsg s sa bufsizs cmsgs flags = do
237249
c_sendmsg fd msgHdrPtr (fromIntegral cflags) send_ptr nullPtr nullPtr
238250
#endif
239251
return $ fromIntegral sz
252+
#else
253+
sendBufMsg _ _ _ _ _ = unsupported "sendBufMsg"
254+
{-# WARNING sendBufMsg "operation will throw 'IOError' \"unsupported operation\"" #-}
255+
#endif
240256

241257
-- | Receive data from the socket using recvmsg(2). The supplied
242258
-- buffers are filled in order, with subsequent buffers used only
@@ -252,6 +268,7 @@ recvBufMsg :: SocketAddress sa
252268
-- 'MSG_CTRUNC' is returned
253269
-> MsgFlag -- ^ Message flags
254270
-> IO (sa,Int,[Cmsg],MsgFlag) -- ^ Source address, total bytes received, control messages and message flags
271+
#ifdef HAVE_STRUCT_CMSGHDR
255272
recvBufMsg s bufsizs clen flags = do
256273
withNewSocketAddress $ \addrPtr addrSize ->
257274
allocaBytes clen $ \ctrlPtr ->
@@ -295,6 +312,10 @@ recvBufMsg s bufsizs clen flags = do
295312
cmsgs <- parseCmsgs msgHdrPtr
296313
let flags' = MsgFlag $ fromIntegral $ msgFlags hdr
297314
return (sockaddr, len, cmsgs, flags')
315+
#else
316+
recvBufMsg _ _ _ _ = unsupported "recvBufMsg"
317+
{-# WARNING recvBufMsg "operation will throw 'IOError' \"unsupported operation\"" #-}
318+
#endif
298319

299320
#if !defined(mingw32_HOST_OS)
300321
foreign import ccall unsafe "send"
@@ -317,8 +338,11 @@ foreign import CALLCONV SAFE_ON_WIN "WSARecvMsg"
317338

318339
foreign import ccall unsafe "recv"
319340
c_recv :: CInt -> Ptr CChar -> CSize -> CInt -> IO CInt
341+
#ifdef HAVE_SENDTO
320342
foreign import CALLCONV SAFE_ON_WIN "sendto"
321343
c_sendto :: CInt -> Ptr a -> CSize -> CInt -> Ptr sa -> CInt -> IO CInt
344+
#endif
345+
#ifdef HAVE_RECVFROM
322346
foreign import CALLCONV SAFE_ON_WIN "recvfrom"
323347
c_recvfrom :: CInt -> Ptr a -> CSize -> CInt -> Ptr sa -> Ptr CInt -> IO CInt
324-
348+
#endif

Network/Socket/Cbits.hsc

+6
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,14 @@ import Network.Socket.Imports
77
-- | This is the value of SOMAXCONN, typically 128.
88
-- 128 is good enough for normal network servers but
99
-- is too small for high performance servers.
10+
--
11+
-- TODO what if not present
1012
maxListenQueue :: Int
13+
#ifdef SOMAXCONN
1114
maxListenQueue = #const SOMAXCONN
15+
#else
16+
maxListenQueue = 1
17+
#endif
1218

1319
#if defined(mingw32_HOST_OS)
1420
wsaNotInitialized :: CInt

Network/Socket/If.hs

+17
Original file line numberDiff line numberDiff line change
@@ -10,29 +10,46 @@ module Network.Socket.If (
1010
import Foreign.Marshal.Alloc (allocaBytes)
1111

1212
import Network.Socket.Imports
13+
#if !defined(HAVE_IF_NAMETOINDEX) || !defined(HAVE_IF_INDEXTONAME)
14+
import Network.Socket.Internal (unsupported)
15+
#endif
1316

1417
-- | Returns the index corresponding to the interface name.
1518
--
1619
-- Since 2.7.0.0.
1720
ifNameToIndex :: String -> IO (Maybe Int)
21+
#ifdef HAVE_IF_NAMETOINDEX
1822
ifNameToIndex ifname = do
1923
index <- withCString ifname c_if_nametoindex
2024
-- On failure zero is returned. We'll return Nothing.
2125
return $ if index == 0 then Nothing else Just $ fromIntegral index
26+
#else
27+
ifNameToIndex _ = unsupported "ifNameToIndex"
28+
{-# WARNING ifNameToIndex "operation will throw 'IOError' \"unsupported operation\"" #-}
29+
#endif
2230

2331
-- | Returns the interface name corresponding to the index.
2432
--
2533
-- Since 2.7.0.0.
2634
ifIndexToName :: Int -> IO (Maybe String)
35+
#ifdef HAVE_IF_INDEXTONAME
2736
ifIndexToName ifn = allocaBytes 16 $ \ptr -> do -- 16 == IFNAMSIZ
2837
r <- c_if_indextoname (fromIntegral ifn) ptr
2938
if r == nullPtr then
3039
return Nothing
3140
else
3241
Just <$> peekCString ptr
42+
#else
43+
ifIndexToName _ = unsupported "ifIndexToName"
44+
{-# WARNING ifIndexToName "operation will throw 'IOError' \"unsupported operation\"" #-}
45+
#endif
3346

47+
#ifdef HAVE_IF_NAMETOINDEX
3448
foreign import CALLCONV safe "if_nametoindex"
3549
c_if_nametoindex :: CString -> IO CUInt
50+
#endif
3651

52+
#ifdef HAVE_IF_INDEXTONAME
3753
foreign import CALLCONV safe "if_indextoname"
3854
c_if_indextoname :: CUInt -> CString -> IO CString
55+
#endif

Network/Socket/Info.hsc

+62-14
Original file line numberDiff line numberDiff line change
@@ -81,14 +81,26 @@ aiFlagMapping =
8181
#else
8282
(AI_ALL, 0),
8383
#endif
84+
#if HAVE_DECL_AI_CANONNAME
8485
(AI_CANONNAME, #const AI_CANONNAME),
86+
#else
87+
(AI_CANONNAME, 0),
88+
#endif
89+
#if HAVE_DECL_AI_NUMERICHOST
8590
(AI_NUMERICHOST, #const AI_NUMERICHOST),
91+
#else
92+
(AI_NUMERICHOST, 0),
93+
#endif
8694
#if HAVE_DECL_AI_NUMERICSERV
8795
(AI_NUMERICSERV, #const AI_NUMERICSERV),
8896
#else
8997
(AI_NUMERICSERV, 0),
9098
#endif
99+
#if HAVE_DECL_AI_PASSIVE
91100
(AI_PASSIVE, #const AI_PASSIVE),
101+
#else
102+
(AI_PASSIVE, 0),
103+
#endif
92104
#if HAVE_DECL_AI_V4MAPPED
93105
(AI_V4MAPPED, #const AI_V4MAPPED)
94106
#else
@@ -110,6 +122,7 @@ data AddrInfo = AddrInfo {
110122
, addrCanonName :: Maybe String
111123
} deriving (Eq, Show)
112124

125+
#if HAVE_STRUCT_ADDRINFO
113126
instance Storable AddrInfo where
114127
sizeOf ~_ = #const sizeof(struct addrinfo)
115128
alignment ~_ = alignment (0 :: CInt)
@@ -149,6 +162,8 @@ instance Storable AddrInfo where
149162
(#poke struct addrinfo, ai_addr) p nullPtr
150163
(#poke struct addrinfo, ai_canonname) p nullPtr
151164
(#poke struct addrinfo, ai_next) p nullPtr
165+
#else
166+
#endif
152167

153168
-- | Flags that control the querying behaviour of 'getNameInfo'.
154169
-- For more information, see <https://tools.ietf.org/html/rfc3493#page-30>
@@ -176,11 +191,34 @@ data NameInfoFlag =
176191

177192
niFlagMapping :: [(NameInfoFlag, CInt)]
178193

179-
niFlagMapping = [(NI_DGRAM, #const NI_DGRAM),
180-
(NI_NAMEREQD, #const NI_NAMEREQD),
181-
(NI_NOFQDN, #const NI_NOFQDN),
182-
(NI_NUMERICHOST, #const NI_NUMERICHOST),
183-
(NI_NUMERICSERV, #const NI_NUMERICSERV)]
194+
niFlagMapping =
195+
[
196+
#if HAVE_DECL_NI_
197+
(NI_DGRAM, #const NI_DGRAM),
198+
#else
199+
(NI_DGRAM, 0),
200+
#endif
201+
#if HAVE_DECL_NI_NAMEREQD
202+
(NI_NAMEREQD, #const NI_NAMEREQD),
203+
#else
204+
(NI_NAMEREQD, 0),
205+
#endif
206+
#if HAVE_DECL_NI_NOFQDN
207+
(NI_NOFQDN, #const NI_NOFQDN),
208+
#else
209+
(NI_NOFQDN, 0),
210+
#endif
211+
#if HAVE_DECL_NI_NUMERICHOST
212+
(NI_NUMERICHOST, #const NI_NUMERICHOST),
213+
#else
214+
(NI_NUMERICHOST, 0),
215+
#endif
216+
#if HAVE_DECL_NI_NUMERICSERV
217+
(NI_NUMERICSERV, #const NI_NUMERICSERV)
218+
#else
219+
(NI_NUMERICSERV, 0)
220+
#endif
221+
]
184222

185223
-- | Default hints for address lookup with 'getAddrInfo'.
186224
--
@@ -268,6 +306,7 @@ getAddrInfoNE
268306
-> Maybe HostName -- ^ host name to look up
269307
-> Maybe ServiceName -- ^ service name to look up
270308
-> IO (NonEmpty AddrInfo) -- ^ resolved addresses, with "best" first
309+
#if HAVE_GETADDRINFO
271310
getAddrInfoNE hints node service = alloc getaddrinfo
272311
where
273312
alloc body = withSocketsDo $ maybeWith withCString node $ \c_node ->
@@ -308,15 +347,6 @@ getAddrInfoNE hints node service = alloc getaddrinfo
308347
filteredHints = hints
309348
#endif
310349

311-
getAddrInfoList
312-
:: Maybe AddrInfo
313-
-> Maybe HostName
314-
-> Maybe ServiceName
315-
-> IO [AddrInfo]
316-
getAddrInfoList hints node service =
317-
-- getAddrInfo never returns an empty list.
318-
NE.toList <$> getAddrInfoNE hints node service
319-
320350
followAddrInfo :: Ptr AddrInfo -> IO (NonEmpty AddrInfo)
321351
followAddrInfo ptr_ai
322352
-- POSIX requires that getaddrinfo(3) returns at least one addrinfo.
@@ -342,6 +372,10 @@ foreign import ccall safe "hsnet_getaddrinfo"
342372

343373
foreign import ccall safe "hsnet_freeaddrinfo"
344374
c_freeaddrinfo :: Ptr AddrInfo -> IO ()
375+
#else
376+
getAddrInfoNE _ _ _ = unsupported "getAddrInfoNE"
377+
{-# WARNING getAddrInfo "operation will throw 'IOError' \"unsupported operation\"" #-}
378+
#endif
345379

346380
gai_strerror :: CInt -> IO String
347381

@@ -354,6 +388,15 @@ foreign import ccall safe "gai_strerror"
354388
gai_strerror n = ioError $ userError $ "Network.Socket.gai_strerror not supported: " ++ show n
355389
#endif
356390

391+
getAddrInfoList
392+
:: Maybe AddrInfo
393+
-> Maybe HostName
394+
-> Maybe ServiceName
395+
-> IO [AddrInfo]
396+
getAddrInfoList hints node service =
397+
-- getAddrInfo never returns an empty list.
398+
NE.toList <$> getAddrInfoNE hints node service
399+
357400
-----------------------------------------------------------------------------
358401

359402
withCStringIf :: Bool -> Int -> (CSize -> CString -> IO a) -> IO a
@@ -382,6 +425,7 @@ getNameInfo
382425
-> Bool -- ^ whether to look up a service name
383426
-> SockAddr -- ^ the address to look up
384427
-> IO (Maybe HostName, Maybe ServiceName)
428+
#if HAVE_GETNAMEINFO
385429
getNameInfo flags doHost doService addr = alloc getnameinfo
386430
where
387431
alloc body = withSocketsDo $
@@ -423,6 +467,10 @@ getNameInfo flags doHost doService addr = alloc getnameinfo
423467
foreign import ccall safe "hsnet_getnameinfo"
424468
c_getnameinfo :: Ptr SockAddr -> CInt{-CSockLen???-} -> CString -> CSize -> CString
425469
-> CSize -> CInt -> IO CInt
470+
#else
471+
getNameInfo _ _ _ _ = unsupported "getNameInfo"
472+
{-# WARNING getNameInfo "operation will throw 'IOError' \"unsupported operation\"" #-}
473+
#endif
426474

427475
-- | Pack a list of values into a bitmask. The possible mappings from
428476
-- value to bit-to-set are given as the first argument. We assume

Network/Socket/Internal.hs

+3
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ module Network.Socket.Internal
5151
-- * Null socket address type
5252
, NullSockAddr (..)
5353

54+
-- * Unsupported functionality
55+
, unsupported
56+
5457
-- * Low-level helpers
5558
, zeroMemory
5659
) where

Network/Socket/Name.hs

+7
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,18 @@ import Network.Socket.Types
1717

1818
-- | Getting peer's socket address.
1919
getPeerName :: SocketAddress sa => Socket -> IO sa
20+
#ifdef HAVE_GETPEERNAME
2021
getPeerName s =
2122
withNewSocketAddress $ \ptr sz ->
2223
with (fromIntegral sz) $ \int_star -> withFdSocket s $ \fd -> do
2324
throwSocketErrorIfMinus1Retry_ "Network.Socket.getPeerName" $
2425
c_getpeername fd ptr int_star
2526
_sz <- peek int_star
2627
peekSocketAddress ptr
28+
#else
29+
getPeerName _ = unsupported "getPeerName"
30+
{-# WARNING getPeerName "operation will throw 'IOError' \"unsupported operation\"" #-}
31+
#endif
2732

2833
-- | Getting my socket address.
2934
getSocketName :: SocketAddress sa => Socket -> IO sa
@@ -34,8 +39,10 @@ getSocketName s =
3439
c_getsockname fd ptr int_star
3540
peekSocketAddress ptr
3641

42+
#ifdef HAVE_GETPEERNAME
3743
foreign import CALLCONV unsafe "getpeername"
3844
c_getpeername :: CInt -> Ptr sa -> Ptr CInt -> IO CInt
45+
#endif
3946
foreign import CALLCONV unsafe "getsockname"
4047
c_getsockname :: CInt -> Ptr sa -> Ptr CInt -> IO CInt
4148

Network/Socket/Options.hsc

+9-1
Original file line numberDiff line numberDiff line change
@@ -404,12 +404,17 @@ setSockOpt :: Storable a
404404
-> SocketOption
405405
-> a
406406
-> IO ()
407+
#ifdef HAVE_SETSOCKOPT
407408
setSockOpt s (SockOpt level opt) v = do
408409
with v $ \ptr -> void $ do
409410
let sz = fromIntegral $ sizeOf v
410411
withFdSocket s $ \fd ->
411412
throwSocketErrorIfMinus1_ "Network.Socket.setSockOpt" $
412413
c_setsockopt fd level opt ptr sz
414+
#else
415+
setSockOpt _ _ _ = unsupported "setSockOpt"
416+
{-# WARNING setSockOpt "operation will throw 'IOError' \"unsupported operation\"" #-}
417+
#endif
413418

414419
-- | Set a socket option value
415420
--
@@ -474,7 +479,7 @@ getSocketType s = unpackSocketType <$> getSockOpt s Type
474479
#if __GLASGOW_HASKELL__ >= 806
475480
{-# COMPLETE CustomSockOpt #-}
476481
#endif
477-
#ifdef SO_LINGER
482+
478483
-- | Low level @SO_LINGER@ option value, which can be used with 'setSockOpt' or
479484
-- @'setSockOptValue' . 'SockOptValue'@.
480485
data StructLinger = StructLinger {
@@ -486,6 +491,7 @@ data StructLinger = StructLinger {
486491
}
487492
deriving (Eq, Ord, Show)
488493

494+
#ifdef SO_LINGER
489495
instance Storable StructLinger where
490496
sizeOf ~_ = (#const sizeof(struct linger))
491497
alignment ~_ = alignment (0 :: CInt)
@@ -540,5 +546,7 @@ instance Storable SocketTimeout where
540546

541547
foreign import CALLCONV unsafe "getsockopt"
542548
c_getsockopt :: CInt -> CInt -> CInt -> Ptr a -> Ptr CInt -> IO CInt
549+
#ifdef HAVE_SETSOCKOPT
543550
foreign import CALLCONV unsafe "setsockopt"
544551
c_setsockopt :: CInt -> CInt -> CInt -> Ptr a -> CInt -> IO CInt
552+
#endif

0 commit comments

Comments
 (0)