/*
* %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%
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "epmd.h" /* Renamed from 'epmd_r4.h' */
#include "epmd_int.h"
#include "erl_printf.h" /* erts_snprintf */
/* forward declarations */
static int conn_to_epmd(EpmdVars*);
static int read_fill(int,char*,int);
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");
epmd_cleanup_exit(g,0);
} else {
printf("Killing not allowed - living nodes in database.\n");
epmd_cleanup_exit(g,1);
}
} 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 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);
}
}
/* what == EPMD_NAMES_REQ || EPMD_DUMP_REQ */
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 conn_to_epmd(EpmdVars *g)
{
struct EPMD_SOCKADDR_IN address;
size_t salen = 0;
int connect_sock;
unsigned short sport = g->port;
#if defined(EPMD6)
SET_ADDR6(address, in6addr_loopback, sport);
salen = sizeof(struct sockaddr_in6);
connect_sock = socket(AF_INET6, SOCK_STREAM, 0);
if (connect_sock>=0) {
if (connect(connect_sock, (struct sockaddr*)&address, salen) == 0)
return connect_sock;
close(connect_sock);
}
#endif
SET_ADDR(address, htonl(INADDR_LOOPBACK), sport);
salen = sizeof(struct sockaddr_in);
connect_sock = socket(AF_INET, SOCK_STREAM, 0);
if (connect_sock<0)
goto error;
if (connect(connect_sock, (struct sockaddr*)&address, salen) < 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;
}
/* Fill buffer, return buffer length, 0 for EOF, < 0 for error. */
static int read_fill(int fd,char *buf,int len)
{
int i;
int got = 0;
do {
if ((i = read(fd, buf+got, len-got)) <= 0)
return (i);
got += i;
} while (got < len);
return (len);
}