1 |
|
%% EPMD implementation which redefines how name lookups work |
2 |
|
%% There is no behaviour for erl_epmd |
3 |
|
-module(mongoose_epmd). |
4 |
|
-export([ |
5 |
|
start/0, |
6 |
|
start_link/0, |
7 |
|
stop/0, |
8 |
|
port_please/2, port_please/3, |
9 |
|
listen_port_please/2, |
10 |
|
names/0, names/1, |
11 |
|
register_node/2, register_node/3, |
12 |
|
address_please/3, |
13 |
|
open/0, open/1, open/2 |
14 |
|
]). |
15 |
|
-include_lib("kernel/include/logger.hrl"). |
16 |
|
|
17 |
|
%% For debugging |
18 |
|
-export([lookup_ip/1]). |
19 |
|
-export([match_node_name/2]). |
20 |
|
|
21 |
|
-type lookup_error() :: |
22 |
|
{no_ip_in_db, node()} |
23 |
|
| {cannot_connect_to_epmd, node(), inet:ip_address()} |
24 |
|
| {no_record_for_node, node()} |
25 |
|
| mongoose_node_address_ets_table_not_found. |
26 |
|
|
27 |
|
-ignore_xref([ |
28 |
|
start/0, |
29 |
|
start_link/0, |
30 |
|
stop/0, |
31 |
|
port_please/2, port_please/3, |
32 |
|
listen_port_please/2, |
33 |
|
names/0, names/1, |
34 |
|
register_node/2, register_node/3, |
35 |
|
address_please/3, |
36 |
|
open/0, open/1, open/2, |
37 |
|
lookup_ip/1, match_node_name/2 |
38 |
|
]). |
39 |
|
|
40 |
:-( |
start() -> erl_epmd:start(). |
41 |
:-( |
start_link() -> erl_epmd:start_link(). |
42 |
:-( |
stop() -> erl_epmd:stop(). |
43 |
:-( |
port_please(A, B) -> erl_epmd:port_please(A, B). |
44 |
:-( |
port_please(A, B, C) -> erl_epmd:port_please(A, B, C). |
45 |
:-( |
listen_port_please(A, B) -> erl_epmd:listen_port_please(A, B). |
46 |
:-( |
names() -> erl_epmd:names(). |
47 |
:-( |
names(A) -> erl_epmd:names(A). |
48 |
:-( |
register_node(A, B) -> erl_epmd:register_node(A, B). |
49 |
:-( |
register_node(A, B, C) -> erl_epmd:register_node(A, B, C). |
50 |
:-( |
open() -> erl_epmd:open(). |
51 |
:-( |
open(A) -> erl_epmd:open(A). |
52 |
:-( |
open(A, B) -> erl_epmd:open(A, B). |
53 |
|
|
54 |
|
address_please(Name, Host, AddressFamily) -> |
55 |
4 |
Node = list_to_binary(Name ++ "@" ++ Host), |
56 |
4 |
case lookup_ip(Node) of |
57 |
|
{ok, _IP} = Res -> |
58 |
2 |
Res; |
59 |
|
_ -> |
60 |
|
%% Fallback to the default behaviour |
61 |
2 |
inet:getaddr(Host, AddressFamily) |
62 |
|
end. |
63 |
|
|
64 |
|
%% This function waits for the IP address to appear. |
65 |
|
%% It only works well in case net_kernel does not contact a lot of |
66 |
|
%% dead nodes. |
67 |
|
%% Generally, we only expect calls for nodes that are alive |
68 |
|
%% and the connect is issued by CETS (but CETS checks that node is |
69 |
|
%% reachable first) or by connect_all feature in the global module of OTP. |
70 |
|
-spec lookup_ip(binary()) -> {ok, inet:ip_address()} | {error, lookup_error()}. |
71 |
|
lookup_ip(Node) -> |
72 |
4 |
try |
73 |
4 |
cets_discovery:wait_for_get_nodes(mongoose_cets_discovery, 3000), |
74 |
3 |
cets_discovery:system_info(mongoose_cets_discovery) |
75 |
|
of |
76 |
|
#{backend_state := BackendState} -> |
77 |
3 |
match_node_name(BackendState, Node) |
78 |
|
catch _:_ -> |
79 |
1 |
{error, failed_to_get_disco_state} |
80 |
|
end. |
81 |
|
|
82 |
|
match_node_name(#{address_pairs := Pairs}, Node) -> |
83 |
7 |
case Pairs of |
84 |
|
#{Node := <<>>} -> |
85 |
|
%% The caller should try DNS. |
86 |
1 |
{error, {no_ip_in_db, Node}}; |
87 |
|
#{Node := Bin} -> |
88 |
5 |
inet:parse_address(binary_to_list(Bin)); |
89 |
|
#{} -> |
90 |
1 |
{error, {no_record_for_node, Node}} |
91 |
|
end; |
92 |
|
match_node_name(BackendState, Node) -> |
93 |
|
%% Could happen if CETS backend is not mongoose_cets_discovery_rdbms |
94 |
1 |
?LOG_ERROR(#{what => cets_no_address_pairs_set, |
95 |
|
backend_state => BackendState, |
96 |
:-( |
remote_node => Node}), |
97 |
1 |
{error, no_address_pairs_set}. |