[erlang-patches] [PATCH] epmd: support IPv6 node registration
Patrik Nyblom
pan@REDACTED
Tue Feb 19 18:08:47 CET 2013
On 02/18/2013 12:28 PM, Fredrik wrote:
> This happens only on windows I should add to the context also..
>
> BR Fredrik
> On 02/18/2013 12:00 PM, Fredrik wrote:
For unknown reasons, you need to drop support for win2k to get
IPPROTO_IPV6 from the windows headers. Either we can up the command line
-D_WIN32_WINVER to 0x0501 (Windows XP) or you can set (#define it) in
epmd_int.h before including winsock2.h.
...
#ifdef _WIN32_WINVER
#undef _WIN32_WINVER
#endif
#define _WIN32_WINVER 0x0501
...
But that will probably be the end of any (theoretical) windows 2000
support. We don't support Win 2000 officially, so I think it will be a
non-issue. Others might disagree though :)
/Patrik
>> 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 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 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 ->
>>
>>
>
>
More information about the erlang-patches
mailing list