@@ -11,23 +11,41 @@ module Network.Socket.Buffer (
11
11
, recvBufFrom
12
12
, recvBuf
13
13
, recvBufNoWait
14
+ , sendBufMsg
15
+ , recvBufMsg
14
16
) where
15
17
16
18
#if !defined(mingw32_HOST_OS)
17
19
import Foreign.C.Error (getErrno , eAGAIN , eWOULDBLOCK )
20
+ #else
21
+ import Foreign.Ptr (nullPtr )
18
22
#endif
19
- import Foreign.Marshal.Alloc (alloca )
23
+ import Foreign.Marshal.Alloc (alloca , allocaBytes )
24
+ import Foreign.Marshal.Utils (with )
20
25
import GHC.IO.Exception (IOErrorType (InvalidArgument ))
21
26
import System.IO.Error (mkIOError , ioeSetErrorString , catchIOError )
22
27
23
28
#if defined(mingw32_HOST_OS)
24
29
import GHC.IO.FD (FD (.. ), readRawBufferPtr , writeRawBufferPtr )
30
+ import Network.Socket.Win32.CmsgHdr
31
+ import Network.Socket.Win32.MsgHdr
32
+ import Network.Socket.Win32.WSABuf
33
+ #else
34
+ import Network.Socket.Posix.CmsgHdr
35
+ import Network.Socket.Posix.MsgHdr
36
+ import Network.Socket.Posix.IOVec
25
37
#endif
26
38
27
39
import Network.Socket.Imports
28
40
import Network.Socket.Internal
29
41
import Network.Socket.Name
30
42
import Network.Socket.Types
43
+ import Network.Socket.Flag
44
+
45
+ #if defined(mingw32_HOST_OS)
46
+ type DWORD = Word32
47
+ type LPDWORD = Ptr DWORD
48
+ #endif
31
49
32
50
-- | Send data to the socket. The recipient can be specified
33
51
-- explicitly, so the socket need not be in a connected state.
@@ -178,18 +196,134 @@ mkInvalidRecvArgError loc = ioeSetErrorString (mkIOError
178
196
InvalidArgument
179
197
loc Nothing Nothing ) " non-positive length"
180
198
199
+ -- | Send data to the socket using sendmsg(2).
200
+ sendBufMsg :: SocketAddress sa
201
+ => Socket -- ^ Socket
202
+ -> sa -- ^ Destination address
203
+ -> [(Ptr Word8 ,Int )] -- ^ Data to be sent
204
+ -> [Cmsg ] -- ^ Control messages
205
+ -> MsgFlag -- ^ Message flags
206
+ -> IO Int -- ^ The length actually sent
207
+ sendBufMsg s sa bufsizs cmsgs flags = do
208
+ sz <- withSocketAddress sa $ \ addrPtr addrSize ->
209
+ #if !defined(mingw32_HOST_OS)
210
+ withIOVec bufsizs $ \ (iovsPtr, iovsLen) -> do
211
+ #else
212
+ withWSABuf bufsizs $ \ (wsaBPtr, wsaBLen) -> do
213
+ #endif
214
+ withCmsgs cmsgs $ \ ctrlPtr ctrlLen -> do
215
+ let msgHdr = MsgHdr {
216
+ msgName = addrPtr
217
+ , msgNameLen = fromIntegral addrSize
218
+ #if !defined(mingw32_HOST_OS)
219
+ , msgIov = iovsPtr
220
+ , msgIovLen = fromIntegral iovsLen
221
+ #else
222
+ , msgBuffer = wsaBPtr
223
+ , msgBufferLen = fromIntegral wsaBLen
224
+ #endif
225
+ , msgCtrl = castPtr ctrlPtr
226
+ , msgCtrlLen = fromIntegral ctrlLen
227
+ , msgFlags = 0
228
+ }
229
+ cflags = fromMsgFlag flags
230
+ withFdSocket s $ \ fd ->
231
+ with msgHdr $ \ msgHdrPtr ->
232
+ throwSocketErrorWaitWrite s " Network.Socket.Buffer.sendMsg" $
233
+ #if !defined(mingw32_HOST_OS)
234
+ c_sendmsg fd msgHdrPtr cflags
235
+ #else
236
+ alloca $ \ send_ptr ->
237
+ c_sendmsg fd msgHdrPtr (fromIntegral cflags) send_ptr nullPtr nullPtr
238
+ #endif
239
+ return $ fromIntegral sz
240
+
241
+ -- | Receive data from the socket using recvmsg(2). The supplied
242
+ -- buffers are filled in order, with subsequent buffers used only
243
+ -- after all the preceding buffers are full. If the message is short
244
+ -- enough some of the supplied buffers may remain unused.
245
+ recvBufMsg :: SocketAddress sa
246
+ => Socket -- ^ Socket
247
+ -> [(Ptr Word8 ,Int )] -- ^ A list of (buffer, buffer-length) pairs.
248
+ -- If the total length is not large enough,
249
+ -- 'MSG_TRUNC' is returned
250
+ -> Int -- ^ The buffer size for control messages.
251
+ -- If the length is not large enough,
252
+ -- 'MSG_CTRUNC' is returned
253
+ -> MsgFlag -- ^ Message flags
254
+ -> IO (sa ,Int ,[Cmsg ],MsgFlag ) -- ^ Source address, total bytes received, control messages and message flags
255
+ recvBufMsg s bufsizs clen flags = do
256
+ withNewSocketAddress $ \ addrPtr addrSize ->
257
+ allocaBytes clen $ \ ctrlPtr ->
258
+ #if !defined(mingw32_HOST_OS)
259
+ withIOVec bufsizs $ \ (iovsPtr, iovsLen) -> do
260
+ #else
261
+ withWSABuf bufsizs $ \ (wsaBPtr, wsaBLen) -> do
262
+ #endif
263
+ let msgHdr = MsgHdr {
264
+ msgName = addrPtr
265
+ , msgNameLen = fromIntegral addrSize
266
+ #if !defined(mingw32_HOST_OS)
267
+ , msgIov = iovsPtr
268
+ , msgIovLen = fromIntegral iovsLen
269
+ #else
270
+ , msgBuffer = wsaBPtr
271
+ , msgBufferLen = fromIntegral wsaBLen
272
+ #endif
273
+ #if !defined(mingw32_HOST_OS)
274
+ , msgCtrl = castPtr ctrlPtr
275
+ #else
276
+ , msgCtrl = if clen == 0 then nullPtr else castPtr ctrlPtr
277
+ #endif
278
+ , msgCtrlLen = fromIntegral clen
279
+ #if !defined(mingw32_HOST_OS)
280
+ , msgFlags = 0
281
+ #else
282
+ , msgFlags = fromIntegral $ fromMsgFlag flags
283
+ #endif
284
+ }
285
+ _cflags = fromMsgFlag flags
286
+ withFdSocket s $ \ fd -> do
287
+ with msgHdr $ \ msgHdrPtr -> do
288
+ len <- (fmap fromIntegral ) <$>
289
+ #if !defined(mingw32_HOST_OS)
290
+ throwSocketErrorWaitRead s " Network.Socket.Buffer.recvmg" $
291
+ c_recvmsg fd msgHdrPtr _cflags
292
+ #else
293
+ alloca $ \ len_ptr -> do
294
+ _ <- throwSocketErrorWaitReadBut (== # {const WSAEMSGSIZE }) s " Network.Socket.Buffer.recvmg" $
295
+ c_recvmsg fd msgHdrPtr len_ptr nullPtr nullPtr
296
+ peek len_ptr
297
+ #endif
298
+ sockaddr <- peekSocketAddress addrPtr `catchIOError` \ _ -> getPeerName s
299
+ hdr <- peek msgHdrPtr
300
+ cmsgs <- parseCmsgs msgHdrPtr
301
+ let flags' = MsgFlag $ fromIntegral $ msgFlags hdr
302
+ return (sockaddr, len, cmsgs, flags')
303
+
181
304
#if !defined(mingw32_HOST_OS)
182
305
foreign import ccall unsafe " send"
183
306
c_send :: CInt -> Ptr a -> CSize -> CInt -> IO CInt
307
+ foreign import ccall unsafe " sendmsg"
308
+ c_sendmsg :: CInt -> Ptr (MsgHdr sa ) -> CInt -> IO CInt -- fixme CSsize
309
+ foreign import ccall unsafe " recvmsg"
310
+ c_recvmsg :: CInt -> Ptr (MsgHdr sa ) -> CInt -> IO CInt
184
311
#else
185
312
foreign import CALLCONV SAFE_ON_WIN " ioctlsocket"
186
313
c_ioctlsocket :: CInt -> CLong -> Ptr CULong -> IO CInt
187
314
foreign import CALLCONV SAFE_ON_WIN " WSAGetLastError"
188
315
c_WSAGetLastError :: IO CInt
316
+ foreign import CALLCONV SAFE_ON_WIN " WSASendMsg"
317
+ -- fixme Handle for SOCKET, see #426
318
+ c_sendmsg :: CInt -> Ptr (MsgHdr sa ) -> DWORD -> LPDWORD -> Ptr () -> Ptr () -> IO CInt
319
+ foreign import CALLCONV SAFE_ON_WIN " WSARecvMsg"
320
+ c_recvmsg :: CInt -> Ptr (MsgHdr sa ) -> LPDWORD -> Ptr () -> Ptr () -> IO CInt
189
321
#endif
322
+
190
323
foreign import ccall unsafe " recv"
191
324
c_recv :: CInt -> Ptr CChar -> CSize -> CInt -> IO CInt
192
325
foreign import CALLCONV SAFE_ON_WIN " sendto"
193
326
c_sendto :: CInt -> Ptr a -> CSize -> CInt -> Ptr sa -> CInt -> IO CInt
194
327
foreign import CALLCONV SAFE_ON_WIN " recvfrom"
195
328
c_recvfrom :: CInt -> Ptr a -> CSize -> CInt -> Ptr sa -> Ptr CInt -> IO CInt
329
+
0 commit comments