/* -*- c-indent-level: 2; c-continued-statement-offset: 2 -*- */ /* * %CopyrightBegin% * * Copyright Ericsson AB 1998-2016. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * %CopyrightEnd% */ /* * This file is for internal use within epmd. */ /* This file don't depend on "sys.h" so we have to do some target definitions ourselves */ #ifdef __WIN32__ #define NO_SYSCONF #define NO_DAEMON #endif #ifdef VXWORKS #define NO_SYSCONF #define NO_DAEMON #define NO_FCNTL #define DONT_USE_MAIN #endif /* ************************************************************************ */ /* Standard includes */ #include #include #include #ifdef __WIN32__ # ifndef WINDOWS_H_INCLUDES_WINSOCK2_H # include # endif # include # include # include #endif #include #include #ifdef VXWORKS # include # include # include # include # include # include # include # include #else /* ! VXWORKS */ #ifndef __WIN32__ # ifdef TIME_WITH_SYS_TIME # include # include # else # ifdef HAVE_SYS_TIME_H # include # else # include # endif # endif #endif #endif /* ! VXWORKS */ #if !defined(__WIN32__) # include # include # include # ifdef DEF_INADDR_LOOPBACK_IN_RPC_TYPES_H # include # endif # include # include #endif /* ! WIN32 */ #include #include #include #ifdef HAVE_SYSLOG_H # include #endif #ifdef SYS_SELECT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif #include #ifdef HAVE_SYSTEMD_DAEMON # include #endif /* HAVE_SYSTEMD_DAEMON */ #if defined(HAVE_IN6) && defined(AF_INET6) && defined(HAVE_INET_PTON) # define EPMD6 #endif /* ************************************************************************ */ /* Replace some functions by others by making the function name a macro */ #ifdef __WIN32__ # define close(s) closesocket((s)) # define write(a,b,c) send((a),(b),(c),0) # define read(a,b,c) recv((a),(char *)(b),(c),0) # define sleep(s) Sleep((s) * 1000) # define ioctl(s,r,o) ioctlsocket((s),(r),(o)) #endif /* WIN32 */ #ifdef VXWORKS #define sleep(n) taskDelay((n) * sysClkRateGet()) #endif /* VXWORKS */ #ifdef USE_BCOPY # define memcpy(a, b, c) bcopy((b), (a), (c)) # define memcmp(a, b, c) bcmp((a), (b), (c)) # define memzero(buf, len) bzero((buf), (len)) #else # define memzero(buf, len) memset((buf), '\0', (len)) #endif /* ************************************************************************ */ /* Try to find replacement values for undefined system parameters */ #if defined(__WIN32__) && !defined(EADDRINUSE) # define EADDRINUSE WSAEADDRINUSE #endif #if defined(__WIN32__) && !defined(ECONNABORTED) # define ECONNABORTED WSAECONNABORTED #endif #ifndef SOMAXCONN # define SOMAXCONN 128 #endif /* * How to get max no of file descriptors? We used to use NOFILE from * , but that tends to have little relation to reality. * Best is to use sysconf() (POSIX), but we'll just punt if that isn't * available. Start out with a high value because it will also be * used as the number of file descriptors given to select() (it's is * a terrible bug not to have all file descriptors included in the select()). * The value will be adjusted down if FD_SETSIZE is smaller. */ #define MAX_FILES 2048 /* if sysconf() isn't available, or fails */ /* ************************************************************************ */ /* Macros that let us use IPv6 */ #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(EPMD6) #define EPMD_SOCKADDR_IN sockaddr_storage #define FAMILY AF_INET6 #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 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 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) #endif /* Not IP v6 */ /* ************************************************************************ */ /* Our own definitions */ #define EPMD_FALSE 0 #define EPMD_TRUE 1 /* If no activity we let select() return every IDLE_TIMEOUT second A file descriptor that has been idle for CLOSE_TIMEOUT seconds and isn't an ALIVE socket has probably hanged and should be closed */ #define IDLE_TIMEOUT 5 #define CLOSE_TIMEOUT 60 /* We save the name of nodes that are unregistered. If a new node register the name we want to increment the "creation", a constant 1..3. But we put an limit to this saving to keep the lookup fast and not to leak memory. */ #define MAX_UNREG_COUNT 1000 #define DEBUG_MAX_UNREG_COUNT 5 /* * Maximum length of a node name == atom name * 255 characters; UTF-8 encoded -> max 255*4 */ #define MAXSYMLEN (255*4) #define MAX_LISTEN_SOCKETS 16 /* * Largest request: ALIVE2_REQ * 2 + 13 + 2*MAXSYMLEN * Largest response: PORT2_RESP * 2 + 14 + 2*MAXSYMLEN * * That is, 3*MAXSYMLEN should be large enough */ #define INBUF_SIZE (3*MAXSYMLEN) #define OUTBUF_SIZE (3*MAXSYMLEN) #define get_int16(s) ((((unsigned char*) (s))[0] << 8) | \ (((unsigned char*) (s))[1])) #define put_int16(i, s) {((unsigned char*)(s))[0] = ((i) >> 8) & 0xff; \ ((unsigned char*)(s))[1] = (i) & 0xff;} #if defined(__GNUC__) # define EPMD_INLINE __inline__ #elif defined(__WIN32__) # define EPMD_INLINE __inline #else # define EPMD_INLINE #endif /* ************************************************************************ */ /* Stuctures used by server */ typedef struct { int fd; /* File descriptor */ unsigned char open; /* TRUE if open */ unsigned char keep; /* Don't close when sent reply */ unsigned char local_peer; /* The peer of this connection is via loopback interface */ unsigned got; /* # of bytes we have got */ unsigned want; /* Number of bytes we want */ char *buf; /* The remaining buffer */ time_t mod_time; /* Last activity on this socket */ } Connection; struct enode { struct enode *next; int fd; /* The socket in use */ unsigned short port; /* Port number of Erlang node */ char symname[MAXSYMLEN+1]; /* Name of the Erlang node */ short creation; /* Started as a random number 1..3 */ char nodetype; /* 77 = normal erlang node 72 = hidden (c-node */ char protocol; /* 0 = tcp/ipv4 */ unsigned short highvsn; /* 0 = OTP-R3 erts-4.6.x, 1 = OTP-R4 erts-4.7.x*/ unsigned short lowvsn; int extralen; char extra[MAXSYMLEN+1]; }; typedef struct enode Node; typedef struct { Node *reg; Node *unreg; Node *unreg_tail; int unreg_count; } Nodes; /* This is the structure with all variables needed to pass on to all functions. This makes this program reentrant */ typedef struct { int port; int debug; int silent; int is_daemon; int brutal_kill; unsigned packet_timeout; unsigned delay_accept; unsigned delay_write; int max_conn; int active_conn; int select_fd_top; char *progname; Connection *conn; Nodes nodes; fd_set orig_read_mask; int listenfd[MAX_LISTEN_SOCKETS]; char *addresses; char **argv; #ifdef HAVE_SYSTEMD_DAEMON int is_systemd; #endif /* HAVE_SYSTEMD_DAEMON */ } EpmdVars; void dbg_printf(EpmdVars*,int,const char*,...); void dbg_tty_printf(EpmdVars*,int,const char*,...); void dbg_perror(EpmdVars*,const char*,...); void kill_epmd(EpmdVars*); void epmd_call(EpmdVars*,int); void run(EpmdVars*); void epmd_cleanup_exit(EpmdVars*, int); int epmd_conn_close(EpmdVars*,Connection*); void stop_cli(EpmdVars *g, char *name); #ifdef DONT_USE_MAIN int start_epmd(char *,char *,char *,char *,char *,char *,char *,char *,char *,char *); int epmd(int,char **); int epmd_dbg(int,int); #endif