batman
batman

Reputation: 1447

Erlang gen_tcp:listen/2 for IPv6

I have .NET TCP Sender sending to an Erlang receiver. The .NET component likes to use the IPv6 address ::1 when resolving localhost. I'm not quite sure how to get Erlang to listen on the IPv6 address using gen_tcp. Here's my attempt. Am I telling the wrong socket to do the listening? Thanks!

listen(Config) ->
    PortString = Config#cfg.eventbusport,
    GoodPort = check_int(PortString),
    Port = if GoodPort -> 
               list_to_integer(PortString);
           true ->
               ?DEFAULT_PORT
           end,                      %% IPv6 here --->
    {ok, XSocket} = gen_tcp:listen(Port, [binary, {packet, line}, {active, false}, {reuseaddr, true}, inet6, {ip, {0,0,0,0,0,0,0,1}}])
    end,
    accept(XSocket, Config).

accept(LSocket, Config) ->
    case gen_tcp:accept(LSocket) of
        {ok, Socket} ->
            spawn_link(fun() -> loop(Socket, Config) end),
            accept(LSocket, Config);
        {error, closed} ->
            logger("Accept: Closed socket.",[],1),
            listen(Config)
    end.

loop(Socket, Config) ->
    case inet:setopts(Socket, [{recbuf, 64000}]) of
        ok ->
            case gen_tcp:recv(Socket, 0) of
                {ok, Data} ->
                    SplitData = binary:split(Data,?CRLF,[global]),
                    discrim(SplitData, Config),
                    loop(Socket, Config);
                {error, closed} ->
                    logger("Loop: Closed socket.",[],1),
                    ok
            end;
        {error, Reason} ->
            logger("ERROR: Couldn't set the recbuf to 64k! Because ~p",[Reason],1)
    end.

Upvotes: 2

Views: 1032

Answers (1)

rvirding
rvirding

Reputation: 20916

What is the actual problem you are having?

You should probably set the controlling process of the socket to the process you spawn to use the connection. So in your accept/2 you would do something like:

accept(LSocket, Config) ->
    case gen_tcp:accept(LSocket) of
        {ok, Socket} ->
            Pid = spawn_link(fun() -> loop(Socket, Config) end),
            gen_tcp:controlling_process(Socket, Pid),
            accept(LSocket, Config);
...

Another way of writing the accept loop is too spawn new accept loops instead. You get something like:

accept_loop(LSocket, Config) ->
    {ok,Socket} = gen_tcp:accept(LSocket),
    spawn_link(fun() -> accept_loop(LSocket, Config) end),
    loop(Socket, Config).

This without the error handling. You can pass the listen socket to other processes without problems. Of course, if the process which opened the listen socket dies then the socket is closed.

Upvotes: 1

Related Questions