diff options
Diffstat (limited to 'lib/kernel/src/inet.erl')
-rw-r--r-- | lib/kernel/src/inet.erl | 81 |
1 files changed, 56 insertions, 25 deletions
diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl index 41d422d7d4..9211134c75 100644 --- a/lib/kernel/src/inet.erl +++ b/lib/kernel/src/inet.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2014. All Rights Reserved. +%% Copyright Ericsson AB 1997-2015. 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 @@ -690,14 +690,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); @@ -722,10 +723,10 @@ con_opt([Opt | Opts], R, 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); @@ -758,14 +759,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 +793,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 +818,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 +841,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 +851,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 +892,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 +944,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 +969,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 +1078,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 +1265,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 +1306,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; |