[erlang-patches] [PATCH] epmd: support IPv6 node registration

Henrik Nord henrik@REDACTED
Wed Nov 7 09:35:56 CET 2012


I have refetched


On 11/07/2012 01:24 AM, Michael Santos wrote:
> Allow IPv6 nodes to register with and query epmd. On systems with
> IPv6 support:
>
> * epmd listens on the IPv4 and IPv6 ANY or loopback sockets
>
> * the epmd cli client connects to epmd using the IPv6 loopback
>
> * distributed nodes started with "-proto_dist inet6_tcp" will register
>    with epmd over IPv6
> ---
>   erts/doc/src/epmd.xml             |    2 +-
>   erts/doc/src/erl.xml              |   22 +++++
>   erts/epmd/src/epmd.c              |    6 +-
>   erts/epmd/src/epmd_cli.c          |   11 ++-
>   erts/epmd/src/epmd_int.h          |   38 ++++----
>   erts/epmd/src/epmd_srv.c          |  184 +++++++++++++++++++++++++------------
>   erts/epmd/test/epmd_SUITE.erl     |   33 ++++++-
>   lib/kernel/src/erl_epmd.erl       |   18 ++--
>   lib/kernel/src/inet6_tcp_dist.erl |    2 +-
>   9 files changed, 223 insertions(+), 93 deletions(-)
>
> diff --git a/erts/doc/src/epmd.xml b/erts/doc/src/epmd.xml
> index 3e70054..3c9313e 100644
> --- a/erts/doc/src/epmd.xml
> +++ b/erts/doc/src/epmd.xml
> @@ -36,7 +36,7 @@
>     <comsummary>
>     <p>Erlang Port Mapper Daemon</p>
>     <taglist>
> -  <tag><c><![CDATA[epmd [-d|-debug] [DbgExtra...] [-port No] [-daemon] [-relaxed_command_check]]]></c></tag>
> +  <tag><c><![CDATA[epmd [-d|-debug] [DbgExtra...] [-address Addresses] [-port No] [-daemon] [-relaxed_command_check]]]></c></tag>
>     <item>
>     <p>Starts the port mapper daemon</p>
>     </item>
> diff --git a/erts/doc/src/erl.xml b/erts/doc/src/erl.xml
> index 6221a23..09dc81e 100644
> --- a/erts/doc/src/erl.xml
> +++ b/erts/doc/src/erl.xml
> @@ -381,6 +381,28 @@
>             similar to <c><![CDATA[code:add_pathsz/1]]></c>. See
>             <seealso marker="kernel:code">code(3)</seealso>.</p>
>         </item>
> +      <tag><c><![CDATA[-proto_dist Proto]]></c></tag>
> +      <item>
> +        <p>Specify a protocol for Erlang distribution.</p>
> +	    <taglist>
> +	      <tag><c>inet_tcp</c></tag>
> +              <item>
> +                  <p>TCP over IPv4 (the default)</p>
> +              </item>
> +	      <tag><c>inet_ssl</c></tag>
> +              <item>
> +                  <p>distribution over SSL</p>
> +              </item>
> +	      <tag><c>inet6_tcp</c></tag>
> +              <item>
> +                  <p>TCP over IPv6</p>
> +              </item>
> +        </taglist>
> +        <p>For example, to start up IPv6 distributed nodes:</p>
> +<pre>
> +% <input>erl -name test@REDACTED -proto_dist inet6_tcp</input>
> +</pre>
> +      </item>
>         <tag><c><![CDATA[-remsh Node]]></c></tag>
>         <item>
>           <p>Starts Erlang with a remote shell connected to <c><![CDATA[Node]]></c>.</p>
> diff --git a/erts/epmd/src/epmd.c b/erts/epmd/src/epmd.c
> index 2267f9b..e2bba09 100644
> --- a/erts/epmd/src/epmd.c
> +++ b/erts/epmd/src/epmd.c
> @@ -335,10 +335,10 @@ static void run_daemon(EpmdVars *g)
>       for (fd = 0; fd < g->max_conn ; fd++) /* close all files ... */
>           close(fd);
>       /* Syslog on linux will try to write to whatever if we dont
> -       inform it of that the log is closed. */
> +       inform it that the log is closed. */
>       closelog();
>   
> -    /* These chouldn't be needed but for safety... */
> +    /* These shouldn't be needed but for safety... */
>   
>       open("/dev/null", O_RDONLY); /* Order is important! */
>       open("/dev/null", O_WRONLY);
> @@ -379,7 +379,7 @@ static void run_daemon(EpmdVars *g)
>       close(1);
>       close(2);
>   
> -    /* These chouldn't be needed but for safety... */
> +    /* These shouldn't be needed but for safety... */
>   
>       open("nul", O_RDONLY);
>       open("nul", O_WRONLY);
> diff --git a/erts/epmd/src/epmd_cli.c b/erts/epmd/src/epmd_cli.c
> index 74408e3..e46a700 100644
> --- a/erts/epmd/src/epmd_cli.c
> +++ b/erts/epmd/src/epmd_cli.c
> @@ -132,6 +132,7 @@ void epmd_call(EpmdVars *g,int what)
>   static int conn_to_epmd(EpmdVars *g)
>   {
>       struct EPMD_SOCKADDR_IN address;
> +    size_t salen = 0;
>       int connect_sock;
>       
>       connect_sock = socket(FAMILY, SOCK_STREAM, 0);
> @@ -140,10 +141,16 @@ static int conn_to_epmd(EpmdVars *g)
>   
>       { /* store port number in unsigned short */
>         unsigned short sport = g->port;
> -      SET_ADDR(address, EPMD_ADDR_LOOPBACK, sport);
> +#if defined(HAVE_IN6) && defined(AF_INET6)
> +      SET_ADDR6(address, in6addr_loopback, sport);
> +      salen = sizeof(struct sockaddr_in6);
> +#else
> +      SET_ADDR(address, htonl(INADDR_LOOPBACK), sport);
> +      salen = sizeof(struct sockaddr_in);
> +#endif
>       }
>   
> -    if (connect(connect_sock, (struct sockaddr*)&address, sizeof address) < 0)
> +    if (connect(connect_sock, (struct sockaddr*)&address, salen) < 0)
>   	goto error;
>       return connect_sock;
>   
> diff --git a/erts/epmd/src/epmd_int.h b/erts/epmd/src/epmd_int.h
> index 14d05c3..9c77e86 100644
> --- a/erts/epmd/src/epmd_int.h
> +++ b/erts/epmd/src/epmd_int.h
> @@ -49,6 +49,7 @@
>   #  ifndef WINDOWS_H_INCLUDES_WINSOCK2_H
>   #    include <winsock2.h>
>   #  endif
> +#  include <ws2tcpip.h>
>   #  include <windows.h>
>   #  include <process.h>
>   #endif
> @@ -165,33 +166,32 @@
>   /* ************************************************************************ */
>   /* Macros that let us use IPv6                                              */
>   
> -#if defined(HAVE_IN6) && defined(AF_INET6) && defined(EPMD6)
> +#define IS_ADDR_LOOPBACK(addr) ((addr).s_addr == htonl(INADDR_LOOPBACK))
> +
> +#if defined(HAVE_IN6) && defined(AF_INET6)
>   
> -#define EPMD_SOCKADDR_IN sockaddr_in6
> -#define EPMD_IN_ADDR in6_addr
> -#define EPMD_S_ADDR s6_addr
> -#define EPMD_ADDR_LOOPBACK in6addr_loopback.s6_addr
> -#define EPMD_ADDR_ANY in6addr_any.s6_addr
> +#define EPMD_SOCKADDR_IN sockaddr_storage
>   #define FAMILY AF_INET6
>   
> -#define SET_ADDR(dst, addr, port) do { \
> -    memset((char*)&(dst), 0, sizeof(dst)); \
> -    memcpy((char*)&(dst).sin6_addr.s6_addr, (char*)&(addr), 16); \
> -    (dst).sin6_family = AF_INET6; \
> -    (dst).sin6_flowinfo = 0; \
> -    (dst).sin6_port = htons(port); \
> +#define SET_ADDR6(dst, addr, port) do { \
> +    struct sockaddr_in6 *sa = (struct sockaddr_in6 *)&(dst); \
> +    memset(sa, 0, sizeof(dst)); \
> +    sa->sin6_family = AF_INET6; \
> +    sa->sin6_addr = (addr); \
> +    sa->sin6_port = htons(port); \
>    } while(0)
>   
> -#define IS_ADDR_LOOPBACK(addr) \
> -    (memcmp((addr).s6_addr, in6addr_loopback.s6_addr, 16) == 0)
> +#define SET_ADDR(dst, addr, port) do { \
> +    struct sockaddr_in *sa = (struct sockaddr_in *)&(dst); \
> +    memset(sa, 0, sizeof(dst)); \
> +    sa->sin_family = AF_INET; \
> +    sa->sin_addr.s_addr = (addr); \
> +    sa->sin_port = htons(port); \
> + } while(0)
>   
>   #else /* Not IP v6 */
>   
>   #define EPMD_SOCKADDR_IN sockaddr_in
> -#define EPMD_IN_ADDR in_addr
> -#define EPMD_S_ADDR s_addr
> -#define EPMD_ADDR_LOOPBACK htonl(INADDR_LOOPBACK)
> -#define EPMD_ADDR_ANY htonl(INADDR_ANY)
>   #define FAMILY AF_INET
>   
>   #define SET_ADDR(dst, addr, port) do { \
> @@ -201,8 +201,6 @@
>       (dst).sin_port = htons(port); \
>    } while(0)
>   
> -#define IS_ADDR_LOOPBACK(addr) ((addr).s_addr == htonl(INADDR_LOOPBACK))
> -
>   #endif /* Not IP v6 */
>   
>   /* ************************************************************************ */
> diff --git a/erts/epmd/src/epmd_srv.c b/erts/epmd/src/epmd_srv.c
> index da575af..538706b 100644
> --- a/erts/epmd/src/epmd_srv.c
> +++ b/erts/epmd/src/epmd_srv.c
> @@ -69,6 +69,7 @@ static time_t current_time(EpmdVars*);
>   
>   static Connection *conn_init(EpmdVars*);
>   static int conn_open(EpmdVars*,int);
> +static int conn_local_peer_check(EpmdVars*, int);
>   static int conn_close_fd(EpmdVars*,int);
>   
>   static void node_init(EpmdVars*);
> @@ -92,7 +93,7 @@ void run(EpmdVars *g)
>   {
>     struct EPMD_SOCKADDR_IN iserv_addr[MAX_LISTEN_SOCKETS];
>     int listensock[MAX_LISTEN_SOCKETS];
> -  int num_sockets;
> +  int num_sockets = 0;
>     int i;
>     int opt;
>     unsigned short sport = g->port;
> @@ -105,64 +106,82 @@ void run(EpmdVars *g)
>     if (g->addresses != NULL && /* String contains non-separator characters if: */
>         g->addresses[strspn(g->addresses," ,")] != '\000')
>       {
> -      char *tmp;
> -      char *token;
> -      int loopback_ok = 0;
> +      char *tmp = NULL;
> +      char *token = NULL;
> +
> +      /* Always listen on the loopback. */
> +      SET_ADDR(iserv_addr[num_sockets],htonl(INADDR_LOOPBACK),sport);
> +      num_sockets++;
> +#if defined(HAVE_IN6) && defined(AF_INET6)
> +      SET_ADDR6(iserv_addr[num_sockets],in6addr_loopback,sport);
> +      num_sockets++;
> +#endif
>   
> -      if ((tmp = (char *)malloc(strlen(g->addresses) + 1)) == NULL)
> +	  if ((tmp = strdup(g->addresses)) == NULL)
>   	{
>   	  dbg_perror(g,"cannot allocate memory");
>   	  epmd_cleanup_exit(g,1);
>   	}
> -      strcpy(tmp,g->addresses);
>   
> -      for(token = strtok(tmp,", "), num_sockets = 0;
> +      for(token = strtok(tmp,", ");
>   	  token != NULL;
> -	  token = strtok(NULL,", "), num_sockets++)
> +	  token = strtok(NULL,", "))
>   	{
> -	  struct EPMD_IN_ADDR addr;
> -#ifdef HAVE_INET_PTON
> -	  int ret;
> +	  struct in_addr addr;
> +#if defined(HAVE_IN6) && defined(AF_INET6)
> +	  struct in6_addr addr6;
> +	  struct sockaddr_storage *sa = &iserv_addr[num_sockets];
>   
> -	  if ((ret = inet_pton(FAMILY,token,&addr)) == -1)
> +	  if (inet_pton(AF_INET,token,&addr) == 1)
>   	    {
> -	      dbg_perror(g,"cannot convert IP address to network format");
> -	      epmd_cleanup_exit(g,1);
> +	      SET_ADDR(iserv_addr[num_sockets],addr.s_addr,sport);
> +	    }
> +	  else if (inet_pton(AF_INET6,token,&addr6) == 1)
> +	    {
> +	      SET_ADDR6(iserv_addr[num_sockets],addr6,sport);
> +	    }
> +	  else
> +#else
> +	  if ((addr.s_addr = inet_addr(token)) != INADDR_NONE)
> +	    {
> +	      SET_ADDR(iserv_addr[num_sockets],addr.s_addr,sport);
>   	    }
> -	  else if (ret == 0)
> -#elif !defined(EPMD6)
> -	  if ((addr.EPMD_S_ADDR = inet_addr(token)) == INADDR_NONE)
> +	  else
>   #endif
>   	    {
>   	      dbg_tty_printf(g,0,"cannot parse IP address \"%s\"",token);
>   	      epmd_cleanup_exit(g,1);
>   	    }
>   
> +#if defined(HAVE_IN6) && defined(AF_INET6)
> +	  if (sa->ss_family == AF_INET6 && IN6_IS_ADDR_LOOPBACK(&addr6))
> +	      continue;
> +
> +	  if (sa->ss_family == AF_INET)
> +#endif
>   	  if (IS_ADDR_LOOPBACK(addr))
> -	    loopback_ok = 1;
> +	    continue;
>   
> -	  if (num_sockets - loopback_ok == MAX_LISTEN_SOCKETS - 1)
> +	  num_sockets++;
> +
> +	  if (num_sockets >= MAX_LISTEN_SOCKETS)
>   	    {
>   	      dbg_tty_printf(g,0,"cannot listen on more than %d IP addresses",
>   			     MAX_LISTEN_SOCKETS);
>   	      epmd_cleanup_exit(g,1);
>   	    }
> -
> -	  SET_ADDR(iserv_addr[num_sockets],addr.EPMD_S_ADDR,sport);
>   	}
>   
>         free(tmp);
> -
> -      if (!loopback_ok)
> -	{
> -	  SET_ADDR(iserv_addr[num_sockets],EPMD_ADDR_LOOPBACK,sport);
> -	  num_sockets++;
> -	}
>       }
>     else
>       {
> -      SET_ADDR(iserv_addr[0],EPMD_ADDR_ANY,sport);
> -      num_sockets = 1;
> +      SET_ADDR(iserv_addr[num_sockets],htonl(INADDR_ANY),sport);
> +      num_sockets++;
> +#if defined(HAVE_IN6) && defined(AF_INET6)
> +      SET_ADDR6(iserv_addr[num_sockets],in6addr_any,sport);
> +      num_sockets++;
> +#endif
>       }
>   
>   #if !defined(__WIN32__)
> @@ -183,13 +202,33 @@ void run(EpmdVars *g)
>   
>     for (i = 0; i < num_sockets; i++)
>       {
> -      if ((listensock[i] = socket(FAMILY,SOCK_STREAM,0)) < 0)
> +      struct sockaddr *sa = (struct sockaddr *)&iserv_addr[i];
> +#if defined(HAVE_IN6) && defined(AF_INET6)
> +      size_t salen = (sa->sa_family == AF_INET6 ?
> +              sizeof(struct sockaddr_in6) :
> +              sizeof(struct sockaddr_in));
> +#else
> +      size_t salen = sizeof(struct sockaddr_in);
> +#endif
> +
> +      if ((listensock[i] = socket(sa->sa_family,SOCK_STREAM,0)) < 0)
>   	{
>   	  dbg_perror(g,"error opening stream socket");
>   	  epmd_cleanup_exit(g,1);
>   	}
>         g->listenfd[i] = listensock[i];
> -
> +
> +#if defined(HAVE_IN6) && defined(AF_INET6)
> +      opt = 1;
> +      if (sa->sa_family == AF_INET6 &&
> +          setsockopt(listensock[i],IPPROTO_IPV6,IPV6_V6ONLY,&opt,
> +              sizeof(opt)) <0)
> +	{
> +	  dbg_perror(g,"can't set IPv6 only socket option");
> +	  epmd_cleanup_exit(g,1);
> +	}
> +#endif
> +
>         /*
>          * Note that we must not enable the SO_REUSEADDR on Windows,
>          * because addresses will be reused even if they are still in use.
> @@ -221,8 +260,7 @@ void run(EpmdVars *g)
>   	dbg_perror(g,"failed to set non-blocking mode of listening socket %d",
>   		   listensock[i]);
>   
> -      if (bind(listensock[i], (struct sockaddr*) &iserv_addr[i],
> -	  sizeof(iserv_addr[i])) < 0)
> +      if (bind(listensock[i], (struct sockaddr*) &iserv_addr[i], salen) < 0)
>   	{
>   	  if (errno == EADDRINUSE)
>   	    {
> @@ -818,15 +856,6 @@ static int conn_open(EpmdVars *g,int fd)
>   
>     for (i = 0; i < g->max_conn; i++) {
>       if (g->conn[i].open == EPMD_FALSE) {
> -      struct sockaddr_in si;
> -      struct sockaddr_in di;
> -#ifdef HAVE_SOCKLEN_T
> -      socklen_t st;
> -#else
> -      int st;
> -#endif
> -      st = sizeof(si);
> -
>         g->active_conn++;
>         s = &g->conn[i];
>        
> @@ -837,20 +866,7 @@ static int conn_open(EpmdVars *g,int fd)
>         s->open = EPMD_TRUE;
>         s->keep = EPMD_FALSE;
>   
> -      /* Determine if connection is from localhost */
> -      if (getpeername(s->fd,(struct sockaddr*) &si,&st) ||
> -	  st < sizeof(si)) {
> -	  /* Failure to get peername is regarded as non local host */
> -	  s->local_peer = EPMD_FALSE;
> -      } else {
> -	  /* Only 127.x.x.x and connections from the host's IP address
> -	     allowed, no false positives */
> -	  s->local_peer =
> -	      (((((unsigned) ntohl(si.sin_addr.s_addr)) & 0xFF000000U) ==
> -	       0x7F000000U) ||
> -	       (getsockname(s->fd,(struct sockaddr*) &di,&st) ?
> -	       EPMD_FALSE : si.sin_addr.s_addr == di.sin_addr.s_addr));
> -      }
> +      s->local_peer = conn_local_peer_check(g, s->fd);
>         dbg_tty_printf(g,2,(s->local_peer) ? "Local peer connected" :
>   		     "Non-local peer connected");
>   
> @@ -858,7 +874,7 @@ static int conn_open(EpmdVars *g,int fd)
>         s->got  = 0;
>         s->mod_time = current_time(g); /* Note activity */
>   
> -      s->buf = (char *)malloc(INBUF_SIZE);
> +      s->buf = malloc(INBUF_SIZE);
>   
>         if (s->buf == NULL) {
>   	dbg_printf(g,0,"epmd: Insufficient memory");
> @@ -876,6 +892,60 @@ static int conn_open(EpmdVars *g,int fd)
>     return EPMD_FALSE;
>   }
>   
> +static int conn_local_peer_check(EpmdVars *g, int fd)
> +{
> +  struct EPMD_SOCKADDR_IN si;
> +  struct EPMD_SOCKADDR_IN di;
> +
> +  struct sockaddr_in *si4 = (struct sockaddr_in *)&si;
> +  struct sockaddr_in *di4 = (struct sockaddr_in *)&di;
> +
> +#if defined(HAVE_IN6) && defined(AF_INET6)
> +  struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)&si;
> +  struct sockaddr_in6 *di6 = (struct sockaddr_in6 *)&di;
> +#endif
> +
> +#ifdef HAVE_SOCKLEN_T
> +  socklen_t st;
> +#else
> +  int st;
> +#endif
> +
> +  st = sizeof(si);
> +
> +  /* Determine if connection is from localhost */
> +  if (getpeername(fd,(struct sockaddr*) &si,&st) ||
> +	  st > sizeof(si)) {
> +	  /* Failure to get peername is regarded as non local host */
> +	  return EPMD_FALSE;
> +  }
> +
> +  /* Only 127.x.x.x and connections from the host's IP address
> +	 allowed, no false positives */
> +#if defined(HAVE_IN6) && defined(AF_INET6)
> +  if (si.ss_family == AF_INET6 && IN6_IS_ADDR_LOOPBACK(&(si6->sin6_addr)))
> +	  return EPMD_TRUE;
> +
> +  if (si.ss_family == AF_INET)
> +#endif
> +  if ((((unsigned) ntohl(si4->sin_addr.s_addr)) & 0xFF000000U) ==
> +	  0x7F000000U)
> +	  return EPMD_TRUE;
> +
> +  if (getsockname(fd,(struct sockaddr*) &di,&st))
> +	  return EPMD_FALSE;
> +
> +#if defined(HAVE_IN6) && defined(AF_INET6)
> +  if (si.ss_family == AF_INET6)
> +      return IN6_ARE_ADDR_EQUAL( &(si6->sin6_addr), &(di6->sin6_addr));
> +  if (si.ss_family == AF_INET)
> +#endif
> +  return si4->sin_addr.s_addr == di4->sin_addr.s_addr;
> +#if defined(HAVE_IN6) && defined(AF_INET6)
> +  return EPMD_FALSE;
> +#endif
> +}
> +
>   static int conn_close_fd(EpmdVars *g,int fd)
>   {
>     int i;
> diff --git a/erts/epmd/test/epmd_SUITE.erl b/erts/epmd/test/epmd_SUITE.erl
> index 3f31cd9..5821cd8 100644
> --- a/erts/epmd/test/epmd_SUITE.erl
> +++ b/erts/epmd/test/epmd_SUITE.erl
> @@ -42,6 +42,7 @@
>   -export(
>      [
>       register_name/1,
> +    register_name_ipv6/1,
>       register_names_1/1,
>       register_names_2/1,
>       register_duplicate_name/1,
> @@ -106,7 +107,8 @@
>   suite() -> [{ct_hooks,[ts_install_cth]}].
>   
>   all() ->
> -    [register_name, register_names_1, register_names_2,
> +    [register_name, register_name_ipv6,
> +     register_names_1, register_names_2,
>        register_duplicate_name, get_port_nr, slow_get_port_nr,
>        unregister_others_name_1, unregister_others_name_2,
>        register_overflow, name_with_null_inside,
> @@ -162,6 +164,24 @@ register_name(Config) when is_list(Config) ->
>       ?line ok = close(Sock),			% Unregister
>       ok.
>   
> +register_name_ipv6(doc) ->
> +    ["Register a name over IPv6"];
> +register_name_ipv6(suite) ->
> +    [];
> +register_name_ipv6(Config) when is_list(Config) ->
> +    % Test if the host has an IPv6 loopback address
> +    Res = gen_tcp:listen(0, [inet6, {ip, {0,0,0,0,0,0,0,1}}]),
> +    case Res of
> +    {ok,LSock} ->
> +	    gen_tcp:close(LSock),
> +	    ?line ok = epmdrun(),
> +	    ?line {ok,Sock} = register_node6("foobar6"),
> +	    ?line ok = close(Sock),         % Unregister
> +	    ok;
> +    _Error ->
> +	    {skip, "Host does not have an IPv6 loopback address"}
> +    end.
> +
>   register_names_1(doc) ->
>       ["Register and unregister two nodes"];
>   register_names_1(suite) ->
> @@ -204,12 +224,17 @@ register_node(Name) ->
>   register_node(Name,Port) ->
>       register_node_v2(Port,$M,0,5,5,Name,"").
>   
> +register_node6(Name) ->
> +    register_node_v2({0,0,0,0,0,0,0,1},?DUMMY_PORT,$M,0,5,5,Name,"").
> +
>   register_node_v2(Port, NodeType, Prot, HVsn, LVsn, Name, Extra) ->
> +    register_node_v2("localhost", Port, NodeType, Prot, HVsn, LVsn, Name, Extra).
> +register_node_v2(Addr, Port, NodeType, Prot, HVsn, LVsn, Name, Extra) ->
>       Req = [?EPMD_ALIVE2_REQ, put16(Port), NodeType, Prot,
>   	   put16(HVsn), put16(LVsn),
>   	   size16(Name), Name,
>   	   size16(Extra), Extra],
> -    case send_req(Req) of
> +    case send_req(Req, Addr) of
>   	{ok,Sock} ->
>   	    case recv(Sock,4) of
>   		{ok, [?EPMD_ALIVE2_RESP,_Res=0,_C0,_C1]} ->
> @@ -1092,7 +1117,9 @@ send_direct(Sock, Bytes) ->
>       end.
>   
>   send_req(Req) ->
> -    case connect() of
> +    send_req(Req, "localhost").
> +send_req(Req, Addr) ->
> +    case connect(Addr) of
>   	{ok,Sock} ->
>   	    case send(Sock, [size16(Req), Req]) of
>   		ok ->
> diff --git a/lib/kernel/src/erl_epmd.erl b/lib/kernel/src/erl_epmd.erl
> index 91af49f..21a3dec 100644
> --- a/lib/kernel/src/erl_epmd.erl
> +++ b/lib/kernel/src/erl_epmd.erl
> @@ -31,7 +31,7 @@
>   %% External exports
>   -export([start/0, start_link/0, stop/0, port_please/2,
>   	 port_please/3, names/0, names/1,
> -	 register_node/2, open/0, open/1, open/2]).
> +	 register_node/2, register_node/3, open/0, open/1, open/2]).
>   
>   %% gen_server callbacks
>   -export([init/1, handle_call/3, handle_cast/2, handle_info/2,
> @@ -106,7 +106,9 @@ names1(HostName) ->
>   
>   
>   register_node(Name, PortNo) ->
> -    gen_server:call(erl_epmd, {register, Name, PortNo}, infinity).
> +    register_node(Name, PortNo, inet).
> +register_node(Name, PortNo, Family) ->
> +    gen_server:call(erl_epmd, {register, Name, PortNo, Family}, infinity).
>   
>   %%%----------------------------------------------------------------------
>   %%% Callback functions from gen_server
> @@ -124,10 +126,10 @@ init(_) ->
>   -spec handle_call(calls(), term(), state()) ->
>           {'reply', term(), state()} | {'stop', 'shutdown', 'ok', state()}.
>   
> -handle_call({register, Name, PortNo}, _From, State) ->
> +handle_call({register, Name, PortNo, Family}, _From, State) ->
>       case State#state.socket of
>   	P when P < 0 ->
> -	    case do_register_node(Name, PortNo) of
> +	    case do_register_node(Name, PortNo, Family) of
>   		{alive, Socket, Creation} ->
>   		    S = State#state{socket = Socket,
>   				    port_no = PortNo,
> @@ -210,8 +212,12 @@ open({A,B,C,D,E,F,G,H}=EpmdAddr, Timeout) when ?ip6(A,B,C,D,E,F,G,H) ->
>   close(Socket) ->
>       gen_tcp:close(Socket).
>   
> -do_register_node(NodeName, TcpPort) ->
> -    case open() of
> +do_register_node(NodeName, TcpPort, Family) ->
> +    Localhost = case Family of
> +        inet -> open({127,0,0,1});
> +        inet6 -> open({0,0,0,0,0,0,0,1})
> +    end,
> +    case Localhost of
>   	{ok, Socket} ->
>   	    Name = to_string(NodeName),
>   	    Extra = "",
> diff --git a/lib/kernel/src/inet6_tcp_dist.erl b/lib/kernel/src/inet6_tcp_dist.erl
> index b9c4fa6..0b5fb44 100644
> --- a/lib/kernel/src/inet6_tcp_dist.erl
> +++ b/lib/kernel/src/inet6_tcp_dist.erl
> @@ -71,7 +71,7 @@ listen(Name) ->
>           {ok, Socket} ->
>               TcpAddress = get_tcp_address(Socket),
>               {_,Port} = TcpAddress#net_address.address,
> -            {ok, Creation} = erl_epmd:register_node(Name, Port),
> +            {ok, Creation} = erl_epmd:register_node(Name, Port, inet6),
>               {ok, {Socket, TcpAddress, Creation}};
>           Error ->
>               Error

-- 
/Henrik Nord Erlang/OTP




More information about the erlang-patches mailing list