void epmd_call(EpmdVars *g,int what) { char buf[OUTBUF_SIZE]; int rval,fd,i,j; fd = conn_to_epmd(g); put_int16(1,buf); buf[2] = what; write(fd,buf,3); if (read(fd,(char *)&i,4) != 4) { if (!g->silent) printf("epmd: no response from local epmd\n"); epmd_cleanup_exit(g,1); } j = ntohl(i); if (!g->silent) printf("epmd: up and running on port %d with data:\n", j); while(1) { if ((rval = read(fd,buf,1)) <= 0) { close(fd); epmd_cleanup_exit(g,0); } buf[rval] = '\0'; if (!g->silent) printf("%s",buf); } }
void stop_cli(EpmdVars *g, char *name) { char buf[1024]; int fd, rval, bsize; bsize = strlen(name); if (bsize > 1000) { printf("epmd: Name too long!"); epmd_cleanup_exit(g, 1); } fd = conn_to_epmd(g); bsize++; put_int16(bsize, buf); buf[2] = EPMD_STOP_REQ; bsize += 2; strcpy(buf+3, name); if (write(fd, buf, bsize) != bsize) { printf("epmd: Can't write to epmd\n"); epmd_cleanup_exit(g,1); } if ((rval = read_fill(fd,buf,7)) == 7) { buf[7] = '\000'; printf("%s\n", buf); epmd_cleanup_exit(g,0); } else if (rval < 0) { printf("epmd: failed to read answer from local epmd\n"); epmd_cleanup_exit(g,1); } else { /* rval is now 0 or 1 */ buf[rval] = '\0'; printf("epmd: local epmd responded with <%s>\n", buf); epmd_cleanup_exit(g,1); } }
void kill_epmd(EpmdVars *g) { char buf[5]; int fd, rval; fd = conn_to_epmd(g); put_int16(1,buf); buf[2] = EPMD_KILL_REQ; if (write(fd, buf, 3) != 3) { printf("epmd: Can't write to epmd\n"); epmd_cleanup_exit(g,1); } if ((rval = read_fill(fd,buf,2)) == 2) { if (buf[0] == 'O' && buf[1] == 'K') { printf("Killed\n"); } else { printf("Killing not allowed - living nodes in database.\n"); } epmd_cleanup_exit(g,0); } else if (rval < 0) { printf("epmd: failed to read answer from local epmd\n"); epmd_cleanup_exit(g,1); } else { /* rval is now 0 or 1 */ buf[rval] = '\0'; printf("epmd: local epmd responded with <%s>\n", buf); epmd_cleanup_exit(g,1); } }
void epmd_call(EpmdVars *g,int what) { char buf[OUTBUF_SIZE]; int rval,fd,i,j; fd = conn_to_epmd(g); put_int16(1,buf); buf[2] = what; if (write(fd, buf, 3) != 3) { printf("epmd: Can't write to epmd\n"); epmd_cleanup_exit(g,1); } if (read(fd,(char *)&i,4) != 4) { if (!g->silent) printf("epmd: no response from local epmd\n"); epmd_cleanup_exit(g,1); } j = ntohl(i); if (!g->silent) { rval = erts_snprintf(buf, OUTBUF_SIZE, "epmd: up and running on port %d with data:\n", j); fwrite(buf, 1, rval, stdout); } while(1) { if ((rval = read(fd,buf,OUTBUF_SIZE)) <= 0) { close(fd); epmd_cleanup_exit(g,0); } if (!g->silent) fwrite(buf, 1, rval, stdout); /* Potentially UTF-8 encoded */ } }
static int do_accept(EpmdVars *g,int listensock) { int msgsock; struct EPMD_SOCKADDR_IN icli_addr; /* workaround for QNX bug - cannot */ int icli_addr_len; /* handle NULL pointers to accept. */ icli_addr_len = sizeof(icli_addr); msgsock = accept(listensock,(struct sockaddr*) &icli_addr, (unsigned int*) &icli_addr_len); if (msgsock < 0) { dbg_perror(g,"error in accept"); switch (errno) { case EAGAIN: case ECONNABORTED: case EINTR: return EPMD_FALSE; default: epmd_cleanup_exit(g,1); } } return conn_open(g,msgsock); }
static int conn_to_epmd(EpmdVars *g) { struct EPMD_SOCKADDR_IN address; int connect_sock; connect_sock = socket(FAMILY, SOCK_STREAM, 0); if (connect_sock<0) goto error; { /* store port number in unsigned short */ unsigned short sport = g->port; SET_ADDR_LOOPBACK(address, FAMILY, sport); } if (connect(connect_sock, (struct sockaddr*)&address, sizeof address) < 0) goto error; return connect_sock; error: if (!g->silent) { fprintf(stderr, "epmd: Cannot connect to local epmd\n"); } epmd_cleanup_exit(g,1); return -1; }
void run(EpmdVars *g) { struct EPMD_SOCKADDR_IN iserv_addr[MAX_LISTEN_SOCKETS]; int listensock[MAX_LISTEN_SOCKETS]; int num_sockets; int i; int opt; unsigned short sport = g->port; node_init(g); g->conn = conn_init(g); #ifdef HAVE_SYSTEMD_DAEMON if (g->is_systemd) { int n; dbg_printf(g,2,"try to obtain sockets from systemd"); n = sd_listen_fds(0); if (n < 0) { dbg_perror(g,"cannot obtain sockets from systemd"); epmd_cleanup_exit(g,1); } else if (n == 0) { dbg_tty_printf(g,0,"systemd provides no sockets"); epmd_cleanup_exit(g,1); } else if (n > MAX_LISTEN_SOCKETS) { dbg_tty_printf(g,0,"cannot listen on more than %d IP addresses", MAX_LISTEN_SOCKETS); epmd_cleanup_exit(g,1); } num_sockets = n; for (i = 0; i < num_sockets; i++) { g->listenfd[i] = listensock[i] = SD_LISTEN_FDS_START + i; } } else { #endif /* HAVE_SYSTEMD_DAEMON */ dbg_printf(g,2,"try to initiate listening port %d", g->port); if (g->addresses != NULL && /* String contains non-separator characters if: */ g->addresses[strspn(g->addresses," ,")] != '\000') { char *tmp; char *token; int loopback_ok = 0; if ((tmp = (char *)malloc(strlen(g->addresses) + 1)) == NULL) { dbg_perror(g,"cannot allocate memory"); epmd_cleanup_exit(g,1); } strcpy(tmp,g->addresses); for(token = strtok(tmp,", "), num_sockets = 0; token != NULL; token = strtok(NULL,", "), num_sockets++) { struct EPMD_IN_ADDR addr; #ifdef HAVE_INET_PTON int ret; if ((ret = inet_pton(FAMILY,token,&addr)) == -1) { dbg_perror(g,"cannot convert IP address to network format"); epmd_cleanup_exit(g,1); } else if (ret == 0) #elif !defined(EPMD6) if ((addr.EPMD_S_ADDR = inet_addr(token)) == INADDR_NONE) #endif { dbg_tty_printf(g,0,"cannot parse IP address \"%s\"",token); epmd_cleanup_exit(g,1); } if (IS_ADDR_LOOPBACK(addr)) loopback_ok = 1; if (num_sockets - loopback_ok == MAX_LISTEN_SOCKETS - 1) { 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; } #ifdef HAVE_SYSTEMD_DAEMON } #endif /* HAVE_SYSTEMD_DAEMON */ #if !defined(__WIN32__) /* We ignore the SIGPIPE signal that is raised when we call write twice on a socket closed by the other end. */ signal(SIGPIPE, SIG_IGN); #endif /* * Initialize number of active file descriptors. * Stdin, stdout, and stderr are still open. */ g->active_conn = 3 + num_sockets; g->max_conn -= num_sockets; FD_ZERO(&g->orig_read_mask); g->select_fd_top = 0; #ifdef HAVE_SYSTEMD_DAEMON if (g->is_systemd) for (i = 0; i < num_sockets; i++) select_fd_set(g, listensock[i]); else { #endif /* HAVE_SYSTEMD_DAEMON */ for (i = 0; i < num_sockets; i++) { if ((listensock[i] = socket(FAMILY,SOCK_STREAM,0)) < 0) { dbg_perror(g,"error opening stream socket"); epmd_cleanup_exit(g,1); } g->listenfd[i] = listensock[i]; /* * Note that we must not enable the SO_REUSEADDR on Windows, * because addresses will be reused even if they are still in use. */ #if !defined(__WIN32__) opt = 1; if (setsockopt(listensock[i],SOL_SOCKET,SO_REUSEADDR,(char* ) &opt, sizeof(opt)) <0) { dbg_perror(g,"can't set sockopt"); epmd_cleanup_exit(g,1); } #endif /* In rare cases select returns because there is someone to accept but the request is withdrawn before the accept function is called. We set the listen socket to be non blocking to prevent us from being hanging in accept() waiting for the next request. */ #if (defined(__WIN32__) || defined(NO_FCNTL)) opt = 1; /* Gives warning in VxWorks */ if (ioctl(listensock[i], FIONBIO, &opt) != 0) #else opt = fcntl(listensock[i], F_GETFL, 0); if (fcntl(listensock[i], F_SETFL, opt | O_NONBLOCK) == -1) #endif /* __WIN32__ || VXWORKS */ 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 (errno == EADDRINUSE) { dbg_tty_printf(g,1,"there is already a epmd running at port %d", g->port); epmd_cleanup_exit(g,0); } else { dbg_perror(g,"failed to bind socket"); epmd_cleanup_exit(g,1); } } if(listen(listensock[i], SOMAXCONN) < 0) { dbg_perror(g,"failed to listen on socket"); epmd_cleanup_exit(g,1); } select_fd_set(g, listensock[i]); } #ifdef HAVE_SYSTEMD_DAEMON } sd_notifyf(0, "READY=1\n" "STATUS=Processing port mapping requests...\n" "MAINPID=%lu", (unsigned long) getpid()); #endif /* HAVE_SYSTEMD_DAEMON */ dbg_tty_printf(g,2,"entering the main select() loop"); select_again: while(1) { fd_set read_mask = g->orig_read_mask; struct timeval timeout; int ret; /* If we are idle we time out now and then to enable the code below to close connections that are old and probably hanging. Make sure that select will return often enough. */ timeout.tv_sec = (g->packet_timeout < IDLE_TIMEOUT) ? 1 : IDLE_TIMEOUT; timeout.tv_usec = 0; if ((ret = select(g->select_fd_top, &read_mask, (fd_set *)0,(fd_set *)0,&timeout)) < 0) { dbg_perror(g,"error in select "); switch (errno) { case EAGAIN: case EINTR: break; default: epmd_cleanup_exit(g,1); } } else { time_t now; if (ret == 0) { FD_ZERO(&read_mask); } if (g->delay_accept) { /* Test of busy server */ sleep(g->delay_accept); } for (i = 0; i < num_sockets; i++) if (FD_ISSET(listensock[i],&read_mask)) { if (do_accept(g, listensock[i]) && g->active_conn < g->max_conn) { /* * The accept() succeeded, and we have at least one file * descriptor still free, which means that another accept() * could succeed. Go do do another select(), in case there * are more incoming connections waiting to be accepted. */ goto select_again; } } /* Check all open streams marked by select for data or a close. We also close all open sockets except ALIVE with no activity for a long period */ now = current_time(g); for (i = 0; i < g->max_conn; i++) { if (g->conn[i].open == EPMD_TRUE) { if (FD_ISSET(g->conn[i].fd,&read_mask)) do_read(g,&g->conn[i]); else if ((g->conn[i].keep == EPMD_FALSE) && ((g->conn[i].mod_time + g->packet_timeout) < now)) { dbg_tty_printf(g,1,"closing because timed out on receive"); epmd_conn_close(g,&g->conn[i]); } } } } } }
void run(EpmdVars *g) { int listensock; int i; int opt; struct EPMD_SOCKADDR_IN iserv_addr; node_init(g); g->conn = conn_init(g); dbg_printf(g,2,"try to initiate listening port %d", g->port); if ((listensock = socket(FAMILY,SOCK_STREAM,0)) < 0) { dbg_perror(g,"error opening stream socket"); epmd_cleanup_exit(g,1); } g->listenfd = listensock; /* * Initialize number of active file descriptors. * Stdin, stdout, and stderr are still open. * One for the listen socket. */ g->active_conn = 3+1; /* * Note that we must not enable the SO_REUSEADDR on Windows, * because addresses will be reused even if they are still in use. */ #if !defined(__WIN32__) /* We ignore the SIGPIPE signal that is raised when we call write twice on a socket closed by the other end. */ signal(SIGPIPE, SIG_IGN); opt = 1; /* Set this option */ if (setsockopt(listensock,SOL_SOCKET,SO_REUSEADDR,(char* ) &opt, sizeof(opt)) <0) { dbg_perror(g,"can't set sockopt"); epmd_cleanup_exit(g,1); } #endif /* In rare cases select returns because there is someone to accept but the request is withdrawn before the accept function is called. We set the listen socket to be non blocking to prevent us from being hanging in accept() waiting for the next request. */ #if (defined(__WIN32__) || defined(NO_FCNTL)) opt = 1; if (ioctl(listensock, FIONBIO, &opt) != 0) /* Gives warning in VxWorks */ #else opt = fcntl(listensock, F_GETFL, 0); if (fcntl(listensock, F_SETFL, opt | O_NONBLOCK) == -1) #endif /* __WIN32__ || VXWORKS */ dbg_perror(g,"failed to set non-blocking mode of listening socket %d", listensock); { /* store port number in unsigned short */ unsigned short sport = g->port; SET_ADDR_ANY(iserv_addr, FAMILY, sport); } if(bind(listensock,(struct sockaddr*) &iserv_addr, sizeof(iserv_addr)) < 0 ) { if (errno == EADDRINUSE) { dbg_tty_printf(g,1,"there is already a epmd running at port %d", g->port); epmd_cleanup_exit(g,0); } else { dbg_perror(g,"failed to bind socket"); epmd_cleanup_exit(g,1); } } dbg_printf(g,2,"starting"); if(listen(listensock, SOMAXCONN) < 0) { dbg_perror(g,"failed to listen on socket"); epmd_cleanup_exit(g,1); } FD_ZERO(&g->orig_read_mask); FD_SET(listensock,&g->orig_read_mask); dbg_tty_printf(g,2,"entering the main select() loop"); select_again: while(1) { fd_set read_mask = g->orig_read_mask; struct timeval timeout; int ret; /* If we are idle we time out now and then to enable the code below to close connections that are old and probably hanging. Make sure that select will return often enough. */ timeout.tv_sec = (g->packet_timeout < IDLE_TIMEOUT) ? 1 : IDLE_TIMEOUT; timeout.tv_usec = 0; if ((ret = select(g->max_conn,&read_mask,(fd_set *)0,(fd_set *)0,&timeout)) < 0) { dbg_perror(g,"error in select "); switch (errno) { case EAGAIN: case EINTR: break; default: epmd_cleanup_exit(g,1); } } else { time_t now; if (ret == 0) { FD_ZERO(&read_mask); } if (g->delay_accept) { /* Test of busy server */ sleep(g->delay_accept); } if (FD_ISSET(listensock,&read_mask)) { if (do_accept(g, listensock) && g->active_conn < g->max_conn) { /* * The accept() succeeded, and we have at least one file * descriptor still free, which means that another accept() * could succeed. Go do do another select(), in case there * are more incoming connections waiting to be accepted. */ goto select_again; } } /* Check all open streams marked by select for data or a close. We also close all open sockets except ALIVE with no activity for a long period */ now = current_time(g); for (i = 0; i < g->max_conn; i++) { if (g->conn[i].open == EPMD_TRUE) { if (FD_ISSET(g->conn[i].fd,&read_mask)) do_read(g,&g->conn[i]); else if ((g->conn[i].keep == EPMD_FALSE) && ((g->conn[i].mod_time + g->packet_timeout) < now)) { dbg_tty_printf(g,1,"closing because timed out on receive"); epmd_conn_close(g,&g->conn[i]); } } } } } }