[erlang-questions] eaddrinuse despite {reuseaddr, true}

JD Bothma jbothma@REDACTED
Fri Sep 6 11:44:34 CEST 2013


On 5 September 2013 13:56, Ahmed Omar <spawn.think@REDACTED> wrote:

> Hi JD,
> I think you are maybe confusing reuseadrr or (SO_REUSEADDR) usage in
> general.
>

Yeah, only BSD worked the way I thought and still can't guarantee it
completely. Thanks for the clear response and link!

AFAIK, In most sockets implementations, you can't bind two sockets with the
> same exact source(port/IP)/protocol combination.
> That's not specific to Erlang, but to most used operating systems.
>

> Here's a good read on the topic (specially the table for possible
> combination)
>
> http://stackoverflow.com/questions/14388706/socket-options-so-reuseaddr-and-so-reuseport-how-do-they-differ-do-they-mean-t
>

If this is correct (and it looks pretty well-thought-through) the BSD
implementation should do what I want with SO_REUSEADDR but the linux
implementation won't.

"BSD:... However, if SO_REUSEADDR is set for the socket you are trying to
bind, another socket bound to the same address and port in state TIME_WAIT
is simply ignored, after all its already "half dead", and your socket can
bind to exactly the same address without any problem."
"Linux:... This option behaves generally the as in BSD with two important
exceptions. One exception is that a if a listening (server) TCP socket is
already bound to a wildcard IP address and a specific port, no other TCP
socket can be bound to the same port, regardless whether either one or both
sockets have this flag set. Not even if it would use a more specific
address (as is allowed in case of BSD)."

I can achieve what I want with Linux kernel 3.9+ and SO_REUSEPORT if OTP
supporteds it, but that's irrelevant for my current kernel.

Lukas also mentioned that it could be that the emulator returns on the port
close before the kernel actually puts the socket in TIME_WAIT (if I
understood correctly) and SMP makes it tricky to get serial guarantees on
things like this.

Both the BSD and Linux 3.9 would have potentially confusing behaviour since
the old socket might still be listening when the new socket starts.

In the end, for my application, it's best accept that bind can fail and
keep trying when the application is designed to rebind the port it had
recently and the environment is designed for nothing else to be binding
there.

JD


>
> A simple example to show one scenario of using reuseaddr:
> %Listening on a specific IP and on a wildcard
>
> > {ok, LSock1} = gen_tcp:listen(12345, [{reuseaddr,
> true},{ip,{127,0,0,1}}]).
> {ok,#Port<0.816>}
> > {ok, LSock2} = gen_tcp:listen(12345, [{reuseaddr,
> true},{ip,{0,0,0,0}}]).
> {ok,#Port<0.817>}
> >
>
> %Same without reuseaddr:
>
> >
> > f().
> ok
> > {ok, LSock1} = gen_tcp:listen(12346, [{ip,{127,0,0,1}}]).
>
> {ok,#Port<0.818>}
> > {ok, LSock2} = gen_tcp:listen(12346, [{ip,{0,0,0,0}}]).
> ** exception error: no match of right hand side value {error,eaddrinuse}
>
> So in your case, sometimes it will succeed (if socket got actually closed
> before the next gen_tcp:listen call, and in other times will fail because
> the socket was not yet closed.
>
> Does this answer your question?
>
> Best Regards,
> Ahmed Omar
>
>
>
> On Thu, Sep 5, 2013 at 10:27 AM, JD Bothma <jbothma@REDACTED> wrote:
>
>> On 5 September 2013 09:58, aman mangal <mangalaman93@REDACTED> wrote:
>>
>>>
>>> The error is thrown in the first line. It is returning *{error, **
>>> eaddrinuse}*  (where you are expeciting *{ok, LSock}*) because the port
>>> is already being used by some different process. Two process cannot listen
>>> on the same port at a time.
>>>
>>
>>  It runs for a while, and sometimes gets through all bind/closes, but
>> sometimes crashes mid-way.
>>
>> reuseaddr should be telling the OS that the closing socket may be reused
>> when this process tries to listen on the same port again.
>>
>> No process was listening on this port before the test. This code should
>> be ensuring that the OS allows listening on the socket even when the last
>> close hasn't completely released the socket. Without reuseaddr, we can
>> sometimes expect eaddrinuse because close returns before the socket is
>> guaranteed to be completely released.
>>
>> That's if I haven't misunderstood something. If this code is correct,
>> either something's happening on my machines that I'm not controlling
>> properly or there's a synchronisation bug in the erlang networking code
>> that I'd like to help identify and solve.
>>
>>
>>>  On Thu, Sep 5, 2013 at 1:16 PM, JD Bothma <jbothma@REDACTED> wrote:
>>>
>>>> Why can this sometimes exit with exception error: no match of right
>>>> hand side value {error,eaddrinuse} ?
>>>>
>>>> As far as I know, nothing's connecting to the socket in this time.
>>>>
>>>> [ begin {ok, LSock} = gen_tcp:listen(12345, [{reuseaddr, true}]),
>>>>            {error, timeout} = gen_tcp:accept(LSock, 0),
>>>>            ok = gen_tcp:close(LSock)
>>>>    end
>>>>   || _X <- lists:seq(1, 100000) ].
>>>>
>>>> This is on R14 and 15 on linux and R16 on OS X.
>>>>
>>>> BTW it doesn't seem to happen if I don't accept. I'm debugging this
>>>> behaviour in yaws with SSL but it also seems to happen with plain gen_tcp.
>>>>
>>>> JD
>>>>
>>>> _______________________________________________
>>>> erlang-questions mailing list
>>>> erlang-questions@REDACTED
>>>> http://erlang.org/mailman/listinfo/erlang-questions
>>>>
>>>>
>>>
>>
>> _______________________________________________
>> erlang-questions mailing list
>> erlang-questions@REDACTED
>> http://erlang.org/mailman/listinfo/erlang-questions
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20130906/16dab5d3/attachment.htm>


More information about the erlang-questions mailing list