Skip to content

Commit

Permalink
Merge PR haskell#424
Browse files Browse the repository at this point in the history
  • Loading branch information
kazu-yamamoto committed Sep 17, 2019
2 parents f853afe + 27d9815 commit f1f6356
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 0 deletions.
1 change: 1 addition & 0 deletions Network/Socket.hs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ module Network.Socket
, withFdSocket
, unsafeFdSocket
, touchSocket
, socketToFd
, fdSocket
, mkSocket
, socketToHandle
Expand Down
28 changes: 28 additions & 0 deletions Network/Socket/Types.hsc
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ module Network.Socket.Types (
, withFdSocket
, unsafeFdSocket
, touchSocket
, socketToFd
, fdSocket
, mkSocket
, invalidateSocket
Expand Down Expand Up @@ -166,6 +167,33 @@ withFdSocket (Socket ref _) f = do
touch ref
return r

-- | Socket is closed and a duplicated file descriptor is returned.
-- The duplicated descriptor is no longer subject to the possibility
-- of unexpectedly being closed if the socket is finalized. It is
-- now the caller's responsibility to ultimately close the
-- duplicated file descriptor.
socketToFd :: Socket -> IO CInt
socketToFd s = do
#if defined(mingw32_HOST_OS)
fd <- unsafeFdSocket s
fd2 <- c_wsaDuplicate fd
-- FIXME: throw error no if -1
close s
return fd2

foreign import ccall unsafe "wsaDuplicate"
c_wsaDuplicate :: CInt -> IO CInt
#else
fd <- unsafeFdSocket s
-- FIXME: throw error no if -1
fd2 <- c_dup fd
close s
return fd2

foreign import ccall unsafe "dup"
c_dup :: CInt -> IO CInt
#endif

-- | Creating a socket from a file descriptor.
mkSocket :: CInt -> IO Socket
mkSocket fd = do
Expand Down
15 changes: 15 additions & 0 deletions cbits/initWinSock.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,19 @@ initWinSock ()
return 0;
}

SOCKET
wsaDuplicate (SOCKET s)
{
WSAPROTOCOL_INFOW protocolInfo;
if (WSADuplicateSocketW (s, GetCurrentProcessId (), &protocolInfo) != 0)
return -1;

SOCKET res = WSASocketW(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO,
FROM_PROTOCOL_INFO, &protocolInfo, 0, 0);
if (res == SOCKET_ERROR)
return -1;

return res;
}

#endif
10 changes: 10 additions & 0 deletions tests/Network/SocketSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -209,3 +209,13 @@ spec = do
threadDelay 10000
void $ recv sock 1024
tcpTest client server

describe "socketToFd" $ do
it "socketToFd can send using fd" $ do
let server sock = do
void $ recv sock 1024
client sock = do
fd <- socketToFd sock
s <- mkSocket fd
sendAll s "HELLO WORLD"
tcpTest client server

0 comments on commit f1f6356

Please sign in to comment.