<div dir="ltr"><div><div><div>Hi,<br><br></div>It seems that file:sendfile/5 in some situations corrupts or unexpectedly closes the socket it uses. I stumbled up on this while using Elli, a small but flexible http server (<a href="https://github.com/knutin/elli">https://github.com/knutin/elli</a>).<br>
<br></div><div>The issue manifests itself when some clients are making single requests (ie. they close the socket after receiving a response) in a short timespan, where the response is a file send back to the clients, using file:sendfile/5. Once in a while, after an acceptor has responded and tries to reuse the connection and calls gen_tcp:recv/3 again, instead of receiving {error, closed}, it receives {error, ebadf}<br>
</div><div><br></div>I created a small example, that imitates Elli's tcp acceptor loop, without all the http parsing stuff. When running this example I can reliably reproduce this issue on two systems.<br><br></div>System one is a dual core Mac Book Pro, running Ubuntu 13.10 and Erlang 16B03. System two is single core VMWare VM, running Ubuntu 12.04 LTS and Erlang 15B03. I tried different async-thread settings on both systems (also disabling async-threads altogether, by using +A 0), which doesn't seem to make a difference.<br>
<div><div><div><div><br>I published the example as a gist at github, which can be found here: <a href="https://gist.github.com/zambal/7927631">https://gist.github.com/zambal/7927631</a><br><br></div><div>In my example, sendfile:server/0 creates a listener, with {active, false} and spawns 10 processes as acceptors on that listening socket. sendfile:clients/0 spawns 50 clients that are all performing a single request, after which they close the connection.<br>
<br></div><div>If you run the example and no {error, ebadf} manifests itself, you can uncomment the timer:sleep(100) call on line 34, as that seems to make it more likely that the error will popup. Note also that you can replace the sendfile call with an alternative implementation that uses file:read_file and gen_tcp:send, by changing the <span class="">sendfile</span><span class="">(</span><span class="">Socket</span><span class="">,</span> <span class="">Path</span><span class="">) call with </span><span class="">sendfile2</span><span class="">(</span><span class="">Socket</span><span class="">,</span> <span class="">Path</span><span class="">) on line 32. Using the alternative implementation, I can not reproduce the issue and everything seems to work as expected.<br>
<br><br></span></div><div><span class="">-vincent</span></div></div></div></div></div>