inet_gethost_native.erl

来自「OTP是开放电信平台的简称」· ERL 代码 · 共 617 行 · 第 1/2 页

ERL
617
字号
%% ``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 via the world wide web at http://www.erlang.org/.%% %% 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.%% %% The Initial Developer of the Original Code is Ericsson Utvecklings AB.%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings%% AB. All Rights Reserved.''%% %%     $Id$%%-module(inet_gethost_native).-behaviour(supervisor_bridge).%% Supervisor bridge exports-export([start_link/0, init/1, terminate/2, start_raw/0, run_once/0]).%% Server export-export([server_init/2, main_loop/1]).%% API exports-export([gethostbyname/1, gethostbyname/2, gethostbyaddr/1, control/1]).%%% Exports for sys:handle_system_msg/6-export([system_continue/3, system_terminate/4, system_code_change/4]).-include_lib("kernel/include/inet.hrl").-define(PROCNAME_SUP, inet_gethost_native_sup).-define(OP_GETHOSTBYNAME,1).-define(OP_GETHOSTBYADDR,2).-define(OP_CANCEL_REQUEST,3).-define(OP_CONTROL,4).-define(PROTO_IPV4,1).-define(PROTO_IPV6,2).%% OP_CONTROL-define(SETOPT_DEBUG_LEVEL, 0).-define(UNIT_ERROR,0).-define(UNIT_IPV4,4).-define(UNIT_IPV6,16).-define(PORT_PROGRAM, "inet_gethost").-define(DEFAULT_POOLSIZE, 4).-define(REQUEST_TIMEOUT, (inet_db:res_option(timeout)*4)).-define(MAX_TIMEOUT, 16#7FFFFFF).-define(INVALID_SERIAL, 16#FFFFFFFF).%-define(DEBUG,1).-ifdef(DEBUG).-define(dbg(A,B), io:format(A,B)).-else.-define(dbg(A,B), noop).-endif.-define(SEND_AFTER(A,B,C),erlang:send_after(A,B,C)).-define(CANCEL_TIMER(A),erlang:cancel_timer(A)).%% In erlang, IPV6 addresses are built as 8-tuples of 16bit values (not 16-tuples of octets).%% This macro, meant to be used in guards checks one such 16bit value in the 8-tuple.-define(VALID_V6(Part), is_integer(Part), Part < 65536).%% The regular IPV4 addresses are represented as 4-tuples of octets, this macro,%% meant to be used in guards, check one such octet.-define(VALID_V4(Part), is_integer(Part), Part < 256).% Requests, one per unbique request to the PORT program, may be more than one client!!!-record(request, {	  rid, % Request id as sent to port	  op,	  proto,	  rdata,	  clients = [] % Can be more than one client per request (Pid's). }).% Statistics, not used yet.-record(statistics, {	  netdb_timeout = 0,	  netdb_internal = 0,	  port_crash = 0,	  notsup = 0,	  host_not_found = 0,	  try_again = 0,	  no_recovery = 0,	  no_data = 0}).% The main loopstate...-record(state, {	  port = noport, % Port() connected to the port program	  timeout = 8000, % Timeout value from inet_db:res_option	  requests, % Table of request	  req_index, % Table of {{op,proto,rdata},rid}	  parent,    % The supervisor bridge	  pool_size = 4, % Number of C processes in pool.	  statistics % Statistics record (records error causes).}).%% The supervisor bridge codeinit([]) -> % Called by supervisor_bridge:start_link    Ref = make_ref(),    SaveTE = process_flag(trap_exit,true),    Pid = spawn_link(?MODULE,server_init,[self(),Ref]),    receive	Ref ->	    process_flag(trap_exit,SaveTE),	    {ok, Pid, Pid};	{'EXIT', Pid, Message} ->	    process_flag(trap_exit,SaveTE),	    {error, Message}    after 10000 ->	    process_flag(trap_exit,SaveTE),	    {error, {timeout, ?MODULE}}    end.start_link() ->    supervisor_bridge:start_link({local, ?PROCNAME_SUP}, ?MODULE, []).%% Only used in fallback situations, no supervisor, no bridge, serve only until%% no requests present...start_raw() ->    spawn(?MODULE,run_once,[]).run_once() ->    Port = do_open_port(get_poolsize(), get_extra_args()),    Timeout = ?REQUEST_TIMEOUT,    {Pid, R, Request} = 	receive	    {{Pid0,R0}, {?OP_GETHOSTBYNAME, Proto0, Name0}} ->		{Pid0, R0, 		 [<<1:32, ?OP_GETHOSTBYNAME:8, Proto0:8>>,Name0,0]};	    {{Pid1,R1}, {?OP_GETHOSTBYADDR, Proto1, Data1}}  ->		{Pid1, R1, 		 <<1:32, ?OP_GETHOSTBYADDR:8, Proto1:8, Data1/binary>>}	after Timeout ->		exit(normal)	end,    (catch port_command(Port, Request)),    receive	{Port, {data, <<1:32, BinReply/binary>>}} ->	    Pid ! {R, {ok, BinReply}}    after Timeout ->	    Pid ! {R,{error,timeout}}    end.terminate(_Reason,Pid) ->    (catch exit(Pid,kill)),    ok.%%-----------------------------------------------------------------------%% Server API%%-----------------------------------------------------------------------server_init(Starter, Ref) ->    process_flag(trap_exit,true),    case whereis(?MODULE) of	undefined ->	    case (catch register(?MODULE,self())) of		true ->		    Starter ! Ref;		_->		    exit({already_started,whereis(?MODULE)})	    end;	Winner ->	   exit({already_started,Winner})    end,    Poolsize = get_poolsize(),    Port = do_open_port(Poolsize, get_extra_args()),    Timeout = ?REQUEST_TIMEOUT,    put(rid,0),    put(num_requests,0),    RequestTab = ets:new(ign_requests,[{keypos,#request.rid},set,protected]),    RequestIndex = ets:new(ign_req_index,[set,protected]),    State = #state{port = Port, timeout = Timeout, requests = RequestTab,		   req_index = RequestIndex, 		   pool_size = Poolsize,		   statistics = #statistics{},		   parent = Starter},    main_loop(State).main_loop(State) ->    receive	Any -> 	    handle_message(Any,State)    end.handle_message({{Pid,_} = Client, {?OP_GETHOSTBYNAME, Proto, Name} = R}, 	       State) when is_pid(Pid) ->    NewState = do_handle_call(R,Client,State,			      [<<?OP_GETHOSTBYNAME:8, Proto:8>>, Name,0]),    main_loop(NewState);handle_message({{Pid,_} = Client, {?OP_GETHOSTBYADDR, Proto, Data} = R}, 	       State) when is_pid(Pid) ->    NewState = do_handle_call(R,Client,State,			      <<?OP_GETHOSTBYADDR:8, Proto:8, Data/binary>>),    main_loop(NewState);handle_message({{Pid,Ref}, {?OP_CONTROL, Ctl, Data}}, State)  when is_pid(Pid) ->    catch port_command(State#state.port, 		       <<?INVALID_SERIAL:32, ?OP_CONTROL:8, 			Ctl:8, Data/binary>>),    Pid ! {Ref, ok},    main_loop(State);handle_message({{Pid,Ref}, restart_port}, State)  when is_pid(Pid) ->    NewPort=restart_port(State),    Pid ! {Ref, ok},    main_loop(State#state{port=NewPort});handle_message({Port, {data, Data}}, State = #state{port = Port}) ->    NewState = case Data of		   <<RID:32, BinReply/binary>> ->		       case BinReply of			   <<Unit, _/binary>> when Unit =:= ?UNIT_ERROR;						   Unit =:= ?UNIT_IPV4;						   Unit =:= ?UNIT_IPV6 ->			       case pick_request(State,RID) of				   false ->				       State;				   Req ->				       lists:foreach(fun({P,R,TR}) ->							     ?CANCEL_TIMER(TR),							     P ! {R,								  {ok,								   BinReply}}						     end,						     Req#request.clients),				       State			       end;			   _UnitError ->			       %% Unexpected data, let's restart it, 			       %% it must be broken.			       NewPort=restart_port(State),			       State#state{port=NewPort}		       end;		   _BasicFormatError ->		       NewPort=restart_port(State),		       State#state{port=NewPort}	       end,        main_loop(NewState);	handle_message({'EXIT',Port,_Reason}, State = #state{port = Port}) ->     ?dbg("Port died.~n",[]),    NewPort=restart_port(State),    main_loop(State#state{port=NewPort});handle_message({Port,eof}, State = #state{port = Port}) ->    ?dbg("Port eof'ed.~n",[]),    NewPort=restart_port(State),    main_loop(State#state{port=NewPort});handle_message({timeout, Pid, RID}, State) ->    case pick_client(State,RID,Pid) of	false ->	    false;	{more, {P,R,_}} ->	    P ! {R,{error,timeout}};	{last, {LP,LR,_}} ->	    LP ! {LR, {error,timeout}},	    %% Remove the whole request structure...	    pick_request(State, RID),	    %% Also cancel the request to the port program...	    (catch port_command(State#state.port, 				<<RID:32,?OP_CANCEL_REQUEST>>))    end,    main_loop(State);handle_message({system, From, Req}, State) ->	    sys:handle_system_msg(Req, From, State#state.parent, ?MODULE, [], 				  State);handle_message(_, State) -> % Stray messages from dying ports etc.    main_loop(State).do_handle_call(R,Client0,State,RData) ->    Req = find_request(State,R),    Timeout = State#state.timeout,    {P,Ref} = Client0,    TR = ?SEND_AFTER(Timeout,self(),{timeout, P, Req#request.rid}),    Client = {P,Ref,TR},    case Req#request.clients of	[] ->	    RealRData = [<<(Req#request.rid):32>>|RData],	    (catch port_command(State#state.port, RealRData)),	    ets:insert(State#state.requests,Req#request{clients = [Client]});	Tail ->	    ets:insert(State#state.requests,Req#request{clients = [Client | Tail]})    end,    State.find_request(State, R = {Op, Proto, Data}) ->    case ets:lookup(State#state.req_index,R) of	[{R, Rid}] ->	    [Ret] = ets:lookup(State#state.requests,Rid),	    Ret;	[] ->

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?