[erlang-questions] A question on EINVAL in active-mode TCP

Magnus Ottenklinger magnus.ottenklinger@REDACTED
Thu Jun 30 10:58:11 CEST 2016


Hi List.

We stumbled over a peculiarity in the usage of ports in a TCP connection (active mode). Specifically, we encountered `einval` when writing to a socket which was closed just before. Our expectation was that the resulting error should be `{error,closed}`. The following module reproduces this on my machine (OTP 19.0). I ran the test module with `erlc test.erl && erl -s test run -noshell` as well as with `erl -smp disable +A 0 -s test run -noshell`. Both executions triggered `einval`.

-module(test).
-export([run/0]).

run() -> run(0).
run(I) -> io:format("Run ~p~n", [I]), run1(), run(I+1).

run1() ->
    {ok,LSock} = gen_tcp:listen(0, []),
    {ok,Port} = inet:port(LSock),
    spawn_link(
      fun() ->
              {ok,Sock} = gen_tcp:accept(LSock),
              gen_tcp:close(LSock),
              gen_tcp:close(Sock)
      end),

    {ok,Sock} = gen_tcp:connect("localhost", Port, []),
    case gen_tcp:send(Sock, "Hello") of
        ok -> ok;
        {error,closed} -> ok
    end,
    gen_tcp:close(Sock).

Here, the execution stops after about 3800 runs with `{case_clause,{error,einval}}`. It seems weird that the test module usually encounters `{error,closed}`, and only after some time hits `{error,einval}`. This hints at a race condition, but I am unsure if this is instead expected behaviour.

So, finally to the actual question: Should we expect `einval` on active-mode TCP and interpret it as `closed`? Or is this a fixable race condition?

Cheers, Magnus


More information about the erlang-questions mailing list