diff options
Diffstat (limited to 'lib/kernel/src')
-rw-r--r-- | lib/kernel/src/file_io_server.erl | 122 | ||||
-rw-r--r-- | lib/kernel/src/inet.erl | 18 | ||||
-rw-r--r-- | lib/kernel/src/inet6_tcp.erl | 19 | ||||
-rw-r--r-- | lib/kernel/src/inet6_tcp_dist.erl | 365 | ||||
-rw-r--r-- | lib/kernel/src/inet_db.erl | 38 | ||||
-rw-r--r-- | lib/kernel/src/inet_dns_record_adts.pl | 6 | ||||
-rw-r--r-- | lib/kernel/src/inet_int.hrl | 1 | ||||
-rw-r--r-- | lib/kernel/src/inet_tcp.erl | 16 | ||||
-rw-r--r-- | lib/kernel/src/inet_tcp_dist.erl | 157 | ||||
-rw-r--r-- | lib/kernel/src/kernel.appup.src | 4 |
10 files changed, 252 insertions, 494 deletions
diff --git a/lib/kernel/src/file_io_server.erl b/lib/kernel/src/file_io_server.erl index bf8b9e2747..deb7b315b1 100644 --- a/lib/kernel/src/file_io_server.erl +++ b/lib/kernel/src/file_io_server.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2013. All Rights Reserved. +%% Copyright Ericsson AB 2000-2015. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -206,8 +206,8 @@ io_reply(From, ReplyAs, Reply) -> file_request({advise,Offset,Length,Advise}, #state{handle=Handle}=State) -> case ?PRIM_FILE:advise(Handle, Offset, Length, Advise) of - {error,_}=Reply -> - {stop,normal,Reply,State}; + {error,Reason}=Reply -> + {stop,Reason,Reply,State}; Reply -> {reply,Reply,State} end; @@ -215,62 +215,91 @@ file_request({allocate, Offset, Length}, #state{handle = Handle} = State) -> Reply = ?PRIM_FILE:allocate(Handle, Offset, Length), {reply, Reply, State}; +file_request({pread,At,Sz}, State) + when At =:= cur; + At =:= {cur,0} -> + case get_chars(Sz, latin1, State) of + {reply,Reply,NewState} + when is_list(Reply); + is_binary(Reply) -> + {reply,{ok,Reply},NewState}; + Other -> + Other + end; file_request({pread,At,Sz}, - #state{handle=Handle,buf=Buf,read_mode=ReadMode}=State) -> + #state{handle=Handle,buf=Buf}=State) -> case position(Handle, At, Buf) of - {ok,_Offs} -> - case ?PRIM_FILE:read(Handle, Sz) of - {ok,Bin} when ReadMode =:= list -> - std_reply({ok,binary_to_list(Bin)}, State); - Reply -> - std_reply(Reply, State) - end; - Reply -> - std_reply(Reply, State) + {error,_} = Reply -> + {error,Reply,State}; + _ -> + case get_chars(Sz, latin1, State#state{buf= <<>>}) of + {reply,Reply,NewState} + when is_list(Reply); + is_binary(Reply) -> + {reply,{ok,Reply},NewState}; + Other -> + Other + end end; +file_request({pwrite,At,Data}, + #state{buf= <<>>}=State) + when At =:= cur; + At =:= {cur,0} -> + put_chars(Data, latin1, State); file_request({pwrite,At,Data}, #state{handle=Handle,buf=Buf}=State) -> case position(Handle, At, Buf) of - {ok,_Offs} -> - std_reply(?PRIM_FILE:write(Handle, Data), State); - Reply -> - std_reply(Reply, State) + {error,_} = Reply -> + {error,Reply,State}; + _ -> + put_chars(Data, latin1, State) end; file_request(datasync, #state{handle=Handle}=State) -> case ?PRIM_FILE:datasync(Handle) of - {error,_}=Reply -> - {stop,normal,Reply,State}; + {error,Reason}=Reply -> + {stop,Reason,Reply,State}; Reply -> {reply,Reply,State} end; file_request(sync, #state{handle=Handle}=State) -> case ?PRIM_FILE:sync(Handle) of - {error,_}=Reply -> - {stop,normal,Reply,State}; + {error,Reason}=Reply -> + {stop,Reason,Reply,State}; Reply -> {reply,Reply,State} end; file_request(close, #state{handle=Handle}=State) -> - {stop,normal,?PRIM_FILE:close(Handle),State#state{buf= <<>>}}; + case ?PRIM_FILE:close(Handle) of + {error,Reason}=Reply -> + {stop,Reason,Reply,State#state{buf= <<>>}}; + Reply -> + {stop,normal,Reply,State#state{buf= <<>>}} + end; file_request({position,At}, #state{handle=Handle,buf=Buf}=State) -> - std_reply(position(Handle, At, Buf), State); + case position(Handle, At, Buf) of + {error,_} = Reply -> + {error,Reply,State}; + Reply -> + std_reply(Reply, State) + end; file_request(truncate, #state{handle=Handle}=State) -> case ?PRIM_FILE:truncate(Handle) of - {error,_Reason}=Reply -> - {stop,normal,Reply,State#state{buf= <<>>}}; + {error,Reason}=Reply -> + {stop,Reason,Reply,State#state{buf= <<>>}}; Reply -> - {reply,Reply,State} + std_reply(Reply, State) end; file_request(Unknown, #state{}=State) -> Reason = {request, Unknown}, {error,{error,Reason},State}. +%% Standard reply and clear buffer std_reply({error,_}=Reply, State) -> {error,Reply,State#state{buf= <<>>}}; std_reply(Reply, State) -> @@ -286,8 +315,8 @@ io_request({put_chars, Enc, Chars}, io_request({put_chars, Enc, Chars}, #state{handle=Handle,buf=Buf}=State) -> case position(Handle, cur, Buf) of - {error,_}=Reply -> - {stop,normal,Reply,State#state{buf= <<>>}}; + {error,Reason}=Reply -> + {stop,Reason,Reply,State}; _ -> put_chars(Chars, Enc, State#state{buf= <<>>}) end; @@ -368,23 +397,27 @@ io_request_loop([Request|Tail], %% I/O request put_chars %% put_chars(Chars, latin1, #state{handle=Handle, unic=latin1}=State) -> + NewState = State#state{buf = <<>>}, case ?PRIM_FILE:write(Handle, Chars) of - {error,_}=Reply -> - {stop,normal,Reply,State}; + {error,Reason}=Reply -> + {stop,Reason,Reply,NewState}; Reply -> - {reply,Reply,State} + {reply,Reply,NewState} end; put_chars(Chars, InEncoding, #state{handle=Handle, unic=OutEncoding}=State) -> + NewState = State#state{buf = <<>>}, case unicode:characters_to_binary(Chars,InEncoding,OutEncoding) of Bin when is_binary(Bin) -> case ?PRIM_FILE:write(Handle, Bin) of - {error,_}=Reply -> - {stop,normal,Reply,State}; + {error,Reason}=Reply -> + {stop,Reason,Reply,NewState}; Reply -> - {reply,Reply,State} + {reply,Reply,NewState} end; {error,_,_} -> - {stop,normal,{error,{no_translation, InEncoding, OutEncoding}},State} + {stop,no_translation, + {error,{no_translation, InEncoding, OutEncoding}}, + NewState} end. get_line(S, {<<>>, Cont}, OutEnc, @@ -884,11 +917,14 @@ cbv({utf32,little},_) -> %% Compensates ?PRIM_FILE:position/2 for the number of bytes %% we have buffered - -position(Handle, cur, Buf) -> - position(Handle, {cur, 0}, Buf); -position(Handle, {cur, Offs}, Buf) when is_binary(Buf) -> - ?PRIM_FILE:position(Handle, {cur, Offs-byte_size(Buf)}); -position(Handle, At, _Buf) -> - ?PRIM_FILE:position(Handle, At). - +position(Handle, At, Buf) -> + ?PRIM_FILE:position( + Handle, + case At of + cur -> + {cur, -byte_size(Buf)}; + {cur, Offs} -> + {cur, Offs-byte_size(Buf)}; + _ -> + At + end). diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl index da7f04089d..b573112445 100644 --- a/lib/kernel/src/inet.erl +++ b/lib/kernel/src/inet.erl @@ -671,7 +671,7 @@ 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, show_econnreset]. @@ -692,6 +692,7 @@ 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 @@ -721,6 +722,8 @@ con_opt([Opt | Opts], #connect_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; @@ -760,6 +763,7 @@ 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 @@ -818,6 +822,7 @@ 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 @@ -891,9 +896,12 @@ 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. @@ -965,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]}; diff --git a/lib/kernel/src/inet6_tcp.erl b/lib/kernel/src/inet6_tcp.erl index 2ea017285c..1978307b3c 100644 --- a/lib/kernel/src/inet6_tcp.erl +++ b/lib/kernel/src/inet6_tcp.erl @@ -25,10 +25,29 @@ -export([controlling_process/2]). -export([fdopen/2]). +-export([family/0, mask/2, parse_address/1]). -export([getserv/1, getaddr/1, getaddr/2, getaddrs/1, getaddrs/2]). -include("inet_int.hrl"). +%% my address family +family() -> inet6. + +%% Apply netmask on address +mask({M1,M2,M3,M4,M5,M6,M7,M8}, {IP1,IP2,IP3,IP4,IP5,IP6,IP7,IP8}) -> + {M1 band IP1, + M2 band IP2, + M3 band IP3, + M4 band IP4, + M5 band IP5, + M6 band IP6, + M7 band IP7, + M8 band IP8 }. + +%% Parse address string +parse_address(Host) -> + inet_parse:ipv6strict_address(Host). + %% inet_tcp port lookup getserv(Port) when is_integer(Port) -> {ok, Port}; getserv(Name) when is_atom(Name) -> inet:getservbyname(Name,tcp). diff --git a/lib/kernel/src/inet6_tcp_dist.erl b/lib/kernel/src/inet6_tcp_dist.erl index a74a4916ba..3ab7f269bb 100644 --- a/lib/kernel/src/inet6_tcp_dist.erl +++ b/lib/kernel/src/inet6_tcp_dist.erl @@ -24,28 +24,6 @@ -export([listen/1, accept/1, accept_connection/5, setup/5, close/1, select/1, is_node_name/1]). -%% internal exports - --export([accept_loop/2,do_accept/6,do_setup/6, getstat/1,tick/1]). - --import(error_logger,[error_msg/2]). - --include("net_address.hrl"). - - - --define(to_port(Socket, Data, Opts), - case inet6_tcp:send(Socket, Data, Opts) of - {error, closed} -> - self() ! {tcp_closed, Socket}, - {error, closed}; - R -> - R - end). - - --include("dist.hrl"). --include("dist_util.hrl"). %% ------------------------------------------------------------ %% Select this protocol based on node name @@ -53,14 +31,7 @@ %% ------------------------------------------------------------ select(Node) -> - case split_node(atom_to_list(Node), $@, []) of - [_, Host] -> - case inet:getaddr(Host,inet6) of - {ok,_} -> true; - _ -> false - end; - _ -> false - end. + inet_tcp_dist:gen_select(inet6_tcp, Node). %% ------------------------------------------------------------ %% Create the listen socket, i.e. the port that this erlang @@ -68,59 +39,14 @@ select(Node) -> %% ------------------------------------------------------------ listen(Name) -> - case inet6_tcp:listen(0, [{active, false}, {packet,2}]) of - {ok, Socket} -> - TcpAddress = get_tcp_address(Socket), - {_,Port} = TcpAddress#net_address.address, - case erl_epmd:register_node(Name, Port) of - {ok, Creation} -> - {ok, {Socket, TcpAddress, Creation}}; - Error -> - Error - end; - Error -> - Error - end. + inet_tcp_dist:gen_listen(inet6_tcp, Name). %% ------------------------------------------------------------ %% Accepts new connection attempts from other Erlang nodes. %% ------------------------------------------------------------ accept(Listen) -> - spawn_opt(?MODULE, accept_loop, [self(), Listen], [link, {priority, max}]). - -accept_loop(Kernel, Listen) -> - case inet6_tcp:accept(Listen) of - {ok, Socket} -> - Kernel ! {accept,self(),Socket,inet6,tcp}, - _ = controller(Kernel, Socket), - accept_loop(Kernel, Listen); - Error -> - exit(Error) - end. - -controller(Kernel, Socket) -> - receive - {Kernel, controller, Pid} -> - flush_controller(Pid, Socket), - inet6_tcp:controlling_process(Socket, Pid), - flush_controller(Pid, Socket), - Pid ! {self(), controller}; - {Kernel, unsupported_protocol} -> - exit(unsupported_protocol) - end. - -flush_controller(Pid, Socket) -> - receive - {tcp, Socket, Data} -> - Pid ! {tcp, Socket, Data}, - flush_controller(Pid, Socket); - {tcp_closed, Socket} -> - Pid ! {tcp_closed, Socket}, - flush_controller(Pid, Socket) - after 0 -> - ok - end. + inet_tcp_dist:gen_accept(inet6_tcp, Listen). %% ------------------------------------------------------------ %% Accepts a new connection attempt from another Erlang node. @@ -128,85 +54,7 @@ flush_controller(Pid, Socket) -> %% ------------------------------------------------------------ accept_connection(AcceptPid, Socket, MyNode, Allowed, SetupTime) -> - spawn_opt(?MODULE, do_accept, - [self(), AcceptPid, Socket, MyNode, Allowed, SetupTime], - [link, {priority, max}]). - -do_accept(Kernel, AcceptPid, Socket, MyNode, Allowed, SetupTime) -> - receive - {AcceptPid, controller} -> - Timer = dist_util:start_timer(SetupTime), - case check_ip(Socket) of - true -> - HSData = #hs_data{ - kernel_pid = Kernel, - this_node = MyNode, - socket = Socket, - timer = Timer, - this_flags = 0, - allowed = Allowed, - f_send = fun(S,D) -> inet6_tcp:send(S,D) end, - f_recv = fun(S,N,T) -> inet6_tcp:recv(S,N,T) - end, - f_setopts_pre_nodeup = - fun(S) -> - inet:setopts(S, - [{active, false}, - {packet, 4}, - nodelay()]) - end, - f_setopts_post_nodeup = - fun(S) -> - inet:setopts(S, - [{active, true}, - {deliver, port}, - {packet, 4}, - nodelay()]) - end, - f_getll = fun(S) -> - inet:getll(S) - end, - f_address = fun get_remote_id/2, - mf_tick = fun ?MODULE:tick/1, - mf_getstat = fun ?MODULE:getstat/1 - }, - dist_util:handshake_other_started(HSData); - {false,IP} -> - error_msg("** Connection attempt from " - "disallowed IP ~w ** ~n", [IP]), - ?shutdown(no_node) - end - end. - - -%% we may not always want the nodelay behaviour -%% for performance reasons - -nodelay() -> - case application:get_env(kernel, dist_nodelay) of - undefined -> - {nodelay, true}; - {ok, true} -> - {nodelay, true}; - {ok, false} -> - {nodelay, false}; - _ -> - {nodelay, true} - end. - - -%% ------------------------------------------------------------ -%% Get remote information about a Socket. -%% ------------------------------------------------------------ - -get_remote_id(Socket, Node) -> - {ok, Address} = inet:peername(Socket), - [_, Host] = split_node(atom_to_list(Node), $@, []), - #net_address { - address = Address, - host = Host, - protocol = tcp, - family = inet6 }. + inet_tcp_dist:gen_accept_connection(inet6_tcp, AcceptPid, Socket, MyNode, Allowed, SetupTime). %% ------------------------------------------------------------ %% Setup a new connection to another Erlang node. @@ -214,214 +62,13 @@ get_remote_id(Socket, Node) -> %% ------------------------------------------------------------ setup(Node, Type, MyNode, LongOrShortNames,SetupTime) -> - spawn_opt(?MODULE, do_setup, - [self(), Node, Type, MyNode, LongOrShortNames, SetupTime], - [link, {priority, max}]). - -do_setup(Kernel, Node, Type, MyNode, LongOrShortNames,SetupTime) -> - ?trace("~p~n",[{?MODULE,self(),setup,Node}]), - [Name, Address] = splitnode(Node, LongOrShortNames), - case inet:getaddr(Address, inet6) of - {ok, Ip} -> - Timer = dist_util:start_timer(SetupTime), - case erl_epmd:port_please(Name, Ip) of - {port, TcpPort, Version} -> - ?trace("port_please(~p) -> version ~p~n", - [Node,Version]), - dist_util:reset_timer(Timer), - case inet6_tcp:connect(Ip, TcpPort, - [{active, false}, - {packet,2}]) of - {ok, Socket} -> - HSData = #hs_data{ - kernel_pid = Kernel, - other_node = Node, - this_node = MyNode, - socket = Socket, - timer = Timer, - this_flags = 0, - other_version = Version, - f_send = fun inet6_tcp:send/2, - f_recv = fun inet6_tcp:recv/3, - f_setopts_pre_nodeup = - fun(S) -> - inet:setopts - (S, - [{active, false}, - {packet, 4}, - nodelay()]) - end, - f_setopts_post_nodeup = - fun(S) -> - inet:setopts - (S, - [{active, true}, - {deliver, port}, - {packet, 4}, - nodelay()]) - end, - f_getll = fun inet:getll/1, - f_address = - fun(_,_) -> - #net_address { - address = {Ip,TcpPort}, - host = Address, - protocol = tcp, - family = inet6} - end, - mf_tick = fun ?MODULE:tick/1, - mf_getstat = fun ?MODULE:getstat/1, - request_type = Type - }, - dist_util:handshake_we_started(HSData); - _ -> - %% Other Node may have closed since - %% port_please ! - ?trace("other node (~p) " - "closed since port_please.~n", - [Node]), - ?shutdown(Node) - end; - _ -> - ?trace("port_please (~p) " - "failed.~n", [Node]), - ?shutdown(Node) - end; - __Other -> - ?trace("inet_getaddr(~p) " - "failed (~p).~n", [Node,__Other]), - ?shutdown(Node) - end. + inet_tcp_dist:gen_setup(inet6_tcp, Node, Type, MyNode, LongOrShortNames, SetupTime). %% %% Close a socket. %% close(Socket) -> inet6_tcp:close(Socket). - - -%% If Node is illegal terminate the connection setup!! -splitnode(Node, LongOrShortNames) -> - case split_node(atom_to_list(Node), $@, []) of - [Name|Tail] when Tail =/= [] -> - Host = lists:append(Tail), - case split_node(Host, $., []) of - [_] when LongOrShortNames =:= longnames -> - case inet_parse:ipv6strict_address(Host) of - {ok, _} -> - [Name, Host]; - _ -> - error_msg("** System running to use " - "fully qualified " - "hostnames **~n" - "** Hostname ~s is illegal **~n", - [Host]), - ?shutdown(Node) - end; - L when length(L) > 1, LongOrShortNames =:= shortnames -> - error_msg("** System NOT running to use fully qualified " - "hostnames **~n" - "** Hostname ~s is illegal **~n", - [Host]), - ?shutdown(Node); - _ -> - [Name, Host] - end; - [_] -> - error_msg("** Nodename ~p illegal, no '@' character **~n", - [Node]), - ?shutdown(Node); - _ -> - error_msg("** Nodename ~p illegal **~n", [Node]), - ?shutdown(Node) - end. - -split_node([Chr|T], Chr, Ack) -> [lists:reverse(Ack)|split_node(T, Chr, [])]; -split_node([H|T], Chr, Ack) -> split_node(T, Chr, [H|Ack]); -split_node([], _, Ack) -> [lists:reverse(Ack)]. - -%% ------------------------------------------------------------ -%% Fetch local information about a Socket. -%% ------------------------------------------------------------ -get_tcp_address(Socket) -> - {ok, Address} = inet:sockname(Socket), - {ok, Host} = inet:gethostname(), - #net_address { - address = Address, - host = Host, - protocol = tcp, - family = inet6 - }. - -%% ------------------------------------------------------------ -%% Do only accept new connection attempts from nodes at our -%% own LAN, if the check_ip environment parameter is true. -%% ------------------------------------------------------------ -check_ip(Socket) -> - case application:get_env(check_ip) of - {ok, true} -> - case get_ifs(Socket) of - {ok, IFs, IP} -> - check_ip(IFs, IP); - _ -> - ?shutdown(no_node) - end; - _ -> - true - end. - -get_ifs(Socket) -> - case inet:peername(Socket) of - {ok, {IP, _}} -> - case inet:getif(Socket) of - {ok, IFs} -> {ok, IFs, IP}; - Error -> Error - end; - Error -> - Error - end. - -check_ip([{OwnIP, _, Netmask}|IFs], PeerIP) -> - case {mask(Netmask, PeerIP), mask(Netmask, OwnIP)} of - {M, M} -> true; - _ -> check_ip(IFs, PeerIP) - end; -check_ip([], PeerIP) -> - {false, PeerIP}. -mask({M1,M2,M3,M4,M5,M6,M7,M8}, {IP1,IP2,IP3,IP4,IP5,IP6,IP7,IP8}) -> - {M1 band IP1, - M2 band IP2, - M3 band IP3, - M4 band IP4, - M5 band IP5, - M6 band IP6, - M7 band IP7, - M8 band IP8 }. - is_node_name(Node) when is_atom(Node) -> - case split_node(atom_to_list(Node), $@, []) of - [_,_Host] -> true; - _ -> false - end; -is_node_name(_Node) -> - false. -tick(Sock) -> - ?to_port(Sock,[],[force]). -getstat(Socket) -> - case inet:getstat(Socket, [recv_cnt, send_cnt, send_pend]) of - {ok, Stat} -> - split_stat(Stat,0,0,0); - Error -> - Error - end. - -split_stat([{recv_cnt, R}|Stat], _, W, P) -> - split_stat(Stat, R, W, P); -split_stat([{send_cnt, W}|Stat], R, _, P) -> - split_stat(Stat, R, W, P); -split_stat([{send_pend, P}|Stat], R, W, _) -> - split_stat(Stat, R, W, P); -split_stat([], R, W, P) -> - {ok, R, W, P}. - + inet_tcp_dist:is_node_name(Node). diff --git a/lib/kernel/src/inet_db.erl b/lib/kernel/src/inet_db.erl index 1621efbfd7..108a803610 100644 --- a/lib/kernel/src/inet_db.erl +++ b/lib/kernel/src/inet_db.erl @@ -633,20 +633,22 @@ make_hostent(Name, Datas, Aliases, Type) -> hostent_by_domain(Domain, Type) -> ?dbg("hostent_by_domain: ~p~n", [Domain]), - hostent_by_domain(stripdot(Domain), [], Type). + hostent_by_domain(stripdot(Domain), [], [], Type). -hostent_by_domain(Domain, Aliases, Type) -> +hostent_by_domain(Domain, Aliases, LAliases, Type) -> case lookup_type(Domain, Type) of [] -> case lookup_cname(Domain) of [] -> {error, nxdomain}; [CName | _] -> - case lists:member(CName, [Domain | Aliases]) of + LDomain = tolower(Domain), + case lists:member(CName, [LDomain | LAliases]) of true -> {error, nxdomain}; false -> - hostent_by_domain(CName, [Domain | Aliases], Type) + hostent_by_domain(CName, [Domain | Aliases], + [LDomain | LAliases], Type) end end; Addrs -> @@ -671,24 +673,26 @@ lookup_rr(Domain, Class, Type) -> %% match data field directly and cache RRs. %% res_hostent_by_domain(Domain, Type, Rec) -> - res_cache_answer(Rec), - RRs = Rec#dns_rec.anlist, + RRs = lists:map(fun lower_rr/1, Rec#dns_rec.anlist), + res_cache_answer(Rec#dns_rec{anlist = RRs}), ?dbg("res_hostent_by_domain: ~p - ~p~n", [Domain, RRs]), - res_hostent_by_domain(stripdot(Domain), [], Type, RRs). + res_hostent_by_domain(stripdot(Domain), [], [], Type, RRs). -res_hostent_by_domain(Domain, Aliases, Type, RRs) -> - case res_lookup_type(Domain, Type, RRs) of +res_hostent_by_domain(Domain, Aliases, LAliases, Type, RRs) -> + LDomain = tolower(Domain), + case res_lookup_type(LDomain, Type, RRs) of [] -> - case res_lookup_type(Domain, ?S_CNAME, RRs) of + case res_lookup_type(LDomain, ?S_CNAME, RRs) of [] -> {error, nxdomain}; [CName | _] -> - case lists:member(CName, [Domain | Aliases]) of + case lists:member(tolower(CName), [LDomain | LAliases]) of true -> {error, nxdomain}; false -> res_hostent_by_domain(CName, [Domain | Aliases], - Type, RRs) + [LDomain | LAliases], Type, + RRs) end end; Addrs -> @@ -721,7 +725,8 @@ gethostbyaddr(IP) -> %% res_gethostbyaddr(IP, Rec) -> {ok, {IP1, HType, HLen}} = dnt(IP), - res_cache_answer(Rec), + RRs = lists:map(fun lower_rr/1, Rec#dns_rec.anlist), + res_cache_answer(Rec#dns_rec{anlist = RRs}), ent_gethostbyaddr(Rec#dns_rec.anlist, IP1, HType, HLen). ent_gethostbyaddr(RRs, IP, AddrType, Length) -> @@ -1378,7 +1383,7 @@ times() -> %% lookup and remove old entries do_lookup_rr(Domain, Class, Type) -> - match_rr(#dns_rr{domain = Domain, class = Class,type = Type, + match_rr(#dns_rr{domain = tolower(Domain), class = Class,type = Type, cnt = '_', tm = '_', ttl = '_', bm = '_', func = '_', data = '_'}). @@ -1400,6 +1405,11 @@ filter_rr([RR | RRs], Time) -> [RR | filter_rr(RRs, Time)]; filter_rr([], _Time) -> []. +%% Lower case the domain name before storage. +%% +lower_rr(#dns_rr{domain=Domain}=RR) when is_list(Domain) -> + RR#dns_rr { domain = tolower(Domain) }; +lower_rr(RR) -> RR. %% %% Case fold upper-case to lower-case according to RFC 4343 diff --git a/lib/kernel/src/inet_dns_record_adts.pl b/lib/kernel/src/inet_dns_record_adts.pl index 657d2b9d35..6d719d836e 100644 --- a/lib/kernel/src/inet_dns_record_adts.pl +++ b/lib/kernel/src/inet_dns_record_adts.pl @@ -57,7 +57,8 @@ while(<DATA>) { $" = ','; $\ = "\n"; -while( my ($Name, $r) = each(%Names)) { +foreach my $Name (sort keys %Names) { + my $r = $Names{$Name}; # Create substitutions for this Name my ($Record, @Fields) = @{ $r }; my @FieldMatchValues; @@ -110,7 +111,8 @@ while( my ($Name, $r) = each(%Names)) { for my $i ( 0 .. $#INDEX ) { my $line = $INDEX[$i]; if ($line =~ s/^[*]//) { - while( my ($Name, $r) = each(%Names)) { + foreach my $Name (sort keys %Names) { + my $r = $Names{$Name}; my ($Record) = @{ $r }; $_ = $line; s/Name\b/$Name/g; diff --git a/lib/kernel/src/inet_int.hrl b/lib/kernel/src/inet_int.hrl index bfe4c9ec8c..e7c6cf8ae2 100644 --- a/lib/kernel/src/inet_int.hrl +++ b/lib/kernel/src/inet_int.hrl @@ -149,6 +149,7 @@ -define(INET_LOPT_MSGQ_LOWTRMRK, 37). -define(INET_LOPT_NETNS, 38). -define(INET_LOPT_TCP_SHOW_ECONNRESET, 39). +-define(INET_LOPT_LINE_DELIM, 40). % Specific SCTP options: separate range: -define(SCTP_OPT_RTOINFO, 100). -define(SCTP_OPT_ASSOCINFO, 101). diff --git a/lib/kernel/src/inet_tcp.erl b/lib/kernel/src/inet_tcp.erl index b5c758c02c..f551af9709 100644 --- a/lib/kernel/src/inet_tcp.erl +++ b/lib/kernel/src/inet_tcp.erl @@ -27,11 +27,25 @@ -export([controlling_process/2]). -export([fdopen/2]). +-export([family/0, mask/2, parse_address/1]). -export([getserv/1, getaddr/1, getaddr/2, getaddrs/1, getaddrs/2]). - -include("inet_int.hrl"). +%% my address family +family() -> inet. + +%% Apply netmask on address +mask({M1,M2,M3,M4}, {IP1,IP2,IP3,IP4}) -> + {M1 band IP1, + M2 band IP2, + M3 band IP3, + M4 band IP4}. + +%% Parse address string +parse_address(Host) -> + inet_parse:ipv4strict_address(Host). + %% inet_tcp port lookup getserv(Port) when is_integer(Port) -> {ok, Port}; getserv(Name) when is_atom(Name) -> inet:getservbyname(Name,tcp). diff --git a/lib/kernel/src/inet_tcp_dist.erl b/lib/kernel/src/inet_tcp_dist.erl index 1bdc1c9ed8..64b28bb49b 100644 --- a/lib/kernel/src/inet_tcp_dist.erl +++ b/lib/kernel/src/inet_tcp_dist.erl @@ -24,9 +24,13 @@ -export([listen/1, accept/1, accept_connection/5, setup/5, close/1, select/1, is_node_name/1]). +%% Generalized dist API +-export([gen_listen/2, gen_accept/2, gen_accept_connection/6, + gen_setup/6, gen_select/2]). + %% internal exports --export([accept_loop/2,do_accept/6,do_setup/6,getstat/1,tick/1]). +-export([accept_loop/3,do_accept/7,do_setup/7,getstat/1]). -import(error_logger,[error_msg/2]). @@ -34,15 +38,6 @@ --define(to_port(Socket, Data, Opts), - case inet_tcp:send(Socket, Data, Opts) of - {error, closed} -> - self() ! {tcp_closed, Socket}, - {error, closed}; - R -> - R - end). - -include("dist.hrl"). -include("dist_util.hrl"). @@ -53,8 +48,15 @@ %% ------------------------------------------------------------ select(Node) -> + gen_select(inet_tcp, Node). + +gen_select(Driver, Node) -> case split_node(atom_to_list(Node), $@, []) of - [_,_Host] -> true; + [_, Host] -> + case inet:getaddr(Host, Driver:family()) of + {ok,_} -> true; + _ -> false + end; _ -> false end. @@ -64,9 +66,12 @@ select(Node) -> %% ------------------------------------------------------------ listen(Name) -> - case do_listen([{active, false}, {packet,2}, {reuseaddr, true}]) of + gen_listen(inet_tcp, Name). + +gen_listen(Driver, Name) -> + case do_listen(Driver, [{active, false}, {packet,2}, {reuseaddr, true}]) of {ok, Socket} -> - TcpAddress = get_tcp_address(Socket), + TcpAddress = get_tcp_address(Driver, Socket), {_,Port} = TcpAddress#net_address.address, case erl_epmd:register_node(Name, Port) of {ok, Creation} -> @@ -78,7 +83,7 @@ listen(Name) -> Error end. -do_listen(Options) -> +do_listen(Driver, Options) -> {First,Last} = case application:get_env(kernel,inet_dist_listen_min) of {ok,N} when is_integer(N) -> case application:get_env(kernel, @@ -91,14 +96,14 @@ do_listen(Options) -> _ -> {0,0} end, - do_listen(First, Last, listen_options([{backlog,128}|Options])). + do_listen(Driver, First, Last, listen_options([{backlog,128}|Options])). -do_listen(First,Last,_) when First > Last -> +do_listen(_Driver, First,Last,_) when First > Last -> {error,eaddrinuse}; -do_listen(First,Last,Options) -> - case inet_tcp:listen(First, Options) of +do_listen(Driver, First,Last,Options) -> + case Driver:listen(First, Options) of {error, eaddrinuse} -> - do_listen(First+1,Last,Options); + do_listen(Driver, First+1,Last,Options); Other -> Other end. @@ -124,23 +129,26 @@ listen_options(Opts0) -> %% ------------------------------------------------------------ accept(Listen) -> - spawn_opt(?MODULE, accept_loop, [self(), Listen], [link, {priority, max}]). + gen_accept(inet_tcp, Listen). -accept_loop(Kernel, Listen) -> - case inet_tcp:accept(Listen) of +gen_accept(Driver, Listen) -> + spawn_opt(?MODULE, accept_loop, [Driver, self(), Listen], [link, {priority, max}]). + +accept_loop(Driver, Kernel, Listen) -> + case Driver:accept(Listen) of {ok, Socket} -> - Kernel ! {accept,self(),Socket,inet,tcp}, - _ = controller(Kernel, Socket), - accept_loop(Kernel, Listen); + Kernel ! {accept,self(),Socket,Driver:family(),tcp}, + _ = controller(Driver, Kernel, Socket), + accept_loop(Driver, Kernel, Listen); Error -> exit(Error) end. -controller(Kernel, Socket) -> +controller(Driver, Kernel, Socket) -> receive {Kernel, controller, Pid} -> flush_controller(Pid, Socket), - inet_tcp:controlling_process(Socket, Pid), + Driver:controlling_process(Socket, Pid), flush_controller(Pid, Socket), Pid ! {self(), controller}; {Kernel, unsupported_protocol} -> @@ -165,15 +173,18 @@ flush_controller(Pid, Socket) -> %% ------------------------------------------------------------ accept_connection(AcceptPid, Socket, MyNode, Allowed, SetupTime) -> + gen_accept_connection(inet_tcp, AcceptPid, Socket, MyNode, Allowed, SetupTime). + +gen_accept_connection(Driver, AcceptPid, Socket, MyNode, Allowed, SetupTime) -> spawn_opt(?MODULE, do_accept, - [self(), AcceptPid, Socket, MyNode, Allowed, SetupTime], + [Driver, self(), AcceptPid, Socket, MyNode, Allowed, SetupTime], [link, {priority, max}]). -do_accept(Kernel, AcceptPid, Socket, MyNode, Allowed, SetupTime) -> +do_accept(Driver, Kernel, AcceptPid, Socket, MyNode, Allowed, SetupTime) -> receive {AcceptPid, controller} -> Timer = dist_util:start_timer(SetupTime), - case check_ip(Socket) of + case check_ip(Driver, Socket) of true -> HSData = #hs_data{ kernel_pid = Kernel, @@ -182,9 +193,8 @@ do_accept(Kernel, AcceptPid, Socket, MyNode, Allowed, SetupTime) -> timer = Timer, this_flags = 0, allowed = Allowed, - f_send = fun(S,D) -> inet_tcp:send(S,D) end, - f_recv = fun(S,N,T) -> inet_tcp:recv(S,N,T) - end, + f_send = fun Driver:send/2, + f_recv = fun Driver:recv/3, f_setopts_pre_nodeup = fun(S) -> inet:setopts(S, @@ -203,8 +213,8 @@ do_accept(Kernel, AcceptPid, Socket, MyNode, Allowed, SetupTime) -> f_getll = fun(S) -> inet:getll(S) end, - f_address = fun get_remote_id/2, - mf_tick = fun ?MODULE:tick/1, + f_address = fun(S, Node) -> get_remote_id(Driver, S, Node) end, + mf_tick = fun(S) -> tick(Driver, S) end, mf_getstat = fun ?MODULE:getstat/1 }, dist_util:handshake_other_started(HSData); @@ -235,13 +245,13 @@ nodelay() -> %% ------------------------------------------------------------ %% Get remote information about a Socket. %% ------------------------------------------------------------ -get_remote_id(Socket, Node) -> +get_remote_id(Driver, Socket, Node) -> case inet:peername(Socket) of {ok,Address} -> case split_node(atom_to_list(Node), $@, []) of [_,Host] -> #net_address{address=Address,host=Host, - protocol=tcp,family=inet}; + protocol=tcp,family=Driver:family()}; _ -> %% No '@' or more than one '@' in node name. ?shutdown(no_node) @@ -256,14 +266,18 @@ get_remote_id(Socket, Node) -> %% ------------------------------------------------------------ setup(Node, Type, MyNode, LongOrShortNames,SetupTime) -> + gen_setup(inet_tcp, Node, Type, MyNode, LongOrShortNames, SetupTime). + +gen_setup(Driver, Node, Type, MyNode, LongOrShortNames, SetupTime) -> spawn_opt(?MODULE, do_setup, - [self(), Node, Type, MyNode, LongOrShortNames, SetupTime], + [Driver, self(), Node, Type, MyNode, LongOrShortNames, SetupTime], [link, {priority, max}]). -do_setup(Kernel, Node, Type, MyNode, LongOrShortNames,SetupTime) -> +do_setup(Driver, Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime) -> ?trace("~p~n",[{inet_tcp_dist,self(),setup,Node}]), - [Name, Address] = splitnode(Node, LongOrShortNames), - case inet:getaddr(Address, inet) of + [Name, Address] = splitnode(Driver, Node, LongOrShortNames), + AddressFamily = Driver:family(), + case inet:getaddr(Address, AddressFamily) of {ok, Ip} -> Timer = dist_util:start_timer(SetupTime), case erl_epmd:port_please(Name, Ip) of @@ -272,7 +286,7 @@ do_setup(Kernel, Node, Type, MyNode, LongOrShortNames,SetupTime) -> [Node,Version]), dist_util:reset_timer(Timer), case - inet_tcp:connect( + Driver:connect( Ip, TcpPort, connect_options([{active, false}, {packet, 2}])) of @@ -285,8 +299,8 @@ do_setup(Kernel, Node, Type, MyNode, LongOrShortNames,SetupTime) -> timer = Timer, this_flags = 0, other_version = Version, - f_send = fun inet_tcp:send/2, - f_recv = fun inet_tcp:recv/3, + f_send = fun Driver:send/2, + f_recv = fun Driver:recv/3, f_setopts_pre_nodeup = fun(S) -> inet:setopts @@ -311,9 +325,9 @@ do_setup(Kernel, Node, Type, MyNode, LongOrShortNames,SetupTime) -> address = {Ip,TcpPort}, host = Address, protocol = tcp, - family = inet} + family = AddressFamily} end, - mf_tick = fun ?MODULE:tick/1, + mf_tick = fun(S) -> tick(Driver, S) end, mf_getstat = fun ?MODULE:getstat/1, request_type = Type }, @@ -353,18 +367,23 @@ close(Socket) -> %% If Node is illegal terminate the connection setup!! -splitnode(Node, LongOrShortNames) -> +splitnode(Driver, Node, LongOrShortNames) -> case split_node(atom_to_list(Node), $@, []) of [Name|Tail] when Tail =/= [] -> Host = lists:append(Tail), case split_node(Host, $., []) of [_] when LongOrShortNames =:= longnames -> - error_msg("** System running to use " - "fully qualified " - "hostnames **~n" - "** Hostname ~s is illegal **~n", - [Host]), - ?shutdown(Node); + case Driver:parse_address(Host) of + {ok, _} -> + [Name, Host]; + _ -> + error_msg("** System running to use " + "fully qualified " + "hostnames **~n" + "** Hostname ~s is illegal **~n", + [Host]), + ?shutdown(Node) + end; L when length(L) > 1, LongOrShortNames =:= shortnames -> error_msg("** System NOT running to use fully qualified " "hostnames **~n" @@ -390,26 +409,26 @@ split_node([], _, Ack) -> [lists:reverse(Ack)]. %% ------------------------------------------------------------ %% Fetch local information about a Socket. %% ------------------------------------------------------------ -get_tcp_address(Socket) -> +get_tcp_address(Driver, Socket) -> {ok, Address} = inet:sockname(Socket), {ok, Host} = inet:gethostname(), #net_address { address = Address, host = Host, protocol = tcp, - family = inet + family = Driver:family() }. %% ------------------------------------------------------------ %% Do only accept new connection attempts from nodes at our %% own LAN, if the check_ip environment parameter is true. %% ------------------------------------------------------------ -check_ip(Socket) -> +check_ip(Driver, Socket) -> case application:get_env(check_ip) of {ok, true} -> case get_ifs(Socket) of {ok, IFs, IP} -> - check_ip(IFs, IP); + check_ip(Driver, IFs, IP); _ -> ?shutdown(no_node) end; @@ -428,20 +447,14 @@ get_ifs(Socket) -> Error end. -check_ip([{OwnIP, _, Netmask}|IFs], PeerIP) -> - case {mask(Netmask, PeerIP), mask(Netmask, OwnIP)} of +check_ip(Driver, [{OwnIP, _, Netmask}|IFs], PeerIP) -> + case {Driver:mask(Netmask, PeerIP), Driver:mask(Netmask, OwnIP)} of {M, M} -> true; - _ -> check_ip(IFs, PeerIP) + _ -> check_ip(Driver, IFs, PeerIP) end; -check_ip([], PeerIP) -> +check_ip(_Driver, [], PeerIP) -> {false, PeerIP}. -mask({M1,M2,M3,M4}, {IP1,IP2,IP3,IP4}) -> - {M1 band IP1, - M2 band IP2, - M3 band IP3, - M4 band IP4}. - is_node_name(Node) when is_atom(Node) -> case split_node(atom_to_list(Node), $@, []) of [_, _Host] -> true; @@ -450,8 +463,14 @@ is_node_name(Node) when is_atom(Node) -> is_node_name(_Node) -> false. -tick(Sock) -> - ?to_port(Sock,[],[force]). +tick(Driver, Socket) -> + case Driver:send(Socket, [], [force]) of + {error, closed} -> + self() ! {tcp_closed, Socket}, + {error, closed}; + R -> + R + end. getstat(Socket) -> case inet:getstat(Socket, [recv_cnt, send_cnt, send_pend]) of diff --git a/lib/kernel/src/kernel.appup.src b/lib/kernel/src/kernel.appup.src index 3fda55d1a9..860d3640d0 100644 --- a/lib/kernel/src/kernel.appup.src +++ b/lib/kernel/src/kernel.appup.src @@ -18,9 +18,9 @@ %% %CopyrightEnd% {"%VSN%", %% Up from - max one major revision back - [{<<"4\\.0(\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-18.0.* + [{<<"4\\.[0-1](\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-18.* {<<"3\\.[0-2](\\.[0-9]+)*">>,[restart_new_emulator]}], % OTP-17 %% Down to - max one major revision back - [{<<"4\\.0(\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-18.0.* + [{<<"4\\.[0-1](\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-18.* {<<"3\\.[0-2](\\.[0-9]+)*">>,[restart_new_emulator]}] % OTP-17 }. |