erl_epmd(3)

πŸ“¦
version 29.0.6 Β· 3 versions
, in ubuntu stonking

πŸ’– erl_epmd β€” bestie edition πŸ’–

okay so you found the erl_epmd page, and honestly? iconic. this is the Erlang interface that talks to epmd, and i'm gonna walk you through every single thing on it, no skips, no skimming, periodt. ✨


πŸŽ€ NAME πŸŽ€

erl_epmd β€” the Erlang interface towards epmd. that's it, that's the whole name section, shoutout to brevity. πŸ’…


🌸 DESCRIPTION 🌸

so this module communicates with the EPMD daemon β€” go look at epmd for the deets on that guy.

and hiii, if you're the type of main character who wants to build your own epmd module instead of using the standard one? the universe has a doc for that: ERTS User's Guide: How to Implement an Alternative Node Discovery for Erlang Distribution. go read it, you got this. πŸ¦‹


✨ FUNCTIONS ✨

πŸ’« address_please(Name, Host, AddressFamily) -> Success | {error, term()}

lowkey the type signature here is giving:

address_please(Name, Host, AddressFamily) ->
                        Success | {error, term()}
                        when
                            Name :: string(),
                            Host :: string() | inet:ip_address(),
                            AddressFamily :: inet | inet6,
                            Port :: non_neg_integer(),
                            Version :: non_neg_integer(),
                            Success ::
                                {ok, inet:ip_address()} |
                                {ok, inet:ip_address(), Port, Version}.

this one gets called by the distribution module to resolve the Host into an IP address for a remote node. it's giving DNS but for Erlang, fr fr.

and here's the lil optimization moment: this function may also hand you back the port and version of that remote node. and if it does return port and version? then port_please/3 won't even get called. efficient queen. πŸ‘‘

  • Name :: string()
  • Host :: string() | inet:ip_address()
  • AddressFamily :: inet | inet6
  • Port :: non_neg_integer()
  • Version :: non_neg_integer()
  • Success :: {ok, inet:ip_address()} | {ok, inet:ip_address(), Port, Version}

πŸ’« listen_port_please(Name, Host) -> {ok, Port}

listen_port_please(Name, Host) -> {ok, Port}
                            when
                                Name :: atom() | string(),
                                Host ::
                                    atom() |
                                    string() |
                                    inet:ip_address(),
                                Port :: non_neg_integer().

called by the distribution module to figure out which port the local node should listen to when it's accepting brand new distribution requests. basically "babe, which door are we answering?" πŸšͺ✨

  • Name :: atom() | string()
  • Host :: atom() | string() | inet:ip_address()
  • Port :: non_neg_integer()

πŸ’« names(Host) -> {ok, [{Name, Port}]} | {error, Reason}

names(Host) -> {ok, [{Name, Port}]} | {error, Reason}
               when
                   Host :: atom() | string() | inet:ip_address(),
                   Name :: string(),
                   Port :: non_neg_integer(),
                   Reason :: address | file:posix().

this one is called by net_adm:names/0. Host defaults to the localhost, cute.

it returns the names and associated port numbers of all the Erlang nodes that epmd registered on the specified host. and if epmd is literally not operational? you get {error, address}. not a vibe, but you'll know. πŸ’€

example, bestie:

(arne@dunn)1> erl_epmd:names(localhost).
{ok,[{"arne",40262}]}

see? arne is out here on port 40262. slay.

  • Host :: atom() | string() | inet:ip_address()
  • Name :: string()
  • Port :: non_neg_integer()
  • Reason :: address | file:posix()

πŸ’« port_please(Name, Host, Timeout) -> {port, Port, Version} | noport | closed | {error, term()}

port_please(Name, Host, Timeout) ->
                     {port, Port, Version} |
                     noport | closed |
                     {error, term()}
                     when
                         Name :: atom() | string(),
                         Host :: atom() | string() | inet:ip_address(),
                         Timeout :: non_neg_integer() | infinity,
                         Port :: non_neg_integer(),
                         Version :: non_neg_integer().

this bad boy requests the distribution port for the given node of an EPMD instance. and along with the port, it hands you a distribution protocol version β€” which has been 5 ever since Erlang/OTP R6. yes bestie, 5, that number has not moved in a MINUTE. πŸ•°οΈ

  • Name :: atom() | string()
  • Host :: atom() | string() | inet:ip_address()
  • Timeout :: non_neg_integer() | infinity
  • Port :: non_neg_integer()
  • Version :: non_neg_integer()

πŸ’« register_node(Name, Port, Driver) -> Result

register_node(Name, Port, Driver) -> Result
                          when
                              Name :: string(),
                              Port :: non_neg_integer(),
                              Driver :: inet_tcp | inet6_tcp | inet | inet6,
                              Creation :: non_neg_integer() | -1,
                              Result ::
                                  {ok, Creation} |
                                  {error, already_registered} |
                                  term().

so this one registers the node with epmd and tells epmd exactly what port the current node is gonna use. it gives you back a creation number, and that number gets incremented on every single register β€” the whole point being to help tell apart a new node instance that's connecting to epmd with the same old name. messy name collisions? handled. πŸ’…

and here's the glow-up: once the node has successfully registered with epmd, it will automatically attempt to reconnect to the daemon if the connection breaks. self-healing behavior, we love to see it. 🫢

  • Name :: string()
  • Port :: non_neg_integer()
  • Driver :: inet_tcp | inet6_tcp | inet | inet6
  • Creation :: non_neg_integer() | -1
  • Result :: {ok, Creation} | {error, already_registered} | term()

start_link() -> {ok, pid()} | ignore | {error, term()}.

this function gets invoked because this module is added as a child of the erl_distribution supervisor. it's giving "i'm part of the family now." 🌈


okay bestie that's the whole page, every option, every type, every example, all present and accounted for, no cap. πŸŽ€

mwah, this doc came from Ericsson AB, part of kernel 11.0.3, and it's the erl_epmd(3) page. go forth and distribute, you gorgeous node. πŸ’–βœ¨πŸ¦‹

πŸ“¦ where this page comes from