Skip to content

Commit

Permalink
Allow user to specify the IP address epmd binds to
Browse files Browse the repository at this point in the history
The IP address(es) epmd binds to can now be specified by the user,
either via epmd's new "-address" option or (if that's not used) by
setting the environment variable ERL_EPMD_ADDRESS. Multiple addresses
may be specified using a comma-separated list. If the loopback address
is not in this list, it will be added implicitly, so that the daemon can
be queried by an interactive epmd process.
  • Loading branch information
weiss committed Nov 17, 2010
1 parent f26528b commit bcf3b3d
Show file tree
Hide file tree
Showing 7 changed files with 224 additions and 111 deletions.
2 changes: 1 addition & 1 deletion erts/configure.in
Original file line number Diff line number Diff line change
Expand Up @@ -1716,7 +1716,7 @@ AC_CHECK_FUNCS([getnameinfo getipnodebyname getipnodebyaddr gethostbyname2])

AC_CHECK_FUNCS([ieee_handler fpsetmask finite isnan isinf res_gethostbyname dlopen \
pread pwrite writev memmove strerror strerror_r strncasecmp \
gethrtime localtime_r gmtime_r mmap mremap memcpy mallopt \
gethrtime localtime_r gmtime_r inet_pton mmap mremap memcpy mallopt \
sbrk _sbrk __sbrk brk _brk __brk \
flockfile fstat strlcpy strlcat setsid posix2time setlocale nl_langinfo poll])

Expand Down
19 changes: 19 additions & 0 deletions erts/doc/src/epmd.xml
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,16 @@

<p>These options are available when starting the actual name server. The name server is normally started automatically by the <c>erl</c> command (if not already available), but it can also be started at i.e. system start-up.</p>
<taglist>
<tag><c><![CDATA[-address List]]></c></tag>
<item>
<p>Let this instance of <c>epmd</c> listen only on the
comma-separated list of IP addresses and on the loopback address
(which is implicitely added to the list if it has not been
specified). This can also be set using the
<c><![CDATA[ERL_EPMD_ADDRESS]]></c> environment variable, see the
section <seealso marker="#environment_variables">Environment
variables</seealso> below.</p>
</item>
<tag><c><![CDATA[-port No]]></c></tag>
<item>
<p>Let this instance of epmd listen to another TCP port than
Expand Down Expand Up @@ -228,6 +238,15 @@
<marker id="environment_variables"></marker>
<title>Environment variables</title>
<taglist>
<tag><c><![CDATA[ERL_EPMD_ADDRESS]]></c></tag>
<item>
<p>This environment variable may be set to a comma-separated
list of IP addresses, in which case the <c>epmd</c> daemon
will listen only on the specified address(es) and on the
loopback address (which is implicitely added to the list if it
has not been specified). The default behaviour is to listen on
all available IP addresses.</p>
</item>
<tag><c><![CDATA[ERL_EPMD_PORT]]></c></tag>
<item>
<p>This environment variable can contain the port number epmd will use.
Expand Down
9 changes: 9 additions & 0 deletions erts/doc/src/erl.xml
Original file line number Diff line number Diff line change
Expand Up @@ -981,6 +981,15 @@
add to the code path.
See <seealso marker="kernel:code">code(3)</seealso>.</p>
</item>
<tag><c><![CDATA[ERL_EPMD_ADDRESS]]></c></tag>
<item>
<p>This environment variable may be set to a comma-separated
list of IP addresses, in which case the
<seealso marker="epmd">epmd</seealso> daemon
will listen only on the specified address(es) and on the
loopback address (which is implicitely added to the list if it
has not been specified).</p>
</item>
<tag><c><![CDATA[ERL_EPMD_PORT]]></c></tag>
<item>
<p>This environment variable can contain the port number to use when
Expand Down
37 changes: 26 additions & 11 deletions erts/epmd/src/epmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@

static void usage(EpmdVars *);
static void run_daemon(EpmdVars*);
static char* get_addresses(void);
static int get_port_no(void);
static int check_relaxed(void);
#ifdef __WIN32__
Expand Down Expand Up @@ -133,6 +134,7 @@ int main(int argc, char** argv)
{
EpmdVars g_empd_vars;
EpmdVars *g = &g_empd_vars;
int i;
#ifdef __WIN32__
WORD wVersionRequested;
WSADATA wsaData;
Expand All @@ -158,8 +160,9 @@ int main(int argc, char** argv)
g->argv = NULL;
#endif

g->port = get_port_no();
g->debug = 0;
g->addresses = get_addresses();
g->port = get_port_no();
g->debug = 0;

g->silent = 0;
g->is_daemon = 0;
Expand All @@ -168,12 +171,14 @@ int main(int argc, char** argv)
g->delay_accept = 0;
g->delay_write = 0;
g->progname = argv[0];
g->listenfd = -1;
g->conn = NULL;
g->nodes.reg = g->nodes.unreg = g->nodes.unreg_tail = NULL;
g->nodes.unreg_count = 0;
g->active_conn = 0;

for (i = 0; i < MAX_LISTEN_SOCKETS; i++)
g->listenfd[i] = -1;

argc--;
argv++;
while (argc > 0) {
Expand Down Expand Up @@ -208,6 +213,11 @@ int main(int argc, char** argv)
else
usage(g);
epmd_cleanup_exit(g,0);
} else if (strcmp(argv[0], "-address") == 0) {
if (argc == 1)
usage(g);
g->addresses = argv[1];
argv += 2; argc -= 2;
} else if (strcmp(argv[0], "-port") == 0) {
if ((argc == 1) ||
((g->port = atoi(argv[1])) == 0))
Expand Down Expand Up @@ -252,13 +262,10 @@ int main(int argc, char** argv)
/*
* max_conn must not be greater than FD_SETSIZE.
* (at least QNX crashes)
*
* More correctly, it must be FD_SETSIZE - 1, beacuse the
* listen FD is stored outside the connection array.
*/

if (g->max_conn > FD_SETSIZE) {
g->max_conn = FD_SETSIZE - 1;
g->max_conn = FD_SETSIZE;
}

if (g->is_daemon) {
Expand Down Expand Up @@ -393,11 +400,14 @@ static void run_daemon(EpmdVars *g)

static void usage(EpmdVars *g)
{
fprintf(stderr, "usage: epmd [-d|-debug] [DbgExtra...] [-port No] [-daemon]\n");
fprintf(stderr, " [-relaxed_command_check]\n");
fprintf(stderr, "usage: epmd [-d|-debug] [DbgExtra...] [-address List]\n");
fprintf(stderr, " [-port No] [-daemon] [-relaxed_command_check]\n");
fprintf(stderr, " epmd [-d|-debug] [-port No] [-names|-kill|-stop name]\n\n");
fprintf(stderr, "See the Erlang epmd manual page for info about the usage.\n\n");
fprintf(stderr, "Regular options\n");
fprintf(stderr, " -address List\n");
fprintf(stderr, " Let epmd listen only on the comma-separated list of IP\n");
fprintf(stderr, " addresses (and on the loopback interface).\n");
fprintf(stderr, " -port No\n");
fprintf(stderr, " Let epmd listen to another port than default %d\n",
EPMD_PORT_NO);
Expand Down Expand Up @@ -555,8 +565,9 @@ void epmd_cleanup_exit(EpmdVars *g, int exitval)
epmd_conn_close(g,&g->conn[i]);
free(g->conn);
}
if(g->listenfd >= 0)
close(g->listenfd);
for(i=0; i < MAX_LISTEN_SOCKETS; i++)
if(g->listenfd[i] >= 0)
close(g->listenfd[i]);
free_all_nodes(g);
if(g->argv){
for(i=0; g->argv[i] != NULL; ++i)
Expand All @@ -568,6 +579,10 @@ void epmd_cleanup_exit(EpmdVars *g, int exitval)
exit(exitval);
}

static char* get_addresses(void)
{
return getenv("ERL_EPMD_ADDRESS");
}
static int get_port_no(void)
{
char* port_str = getenv("ERL_EPMD_PORT");
Expand Down
2 changes: 1 addition & 1 deletion erts/epmd/src/epmd_cli.c
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ static int conn_to_epmd(EpmdVars *g)

{ /* store port number in unsigned short */
unsigned short sport = g->port;
SET_ADDR_LOOPBACK(address, FAMILY, sport);
SET_ADDR(address, EPMD_ADDR_LOOPBACK, sport);
}

if (connect(connect_sock, (struct sockaddr*)&address, sizeof address) < 0)
Expand Down
59 changes: 30 additions & 29 deletions erts/epmd/src/epmd_int.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,42 +168,40 @@
#if defined(HAVE_IN6) && defined(AF_INET6) && defined(EPMD6)

#define EPMD_SOCKADDR_IN sockaddr_in6
#define FAMILY AF_INET6

#define SET_ADDR_LOOPBACK(addr, af, port) do { \
memset((char*)&(addr), 0, sizeof(addr)); \
(addr).sin6_family = (af); \
(addr).sin6_flowinfo = 0; \
(addr).sin6_addr = in6addr_loopback; \
(addr).sin6_port = htons(port); \
#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 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); \
} while(0)

#define SET_ADDR_ANY(addr, af, port) do { \
memset((char*)&(addr), 0, sizeof(addr)); \
(addr).sin6_family = (af); \
(addr).sin6_flowinfo = 0; \
(addr).sin6_addr = in6addr_any; \
(addr).sin6_port = htons(port); \
} while(0)
#define IS_ADDR_LOOPBACK(addr) \
(memcmp((addr).s6_addr, in6addr_loopback.s6_addr, 16) == 0)

#else /* Not IP v6 */

#define EPMD_SOCKADDR_IN sockaddr_in
#define FAMILY AF_INET

#define SET_ADDR_LOOPBACK(addr, af, port) do { \
memset((char*)&(addr), 0, sizeof(addr)); \
(addr).sin_family = (af); \
(addr).sin_addr.s_addr = htonl(INADDR_LOOPBACK); \
(addr).sin_port = htons(port); \
#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 { \
memset((char*)&(dst), 0, sizeof(dst)); \
(dst).sin_family = AF_INET; \
(dst).sin_addr.s_addr = (addr); \
(dst).sin_port = htons(port); \
} while(0)

#define SET_ADDR_ANY(addr, af, port) do { \
memset((char*)&(addr), 0, sizeof(addr)); \
(addr).sin_family = (af); \
(addr).sin_addr.s_addr = htonl(INADDR_ANY); \
(addr).sin_port = htons(port); \
} while(0)
#define IS_ADDR_LOOPBACK(addr) ((addr).s_addr == htonl(INADDR_LOOPBACK))

#endif /* Not IP v6 */

Expand Down Expand Up @@ -231,6 +229,8 @@
/* Maximum length of a node name == atom name */
#define MAXSYMLEN 255

#define MAX_LISTEN_SOCKETS 16

#define INBUF_SIZE 1024
#define OUTBUF_SIZE 1024

Expand Down Expand Up @@ -299,7 +299,8 @@ typedef struct {
Connection *conn;
Nodes nodes;
fd_set orig_read_mask;
int listenfd;
int listenfd[MAX_LISTEN_SOCKETS];
char *addresses;
char **argv;
} EpmdVars;

Expand Down
Loading

0 comments on commit bcf3b3d

Please sign in to comment.