getServiceByPort, -- :: PortNumber -> ProtocolName -> IO ServiceEntry
getServicePortNumber, -- :: ServiceName -> IO PortNumber
-#ifndef cygwin32_TARGET_OS
+#ifndef _WIN32
getServiceEntry, -- :: IO ServiceEntry
setServiceEntry, -- :: Bool -> IO ()
endServiceEntry, -- :: IO ()
getProtocolByNumber, -- :: ProtocolNumber -> IO ProtcolEntry
getProtocolNumber, -- :: ProtocolName -> ProtocolNumber
-#ifndef cygwin32_TARGET_OS
+#ifndef _WIN32
setProtocolEntry, -- :: Bool -> IO ()
getProtocolEntry, -- :: IO ProtocolEntry
endProtocolEntry, -- :: IO ()
getHostByAddr, -- :: HostAddress -> Family -> IO HostEntry
hostAddress, -- :: HostEntry -> HostAddress
-#ifndef cygwin32_TARGET_OS
+#ifndef _WIN32
setHostEntry, -- :: Bool -> IO ()
getHostEntry, -- :: IO HostEntry
endHostEntry, -- :: IO ()
NetworkName,
NetworkAddr,
NetworkEntry(..)
-#ifndef cygwin32_TARGET_OS
+#ifndef _WIN32
, getNetworkByName -- :: NetworkName -> IO NetworkEntry
, getNetworkByAddr -- :: NetworkAddr -> Family -> IO NetworkEntry
, setNetworkEntry -- :: Bool -> IO ()
(ServiceEntry _ _ port _) <- getServiceByName name "tcp"
return port
-#ifndef cygwin32_TARGET_OS
+#ifndef _WIN32
getServiceEntry :: IO ServiceEntry
getServiceEntry = do
ptr <- _ccall_ getservent
getProtocolByNumber :: ProtocolNumber -> IO ProtocolEntry
getProtocolNumber :: ProtocolName -> IO ProtocolNumber
-#ifndef cygwin32_TARGET_OS
+#ifndef _WIN32
setProtocolEntry :: Bool -> IO () -- Keep DB Open ?
getProtocolEntry :: IO ProtocolEntry -- Next Protocol Entry from DB
endProtocolEntry :: IO ()
(ProtocolEntry _ _ num) <- getProtocolByName proto
return num
-#ifndef cygwin32_TARGET_OS
+#ifndef _WIN32
--getProtocolEntry :: IO ProtocolEntry -- Next Protocol Entry from DB
getProtocolEntry = do
ptr <- _ccall_ getprotoent
then ioError (IOError Nothing NoSuchThing "getHostByAddr" "no such host entry")
else unpackHostEntry ptr
-#ifndef cygwin32_TARGET_OS
+#ifndef _WIN32
getHostEntry :: IO HostEntry
getHostEntry = do
ptr <- _ccall_ gethostent
networkFamily :: Family, -- type
networkAddress :: NetworkAddr
}
-#ifndef cygwin32_TARGET_OS
+#ifndef _WIN32
getNetworkByName :: NetworkName -> IO NetworkEntry
getNetworkByName name = do
ptr <- _ccall_ getnetbyname name
sendTo, -- :: Hostname -> PortID -> String -> IO ()
recvFrom, -- :: Hostname -> PortID -> IO String
- socketPort -- :: Socket -> IO PortID
+ socketPort, -- :: Socket -> IO PortID
+
+ withSocketsDo, -- :: IO a -> IO a
+
+ PortNumber,
+ mkPortNumber -- :: Int -> PortNumber
) where
data PortID =
Service String -- Service Name eg "ftp"
| PortNumber PortNumber -- User defined Port Number
-#ifndef cygwin32_TARGET_OS
+#ifndef _WIN32
| UnixSocket String -- Unix family socket in file system
#endif
connect sock (SockAddrInet port (hostAddress he))
socketToHandle sock ReadWriteMode
-#ifndef cygwin32_TARGET_OS
+#ifndef _WIN32
connectTo _ (UnixSocket path) = do
sock <- socket AF_UNIX Datagram 0
connect sock (SockAddrUnix path)
listen sock maxListenQueue
return sock
-#ifndef cygwin32_TARGET_OS
+#ifndef _WIN32
listenOn (UnixSocket path) = do
sock <- socket AF_UNIX Datagram 0
bindSocket sock (SockAddrUnix path)
portID sa =
case sa of
SockAddrInet port _ -> PortNumber port
-#ifndef cygwin32_TARGET_OS
+#ifndef _WIN32
SockAddrUnix path -> UnixSocket path
#endif
packSocketType,
packSockAddr, unpackSockAddr
+ , withSocketsDo -- :: IO a -> IO a
+
) where
import GlaExts
import PrelIOBase -- IOError, Handle representation
import PrelHandle
import Foreign
+import Addr ( nullAddr )
import IO
import IOExts ( IORef, newIORef, readIORef, writeIORef )
signum n = mkPortNumber (signum (ntohs n))
data SockAddr -- C Names
-#ifndef cygwin32_TARGET_OS
+#if !defined(cygwin32_TARGET_OS) && !defined(mingw32_TARGET_OS)
= SockAddrUnix -- struct sockaddr_un
String -- sun_path
| SockAddrInet -- struct sockaddr_in
-> IO ()
bindSocket (MkSocket s _family _stype _protocol socketStatus) addr = do
-#ifndef cygwin32_TARGET_OS
+#if !defined(cygwin32_TARGET_OS) && !defined(mingw32_TARGET_OS)
let isDomainSocket = if _family == AF_UNIX then 1 else (0::Int)
#else
let isDomainSocket = 0
-> IO ()
connect (MkSocket s _family _stype _protocol socketStatus) addr = do
-#ifndef cygwin32_TARGET_OS
+#ifndef _WIN32
let isDomainSocket = if _family == AF_UNIX then 1 else (0::Int)
#else
let isDomainSocket = 0
| RecvBuffer {- SO_RCVBUF -}
| KeepAlive {- SO_KEEPALIVE -}
| OOBInline {- SO_OOBINLINE -}
+#ifndef _WIN32
| MaxSegment {- TCP_MAXSEG -}
+#endif
| NoDelay {- TCP_NODELAY -}
-- | Linger {- SO_LINGER -}
#if 0
RecvBuffer -> ``SO_RCVBUF''
KeepAlive -> ``SO_KEEPALIVE''
OOBInline -> ``SO_OOBINLINE''
+#ifndef _WIN32
MaxSegment -> ``TCP_MAXSEG''
+#endif
NoDelay -> ``TCP_NODELAY''
#if 0
ReusePort -> ``SO_REUSEPORT'' -- BSD only?
#endif
-#if cygwin32_TARGET_OS
+#if defined(cygwin32_TARGET_OS) || defined(mingw32_TARGET_OS)
data Family =
AF_UNSPEC -- unspecified
-- This is for a box running cygwin32 toolchain.
-#if defined(cygwin32_TARGET_OS)
+#if defined(_WIN32)
data SocketType =
Stream
| Datagram
| Raw
| RDM -- reliably delivered msg
| SeqPacket
- | Packet
deriving (Eq, Ord, Ix, Show)
packSocketType stype =
Raw -> ``SOCK_RAW''
RDM -> ``SOCK_RDM''
SeqPacket -> ``SOCK_SEQPACKET''
- Packet -> ``SOCK_PACKET''
#endif
-------------------------------------------------------------------------------
sIsAcceptable :: Socket -> IO Bool
-#ifndef cygwin32_TARGET_OS
+#if !defined(cygwin32_TARGET_OS) && !defined(mingw32_TARGET_OS)
sIsAcceptable (MkSocket _ AF_UNIX Stream _ status) = do
value <- readIORef status
return (value == Connected || value == Bound || value == Listening)
allocSockAddr :: Family -> IO (MutableByteArray RealWorld Int, Int)
-#ifndef cygwin32_TARGET_OS
+#if !defined(cygwin32_TARGET_OS) && !defined(mingw32_TARGET_OS)
allocSockAddr AF_UNIX = do
ptr <- allocChars ``sizeof(struct sockaddr_un)''
let (_,sz) = boundsOfMutableByteArray ptr
unpackSockAddr arr len = do
fam <- _casm_ ``%r = ((struct sockaddr*)%0)->sa_family;'' arr
case unpackFamily fam of
-#ifndef cygwin32_TARGET_OS
+#if !defined(cygwin32_TARGET_OS) && !defined(mingw32_TARGET_OS)
AF_UNIX -> unpackSockAddrUnix arr (len - ``sizeof(short)'')
#endif
AF_INET -> unpackSockAddrInet arr
-------------------------------------------------------------------------------
-#ifndef cygwin32_TARGET_OS
+#if !defined(cygwin32_TARGET_OS) && !defined(mingw32_TARGET_OS)
{-
sun_path is *not* NULL terminated, hence we *do* need to know the
packSockAddr :: SockAddr -> IO (MutableByteArray RealWorld Int)
-#ifndef cygwin32_TARGET_OS
+#if !defined(cygwin32_TARGET_OS) && !defined(mingw32_TARGET_OS)
packSockAddr (SockAddrUnix path) = do
(ptr,_) <- allocSockAddr AF_UNIX
_casm_ ``(((struct sockaddr_un *)%0)->sun_family) = AF_UNIX;'' ptr
socketToHandle :: Socket -> IOMode -> IO Handle
socketToHandle (MkSocket fd _ _ _ _) m = do
- fileobj <- _ccall_ openFd fd (file_mode::Int) (flush_on_close::Int)
- fo <- mkForeignObj fileobj
- addForeignFinalizer fo (freeFileObject fo)
- mkBuffer__ fo 0 -- not buffered
- hndl <- newHandle (Handle__ fo htype NoBuffering socket_str)
- return hndl
+ fileobj <- _ccall_ openFd fd (file_mode::Int) (file_flags::Int)
+ if fileobj == nullAddr then
+ ioError (userError "socketHandle: Failed to open file desc")
+ else do
+ fo <- mkForeignObj fileobj
+ addForeignFinalizer fo (freeFileObject fo)
+ mkBuffer__ fo 0 -- not buffered
+ hndl <- newHandle (Handle__ fo htype NoBuffering socket_str)
+ return hndl
where
socket_str = "<socket: "++show fd
+#ifdef _WIN32
+ file_flags = flush_on_close + 1024{-I'm a socket fd, me!-}
+#else
+ file_flags = flush_on_close
+#endif
+
(flush_on_close, file_mode) =
case m of
AppendMode -> (1, 0)
#endif
\end{code}
+If you're using WinSock, the programmer has to call a startup
+routine before starting to use the goods. So, if you want to
+stay portable across all ghc-supported platforms, you have to
+use @withSocketsDo@...:
+
+\begin{code}
+withSocketsDo :: IO a -> IO a
+#ifndef _WIN32
+withSocketsDo x = x
+#else
+withSocketsDo act = do
+ x <- initWinSock
+ if ( x /= 0 ) then
+ ioError (userError "Failed to initialise WinSock")
+ else do
+ v <- act
+ shutdownWinSock
+ return v
+
+foreign import "initWinSock" initWinSock :: IO Int
+foreign import "shutdownWinSock" shutdownWinSock :: IO ()
+
+#endif
+
+\end{code}