@@ -11,7 +11,7 @@ module Network.Socket.Shutdown (
11
11
import qualified Control.Exception as E
12
12
import Foreign.Marshal.Alloc (mallocBytes , free )
13
13
14
- import Control.Concurrent (threadDelay )
14
+ import Control.Concurrent (threadDelay , yield )
15
15
16
16
import Network.Socket.Buffer
17
17
import Network.Socket.Imports
@@ -47,31 +47,31 @@ foreign import CALLCONV unsafe "shutdown"
47
47
--
48
48
-- Since: 3.1.1.0
49
49
gracefulClose :: Socket -> Int -> IO ()
50
- gracefulClose s tmout = sendRecvFIN `E.finally` close s
50
+ gracefulClose s tmout0 = sendRecvFIN `E.finally` close s
51
51
where
52
52
sendRecvFIN = do
53
53
-- Sending TCP FIN.
54
54
ex <- E. try $ shutdown s ShutdownSend
55
55
case ex of
56
56
Left (E. SomeException _) -> return ()
57
57
Right () -> do
58
+ -- Giving CPU time to other threads hoping that
59
+ -- FIN arrives meanwhile.
60
+ yield
58
61
-- Waiting TCP FIN.
59
62
E. bracket (mallocBytes bufSize) free recvEOFloop
60
- -- milliseconds. Taken from BSD fast clock value.
61
- clock = 200
62
- recvEOFloop buf = loop 0
63
+ recvEOFloop buf = loop 1 0
63
64
where
64
- loop delay = do
65
+ loop delay tmout = do
65
66
-- We don't check the (positive) length.
66
67
-- In normal case, it's 0. That is, only FIN is received.
67
68
-- In error cases, data is available. But there is no
68
69
-- application which can read it. So, let's stop receiving
69
70
-- to prevent attacks.
70
71
r <- recvBufNoWait s buf bufSize
71
- let delay' = delay + clock
72
- when (r == - 1 && delay' < tmout) $ do
73
- threadDelay (clock * 1000 )
74
- loop delay'
72
+ when (r == - 1 && tmout < tmout0) $ do
73
+ threadDelay (delay * 1000 )
74
+ loop (delay * 2 ) (tmout + delay)
75
75
-- Don't use 4092 here. The GHC runtime takes the global lock
76
76
-- if the length is over 3276 bytes in 32bit or 3272 bytes in 64bit.
77
77
bufSize = 1024
0 commit comments