Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

254 lines (212 sloc) 6.997 kb
%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 1996-2013. 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/.
%%
%% 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.
%%
%% %CopyrightEnd%
%%
-module(net_adm).
-export([host_file/0,
localhost/0,
names/0, names/1,
ping_list/1,
world/0,world/1,
world_list/1, world_list/2,
dns_hostname/1,
ping/1]).
%%------------------------------------------------------------------------
-type verbosity() :: 'silent' | 'verbose'.
%%------------------------------------------------------------------------
%% Try to read .hosts.erlang file in
%% 1. cwd , 2. $HOME 3. init:root_dir()
-spec host_file() -> Hosts | {error, Reason} when
Hosts :: [Host :: atom()],
%% Copied from file:path_consult/2:
Reason :: file:posix() | badarg | terminated | system_limit
| {Line :: integer(), Mod :: module(), Term :: term()}.
host_file() ->
Home = case init:get_argument(home) of
{ok, [[H]]} -> [H];
_ -> []
end,
case file:path_consult(["."] ++ Home ++ [code:root_dir()], ".hosts.erlang") of
{ok, Hosts, _} -> Hosts;
Error -> Error
end.
%% Check whether a node is up or down
%% side effect: set up a connection to Node if there not yet is one.
-spec ping(Node) -> pong | pang when
Node :: atom().
ping(Node) when is_atom(Node) ->
case catch gen:call({net_kernel, Node},
'$gen_call',
{is_auth, node()},
infinity) of
{ok, yes} -> pong;
_ ->
erlang:disconnect_node(Node),
pang
end.
-spec localhost() -> Name when
Name :: string().
localhost() ->
{ok, Host} = inet:gethostname(),
case inet_db:res_option(domain) of
"" -> Host;
Domain -> Host ++ "." ++ Domain
end.
-spec names() -> {ok, [{Name, Port}]} | {error, Reason} when
Name :: string(),
Port :: non_neg_integer(),
Reason :: address | file:posix().
names() ->
names(localhost()).
-spec names(Host) -> {ok, [{Name, Port}]} | {error, Reason} when
Host :: atom() | string() | inet:ip_address(),
Name :: string(),
Port :: non_neg_integer(),
Reason :: address | file:posix().
names(Hostname) ->
erl_epmd:names(Hostname).
-spec dns_hostname(Host) -> {ok, Name} | {error, Host} when
Host :: atom() | string(),
Name :: string().
dns_hostname(Hostname) ->
case inet:gethostbyname(Hostname) of
{ok,{hostent, Name, _ , _Af, _Size, _Addr}} ->
{ok, Name};
_ ->
{error, Hostname}
end.
%% A common situation in "life" is to have a configuration file with a list
%% of nodes, and then at startup, all nodes in the list are ping'ed
%% this can lead to no end of troubles if two disconnected nodes
%% simultaneously ping each other.
%% Use this function in order to do it safely.
%% It assumes a working global.erl which ensures a fully
%% connected network.
%% Had the erlang runtime system been able to fully cope with
%% the possibility of two simultaneous (unix) connects, this function would
%% merley be lists:map({net_adm, ping}, [], Nodelist).
%% It is also assumed, that the same (identical) Nodelist is given to all
%% nodes which are to perform this call (possibly simultaneously).
%% Even this code has a flaw, and that is the case where two
%% nodes simultaneously and without *any* other already
%% running nodes execute this code. :-(
-spec ping_list([atom()]) -> [atom()].
ping_list(Nodelist) ->
ok = net_kernel:monitor_nodes(true),
Sofar = ping_first(Nodelist, nodes()),
collect_new(Sofar, Nodelist).
ping_first([], _S) ->
[];
ping_first([Node|Nodes], S) ->
case lists:member(Node, S) of
true -> [Node | ping_first(Nodes, S)];
false ->
case ping(Node) of
pong -> [Node];
pang -> ping_first(Nodes, S)
end
end.
collect_new(Sofar, Nodelist) ->
receive
{nodeup, Node} ->
case lists:member(Node, Nodelist) of
true ->
collect_new(Sofar, Nodelist);
false ->
collect_new([Node | Sofar], Nodelist)
end
after 3000 ->
ok = net_kernel:monitor_nodes(false),
Sofar
end.
%% This function polls a set of hosts according to a file called
%% .hosts.erlang that need to reside either in the current directory
%% or in your home directory. (The current directory is tried first.)
%% world() returns a list of all nodes on the network that can be
%% found (including ourselves). Note: the $HOME variable is inspected.
%%
%% Added possibility to supply a list of hosts instead of reading
%% the .hosts.erlang file. 971016 patrik@erix.ericsson.se
%% e.g.
%% net_adm:world_list(['elrond.du.etx.ericsson.se', 'thorin.du.etx.ericsson.se']).
-spec world() -> [node()].
world() ->
world(silent).
-spec world(Arg) -> [node()] when
Arg :: verbosity().
world(Verbose) ->
case net_adm:host_file() of
{error,R} -> exit({error, R});
Hosts -> expand_hosts(Hosts, Verbose)
end.
-spec world_list(Hosts) -> [node()] when
Hosts :: [atom()].
world_list(Hosts) when is_list(Hosts) ->
expand_hosts(Hosts, silent).
-spec world_list(Hosts, Arg) -> [node()] when
Hosts :: [atom()],
Arg :: verbosity().
world_list(Hosts, Verbose) when is_list(Hosts) ->
expand_hosts(Hosts, Verbose).
expand_hosts(Hosts, Verbose) ->
lists:flatten(collect_nodes(Hosts, Verbose)).
collect_nodes([], _) -> [];
collect_nodes([Host|Tail], Verbose) ->
case collect_host_nodes(Host, Verbose) of
nil ->
collect_nodes(Tail, Verbose);
L ->
[L|collect_nodes(Tail, Verbose)]
end.
collect_host_nodes(Host, Verbose) ->
case names(Host) of
{ok, Namelist} ->
do_ping(Namelist, atom_to_list(Host), Verbose);
_ ->
nil
end.
do_ping(Names, Host0, Verbose) ->
case longshort(Host0) of
ignored -> [];
Host -> do_ping_1(Names, Host, Verbose)
end.
do_ping_1([], _Host, _Verbose) ->
[];
do_ping_1([{Name, _} | Rest], Host, Verbose) ->
Node = list_to_atom(Name ++ "@" ++ longshort(Host)),
verbose(Verbose, "Pinging ~w -> ", [Node]),
Result = ping(Node),
verbose(Verbose, "~p\n", [Result]),
case Result of
pong ->
[Node | do_ping_1(Rest, Host, Verbose)];
pang ->
do_ping_1(Rest, Host, Verbose)
end.
verbose(verbose, Format, Args) ->
io:format(Format, Args);
verbose(_, _, _) ->
ok.
longshort(Host) ->
case net_kernel:longnames() of
false -> uptodot(Host);
true -> Host;
ignored -> ignored
end.
uptodot([$.|_]) -> [];
uptodot([])-> [];
uptodot([H|T]) -> [H|uptodot(T)].
Jump to Line
Something went wrong with that request. Please try again.