aboutsummaryrefslogtreecommitdiffstats
path: root/lib/kernel/src/inet.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/kernel/src/inet.erl')
-rw-r--r--lib/kernel/src/inet.erl137
1 files changed, 87 insertions, 50 deletions
diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl
index 41d422d7d4..c1ae99ea24 100644
--- a/lib/kernel/src/inet.erl
+++ b/lib/kernel/src/inet.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2014. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
%%
%% %CopyrightEnd%
%%
@@ -288,7 +289,7 @@ getifaddrs(Socket) ->
-spec getifaddrs() -> {ok, Iflist} | {error, posix()} when
Iflist :: [{Ifname,[Ifopt]}],
Ifname :: string(),
- Ifopt :: {flag,[Flag]} | {addr,Addr} | {netmask,Netmask}
+ Ifopt :: {flags,[Flag]} | {addr,Addr} | {netmask,Netmask}
| {broadaddr,Broadaddr} | {dstaddr,Dstaddr}
| {hwaddr,Hwaddr},
Flag :: up | broadcast | loopback | pointtopoint
@@ -654,7 +655,7 @@ options() ->
multicast_if, multicast_ttl, multicast_loop,
exit_on_close, high_watermark, low_watermark,
high_msgq_watermark, low_msgq_watermark,
- send_timeout, send_timeout_close
+ send_timeout, send_timeout_close, show_econnreset
].
%% Return a list of statistics options
@@ -670,9 +671,10 @@ stats() ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
connect_options() ->
[tos, priority, reuseaddr, keepalive, linger, sndbuf, recbuf, nodelay,
- header, active, packet, packet_size, buffer, mode, deliver,
+ header, active, packet, packet_size, buffer, mode, deliver, line_delimiter,
exit_on_close, high_watermark, low_watermark, high_msgq_watermark,
- low_msgq_watermark, send_timeout, send_timeout_close, delay_send, raw].
+ low_msgq_watermark, send_timeout, send_timeout_close, delay_send, raw,
+ show_econnreset].
connect_options(Opts, Family) ->
BaseOpts =
@@ -690,14 +692,15 @@ connect_options(Opts, Family) ->
case con_opt(Opts, BaseOpts, connect_options()) of
{ok, R} ->
{ok, R#connect_opts {
+ opts = lists:reverse(R#connect_opts.opts),
ifaddr = translate_ip(R#connect_opts.ifaddr, Family)
}};
Error -> Error
end.
-con_opt([{raw,A,B,C}|Opts],R,As) ->
+con_opt([{raw,A,B,C}|Opts],#connect_opts{} = R,As) ->
con_opt([{raw,{A,B,C}}|Opts],R,As);
-con_opt([Opt | Opts], R, As) ->
+con_opt([Opt | Opts], #connect_opts{} = R, As) ->
case Opt of
{ip,IP} -> con_opt(Opts, R#connect_opts { ifaddr = IP }, As);
{ifaddr,IP} -> con_opt(Opts, R#connect_opts { ifaddr = IP }, As);
@@ -719,13 +722,15 @@ con_opt([Opt | Opts], R, As) ->
{active,N} when is_integer(N), N < 32768, N >= -32768 ->
NOpts = lists:keydelete(active, 1, R#connect_opts.opts),
con_opt(Opts, R#connect_opts { opts = [{active,N}|NOpts] }, As);
+ {line_delimiter,C} when is_integer(C), C >= 0, C =< 255 ->
+ con_add(line_delimiter, C, R, Opts, As);
{Name,Val} when is_atom(Name) -> con_add(Name, Val, R, Opts, As);
_ -> {error, badarg}
end;
-con_opt([], R, _) ->
+con_opt([], #connect_opts{} = R, _) ->
{ok, R}.
-con_add(Name, Val, R, Opts, AllOpts) ->
+con_add(Name, Val, #connect_opts{} = R, Opts, AllOpts) ->
case add_opt(Name, Val, R#connect_opts.opts, AllOpts) of
{ok, SOpts} ->
con_opt(Opts, R#connect_opts { opts = SOpts }, AllOpts);
@@ -740,7 +745,7 @@ listen_options() ->
header, active, packet, buffer, mode, deliver, backlog, ipv6_v6only,
exit_on_close, high_watermark, low_watermark, high_msgq_watermark,
low_msgq_watermark, send_timeout, send_timeout_close, delay_send,
- packet_size, raw].
+ packet_size, raw, show_econnreset].
listen_options(Opts, Family) ->
BaseOpts =
@@ -758,14 +763,15 @@ listen_options(Opts, Family) ->
case list_opt(Opts, BaseOpts, listen_options()) of
{ok, R} ->
{ok, R#listen_opts {
+ opts = lists:reverse(R#listen_opts.opts),
ifaddr = translate_ip(R#listen_opts.ifaddr, Family)
}};
Error -> Error
end.
-list_opt([{raw,A,B,C}|Opts], R, As) ->
+list_opt([{raw,A,B,C}|Opts], #listen_opts{} = R, As) ->
list_opt([{raw,{A,B,C}}|Opts], R, As);
-list_opt([Opt | Opts], R, As) ->
+list_opt([Opt | Opts], #listen_opts{} = R, As) ->
case Opt of
{ip,IP} -> list_opt(Opts, R#listen_opts { ifaddr = IP }, As);
{ifaddr,IP} -> list_opt(Opts, R#listen_opts { ifaddr = IP }, As);
@@ -791,10 +797,10 @@ list_opt([Opt | Opts], R, As) ->
{Name,Val} when is_atom(Name) -> list_add(Name, Val, R, Opts, As);
_ -> {error, badarg}
end;
-list_opt([], R, _SockOpts) ->
+list_opt([], #listen_opts{} = R, _SockOpts) ->
{ok, R}.
-list_add(Name, Val, R, Opts, As) ->
+list_add(Name, Val, #listen_opts{} = R, Opts, As) ->
case add_opt(Name, Val, R#listen_opts.opts, As) of
{ok, SOpts} ->
list_opt(Opts, R#listen_opts { opts = SOpts }, As);
@@ -816,14 +822,15 @@ udp_options(Opts, Family) ->
case udp_opt(Opts, #udp_opts { }, udp_options()) of
{ok, R} ->
{ok, R#udp_opts {
+ opts = lists:reverse(R#udp_opts.opts),
ifaddr = translate_ip(R#udp_opts.ifaddr, Family)
}};
Error -> Error
end.
-udp_opt([{raw,A,B,C}|Opts], R, As) ->
+udp_opt([{raw,A,B,C}|Opts], #udp_opts{} = R, As) ->
udp_opt([{raw,{A,B,C}}|Opts], R, As);
-udp_opt([Opt | Opts], R, As) ->
+udp_opt([Opt | Opts], #udp_opts{} = R, As) ->
case Opt of
{ip,IP} -> udp_opt(Opts, R#udp_opts { ifaddr = IP }, As);
{ifaddr,IP} -> udp_opt(Opts, R#udp_opts { ifaddr = IP }, As);
@@ -838,7 +845,7 @@ udp_opt([Opt | Opts], R, As) ->
BinNS = filename2binary(NS),
case prim_inet:is_sockopt_val(netns, BinNS) of
true ->
- list_opt(Opts, R#udp_opts { fd = [{netns,BinNS}] }, As);
+ udp_opt(Opts, R#udp_opts { fd = [{netns,BinNS}] }, As);
false ->
{error, badarg}
end;
@@ -848,10 +855,10 @@ udp_opt([Opt | Opts], R, As) ->
{Name,Val} when is_atom(Name) -> udp_add(Name, Val, R, Opts, As);
_ -> {error, badarg}
end;
-udp_opt([], R, _SockOpts) ->
+udp_opt([], #udp_opts{} = R, _SockOpts) ->
{ok, R}.
-udp_add(Name, Val, R, Opts, As) ->
+udp_add(Name, Val, #udp_opts{} = R, Opts, As) ->
case add_opt(Name, Val, R#udp_opts.opts, As) of
{ok, SOpts} ->
udp_opt(Opts, R#udp_opts { opts = SOpts }, As);
@@ -889,13 +896,16 @@ sctp_options() ->
sctp_options(Opts, Mod) ->
case sctp_opt(Opts, Mod, #sctp_opts{}, sctp_options()) of
{ok,#sctp_opts{ifaddr=undefined}=SO} ->
- {ok,SO#sctp_opts{ifaddr=Mod:translate_ip(?SCTP_DEF_IFADDR)}};
- {ok,_}=OK ->
- OK;
+ {ok,
+ SO#sctp_opts{
+ opts=lists:reverse(SO#sctp_opts.opts),
+ ifaddr=Mod:translate_ip(?SCTP_DEF_IFADDR)}};
+ {ok,SO} ->
+ {ok,SO#sctp_opts{opts=lists:reverse(SO#sctp_opts.opts)}};
Error -> Error
end.
-sctp_opt([Opt|Opts], Mod, R, As) ->
+sctp_opt([Opt|Opts], Mod, #sctp_opts{} = R, As) ->
case Opt of
{ip,IP} ->
sctp_opt_ifaddr(Opts, Mod, R, As, IP);
@@ -938,7 +948,7 @@ sctp_opt([], _Mod, #sctp_opts{ifaddr=IfAddr}=R, _SockOpts) ->
{ok, R}
end.
-sctp_opt(Opts, Mod, R, As, Name, Val) ->
+sctp_opt(Opts, Mod, #sctp_opts{} = R, As, Name, Val) ->
case add_opt(Name, Val, R#sctp_opts.opts, As) of
{ok,SocketOpts} ->
sctp_opt(Opts, Mod, R#sctp_opts{opts=SocketOpts}, As);
@@ -963,6 +973,8 @@ add_opt(Name, Val, Opts, As) ->
case lists:member(Name, As) of
true ->
case prim_inet:is_sockopt_val(Name, Val) of
+ true when Name =:= raw ->
+ {ok, [{Name,Val} | Opts]};
true ->
Opts1 = lists:keydelete(Name, 1, Opts),
{ok, [{Name,Val} | Opts1]};
@@ -1070,7 +1082,7 @@ gethostbyname_tm(Name, Type, Timer, [wins|_]=Opts) ->
gethostbyname_tm_native(Name, Type, Timer, Opts);
gethostbyname_tm(Name, Type, Timer, [native|_]=Opts) ->
gethostbyname_tm_native(Name, Type, Timer, Opts);
-gethostbyname_tm(Name, Type, Timer, [_|_]=Opts) ->
+gethostbyname_tm(Name, Type, Timer, [_|Opts]) ->
gethostbyname_tm(Name, Type, Timer, Opts);
%% Make sure we always can look up our own hostname.
gethostbyname_tm(Name, Type, Timer, []) ->
@@ -1257,9 +1269,9 @@ open(FdO, Addr, Port, Opts, Protocol, Family, Type, Module)
Error ->
Error
end;
-open(Fd, _Addr, _Port, Opts, Protocol, Family, Type, Module)
+open(Fd, Addr, Port, Opts, Protocol, Family, Type, Module)
when is_integer(Fd) ->
- fdopen(Fd, Opts, Protocol, Family, Type, Module).
+ fdopen(Fd, Addr, Port, Opts, Protocol, Family, Type, Module).
bindx(S, [Addr], Port0) ->
{IP, Port} = set_bindx_port(Addr, Port0),
@@ -1298,12 +1310,35 @@ change_bindx_0_port({_IP, _Port}=Addr, _AssignedPort) ->
{'ok', socket()} | {'error', posix()}.
fdopen(Fd, Opts, Protocol, Family, Type, Module) ->
- case prim_inet:fdopen(Protocol, Family, Type, Fd) of
+ fdopen(Fd, any, 0, Opts, Protocol, Family, Type, Module).
+
+fdopen(Fd, Addr, Port, Opts, Protocol, Family, Type, Module) ->
+ IsAnyAddr = (Addr == {0,0,0,0} orelse Addr == {0,0,0,0,0,0,0,0}
+ orelse Addr == any),
+ Bound = Port == 0 andalso IsAnyAddr,
+ case prim_inet:fdopen(Protocol, Family, Type, Fd, Bound) of
{ok, S} ->
case prim_inet:setopts(S, Opts) of
ok ->
- inet_db:register_socket(S, Module),
- {ok, S};
+ case if
+ Bound ->
+ %% We do not do any binding if default
+ %% port+addr options where given in order
+ %% to keep backwards compatability with
+ %% pre Erlang/TOP 17
+ {ok, ok};
+ is_list(Addr) ->
+ bindx(S, Addr, Port);
+ true ->
+ prim_inet:bind(S, Addr, Port)
+ end of
+ {ok, _} ->
+ inet_db:register_socket(S, Module),
+ {ok, S};
+ Error ->
+ prim_inet:close(S),
+ Error
+ end;
Error ->
prim_inet:close(S), Error
end;
@@ -1504,26 +1539,28 @@ tcp_controlling_process(S, NewOwner) when is_port(S), is_pid(NewOwner) ->
_ ->
case prim_inet:getopt(S, active) of
{ok, A0} ->
- case A0 of
- false -> ok;
- _ -> ok = prim_inet:setopt(S, active, false)
- end,
- case tcp_sync_input(S, NewOwner, false) of
- true -> %% socket already closed,
+ SetOptRes =
+ case A0 of
+ false -> ok;
+ _ -> prim_inet:setopt(S, active, false)
+ end,
+ case {tcp_sync_input(S, NewOwner, false), SetOptRes} of
+ {true, _} -> %% socket already closed
ok;
- false ->
+ {false, ok} ->
try erlang:port_connect(S, NewOwner) of
true ->
unlink(S), %% unlink from port
case A0 of
false -> ok;
- _ -> ok = prim_inet:setopt(S, active, A0)
- end,
- ok
+ _ -> prim_inet:setopt(S, active, A0)
+ end
catch
error:Reason ->
{error, Reason}
- end
+ end;
+ {false, Error} ->
+ Error
end;
Error ->
Error