[Haskell-cafe] Fwd: Safe TCP accept loop

Ömer Sinan Ağacan omeragacan at gmail.com
Wed Oct 25 06:30:03 UTC 2017


Your pseudo code doesn't look right although I couldn't completely understand
it. You need something like this:

  {-# LANGUAGE ScopedTypeVariables #-}

  import Network.Socket
  import Control.Concurrent
  import Control.Exception

  acceptLoop :: Socket -> IO ()
  acceptLoop sock =
      mask_ loop
    where
      loop = do
        -- only safe point in the loop for exceptions
        allowInterrupt

        (connected_sock, _) <- accept sock
        -- use forkIOWithUnmask: we want the thread to be
interruptable no matter
        -- what the inherited masking state is
        _thr_id <- forkIOWithUnmask (handle_conn connected_sock)

        loop

      handle_conn connected_sock unmask =
        -- register cleanup action, run the handler in interruptable state to be
        -- able to kill the thread.
        catch (unmask (handler connected_sock)) (\(_exc ::
SomeException) -> close connected_sock)

      handler connected_sock =
        -- fill here
        return ()


Ömer

2017-10-25 8:52 GMT+03:00 Sumit Raja <sumitraja at gmail.com>:
> Hi Ömer
>
>> You need to mask async exceptions between `accept()` and cleanup action
>> registration, because an exception in between these operations will cause the
>> socket to leak.
>>
>> You can take a look at warp's accept loop:
>>
>> https://github.com/yesodweb/wai/blob/master/warp/Network/Wai/Handler/Warp/Run.hs#L211
>>
>
> Trying to map steps for the code you've pointed me to in bad pseudo code:
>
> finally (mask >> acceptLoop serverSocket) (close serverSocket)
>
> acceptLoop =
>   unmask
>   sock <- accept serverSock
>   mask
>     forkIO $ do
>        mask
>        finally (unmask >> process sock) (close sock)
>   acceptLoop
>
> Is this correct?
>
> Thanks
> Sumit


More information about the Haskell-Cafe mailing list