in erts/epmd/src/epmd_srv.c [726:1066]
static void do_request(g, fd, s, buf, bsize)
EpmdVars *g;
int fd;
Connection *s;
char *buf;
int bsize;
{
char wbuf[OUTBUF_SIZE]; /* Buffer for writing */
int i;
buf[bsize] = '\0'; /* Needed for strcmp in PORT2 and STOP requests
buf is always large enough */
switch (*buf)
{
case EPMD_ALIVE2_REQ:
dbg_printf(g,1,"** got ALIVE2_REQ");
if (!s->local_peer) {
dbg_printf(g,0,"ALIVE2_REQ from non local address");
return;
}
/* The packet has the format "axxyyyyyy" where xx is port, given
in network byte order, and yyyyyy is symname, possibly null
terminated. */
if (bsize <= 13) /* at least one character for the node name */
{
dbg_printf(g,0,"packet to small for request ALIVE2_REQ (%d)",bsize);
return;
}
{
Node *node;
int eport;
unsigned char nodetype;
unsigned char protocol;
unsigned short highvsn;
unsigned short lowvsn;
unsigned int creation;
int namelen;
int extralen;
int replylen;
char *name;
char *extra;
eport = get_int16(&buf[1]);
nodetype = buf[3];
protocol = buf[4];
highvsn = get_int16(&buf[5]);
lowvsn = get_int16(&buf[7]);
namelen = get_int16(&buf[9]);
if (namelen + 13 > bsize) {
dbg_printf(g,0,"Node name size error in ALIVE2_REQ");
return;
}
extralen = get_int16(&buf[11+namelen]);
if (extralen + namelen + 13 > bsize) {
dbg_printf(g,0,"Extra info size error in ALIVE2_REQ");
return;
}
for (i = 11 ; i < 11 + namelen; i ++)
if (buf[i] == '\000') {
dbg_printf(g,0,"node name contains ascii 0 in ALIVE2_REQ");
return;
}
name = &buf[11];
name[namelen]='\000';
extra = &buf[11+namelen+2];
extra[extralen]='\000';
node = node_reg2(g, namelen, name, fd, eport, nodetype, protocol,
highvsn, lowvsn, extralen, extra);
creation = node ? get_creation(node) : 99;
wbuf[1] = node ? 0 : 1; /* ok | error */
if (highvsn >= 6) {
wbuf[0] = EPMD_ALIVE2_X_RESP;
put_int32(creation, wbuf+2);
replylen = 6;
}
else {
wbuf[0] = EPMD_ALIVE2_RESP;
put_int16(creation, wbuf+2);
replylen = 4;
}
if (!reply(g, fd, wbuf, replylen))
{
node_unreg(g, name);
dbg_tty_printf(g,1,"** failed to send ALIVE2_RESP for \"%s\"",
name);
return;
}
dbg_tty_printf(g,1,"** sent ALIVE2_RESP for \"%s\"",name);
s->keep = EPMD_TRUE; /* Don't close on inactivity */
}
break;
case EPMD_PORT2_REQ:
dbg_printf(g,1,"** got PORT2_REQ");
if (buf[bsize - 1] == '\000') /* Skip null termination */
bsize--;
if (bsize <= 1)
{
dbg_printf(g,0,"packet too small for request PORT2_REQ (%d)", bsize);
return;
}
for (i = 1; i < bsize; i++)
if (buf[i] == '\000')
{
dbg_printf(g,0,"node name contains ascii 0 in PORT2_REQ");
return;
}
{
char *name = &buf[1]; /* Points to node name */
int nsz;
Node *node;
nsz = verify_utf8(name, bsize, 0);
if (nsz < 1 || 255 < nsz) {
dbg_printf(g,0,"invalid node name in PORT2_REQ");
return;
}
wbuf[0] = EPMD_PORT2_RESP;
for (node = g->nodes.reg; node; node = node->next) {
int offset;
if (is_same_str(node->symname, name)) {
wbuf[1] = 0; /* ok */
put_int16(node->port,wbuf+2);
wbuf[4] = node->nodetype;
wbuf[5] = node->protocol;
put_int16(node->highvsn,wbuf+6);
put_int16(node->lowvsn,wbuf+8);
put_int16(length_str(node->symname),wbuf+10);
offset = 12;
offset += copy_str(wbuf + offset,node->symname);
put_int16(node->extralen,wbuf + offset);
offset += 2;
memcpy(wbuf + offset,node->extra,node->extralen);
offset += node->extralen;
if (!reply(g, fd, wbuf, offset))
{
dbg_tty_printf(g,1,"** failed to send PORT2_RESP (ok) for \"%s\"",name);
return;
}
dbg_tty_printf(g,1,"** sent PORT2_RESP (ok) for \"%s\"",name);
return;
}
}
wbuf[1] = 1; /* error */
if (!reply(g, fd, wbuf, 2))
{
dbg_tty_printf(g,1,"** failed to send PORT2_RESP (error) for \"%s\"",name);
return;
}
dbg_tty_printf(g,1,"** sent PORT2_RESP (error) for \"%s\"",name);
return;
}
break;
case EPMD_NAMES_REQ:
dbg_printf(g,1,"** got NAMES_REQ");
{
Node *node;
i = htonl(g->port);
memcpy(wbuf,&i,4);
if (!reply(g, fd,wbuf,4))
{
dbg_tty_printf(g,1,"failed to send NAMES_RESP");
return;
}
for (node = g->nodes.reg; node; node = node->next)
{
int len = 0;
int r;
/* CAREFUL!!! These are parsed by "erl_epmd.erl" so a slight
change in syntax will break < OTP R3A */
len += copy_str(&wbuf[len], "name ");
len += copy_str(&wbuf[len], node->symname);
r = erts_snprintf(&wbuf[len], sizeof(wbuf)-len,
" at port %d\n", node->port);
if (r < 0)
goto failed_names_resp;
len += r;
if (!reply(g, fd, wbuf, len))
{
failed_names_resp:
dbg_tty_printf(g,1,"failed to send NAMES_RESP");
return;
}
}
}
dbg_tty_printf(g,1,"** sent NAMES_RESP");
break;
case EPMD_DUMP_REQ:
dbg_printf(g,1,"** got DUMP_REQ");
if (!s->local_peer) {
dbg_printf(g,0,"DUMP_REQ from non local address");
return;
}
{
Node *node;
i = htonl(g->port);
memcpy(wbuf,&i,4);
if (!reply(g, fd,wbuf,4))
{
dbg_tty_printf(g,1,"failed to send DUMP_RESP");
return;
}
for (node = g->nodes.reg; node; node = node->next)
{
int len = 0, r;
/* CAREFUL!!! These are parsed by "erl_epmd.erl" so a slight
change in syntax will break < OTP R3A */
len += copy_str(&wbuf[len], "active name <");
len += copy_str(&wbuf[len], node->symname);
r = erts_snprintf(&wbuf[len], sizeof(wbuf)-len,
"> at port %d, fd = %d\n",
node->port, node->fd);
if (r < 0)
goto failed_dump_resp;
len += r + 1;
if (!reply(g, fd,wbuf,len))
{
failed_dump_resp:
dbg_tty_printf(g,1,"failed to send DUMP_RESP");
return;
}
}
for (node = g->nodes.unreg; node; node = node->next)
{
int len = 0, r;
/* CAREFUL!!! These are parsed by "erl_epmd.erl" so a slight
change in syntax will break < OTP R3A */
len += copy_str(&wbuf[len], "old/unused name <");
len += copy_str(&wbuf[len], node->symname);
r = erts_snprintf(&wbuf[len], sizeof(wbuf)-len,
">, port = %d, fd = %d \n",
node->port, node->fd);
if (r < 0)
goto failed_dump_resp2;
len += r + 1;
if (!reply(g, fd,wbuf,len))
{
failed_dump_resp2:
dbg_tty_printf(g,1,"failed to send DUMP_RESP");
return;
}
}
}
dbg_tty_printf(g,1,"** sent DUMP_RESP");
break;
case EPMD_KILL_REQ:
if (!s->local_peer) {
dbg_printf(g,0,"KILL_REQ from non local address");
return;
}
dbg_printf(g,1,"** got KILL_REQ");
if (!g->brutal_kill && (g->nodes.reg != NULL)) {
dbg_printf(g,0,"Disallowed KILL_REQ, live nodes");
if (!reply(g, fd,"NO",2))
dbg_printf(g,0,"failed to send reply to KILL_REQ");
return;
}
if (!reply(g, fd,"OK",2))
dbg_printf(g,0,"failed to send reply to KILL_REQ");
dbg_tty_printf(g,1,"epmd killed");
conn_close_fd(g,fd); /* We never return to caller so close here */
dbg_printf(g,0,"got KILL_REQ - terminates normal");
epmd_cleanup_exit(g,0); /* Normal exit */
case EPMD_STOP_REQ:
dbg_printf(g,1,"** got STOP_REQ");
if (!s->local_peer) {
dbg_printf(g,0,"STOP_REQ from non local address");
return;
}
if (!g->brutal_kill) {
dbg_printf(g,0,"Disallowed STOP_REQ, no relaxed_command_check");
return;
}
if (bsize <= 1 )
{
dbg_printf(g,0,"packet too small for request STOP_REQ (%d)",bsize);
return;
}
{
char *name = &buf[1]; /* Points to node name */
int node_fd;
if ((node_fd = node_unreg(g,name)) < 0)
{
if (!reply(g, fd,"NOEXIST",7))
{
dbg_tty_printf(g,1,"failed to send STOP_RESP NOEXIST");
return;
}
dbg_tty_printf(g,1,"** sent STOP_RESP NOEXIST");
}
conn_close_fd(g,node_fd);
dbg_tty_printf(g,1,"epmd connection stopped");
if (!reply(g, fd,"STOPPED",7))
{
dbg_tty_printf(g,1,"failed to send STOP_RESP STOPPED");
return;
}
dbg_tty_printf(g,1,"** sent STOP_RESP STOPPED");
}
break;
default:
dbg_printf(g,0,"got garbage ");
}
}