static void do_request()

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 ");
    }
}