/* * %CopyrightBegin% * * Copyright Ericsson AB 1998-2010. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved online at http://www.erlang.org/. * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights 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_SYSLOG #define NO_SYSCONF #define NO_DAEMON #endif #ifdef VXWORKS #define NO_SYSLOG #define NO_SYSCONF #define NO_DAEMON #define NO_FCNTL #define DONT_USE_MAIN #endif /* ************************************************************************ */ /* Standard includes */ #include <stdio.h> #include <stdlib.h> #include <string.h> #ifdef __WIN32__ # ifndef WINDOWS_H_INCLUDES_WINSOCK2_H # include <winsock2.h> # endif # include <windows.h> # include <process.h> #endif #include <sys/types.h> #include <fcntl.h> #ifdef VXWORKS # include <sys/times.h> # include <time.h> # include <selectLib.h> # include <sysLib.h> # include <sockLib.h> # include <ioLib.h> # include <taskLib.h> # include <rpc/rpc.h> #else /* ! VXWORKS */ #ifndef __WIN32__ # ifdef TIME_WITH_SYS_TIME # include <sys/time.h> # include <time.h> # else # ifdef HAVE_SYS_TIME_H # include <sys/time.h> # else # include <time.h> # endif # endif #endif #endif /* ! VXWORKS */ #if !defined(__WIN32__) # include <netinet/in.h> # include <sys/socket.h> # include <sys/stat.h> # ifdef DEF_INADDR_LOOPBACK_IN_RPC_TYPES_H # include <rpc/types.h> # endif # include <arpa/inet.h> # include <netinet/tcp.h> #endif /* ! WIN32 */ #include <ctype.h> #include <signal.h> #include <errno.h> #ifndef NO_SYSLOG # include <syslog.h> #endif #ifdef SYS_SELECT_H # include <sys/select.h> #endif #ifdef HAVE_UNISTD_H # include <unistd.h> #endif #include <stdarg.h> /* ************************************************************************ */ /* 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 * <sys/param.h>, 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 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); \ } 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) #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); \ } 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) #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 are idle for CLOSE_TIMEOUT seconds and isn't a ALIVE socket is probably hanging and we close it */ #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 */ #define MAXSYMLEN 255 #define INBUF_SIZE 1024 #define OUTBUF_SIZE 1024 #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;} /* ************************************************************************ */ /* Stuctures used by server */ typedef struct { int fd; /* File descriptor */ unsigned open:1; /* TRUE if open */ unsigned keep:1; /* Don't close when sent reply */ 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; unsigned packet_timeout; unsigned delay_accept; unsigned delay_write; int max_conn; int active_conn; char *progname; Connection *conn; Nodes nodes; fd_set orig_read_mask; int listenfd; char **argv; } 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*); #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