Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Supporting sendMsg and recvMsg. #433

Merged
merged 48 commits into from
Apr 8, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
1ae887f
defining RECV options.
kazu-yamamoto Nov 29, 2019
1fb594e
extending MsgHdr.
kazu-yamamoto Nov 29, 2019
3bca80b
implementing MsgFlag.
kazu-yamamoto Nov 29, 2019
5e79cbf
implementing sendMsg and recvMsg.
kazu-yamamoto Dec 4, 2019
69109a5
implementing Cmsg.
kazu-yamamoto Dec 2, 2019
579b945
implementing Auxiliary.
kazu-yamamoto Dec 3, 2019
54e0892
making recvMsg usable for TCP.
kazu-yamamoto Dec 4, 2019
9d5a69c
adding tests.
kazu-yamamoto Dec 4, 2019
1084502
dropping support for GHC 7.x.
kazu-yamamoto Jan 9, 2020
68f2990
fixing typos: s/auxiliary/ancillary/
kazu-yamamoto Jan 9, 2020
ca7b6ed
adding fields for CmsgHdr.
kazu-yamamoto Jan 9, 2020
367a5aa
deleting outdated comment.
kazu-yamamoto Jan 9, 2020
2e3cfdd
MsgFlag is now a newtype of CInt.
kazu-yamamoto Jan 9, 2020
a52c4df
making Posix directory.
kazu-yamamoto Jan 9, 2020
3d666ce
implementing sendBufMsg and recvBufMsg.
kazu-yamamoto Jan 10, 2020
d5b5d0e
recvMsg now takes Int instead of [Int].
kazu-yamamoto Jan 10, 2020
5aac55f
generalizing sendBufMsg and recvBufMsg.
kazu-yamamoto Jan 10, 2020
58ca30c
implementing sendFd and recvFd on sendBufMsg and recvBufMsg.
kazu-yamamoto Jan 10, 2020
e3c38f8
Semigroup hack for GHC 8.0 and 8.2.
kazu-yamamoto Jan 10, 2020
ef226a8
let Ancillary be a subclass of Storable.
kazu-yamamoto Jan 10, 2020
b1bdfba
pattern synopsis for SocketOption.
kazu-yamamoto Jan 10, 2020
8efb7af
implementing getSockOpt and setSockOpt.
kazu-yamamoto Jan 10, 2020
a19f5af
using getSockOpt for cred.
kazu-yamamoto Jan 10, 2020
5f1cc58
exporting SockOpt.
kazu-yamamoto Jan 10, 2020
77aa0f4
importing getSockOpt.
kazu-yamamoto Jan 10, 2020
1eec5dc
fixing cred again.
kazu-yamamoto Jan 10, 2020
e255097
SocketOption now contains CInt directly.
kazu-yamamoto Jan 14, 2020
f8305c4
renaming: cmsg instead of ancillary
kazu-yamamoto Jan 14, 2020
7ff9f9f
making fields strict.
kazu-yamamoto Jan 14, 2020
b1df8f2
fix for Linux.
kazu-yamamoto Jan 14, 2020
5676bc9
TTL is CInt on Linux.
kazu-yamamoto Jan 14, 2020
5f3706f
Using Int in IPv4PktInfo.
kazu-yamamoto Jan 14, 2020
d040a33
fixing the Storable instance.
kazu-yamamoto Jan 14, 2020
031df10
fixing alignment.
kazu-yamamoto Jan 15, 2020
aef4e42
IPv4PktInfo now contains ipi_spec_dst.
kazu-yamamoto Jan 16, 2020
54f3afc
adding filterCmsg.
kazu-yamamoto Jan 16, 2020
3da86ef
fixing pattern synonym.
kazu-yamamoto Feb 5, 2020
e1a4057
network: Initial implementation
Mistuke Feb 23, 2020
4ae61a3
network: Add explicit cast
Mistuke Feb 23, 2020
834e6ff
First implementation Windows msg
Mistuke Mar 16, 2020
9683add
Fix Win32 linking issues. now need to fixtest failures
Mistuke Mar 16, 2020
fb8529f
Fix bindist missin header
Mistuke Mar 16, 2020
507a2c0
Finish windows implementation
Mistuke Apr 5, 2020
7cc239a
fixing a gap between Unix and Windows.
kazu-yamamoto Apr 8, 2020
f536d35
improving docs and definitions as suggested by vdukhovni.
kazu-yamamoto Apr 8, 2020
3aa7b18
using GHC 8.8.3.
kazu-yamamoto Apr 8, 2020
15193be
improving docs as suggested by vdukhovni.
kazu-yamamoto Apr 8, 2020
f6b1f7c
using GHC 8.6.5.
kazu-yamamoto Apr 8, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ cabal.sandbox.config
.cabal-sandbox
.stack-work/
.ghc.*
.vscode
8 changes: 1 addition & 7 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,6 @@ before_cache:

matrix:
include:
- compiler: "ghc-7.8.4"
# env: TEST=--disable-tests BENCH=--disable-benchmarks
addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-7.8.4], sources: [hvr-ghc]}}
- compiler: "ghc-7.10.3"
# env: TEST=--disable-tests BENCH=--disable-benchmarks
addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-7.10.3], sources: [hvr-ghc]}}
- compiler: "ghc-8.0.2"
# env: TEST=--disable-tests BENCH=--disable-benchmarks
addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.0.2], sources: [hvr-ghc]}}
Expand All @@ -44,7 +38,7 @@ matrix:
- compiler: "ghc-8.6.5"
# env: TEST=--disable-tests BENCH=--disable-benchmarks
addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.6.5], sources: [hvr-ghc]}}
- compiler: "ghc-8.8.1"
- compiler: "ghc-8.8.3"
# env: TEST=--disable-tests BENCH=--disable-benchmarks
addons: {apt: {packages: [ghc-ppa-tools,cabal-install-3.0,ghc-8.8.1], sources: [hvr-ghc]}}
- compiler: "ghc-head"
Expand Down
49 changes: 46 additions & 3 deletions Network/Socket.hs
Original file line number Diff line number Diff line change
Expand Up @@ -131,10 +131,20 @@ module Network.Socket
, ShutdownCmd(..)

-- * Socket options
, SocketOption(..)
, SocketOption(SockOpt
,Debug,ReuseAddr,Type,SoError,DontRoute,Broadcast
,SendBuffer,RecvBuffer,KeepAlive,OOBInline,TimeToLive
,MaxSegment,NoDelay,Cork,Linger,ReusePort
,RecvLowWater,SendLowWater,RecvTimeOut,SendTimeOut
,UseLoopBack,UserTimeout,IPv6Only
,RecvIPv4TTL,RecvIPv4TOS,RecvIPv4PktInfo
,RecvIPv6HopLimit,RecvIPv6TClass,RecvIPv6PktInfo)
, isSupportedSocketOption
, whenSupported
, getSocketOption
, setSocketOption
, getSockOpt
, setSockOpt

-- * Socket
, Socket
Expand Down Expand Up @@ -183,12 +193,14 @@ module Network.Socket
, socketPortSafe
, socketPort

#if !defined(mingw32_HOST_OS)
-- * UNIX-domain socket
, isUnixDomainSocketAvailable
, socketPair
, sendFd
, recvFd
, getPeerCredential
#endif

-- * Name information
, getNameInfo
Expand All @@ -205,14 +217,40 @@ module Network.Socket
, recvBuf
, sendBufTo
, recvBufFrom

-- ** Advanced IO
, sendBufMsg
, recvBufMsg
, MsgFlag(MSG_OOB,MSG_DONTROUTE,MSG_PEEK,MSG_EOR,MSG_TRUNC,MSG_CTRUNC,MSG_WAITALL)
-- ** Control message (ancillary data)
, Cmsg(..)
, CmsgId(CmsgId
,CmsgIdIPv4TTL
,CmsgIdIPv6HopLimit
,CmsgIdIPv4TOS
,CmsgIdIPv6TClass
,CmsgIdIPv4PktInfo
,CmsgIdIPv6PktInfo)
-- ** APIs for control message
, lookupCmsg
, filterCmsg
, decodeCmsg
, encodeCmsg
-- ** Class and yypes for control message
, ControlMessage(..)
, IPv4TTL(..)
, IPv6HopLimit(..)
, IPv4TOS(..)
, IPv6TClass(..)
, IPv4PktInfo(..)
, IPv6PktInfo(..)
-- * Special constants
, maxListenQueue
) where

import Network.Socket.Buffer hiding (sendBufTo, recvBufFrom)
import Network.Socket.Buffer hiding (sendBufTo, recvBufFrom, sendBufMsg, recvBufMsg)
import Network.Socket.Cbits
import Network.Socket.Fcntl
import Network.Socket.Flag
import Network.Socket.Handle
import Network.Socket.If
import Network.Socket.Info
Expand All @@ -223,4 +261,9 @@ import Network.Socket.Shutdown
import Network.Socket.SockAddr
import Network.Socket.Syscall hiding (connect, bind, accept)
import Network.Socket.Types
#if !defined(mingw32_HOST_OS)
import Network.Socket.Posix.Cmsg
import Network.Socket.Unix
#else
import Network.Socket.Win32.Cmsg
#endif
3 changes: 3 additions & 0 deletions Network/Socket/Address.hs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ module Network.Socket.Address (
-- * Sending and receiving data from a buffer
, sendBufTo
, recvBufFrom
-- * Advanced IO
, sendBufMsg
, recvBufMsg
) where

import Network.Socket.ByteString.IO
Expand Down
136 changes: 135 additions & 1 deletion Network/Socket/Buffer.hsc
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,41 @@ module Network.Socket.Buffer (
, recvBufFrom
, recvBuf
, recvBufNoWait
, sendBufMsg
, recvBufMsg
) where

#if !defined(mingw32_HOST_OS)
import Foreign.C.Error (getErrno, eAGAIN, eWOULDBLOCK)
#else
import Foreign.Ptr (nullPtr)
#endif
import Foreign.Marshal.Alloc (alloca)
import Foreign.Marshal.Alloc (alloca, allocaBytes)
import Foreign.Marshal.Utils (with)
import GHC.IO.Exception (IOErrorType(InvalidArgument))
import System.IO.Error (mkIOError, ioeSetErrorString, catchIOError)

#if defined(mingw32_HOST_OS)
import GHC.IO.FD (FD(..), readRawBufferPtr, writeRawBufferPtr)
import Network.Socket.Win32.CmsgHdr
import Network.Socket.Win32.MsgHdr
import Network.Socket.Win32.WSABuf
#else
import Network.Socket.Posix.CmsgHdr
import Network.Socket.Posix.MsgHdr
import Network.Socket.Posix.IOVec
#endif

import Network.Socket.Imports
import Network.Socket.Internal
import Network.Socket.Name
import Network.Socket.Types
import Network.Socket.Flag

#if defined(mingw32_HOST_OS)
type DWORD = Word32
type LPDWORD = Ptr DWORD
#endif

-- | Send data to the socket. The recipient can be specified
-- explicitly, so the socket need not be in a connected state.
Expand Down Expand Up @@ -178,18 +196,134 @@ mkInvalidRecvArgError loc = ioeSetErrorString (mkIOError
InvalidArgument
loc Nothing Nothing) "non-positive length"

-- | Send data to the socket using sendmsg(2).
sendBufMsg :: SocketAddress sa
=> Socket -- ^ Socket
-> sa -- ^ Destination address
-> [(Ptr Word8,Int)] -- ^ Data to be sent
-> [Cmsg] -- ^ Control messages
-> MsgFlag -- ^ Message flags
-> IO Int -- ^ The length actually sent
sendBufMsg s sa bufsizs cmsgs flags = do
sz <- withSocketAddress sa $ \addrPtr addrSize ->
#if !defined(mingw32_HOST_OS)
withIOVec bufsizs $ \(iovsPtr, iovsLen) -> do
#else
withWSABuf bufsizs $ \(wsaBPtr, wsaBLen) -> do
#endif
withCmsgs cmsgs $ \ctrlPtr ctrlLen -> do
let msgHdr = MsgHdr {
msgName = addrPtr
, msgNameLen = fromIntegral addrSize
#if !defined(mingw32_HOST_OS)
, msgIov = iovsPtr
, msgIovLen = fromIntegral iovsLen
#else
, msgBuffer = wsaBPtr
, msgBufferLen = fromIntegral wsaBLen
#endif
, msgCtrl = castPtr ctrlPtr
, msgCtrlLen = fromIntegral ctrlLen
, msgFlags = 0
}
cflags = fromMsgFlag flags
withFdSocket s $ \fd ->
with msgHdr $ \msgHdrPtr ->
throwSocketErrorWaitWrite s "Network.Socket.Buffer.sendMsg" $
#if !defined(mingw32_HOST_OS)
c_sendmsg fd msgHdrPtr cflags
#else
alloca $ \send_ptr ->
c_sendmsg fd msgHdrPtr (fromIntegral cflags) send_ptr nullPtr nullPtr
#endif
return $ fromIntegral sz

-- | Receive data from the socket using recvmsg(2). The supplied
-- buffers are filled in order, with subsequent buffers used only
-- after all the preceding buffers are full. If the message is short
-- enough some of the supplied buffers may remain unused.
recvBufMsg :: SocketAddress sa
=> Socket -- ^ Socket
-> [(Ptr Word8,Int)] -- ^ A list of (buffer, buffer-length) pairs.
-- If the total length is not large enough,
-- 'MSG_TRUNC' is returned
-> Int -- ^ The buffer size for control messages.
-- If the length is not large enough,
-- 'MSG_CTRUNC' is returned
-> MsgFlag -- ^ Message flags
-> IO (sa,Int,[Cmsg],MsgFlag) -- ^ Source address, total bytes received, control messages and message flags
recvBufMsg s bufsizs clen flags = do
withNewSocketAddress $ \addrPtr addrSize ->
allocaBytes clen $ \ctrlPtr ->
#if !defined(mingw32_HOST_OS)
withIOVec bufsizs $ \(iovsPtr, iovsLen) -> do
#else
withWSABuf bufsizs $ \(wsaBPtr, wsaBLen) -> do
#endif
let msgHdr = MsgHdr {
msgName = addrPtr
, msgNameLen = fromIntegral addrSize
#if !defined(mingw32_HOST_OS)
, msgIov = iovsPtr
, msgIovLen = fromIntegral iovsLen
#else
, msgBuffer = wsaBPtr
, msgBufferLen = fromIntegral wsaBLen
#endif
#if !defined(mingw32_HOST_OS)
, msgCtrl = castPtr ctrlPtr
#else
, msgCtrl = if clen == 0 then nullPtr else castPtr ctrlPtr
#endif
, msgCtrlLen = fromIntegral clen
#if !defined(mingw32_HOST_OS)
, msgFlags = 0
#else
, msgFlags = fromIntegral $ fromMsgFlag flags
#endif
}
_cflags = fromMsgFlag flags
withFdSocket s $ \fd -> do
with msgHdr $ \msgHdrPtr -> do
len <- (fmap fromIntegral) <$>
#if !defined(mingw32_HOST_OS)
throwSocketErrorWaitRead s "Network.Socket.Buffer.recvmg" $
c_recvmsg fd msgHdrPtr _cflags
#else
alloca $ \len_ptr -> do
_ <- throwSocketErrorWaitReadBut (== #{const WSAEMSGSIZE}) s "Network.Socket.Buffer.recvmg" $
c_recvmsg fd msgHdrPtr len_ptr nullPtr nullPtr
peek len_ptr
#endif
sockaddr <- peekSocketAddress addrPtr `catchIOError` \_ -> getPeerName s
hdr <- peek msgHdrPtr
cmsgs <- parseCmsgs msgHdrPtr
let flags' = MsgFlag $ fromIntegral $ msgFlags hdr
return (sockaddr, len, cmsgs, flags')

#if !defined(mingw32_HOST_OS)
foreign import ccall unsafe "send"
c_send :: CInt -> Ptr a -> CSize -> CInt -> IO CInt
foreign import ccall unsafe "sendmsg"
c_sendmsg :: CInt -> Ptr (MsgHdr sa) -> CInt -> IO CInt -- fixme CSsize
foreign import ccall unsafe "recvmsg"
c_recvmsg :: CInt -> Ptr (MsgHdr sa) -> CInt -> IO CInt
#else
foreign import CALLCONV SAFE_ON_WIN "ioctlsocket"
c_ioctlsocket :: CInt -> CLong -> Ptr CULong -> IO CInt
foreign import CALLCONV SAFE_ON_WIN "WSAGetLastError"
c_WSAGetLastError :: IO CInt
foreign import CALLCONV SAFE_ON_WIN "WSASendMsg"
-- fixme Handle for SOCKET, see #426
c_sendmsg :: CInt -> Ptr (MsgHdr sa) -> DWORD -> LPDWORD -> Ptr () -> Ptr () -> IO CInt
foreign import CALLCONV SAFE_ON_WIN "WSARecvMsg"
c_recvmsg :: CInt -> Ptr (MsgHdr sa) -> LPDWORD -> Ptr () -> Ptr () -> IO CInt
#endif

foreign import ccall unsafe "recv"
c_recv :: CInt -> Ptr CChar -> CSize -> CInt -> IO CInt
foreign import CALLCONV SAFE_ON_WIN "sendto"
c_sendto :: CInt -> Ptr a -> CSize -> CInt -> Ptr sa -> CInt -> IO CInt
foreign import CALLCONV SAFE_ON_WIN "recvfrom"
c_recvfrom :: CInt -> Ptr a -> CSize -> CInt -> Ptr sa -> Ptr CInt -> IO CInt

6 changes: 5 additions & 1 deletion Network/Socket/ByteString.hs
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,16 @@ module Network.Socket.ByteString
-- * Receive data from a socket
, recv
, recvFrom

-- * Advanced send and recv
, sendMsg
, recvMsg
) where

import Data.ByteString (ByteString)

import Network.Socket.ByteString.IO hiding (sendTo, sendAllTo, recvFrom)
import qualified Network.Socket.ByteString.IO as G
import Network.Socket.ByteString.IO hiding (sendTo, sendAllTo, recvFrom)
import Network.Socket.Types

-- ----------------------------------------------------------------------------
Expand Down
Loading