1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 1998-2020. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20-module(erl_epmd).
21
22-behaviour(gen_server).
23
24-ifdef(DEBUG).
25-define(port_please_failure(), io:format("Net Kernel 2: EPMD port please failed at ~p:~p~n", [?MODULE,?LINE])).
26-define(port_please_failure2(Term), io:format("Net Kernel 2: EPMD port please failed at ~p:~p [~p]~n", [?MODULE,?LINE,Term])).
27-else.
28-define(port_please_failure(), noop).
29-define(port_please_failure2(Term), noop).
30-endif.
31
32-include("dist.hrl").
33
34-ifndef(erlang_daemon_port).
35-define(erlang_daemon_port, 4369).
36-endif.
37-ifndef(epmd_dist_high).
38-define(epmd_dist_high, ?ERL_DIST_VER_HIGH).
39-endif.
40-ifndef(epmd_dist_low).
41-define(epmd_dist_low, ?ERL_DIST_VER_LOW).
42-endif.
43
44%% External exports
45-export([start/0, start_link/0, stop/0,
46         port_please/2, port_please/3, listen_port_please/2,
47         names/0, names/1,
48	 register_node/2, register_node/3, address_please/3, open/0, open/1, open/2]).
49
50%% gen_server callbacks
51-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
52	 terminate/2, code_change/3]).
53
54-import(lists, [reverse/1]).
55
56-record(state, {socket, port_no = -1, name = "", family}).
57-type state() :: #state{}.
58
59-include("inet_int.hrl").
60-include("erl_epmd.hrl").
61-include_lib("kernel/include/inet.hrl").
62
63-define(RECONNECT_TIME, 2000).
64
65%%%----------------------------------------------------------------------
66%%% API
67%%%----------------------------------------------------------------------
68start() ->
69    gen_server:start({local, erl_epmd}, ?MODULE, [], []).
70
71-spec start_link() -> {ok, pid()} | ignore | {error,term()}.
72start_link() ->
73    gen_server:start_link({local, erl_epmd}, ?MODULE, [], []).
74
75
76stop() ->
77    gen_server:call(?MODULE, stop, infinity).
78
79
80%% Lookup a node "Name" at Host
81%% return {port, P, Version} | noport
82%%
83
84-spec port_please(Name, Host) -> {port, Port, Version} | noport | closed | {error, term()} when
85	  Name :: atom() | string(),
86	  Host :: atom() | string() | inet:ip_address(),
87	  Port :: non_neg_integer(),
88	  Version :: non_neg_integer().
89
90port_please(Node, Host) ->
91  port_please(Node, Host, infinity).
92
93-spec port_please(Name, Host, Timeout) -> {port, Port, Version} | noport | closed | {error, term()} when
94	  Name :: atom() | string(),
95	  Host :: atom() | string() | inet:ip_address(),
96	  Timeout :: non_neg_integer() | infinity,
97	  Port :: non_neg_integer(),
98	  Version :: non_neg_integer().
99
100port_please(Node, HostName, Timeout) ->
101    case listen_port_please(Node, HostName) of
102        {ok, 0} ->
103            case getepmdbyname(HostName, Timeout) of
104                {ok, EpmdAddr} ->
105                    get_port(Node, EpmdAddr, Timeout);
106                _Error ->
107                    ?port_please_failure2(_Error),
108                    noport
109            end;
110        {ok, Prt} ->
111            %% We don't know which dist version the other node is running
112            %% so return the low version so that we can talk to older nodes
113            {port, Prt, ?epmd_dist_low}
114    end.
115
116getepmdbyname(HostName, Timeout) when is_atom(HostName) ->
117    getepmdbyname(atom_to_list(HostName), Timeout);
118getepmdbyname(HostName, Timeout) when is_list(HostName) ->
119    Family = case inet_db:res_option(inet6) of
120                 true ->
121                     inet6;
122                 false ->
123                     inet
124             end,
125    case inet:gethostbyname(HostName, Family, Timeout) of
126        {ok,#hostent{ h_addr_list = [EpmdAddr | _]}} ->
127            {ok, EpmdAddr};
128        Else ->
129            Else
130    end;
131getepmdbyname(HostName, _Timeout) ->
132    {ok, HostName}.
133
134-spec listen_port_please(Name, Host) -> {ok, Port} when
135      Name :: atom() | string(),
136      Host :: atom() | string() | inet:ip_address(),
137      Port :: non_neg_integer().
138listen_port_please(_Name, _Host) ->
139    try
140        %% Should come up with a new name for this as ERL_EPMD_PORT describes what
141        %% port epmd runs on which could easily be confused with this.
142        {ok, [[StringPort]]} = init:get_argument(erl_epmd_port),
143        Port = list_to_integer(StringPort),
144        {ok, Port}
145    catch error:_ ->
146            {ok, 0}
147    end.
148
149-spec names() -> {ok, [{Name, Port}]} | {error, Reason} when
150	  Name :: string(),
151	  Port :: non_neg_integer(),
152	  Reason :: address | file:posix().
153
154names() ->
155    {ok, H} = inet:gethostname(),
156    names(H).
157
158-spec names(Host) -> {ok, [{Name, Port}]} | {error, Reason} when
159      Host :: atom() | string() | inet:ip_address(),
160      Name :: string(),
161      Port :: non_neg_integer(),
162      Reason :: address | file:posix().
163
164names(HostName) ->
165    case getepmdbyname(HostName, infinity) of
166        {ok,EpmdAddr} ->
167            get_names(EpmdAddr);
168        Else ->
169            Else
170    end.
171
172-spec register_node(Name, Port) -> Result when
173	  Name :: string(),
174	  Port :: non_neg_integer(),
175	  Creation :: non_neg_integer(),
176	  Result :: {ok, Creation} | {error, already_registered} | term().
177
178register_node(Name, PortNo) ->
179	register_node(Name, PortNo, inet).
180
181-spec register_node(Name, Port, Driver) -> Result when
182	  Name :: string(),
183	  Port :: non_neg_integer(),
184	  Driver :: inet_tcp | inet6_tcp | inet | inet6,
185	  Creation :: non_neg_integer() | -1,
186	  Result :: {ok, Creation} | {error, already_registered} | term().
187
188register_node(Name, PortNo, inet_tcp) ->
189    register_node(Name, PortNo, inet);
190register_node(Name, PortNo, inet6_tcp) ->
191    register_node(Name, PortNo, inet6);
192register_node(Name, PortNo, Family) ->
193    gen_server:call(erl_epmd, {register, Name, PortNo, Family}, infinity).
194
195-spec address_please(Name, Host, AddressFamily) -> Success | {error, term()} when
196	  Name :: string(),
197	  Host :: string() | inet:ip_address(),
198	  AddressFamily :: inet | inet6,
199	  Port :: non_neg_integer(),
200	  Version :: non_neg_integer(),
201	  Success :: {ok, inet:ip_address()} |
202                     %% This is not returned here, but is in the spec for
203                     %% the documentation to show that it is possible to
204                     %% return when using a custom erl_epmd
205                     {ok, inet:ip_address(), Port, Version}.
206
207address_please(_Name, Host, AddressFamily) ->
208    inet:getaddr(Host, AddressFamily).
209
210%%%----------------------------------------------------------------------
211%%% Callback functions from gen_server
212%%%----------------------------------------------------------------------
213
214-spec init(_) -> {'ok', state()}.
215
216init(_) ->
217    {ok, #state{socket = -1}}.
218
219%%----------------------------------------------------------------------
220
221-type calls() :: 'client_info_req' | 'stop' | {'register', term(), term()}.
222
223-spec handle_call(calls(), term(), state()) ->
224        {'reply', term(), state()} | {'stop', 'shutdown', 'ok', state()}.
225
226handle_call({register, Name, PortNo, Family}, _From, State) ->
227    case State#state.socket of
228	P when P < 0 ->
229	    case do_register_node(Name, PortNo, Family) of
230		{alive, Socket, Creation} ->
231		    S = State#state{socket = Socket,
232				    port_no = PortNo,
233				    name = Name,
234				    family = Family},
235		    {reply, {ok, Creation}, S};
236                Error ->
237                    case init:get_argument(erl_epmd_port) of
238                        {ok, _} ->
239                            {reply, {ok, -1}, State#state{ socket = -1,
240                                                           port_no = PortNo,
241                                                           name = Name} };
242                        error ->
243                            {reply, Error, State}
244                    end
245	    end;
246	_ ->
247	    {reply, {error, already_registered}, State}
248    end;
249
250handle_call(client_info_req, _From, State) ->
251    Reply = {ok,{r4,State#state.name,State#state.port_no}},
252    {reply, Reply, State};
253
254handle_call(stop, _From, State) ->
255    {stop, shutdown, ok, State}.
256
257%%----------------------------------------------------------------------
258
259-spec handle_cast(term(), state()) -> {'noreply', state()}.
260
261handle_cast(_, State) ->
262    {noreply, State}.
263
264%%----------------------------------------------------------------------
265
266-spec handle_info(term(), state()) -> {'noreply', state()}.
267
268handle_info({tcp_closed, Socket}, State) when State#state.socket =:= Socket ->
269    erlang:send_after(?RECONNECT_TIME, self(), reconnect),
270    {noreply, State#state{socket = -1}};
271handle_info(reconnect, State) when State#state.socket =:= -1 ->
272    case do_register_node(State#state.name, State#state.port_no, State#state.family) of
273	{alive, Socket, _Creation} ->
274            %% ignore the received creation
275            {noreply, State#state{socket = Socket}};
276	_Error ->
277	    erlang:send_after(?RECONNECT_TIME, self(), reconnect),
278	    {noreply, State}
279    end;
280handle_info(_, State) ->
281    {noreply, State}.
282
283%%----------------------------------------------------------------------
284
285-spec terminate(term(), state()) -> 'ok'.
286
287terminate(_, #state{socket = Socket}) when Socket > 0 ->
288    close(Socket),
289    ok;
290terminate(_, _) ->
291    ok.
292
293%%----------------------------------------------------------------------
294
295-spec code_change(term(), state(), term()) -> {'ok', state()}.
296
297code_change(_OldVsn, State, _Extra) ->
298    {ok, State}.
299
300%%%----------------------------------------------------------------------
301%%% Internal functions
302%%%----------------------------------------------------------------------
303
304get_epmd_port() ->
305    case init:get_argument(epmd_port) of
306	{ok, [[PortStr|_]|_]} when is_list(PortStr) ->
307	    list_to_integer(PortStr);
308	error ->
309	    ?erlang_daemon_port
310    end.
311
312%%
313%% Epmd socket
314%%
315open() -> open({127,0,0,1}).  % The localhost IP address.
316
317open({A,B,C,D}=EpmdAddr) when ?ip(A,B,C,D) ->
318    gen_tcp:connect(EpmdAddr, get_epmd_port(), [inet]);
319open({A,B,C,D,E,F,G,H}=EpmdAddr) when ?ip6(A,B,C,D,E,F,G,H) ->
320    gen_tcp:connect(EpmdAddr, get_epmd_port(), [inet6]).
321
322open({A,B,C,D}=EpmdAddr, Timeout) when ?ip(A,B,C,D) ->
323    gen_tcp:connect(EpmdAddr, get_epmd_port(), [inet], Timeout);
324open({A,B,C,D,E,F,G,H}=EpmdAddr, Timeout) when ?ip6(A,B,C,D,E,F,G,H) ->
325    gen_tcp:connect(EpmdAddr, get_epmd_port(), [inet6], Timeout).
326
327close(Socket) ->
328    gen_tcp:close(Socket).
329
330do_register_node(NodeName, TcpPort, Family) ->
331    Localhost = case Family of
332        inet -> open({127,0,0,1});
333        inet6 -> open({0,0,0,0,0,0,0,1})
334    end,
335    case Localhost of
336	{ok, Socket} ->
337	    Name = to_string(NodeName),
338	    Extra = "",
339	    Elen = length(Extra),
340	    Len = 1+2+1+1+2+2+2+length(Name)+2+Elen,
341            Packet = [?int16(Len), ?EPMD_ALIVE2_REQ,
342                      ?int16(TcpPort),
343                      $M,
344                      0,
345                      ?int16(epmd_dist_high()),
346                      ?int16(epmd_dist_low()),
347                      ?int16(length(Name)),
348                      Name,
349                      ?int16(Elen),
350                      Extra],
351	    case gen_tcp:send(Socket, Packet) of
352                ok ->
353                    wait_for_reg_reply(Socket, []);
354                Error ->
355                    close(Socket),
356                    Error
357            end;
358	Error ->
359            Error
360    end.
361
362epmd_dist_high() ->
363    case os:getenv("ERL_EPMD_DIST_HIGH") of
364	false ->
365	   ?epmd_dist_high;
366	Version ->
367	    case (catch list_to_integer(Version)) of
368		N when is_integer(N), N < ?epmd_dist_high ->
369		    N;
370		_ ->
371		   ?epmd_dist_high
372	    end
373    end.
374
375epmd_dist_low() ->
376    case os:getenv("ERL_EPMD_DIST_LOW") of
377	false ->
378	   ?epmd_dist_low;
379	Version ->
380	    case (catch list_to_integer(Version)) of
381		N when is_integer(N), N > ?epmd_dist_low ->
382		    N;
383		_ ->
384		   ?epmd_dist_low
385	    end
386    end.
387
388
389
390%%% (When we reply 'duplicate_name', it's because it's the most likely
391%%% reason; there is no interpretation of the error result code.)
392wait_for_reg_reply(Socket, SoFar) ->
393    receive
394	{tcp, Socket, Data0} ->
395	    case SoFar ++ Data0 of
396		[$v, Result, A, B, C, D] ->
397		    case Result of
398			0 ->
399			    {alive, Socket, ?u32(A, B, C, D)};
400			_ ->
401			    {error, duplicate_name}
402		    end;
403		[$y, Result, A, B] ->
404		    case Result of
405			0 ->
406			    {alive, Socket, ?u16(A, B)};
407			_ ->
408			    {error, duplicate_name}
409		    end;
410		Data when length(Data) < 4 ->
411		    wait_for_reg_reply(Socket, Data);
412		Garbage ->
413		    {error, {garbage_from_epmd, Garbage}}
414	    end;
415	{tcp_closed, Socket} ->
416	    {error, epmd_close}
417    after 10000 ->
418	    gen_tcp:close(Socket),
419	    {error, no_reg_reply_from_epmd}
420    end.
421
422%%
423%% Lookup a node "Name" at Host
424%%
425
426get_port(Node, EpmdAddress, Timeout) ->
427    case open(EpmdAddress, Timeout) of
428	{ok, Socket} ->
429	    Name = to_string(Node),
430	    Len = 1+length(Name),
431	    Msg = [?int16(Len),?EPMD_PORT_PLEASE2_REQ,Name],
432	    case gen_tcp:send(Socket, Msg) of
433		ok ->
434		    wait_for_port_reply(Socket, []);
435		_Error ->
436		    ?port_please_failure2(_Error),
437		    noport
438	    end;
439	_Error ->
440            noport
441    end.
442
443
444wait_for_port_reply(Socket, SoFar) ->
445    receive
446	{tcp, Socket, Data0} ->
447%	    io:format("got ~p~n", [Data0]),
448	    case SoFar ++ Data0 of
449		[$w, Result | Rest] ->
450		    case Result of
451			0 ->
452			    wait_for_port_reply_cont(Socket, Rest);
453			_ ->
454			    ?port_please_failure(),
455			    wait_for_close(Socket, noport)
456		    end;
457		Data when length(Data) < 2 ->
458		    wait_for_port_reply(Socket, Data);
459		Garbage ->
460		    ?port_please_failure(),
461		    {error, {garbage_from_epmd, Garbage}}
462	    end;
463	{tcp_closed, Socket} ->
464	    ?port_please_failure(),
465	    closed
466    after 10000 ->
467	    ?port_please_failure(),
468	    gen_tcp:close(Socket),
469	    noport
470    end.
471
472wait_for_port_reply_cont(Socket, SoFar) when length(SoFar) >= 10 ->
473    wait_for_port_reply_cont2(Socket, SoFar);
474wait_for_port_reply_cont(Socket, SoFar) ->
475    receive
476	{tcp, Socket, Data0} ->
477	    case SoFar ++ Data0 of
478		Data when length(Data) >= 10 ->
479		    wait_for_port_reply_cont2(Socket, Data);
480		Data when length(Data) < 10 ->
481		    wait_for_port_reply_cont(Socket, Data);
482		Garbage ->
483		    ?port_please_failure(),
484		    {error, {garbage_from_epmd, Garbage}}
485	    end;
486	{tcp_closed, Socket} ->
487	    ?port_please_failure(),
488	    noport
489    after 10000 ->
490	    ?port_please_failure(),
491	    gen_tcp:close(Socket),
492	    noport
493    end.
494
495wait_for_port_reply_cont2(Socket, Data) ->
496    [A, B, _Type, _Proto, HighA, HighB,
497     LowA, LowB, NLenA, NLenB | Rest] = Data,
498    wait_for_port_reply_name(Socket,
499			     ?u16(NLenA, NLenB),
500			     Rest),
501    Low = ?u16(LowA, LowB),
502    High = ?u16(HighA, HighB),
503    Version = best_version(Low, High),
504%    io:format("Returning ~p~n", [{port, ?u16(A, B), Version}]),
505    {port, ?u16(A, B), Version}.
506%    {port, ?u16(A, B)}.
507
508%%% Throw away the rest of the message; we won't use any of it anyway,
509%%% currently.
510wait_for_port_reply_name(Socket, Len, Sofar) ->
511    receive
512	{tcp, Socket, _Data} ->
513%	    io:format("data = ~p~n", _Data),
514	    wait_for_port_reply_name(Socket, Len, Sofar);
515	{tcp_closed, Socket} ->
516	    ok
517    end.
518
519
520best_version(Low, High) ->
521    OurLow =  epmd_dist_low(),
522    OurHigh =  epmd_dist_high(),
523    select_best_version(OurLow, OurHigh, Low, High).
524
525%%% We silently assume that the low's are not greater than the high's.
526%%% We should report if the intervals don't overlap.
527select_best_version(L1, _H1, _L2, H2) when L1 > H2 ->
528    0;
529select_best_version(_L1, H1, L2, _H2) when L2 > H1 ->
530    0;
531select_best_version(_L1, H1, _L2, H2) ->
532    erlang:min(H1, H2).
533
534wait_for_close(Socket, Reply) ->
535    receive
536	{tcp_closed, Socket} ->
537	    Reply
538    after 10000 ->
539	    gen_tcp:close(Socket),
540	    Reply
541    end.
542
543
544%%
545%% Creates a (flat) null terminated string from atom or list.
546%%
547
548to_string(S) when is_atom(S) -> atom_to_list(S);
549to_string(S) when is_list(S) -> S.
550
551%%
552%% Find names on epmd
553%%
554%%
555get_names(EpmdAddress) ->
556    case open(EpmdAddress) of
557	{ok, Socket} ->
558	    do_get_names(Socket);
559	_Error ->
560	    {error, address}
561    end.
562
563do_get_names(Socket) ->
564    case gen_tcp:send(Socket, [?int16(1),?EPMD_NAMES]) of
565	ok ->
566	    receive
567		{tcp, Socket, [P0,P1,P2,P3|T]} ->
568		    EpmdPort = ?u32(P0,P1,P2,P3),
569		    case get_epmd_port() of
570			EpmdPort ->
571			    names_loop(Socket, T, []);
572			_ ->
573			    close(Socket),
574			    {error, address}
575		    end;
576		{tcp_closed, Socket} ->
577		    {ok, []}
578	    end;
579	_ ->
580	    close(Socket),
581	    {error, address}
582    end.
583
584names_loop(Socket, Acc, Ps) ->
585    receive
586	{tcp, Socket, Bytes} ->
587	    {NAcc, NPs} = scan_names(Acc ++ Bytes, Ps),
588	    names_loop(Socket, NAcc, NPs);
589	{tcp_closed, Socket} ->
590	    {_, NPs} = scan_names(Acc, Ps),
591	    {ok, NPs}
592    end.
593
594scan_names(Buf, Ps) ->
595    case scan_line(Buf, []) of
596	{Line, NBuf} ->
597	    case parse_line(Line) of
598		{ok, Entry} ->
599		    scan_names(NBuf, [Entry | Ps]);
600		error ->
601		    scan_names(NBuf, Ps)
602	    end;
603	[] -> {Buf, Ps}
604    end.
605
606
607scan_line([$\n | Buf], Line) -> {reverse(Line), Buf};
608scan_line([C | Buf], Line) -> scan_line(Buf, [C|Line]);
609scan_line([], _) -> [].
610
611parse_line("name " ++ Buf0) ->
612    case parse_name(Buf0, []) of
613	{Name, Buf1}  ->
614	    case Buf1 of
615		"at port " ++ Buf2 ->
616		    case catch list_to_integer(Buf2) of
617			{'EXIT', _} -> error;
618			Port -> {ok, {Name, Port}}
619		    end;
620		_ -> error
621	    end;
622	error -> error
623    end;
624parse_line(_) -> error.
625
626
627parse_name([$\s | Buf], Name) -> {reverse(Name), Buf};
628parse_name([C | Buf], Name) -> parse_name(Buf, [C|Name]);
629parse_name([], _Name) -> error.
630