Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
44 changes: 42 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,14 @@
[#509](https://github.com/haskell/network/pull/509)
* Multicast support
[#614](https://github.com/haskell/network/pull/614)
* Watchdog scheme for gracefulClose.
[#620](https://github.com/haskell/network/pull/620)
* gracefulClose waits for the peer's FIN through recvBufWith, which is
one code path on every platform, and drains what arrived before it up
to 128 KiB rather than reading once: data left unread makes close send
RST. It therefore keeps to its timeout on Windows, where
System.Timeout cannot cut a receive short and a peer which stayed open
and silent used to hold the caller for as long as it did. This
replaces the watchdog scheme of
[#620](https://github.com/haskell/network/pull/620).
* Support for getHostName
[#621](https://github.com/haskell/network/pull/621)
* Fixing the misspelled WSAEACCES error description on Windows.
Expand All @@ -17,8 +23,42 @@
[#626](https://github.com/haskell/network/pull/626)
* WINIO: fixing a spurious EOF when a recv completes synchronously.
[#626](https://github.com/haskell/network/pull/626)
* WINIO: raising the ICMP unreachable of a connected datagram socket
rather than taking it as an empty datagram.
* Adding acceptWith, recvWith, recvFromWith, recvBufWith and recvBufFromWith, which take an STM action
beside the operation and let the caller give up on it without closing
the socket or interrupting the thread, and withReadable, which they are
built from.
* Adding isClosedSocketError and isTransientAcceptError, which name what
an accept loop has to tell apart: a socket closed under it, one queued
connection which failed, and the rest.
* On Windows, the Winsock error code is kept in ioe_errno rather than
dropped. Winsock reports every error as OtherError, so the code was
the only thing telling them apart and it was only in the description.
isClosedSocketError and isTransientAcceptError read it, so an accept
loop there now stops when its socket is closed and retries a
connection the peer gave up on.
* On Windows, a datagram socket hears an ICMP unreachable which a send
of its own caused only once it is connected, as on POSIX. Winsock
reports it to every datagram socket, so one reply bouncing off a
client which had gone ended a server's receive loop; socket turns that
off and connect turns it back on.
* The readiness based waitReadSocketSTM and waitWriteSocketSTM cannot
work on Windows, where completion ports report that an operation has
finished rather than that one could be started, and now say so
instead of blocking forever.
* Add unsafeClose
[#629](https://github.com/haskell/network/pull/629)
* Add unsafeGracefulClose and recvMsgWith
* Return the bytes sent from sendMsg on Windows
* Add withWritable, connectWith and the send functions which the caller can give up on
* Raise the error which the first read of recvWith meets, rather than dropping it and waiting
* Add recvBufMsgWith, sendBufMsgWith, the give-up functions of Network.Socket.Address and of Network.Socket.ByteString.Lazy
* On Windows, giving up on an operation no longer cancels other threads' operations on the socket
* recvBufFromWith takes Ptr a, as recvBufFrom does
* Emulate socketPair with TCP over loopback on Windows
[#630](https://github.com/haskell/network/pull/630)
* Add isPortUnreachableError

## Version 3.2.9.0

Expand Down
84 changes: 83 additions & 1 deletion Network/Socket.hs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,9 @@ module Network.Socket (
-- ** Closing
close,
close',
unsafeClose,
gracefulClose,
unsafeGracefulClose,
shutdown,
ShutdownCmd (..),

Expand Down Expand Up @@ -401,7 +403,27 @@ module Network.Socket (
-- * Special constants
maxListenQueue,

-- * STM to check read and write
-- * Event polling
-- $eventpolling

-- ** Giving up on a blocked operation
withReadable,
withWritable,
acceptWith,
connectWith,
recvBufWith,
recvBufFromWith,
sendBufWith,
sendBufToWith,
sendBufMsgWith,
recvBufMsgWith,

-- ** What a given-up operation can fail with
isClosedSocketError,
isTransientAcceptError,
isPortUnreachableError,

-- ** Waiting for readiness (POSIX only)
waitReadSocketSTM,
waitAndCancelReadSocketSTM,
waitWriteSocketSTM,
Expand Down Expand Up @@ -441,8 +463,68 @@ import Network.Socket.SockAddr
import Network.Socket.Syscall hiding (accept, bind, connect)
import Network.Socket.Types
import Network.Socket.Unix
import Network.Socket.Wait (
recvBufFromWith,
isClosedSocketError,
isTransientAcceptError,
isPortUnreachableError,
recvBufWith,
sendBufWith,
withReadable,
withWritable,
)
#if !defined(mingw32_HOST_OS)
import Network.Socket.Posix.Cmsg
#else
import Network.Socket.Win32.Cmsg
#endif

-- $eventpolling
--
-- A thread blocked on a socket is stopped here by being told, not by
-- having the socket closed under it and not by an asynchronous exception
-- thrown into it. Each of 'withReadable', 'acceptWith', 'recvBufWith'
-- and 'recvBufFromWith' takes an 'Control.Concurrent.STM.STM' action
-- beside the operation; whichever settles first decides, 'Left' when the
-- caller gave up and 'Right' when the operation completed, and an
-- operation which has completed wins a tie. They are for one reader at
-- a time, and 'withReadable' says what else they ask of the caller.
-- 'withWritable', 'connectWith', 'sendBufWith' and 'sendBufToWith' do the
-- same for writing, one writer at a time; a stream given up on in the
-- middle of a send is to be closed.
--
-- The other two ways are going away or gone. A close ends a wait only
-- because the event manager tells the waiter so, which 'GHC.Conc.closeFdWith'
-- is to stop doing, and a descriptor number is reused; an asynchronous
-- exception does not reach a thread blocked in a socket call on Windows
-- at all.
--
-- A server loop which is told to stop, rather than having its listening
-- socket closed under it:
--
-- > stopping <- newTVarIO False
-- > -- the shutdown handler runs: atomically $ writeTVar stopping True
-- > let loop = acceptWith sock (check =<< readTVar stopping) >>= \case
-- > Left () -> return ()
-- > Right (conn, _) -> forkIO (serve conn) >> loop
--
-- A receive which gives up on a deadline, where 'System.Timeout.timeout'
-- cannot cut one short:
--
-- > late <- registerDelay (milliseconds * 1000)
-- > r <- recvBufWith s buf size (check =<< readTVar late)
--
-- The 'Control.Concurrent.STM.STM' action is run more than once, so it
-- has to be a test rather than something which takes what it reads.
--
-- Readiness, which these are built from on POSIX, is not available on
-- Windows: completion ports report that an operation finished, not that
-- one could be started. The four readiness functions say so rather than
-- blocking for good, and what runs there instead is the operation itself,
-- on a thread of its own, cancelled with @CancelIoEx@ when the caller
-- gives up. Those for particular operations cancel their own alone,
-- and another thread's operation on the socket carries on; the action
-- given to 'withReadable' or 'withWritable' cannot be told apart, so its
-- cancel ends every operation pending on the socket.
-- "Network.Socket.ByteString" has @recvWith@ and @recvFromWith@ for
-- 'Data.ByteString.ByteString'.
10 changes: 10 additions & 0 deletions Network/Socket/Address.hs
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,35 @@ module Network.Socket.Address (

-- * Socket operations
connect,
connectWith,
bind,
accept,
acceptWith,

-- * Sending and receiving ByteString
sendTo,
sendAllTo,
sendToWith,
recvFrom,
recvWith,
recvFromWith,

-- * Sending and receiving data from a buffer
sendBufTo,
sendBufToWith,
recvBufFrom,
recvBufFromWith,

-- * Advanced IO
sendBufMsg,
sendBufMsgWith,
recvBufMsg,
recvBufMsgWith,
) where

import Network.Socket.Buffer
import Network.Socket.ByteString.IO
import Network.Socket.Name
import Network.Socket.Syscall
import Network.Socket.Types
import Network.Socket.Wait
Loading
Loading