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