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

Fredrik <>
Mon Feb 18 12:28:13 CET 2013


This happens only on windows I should add to the context also..

BR Fredrik
On 02/18/2013 12:00 PM, Fredrik wrote:
> Hello,
> Your patch does not seem to build:
>
> epmd_srv.c(332) : error C2065: 'IPPROTO_IPV6' : undeclared identifier
> epmd_srv.c(332) : warning C4133: 'function' : incompatible types - 
> from 'int *' to 'const char *'
>
>
> Could you please have a look at this problem?
>
> On 02/17/2013 12:23 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          |   59 ++++++++----
>>   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, 244 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 f354d68..aebf4ff 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  -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 94bb74c..0789cc3 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 8817bde..a0dd890 100644
>> --- a/erts/epmd/src/epmd_cli.c
>> +++ b/erts/epmd/src/epmd_cli.c
>> @@ -135,6 +135,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);
>> @@ -143,10 +144,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 ac354dc..b16c137 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,53 @@
>>   /* 
>> ************************************************************************ 
>> */
>>   /* Macros that let us use 
>> IPv6                                              */
>>
>> -#if defined(HAVE_IN6)&&  defined(AF_INET6)&&  defined(EPMD6)
>> +#if HAVE_IN6
>> +#  if ! defined(HAVE_IN6ADDR_ANY) || ! HAVE_IN6ADDR_ANY
>> +#    if HAVE_DECL_IN6ADDR_ANY_INIT
>> +static const struct in6_addr in6addr_any = { { IN6ADDR_ANY_INIT } };
>> +#    else
>> +static const struct in6_addr in6addr_any =
>> +    { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } };
>> +#    endif /* HAVE_IN6ADDR_ANY_INIT */
>> +#  endif /* ! HAVE_DECL_IN6ADDR_ANY */
>> +
>> +#  if ! defined(HAVE_IN6ADDR_LOOPBACK) || ! HAVE_IN6ADDR_LOOPBACK
>> +#    if HAVE_DECL_IN6ADDR_LOOPBACK_INIT
>> +static const struct in6_addr in6addr_loopback =
>> +    { { IN6ADDR_LOOPBACK_INIT } };
>> +#    else
>> +static const struct in6_addr in6addr_loopback =
>> +    { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } };
>> +#    endif /* HAVE_IN6ADDR_LOOPBACK_INIT */
>> +#  endif /* ! HAVE_DECL_IN6ADDR_LOOPBACK */
>> +#endif /* HAVE_IN6 */
>> +
>> +#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 +222,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 90df7cc..1c34f5f 100644
>> --- a/erts/epmd/src/epmd_srv.c
>> +++ b/erts/epmd/src/epmd_srv.c
>> @@ -70,6 +70,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*);
>> @@ -200,7 +201,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;
>> @@ -213,64 +214,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__)
>> @@ -291,13 +310,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.
>> @@ -329,8 +368,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)
>>           {
>> @@ -952,15 +990,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];
>>
>> @@ -971,20 +1000,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");
>>
>> @@ -992,7 +1008,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");
>> @@ -1010,6 +1026,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 cc24a55..ddfe5ab 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,
>> @@ -108,7 +109,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, unicode_name, long_unicode_name,
>>        get_port_nr, slow_get_port_nr,
>>        unregister_others_name_1, unregister_others_name_2,
>> @@ -165,6 +167,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) ->
>> @@ -238,13 +258,18 @@ 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) ->
>>       Utf8Name = unicode:characters_to_binary(Name),
>>       Req = [?EPMD_ALIVE2_REQ, put16(Port), NodeType, Prot,
>>          put16(HVsn), put16(LVsn),
>>          put16(size(Utf8Name)), binary_to_list(Utf8Name),
>>          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]} ->
>> @@ -1129,7 +1154,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 2315a56..bba4d87 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,
>> -            case erl_epmd:register_node(Name, Port) of
>> +            case erl_epmd:register_node(Name, Port, inet6) of
>>                   {ok, Creation} ->
>>                       {ok, {Socket, TcpAddress, Creation}};
>>                   Error ->
>
>


-- 

BR Fredrik Gustafsson
Erlang OTP Team



More information about the erlang-patches mailing list