[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`.


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),
      fun() ->
              {ok,Sock} = gen_tcp:accept(LSock),

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

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