detecting closed connections immediately?

17 views
Skip to first unread message

Steven G

unread,
Jul 16, 2008, 1:57:03 PM7/16/08
to MochiWeb
I'm working on an app that uses comet-style long-polls. So far
Mochiweb has worked out well (after a week with it), but I'd really
like to be able to detect when the client closes the GET request.
(The reason is that I can use it to tell if someone is "logged in",
and I'd like to get the "log out" due to them closing a window ASAP,
i.e. without waiting for a time-out).

From my perusal of the Mochiweb code (and I'm an Erlang newbie here,
forgive me), it appears that there is no mechanism for this.

If I understand gen_tcp right, a socket connection can be either
active or passive. If active, then a closed socket will result in a
message being sent to the controlling process. If passive, then the
error will be returned on a recv.

My feature appears to require the socket connection be in active mode,
and to get the closed message passed up to the application. It looks
like by default the listen places the socket in passive mode. And my
Erlang/Mochiweb mojo is not sufficient yet to tell if it is possible
to adapt it without hacking on the mochiweb src.

Has anyone done this? Any hints on how to proceed?

Thanks,
Steven

PS I will be at BayFP tomorrow if anyone wants to chat about Mochiweb/
Erlang experiences.

Steven Grady

unread,
Aug 5, 2008, 6:57:12 PM8/5/08
to moch...@googlegroups.com
I figured out how to do this. It's pretty simple; the only trick is
that active mode http is undocumented, but there are only 5 messages,
equivalent to the passive mode ones:

Passive
{ok, {http_response, Version, Status, Phrase}}
{ok, {http_request, Mth, Uri, Version}}
{ok, {http_header, Bit, Name, IValue, Value}}
{ok, http_eoh}
{error, {http_error, Line}}

Active
{http_response, S, Version, Status, Phrase}
{http_request, S, Meth, Uri, Version}
{http_header, S, Bit, Name, Code, Value}
{http_eoh, S}
{http_error, S, Line}

Change the "gen_tcp:recv()" to "receive" and it's mostly done.

I don't have a patch, because I just modified it to use active mode,
whereas a real patch would give the developer the option of which mode
to use. But let me know if you have any questions.

Steven

PS Oh and BTW, apparently the Erlang developers are planning on
changing the form of the active messages, so anyone who uses active
mode should be aware of that when the next version comes out.

jacky zhao

unread,
Aug 7, 2008, 4:39:14 AM8/7/08
to moch...@googlegroups.com
Hi Steven,

I had tried your method, seems it doesn't fit my senario. Since there are a lot of calls to gen_tcp:recv() in mochiweb_request.erl. But I don't want to change them all. Your words inspire me anyway. I found a new way to do this, need not to chang any code in mochiweb itself.

in inet module's documents, I found these words:
...To make programming easier, a socket where the peer closed and this was detected while in {active, false} mode, will still generate the message {tcp_closed,Socket} when set to {active, once} or {active, true} mode...
So, I tried these lines:

%% mochiweb's callback loop
loop(Req) ->
    %% parse request or what ever
    %% assume we send out something, waiting for response here
    case wait_data(Req) of
        {error, socket_closed} ->
             %% socket has closed, need not response anymore
             ok;
        {error, timeout} ->
             %% perform timeout response, let them call again
             response(Req, timeout);
        {ok, Data} ->
             %% perform data response, and, let them call again
             response(Req, Data)
    end.

wait_data(Req) ->
    Socket = Req:get(socket),
    inet:setopts(Socket, [{active, once}]),
    receive
         {tcp_closed, Socket} ->
             {error, socket_closed};
         Data ->
             {ok, Data}
    after
         ?TimeOut ->
             {error, timeout}
    end.

It's just works fine for me. Hope these helps.

Jackyz
Reply all
Reply to author
Forward
0 new messages