No subject
Johan Montelius
johan@REDACTED
Tue Mar 14 07:24:06 CET 2006
I encountered this bug while accessing a HTTP server. A GET 1.0 request
resulted in a reply divided
up into several TCP packets. As pointed out by Per Hedland, the last
packet also carried the FIN
flag. It could be that this is part of the problem. The call to
gen_tcp:recv should however return
all data regardless if the FIN flag is in the last data packet or in a
separate packet.
The problem is probably OS-related, I'm running:
Windows XP Professional SP2
Erlang V 5.4.13
I've tried to reconstruct the senario with the tcpbug. Tried to set
{dealy_send, true} on the server
so that the last data segment is buffered and only sent when the socket
was closed. A better
approach woudlof course be to generate the data packet manually.
The server is sending one packet with 1500 bytes, the reciever has a
recbuf of 100 bytes (don't know
how important this is nor why I get 1024 bytes in the first read).
8>tcpbug:cli(3481).
Got 1024 bytes
Got {error,closed}
ok
9> tcpbug:cli(3483).
Got 1024 bytes
Got 476 bytes
Got {error,closed}
ok
10> tcpbug:cli(3485).
Got 1024 bytes
Got 476 bytes
Got {error,closed}
ok
11> tcpbug:cli(3487).
Got 1024 bytes
Got {error,closed}
ok
12> tcpbug:cli(3489).
Got 1024 bytes
Got 476 bytes
Got {error,closed}
ok
13> tcpbug:cli(3491).
Got 1024 bytes
Got 476 bytes
Got {error,closed}
ok
14> tcpbug:cli(3493).
Got 1024 bytes
Got {error,closed}
ok
15>
My guess is that the bug has to do with how the WinSOck API is used.
Looking at the Erlang src
gen_tcp:recv/3 calls inet_db:lookup_socket/1 to see where the socket
belongs or if it is closed ....?
I guess this is where it detects that the socket is closed? If is reports
that the socket is closed
while there is still data in the Erlang socket buffer this is an error.
Afaik, the WinSock API
shoudl not report closed if there is still data in the WinSock buffer.
What happens in erlang:get_port_data/1?
8<------------------------------------------------------------------------
-module(tcpbug).
-export([srv/0, cli/1]).
srv() ->
{ok, S} = gen_tcp:listen(0, [{delay_send, true}]),
{ok, P} = inet:port(S),
io:format("Listen port: ~w~n", [P]),
srv_loop(S).
srv_loop(S) ->
{ok, A} = gen_tcp:accept(S),
gen_tcp:send(A, lists:duplicate(1500, $A)),
gen_tcp:close(A).
cli(P) ->
{ok, S} = gen_tcp:connect("localhost", P,
[list, {recbuf, 100}, {packet,0}, {active, false}]),
cli_loop(S).
cli_loop(S) ->
case gen_tcp:recv(S, 0, 40000) of
{ok, L} ->
io:format("Got ~w bytes~n", [length(L)]),
sleep(500), % parsing...
cli_loop(S);
R ->
io:format("Got ~p~n", [R])
end,
gen_tcp:close(S).
sleep(T) ->
receive
after T ->
ok
end.
--
Johan Montelius
More information about the erlang-bugs
mailing list