Jeremy Shaw wrote:
import Control.Concurrent
import Control.Concurrent.MVar
import System.Posix.Types
data RW = Read | Write
threadWaitReadWrite :: Fd -> IO RW
threadWaitReadWrite fd =
do m <- newEmptyMVar
rid <- forkIO $ threadWaitRead fd >> putMVar m Read
wid <- forkIO $ threadWaitWrite fd >> putMVar m Write
r <- takeMVar m
killThread rid
killThread wid
return r
[--snip--]
I've tested this extensively during this weekend and not a single
"leaked" FD so far.
I think we can safely say that polling an FD for read readiness is
sufficient to properly detect a disconnected client regardless of
why/how the client disconnected.
The only issue I can see with just dropping the above code directly into
the sendfile library is that it may lead to busy-waiting on EAGAIN *if*
the client is actually trying to send data to the server while it's
receiving the file via sendfile(). If the client sends even a single
byte and the server isn't reading it from the socket, then
threadWaitRead will keep returning immediately since it's
level-triggered rather than edge triggered.
In the worst case this could be exploited by evil clients as a trivial
way to DoS a server -- simply send data while the server is sending you
a file. Bam, instant 100% CPU utilization on the server.
Not sure what the best solution for this would be, API-wise... Maybe
actually have sendfile read the data and supply it to a user-defined
function which could react to the data in some way? (Could supply two
standard functions: "disconnect immediately" and "accumulate all
received data into a bytestring".)
Cheers,
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe