Пример #1
0
/* stop the specified node */
int ei_unpublish_tmo(const char *alive, unsigned ms)
{
    char buf[EPMDBUF];
    char *s = (char*)buf;
    int len = 1 + strlen(alive);
    int fd, res;

    if (len > sizeof(buf)-3) {
	erl_errno = ERANGE;
	return -1;
    }

    put16be(s,len);
    put8(s,EI_EPMD_STOP_REQ);
    strcpy(s, alive);

    /* FIXME can't connect, return success?! At least commen whats up */
    if ((fd = ei_epmd_connect_tmo(NULL,ms)) < 0) return fd;

    if ((res = ei_write_fill_t(fd, buf, len+2,ms)) != len+2) {
	closesocket(fd);
	erl_errno = (res == -2) ? ETIMEDOUT : EIO;
	return -1;
    }

    EI_TRACE_CONN1("ei_unpublish_tmo","-> STOP %s",alive);
  
    if ((res = ei_read_fill_t(fd, buf, 7, ms)) != 7) {
	closesocket(fd);
	erl_errno = (res == -2) ? ETIMEDOUT : EIO;
	return -1; 
    }
    closesocket(fd);
    buf[7]=(char)0;		/* terminate the string */
  
    if (!strcmp("STOPPED",(char *)buf)) {
	EI_TRACE_CONN0("ei_unpublish_tmo","<- STOPPED (success)");
	return 0;
    }
    else if (!strcmp("NOEXIST",(char *)buf)) {
	EI_TRACE_ERR0("ei_unpublish_tmo","<- NOEXIST (failure)");
	erl_errno = EIO;
	return -1;
    }
    else {
	EI_TRACE_ERR0("ei_unpublish_tmo","<- unknown (failure)");
	erl_errno = EIO;
	return -1;		/* this shouldn't happen */
    }
    return 0;
}
Пример #2
0
static int initWinSock(void)
{
    WORD wVersionRequested;  
    WSADATA wsaData; 
    int i; 

    static LONG volatile initialized = 0;
    
    wVersionRequested = MAKEWORD(1, 1); 
    if (InterlockedCompareExchange((LPLONG) &initialized,1L,0L) == 0L) {
	/* FIXME not terminate, just a message?! */
	if ((i = WSAStartup(wVersionRequested, &wsaData))) {
	    EI_TRACE_ERR1("ei_connect_init",
			  "ERROR: can't initialize windows sockets: %d",i);
	    initialized = 2L;
	    return 0;
	}
	
	if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) { 
	    EI_TRACE_ERR0("initWinSock","ERROR: this version of windows "
			  "sockets not supported");
	    WSACleanup(); 
	    initialized = 2L;
	    return 0;
	}
	initialized = 3L;
    } else while (initialized < 2) {
	SwitchToThread();
    }
    return (int) (initialized - 2);
}
Пример #3
0
static int send_challenge_ack(int fd, unsigned char digest[16], unsigned ms) 
{
    char *s;
    char buf[DEFBUF_SIZ];
    int siz = 2 + 1 + 16;
    int res;

    s = buf;
    
    put16be(s,siz - 2);
    put8(s, 'a');
    memcpy(s, digest, 16);

    if ((res = ei_write_fill_t(fd, buf, siz, ms)) != siz) {
	EI_TRACE_ERR0("recv_challenge_reply",
		      "-> SEND_CHALLENGE_ACK socket write failed");
	erl_errno = (res == -2) ? ETIMEDOUT : EIO;
	return -1;
    }
    
    if (ei_tracelevel >= 3) {
	char buffer[33];	
    	EI_TRACE_CONN1("recv_challenge_reply",
		   "-> SEND_CHALLENGE_ACK (ok) digest = %s",hex((char *)digest,buffer));
    }
    
    return 0;
}
Пример #4
0
static int send_status(int fd, char *status, unsigned ms)
{
    char *buf, *s;
    char dbuf[DEFBUF_SIZ];
    int siz = strlen(status) + 1 + 2;
    int res;

    buf = (siz > DEFBUF_SIZ) ? malloc(siz) : dbuf;
    if (!buf) {
	erl_errno = ENOMEM;
	return -1;
    }
    s = buf;
    put16be(s,siz - 2);
    put8(s, 's');
    memcpy(s, status, strlen(status));
    if ((res = ei_write_fill_t(fd, buf, siz, ms)) != siz) {
	EI_TRACE_ERR0("send_status","-> SEND_STATUS socket write failed");
	if (buf != dbuf)
	    free(buf);
	erl_errno = (res == -2) ? ETIMEDOUT : EIO;
	return -1;
    }
    EI_TRACE_CONN1("send_status","-> SEND_STATUS (%s)",status);

    if (buf != dbuf)
	free(buf);
    return 0;
}
Пример #5
0
static int recv_challenge_reply (int fd, 
				 unsigned our_challenge,
				 char cookie[], 
				 unsigned *her_challenge,
				 unsigned ms)
{
    char dbuf[DEFBUF_SIZ];
    char *buf = dbuf;
    int is_static = 1;
    int buflen = DEFBUF_SIZ;
    int rlen;
    char *s;
    char tag;
    char her_digest[16], expected_digest[16];
    
    erl_errno = EIO;		/* Default */

    if ((rlen = read_2byte_package(fd, &buf, &buflen, &is_static, ms)) != 21) {
	EI_TRACE_ERR1("recv_challenge_reply",
		      "<- RECV_CHALLENGE_REPLY socket read failed (%d)",rlen);
	goto error;
    }
    
    s = buf;
    if ((tag = get8(s)) != 'r') {
	EI_TRACE_ERR2("recv_challenge_reply",
		      "<- RECV_CHALLENGE_REPLY incorrect tag, "
		      "expected 'r' got '%c' (%u)",tag,tag);
	goto error;
    }
    *her_challenge = get32be(s);
    memcpy(her_digest, s, 16);
    gen_digest(our_challenge, cookie, (unsigned char*)expected_digest);
    if (memcmp(her_digest, expected_digest, 16)) {
	EI_TRACE_ERR0("recv_challenge_reply",
		      "<- RECV_CHALLENGE_REPLY authorization failure");
	goto error;
    }
    if (!is_static)
	free(buf);

   
    if (ei_tracelevel >= 3) {
	char buffer[33];	
        EI_TRACE_CONN2("recv_challenge_reply",
		   "<- RECV_CHALLENGE_REPLY (ok) challenge = %u, digest = %s",
		   *her_challenge,hex(her_digest,buffer));
    }
    erl_errno = 0;
    return 0;
    
error:
    if (!is_static)
	free(buf);
    return -1;
}
Пример #6
0
int ei_accept_tmo(ei_cnode* ec, int lfd, ErlConnect *conp, unsigned ms)
{
    int fd;
    struct sockaddr_in cli_addr;
    int cli_addr_len=sizeof(struct sockaddr_in);
    unsigned her_version, her_flags;
    ErlConnect her_name;

    erl_errno = EIO;		/* Default error code */

    EI_TRACE_CONN0("ei_accept","<- ACCEPT waiting for connection");
    
    if ((fd = ei_accept_t(lfd, (struct sockaddr*) &cli_addr, 
	&cli_addr_len, ms )) < 0) {
	EI_TRACE_ERR0("ei_accept","<- ACCEPT socket accept failed");
	erl_errno = (fd == -2) ? ETIMEDOUT : EIO;
	goto error;
    }
    
    EI_TRACE_CONN0("ei_accept","<- ACCEPT connected to remote");
    
    if (recv_name(fd, &her_version, &her_flags, &her_name, ms)) {
	EI_TRACE_ERR0("ei_accept","<- ACCEPT initial ident failed");
	goto error;
    }
    
    if (her_version <= 4) {
	EI_TRACE_ERR0("ei_accept","<- ACCEPT remote version not compatible");
	goto error;
    }
    else {
	unsigned our_challenge;
	unsigned her_challenge;
	unsigned char our_digest[16];
	
	if (send_status(fd,"ok", ms))
	    goto error;
	our_challenge = gen_challenge();
	if (send_challenge(fd, ec->thisnodename, 
	    our_challenge, her_version, ms))
	    goto error;
	if (recv_challenge_reply(fd, our_challenge, 
	    ec->ei_connect_cookie, 
	    &her_challenge, ms))
	    goto error;
	gen_digest(her_challenge, ec->ei_connect_cookie, our_digest);
	if (send_challenge_ack(fd, our_digest, ms))
	    goto error;
	put_ei_socket_info(fd, her_version, null_cookie, ec);
    }
    if (conp) 
	*conp = her_name;
    
    EI_TRACE_CONN1("ei_accept","<- ACCEPT (ok) remote = %s",her_name.nodename);

    erl_errno = 0;		/* No error */
    return fd;
    
error:
    EI_TRACE_ERR0("ei_accept","<- ACCEPT failed");
    closesocket(fd);
    return ERL_ERROR;
} /* ei_accept */
Пример #7
0
 /* ip_addr is now in network byte order 
  *
  * first we have to get hold of the portnumber to
  *  the node through epmd at that host 
  *
*/
int ei_xconnect_tmo(ei_cnode* ec, Erl_IpAddr adr, char *alivename, unsigned ms)
{
    struct in_addr *ip_addr=(struct in_addr *) adr;
    int rport = 0; /*uint16 rport = 0;*/
    int sockd;
    int one = 1;
    int dist = 0;
    ErlConnect her_name;
    unsigned her_flags, her_version;

    erl_errno = EIO;		/* Default error code */
    
    EI_TRACE_CONN1("ei_xconnect","-> CONNECT attempt to connect to %s",
		   alivename);
    
    if ((rport = ei_epmd_port_tmo(ip_addr,alivename,&dist, ms)) < 0) {
	EI_TRACE_ERR0("ei_xconnect","-> CONNECT can't get remote port");
	/* ei_epmd_port_tmo() has set erl_errno */
	return ERL_NO_PORT;
    }
    
    /* we now have port number to enode, try to connect */
    if((sockd = cnct((uint16)rport, ip_addr, sizeof(struct in_addr),ms)) < 0) {
	EI_TRACE_ERR0("ei_xconnect","-> CONNECT socket connect failed");
	/* cnct() has set erl_errno */
	return ERL_CONNECT_FAIL;
    }
    
    EI_TRACE_CONN0("ei_xconnect","-> CONNECT connected to remote");

    /* FIXME why connect before checking 'dist' output from ei_epmd_port() ?! */
    if (dist <= 4) {
	EI_TRACE_ERR0("ei_xconnect","-> CONNECT remote version not compatible");
	goto error;
    }
    else {
	unsigned our_challenge, her_challenge;
	unsigned char our_digest[16];
	
	if (send_name(sockd, ec->thisnodename, (unsigned) dist, ms))
	    goto error;
	if (recv_status(sockd, ms))
	    goto error;
	if (recv_challenge(sockd, &her_challenge, &her_version,
	    &her_flags, &her_name, ms))
	    goto error;
	our_challenge = gen_challenge();
	gen_digest(her_challenge, ec->ei_connect_cookie, our_digest);
	if (send_challenge_reply(sockd, our_digest, our_challenge, ms))
	    goto error;
	if (recv_challenge_ack(sockd, our_challenge, 
	    ec->ei_connect_cookie, ms))
	    goto error;
	put_ei_socket_info(sockd, dist, null_cookie, ec); /* FIXME check == 0 */
    }
    
    setsockopt(sockd, IPPROTO_TCP, TCP_NODELAY, (char *)&one, sizeof(one));
    setsockopt(sockd, SOL_SOCKET, SO_KEEPALIVE, (char *)&one, sizeof(one));

    EI_TRACE_CONN1("ei_xconnect","-> CONNECT (ok) remote = %s",alivename);
    
    erl_errno = 0;
    return sockd;
    
error:
    EI_TRACE_ERR0("ei_xconnect","-> CONNECT failed");
    closesocket(sockd);
    return ERL_ERROR;
} /* ei_xconnect */
Пример #8
0
  /* 
  * Set up a connection to a given Node, and 
  * interchange hand shake messages with it.
  * Returns a valid file descriptor at success,
  * otherwise a negative error code.
*/
int ei_connect_tmo(ei_cnode* ec, char *nodename, unsigned ms)
{
    char *hostname, alivename[BUFSIZ];
    struct hostent *hp;
#if !defined (__WIN32__) 
    /* these are needed for the call to gethostbyname_r */
    struct hostent host;
    char buffer[1024];
    int ei_h_errno;
#endif /* !win32 */
    
    /* extract the host and alive parts from nodename */
    if (!(hostname = strchr(nodename,'@'))) {
	EI_TRACE_ERR0("ei_connect","Node name has no @ in name");
	return ERL_ERROR;
    } else {
	strncpy(alivename, nodename, hostname - nodename);
	alivename[hostname - nodename] = 0x0;
	hostname++;
    }
    
#ifndef __WIN32__
    hp = ei_gethostbyname_r(hostname,&host,buffer,1024,&ei_h_errno);
    if (hp == NULL) {
	char thishostname[EI_MAXHOSTNAMELEN+1];
	if (gethostname(thishostname,EI_MAXHOSTNAMELEN) < 0) {
	    EI_TRACE_ERR0("ei_connect_tmo",
			  "Failed to get name of this host");
	    erl_errno = EHOSTUNREACH;
	    return ERL_ERROR;
	} else {
	    char *ct;
	    /* We use a short node name */    
	    if ((ct = strchr(thishostname, '.')) != NULL) *ct = '\0';
	}
	if (strcmp(hostname,thishostname) == 0)
	    /* Both nodes on same standalone host, use loopback */
	    hp = ei_gethostbyname_r("localhost",&host,buffer,1024,&ei_h_errno);
	if (hp == NULL) {
	    EI_TRACE_ERR2("ei_connect",
			  "Can't find host for %s: %d\n",nodename,ei_h_errno);
	    erl_errno = EHOSTUNREACH;
	    return ERL_ERROR;
	}
    }
#else /* __WIN32__ */
    if ((hp = ei_gethostbyname(hostname)) == NULL) {
	char thishostname[EI_MAXHOSTNAMELEN+1];
	if (gethostname(thishostname,EI_MAXHOSTNAMELEN) < 0) {
	    EI_TRACE_ERR1("ei_connect_tmo",
			  "Failed to get name of this host: %d", 
			  WSAGetLastError());
	    erl_errno = EHOSTUNREACH;
	    return ERL_ERROR;
	} else {
	    char *ct;
	    /* We use a short node name */    
	    if ((ct = strchr(thishostname, '.')) != NULL) *ct = '\0';
	}
	if (strcmp(hostname,thishostname) == 0)
	    /* Both nodes on same standalone host, use loopback */
	    hp = ei_gethostbyname("localhost");
	if (hp == NULL) {
	    char reason[1024];
	    win32_error(reason,sizeof(reason));
	    EI_TRACE_ERR2("ei_connect",
			  "Can't find host for %s: %s",nodename,reason);
	    erl_errno = EHOSTUNREACH;
	    return ERL_ERROR;
	}
    }
#endif /* win32 */
    return ei_xconnect_tmo(ec, (Erl_IpAddr) *hp->h_addr_list, alivename, ms);
} /* ei_connect */
Пример #9
0
/*
* Initialize by set: thishostname, thisalivename, 
* thisnodename and thisipaddr. At success return 0,
* otherwise return -1.
*/
int ei_connect_init(ei_cnode* ec, const char* this_node_name,
		    const char *cookie, short creation)
{
    struct hostent *hp;
    char thishostname[EI_MAXHOSTNAMELEN+1];
    char thisnodename[MAXNODELEN+1];
    char thisalivename[EI_MAXALIVELEN+1];

#ifdef __WIN32__
    if (!initWinSock()) {
	EI_TRACE_ERR0("ei_connect_xinit","can't initiate winsock");
	return ERL_ERROR;
    }
#endif /* win32 */
#ifdef _REENTRANT
    if (ei_sockets_lock == NULL) {
	ei_sockets_lock = ei_mutex_create();
    }
#endif /* _REENTRANT */
    
    if (gethostname(thishostname, EI_MAXHOSTNAMELEN) == -1) {
#ifdef __WIN32__
	EI_TRACE_ERR1("ei_connect_init","Failed to get host name: %d",
		      WSAGetLastError());
#else
	EI_TRACE_ERR1("ei_connect_init","Failed to get host name: %d", errno);
#endif /* win32 */
	return ERL_ERROR;
    }

    if (this_node_name == NULL) {
	sprintf(thisalivename, "c%d", (int) getpid());
    } else if (strlen(this_node_name) >= sizeof(thisalivename)) {
	EI_TRACE_ERR0("ei_connect_init","ERROR: this_node_name too long");
	return ERL_ERROR;
    } else {
	strcpy(thisalivename, this_node_name);
    }
    
    if ((hp = ei_gethostbyname(thishostname)) == 0) {
	/* Looking up IP given hostname fails. We must be on a standalone
	   host so let's use loopback for communication instead. */
	if ((hp = ei_gethostbyname("localhost")) == 0) {
#ifdef __WIN32__
	    char reason[1024];
	
	    win32_error(reason,sizeof(reason));
	    EI_TRACE_ERR2("ei_connect_init",
			  "Can't get ip address for host %s: %s",
			  thishostname, reason);
#else
	    EI_TRACE_ERR2("ei_connect_init",
			  "Can't get ip address for host %s: %d",
			  thishostname, h_errno);
#endif /* win32 */
	    return ERL_ERROR;
	}
    }
    {
	char* ct;
	if (strcmp(hp->h_name, "localhost") == 0) {
	    /* We use a short node name */    
	    if ((ct = strchr(thishostname, '.')) != NULL) *ct = '\0';
	    sprintf(thisnodename, "%s@%s", this_node_name, thishostname);
	} else {
	    /* We use a short node name */    
	    if ((ct = strchr(hp->h_name, '.')) != NULL) *ct = '\0';
	    strcpy(thishostname, hp->h_name);
	    sprintf(thisnodename, "%s@%s", this_node_name, hp->h_name);
	}
    }
    return ei_connect_xinit(ec, thishostname, thisalivename, thisnodename,
			    (struct in_addr *)*hp->h_addr_list, cookie, creation);
}
Пример #10
0
/*
* Perhaps run this routine instead of ei_connect_init/2 ?
* Initailize by setting:
* thishostname, thisalivename, thisnodename and thisipaddr
*/
int ei_connect_xinit(ei_cnode* ec, const char *thishostname,
		     const char *thisalivename, const char *thisnodename,
		     Erl_IpAddr thisipaddr, const char *cookie,
		     const short creation)
{
    char *dbglevel;
    
/* FIXME this code was enabled for 'erl'_connect_xinit(), why not here? */
#if 0    
#ifdef __WIN32__
    if (!initWinSock()) {
	EI_TRACE_ERR0("ei_connect_xinit","can't initiate winsock");
	return ERL_ERROR;
    }
#endif
#endif

#ifdef _REENTRANT
    if (ei_sockets_lock == NULL) {
	ei_sockets_lock = ei_mutex_create();
    }
#endif /* _REENTRANT */

    ec->creation = creation;
    
    if (cookie) {
	if (strlen(cookie) >= sizeof(ec->ei_connect_cookie)) { 
	    EI_TRACE_ERR0("ei_connect_xinit",
			  "ERROR: Cookie size too large");
	    return ERL_ERROR;
	} else {
	    strcpy(ec->ei_connect_cookie, cookie);
	}
    } else if (!get_cookie(ec->ei_connect_cookie, sizeof(ec->ei_connect_cookie))) {
	return ERL_ERROR;
    }
    
    if (strlen(thishostname) >= sizeof(ec->thishostname)) {
	EI_TRACE_ERR0("ei_connect_xinit","ERROR: Thishostname too long");
	return ERL_ERROR;
    }
    strcpy(ec->thishostname, thishostname);
    
    if (strlen(thisalivename) >= sizeof(ec->thisalivename)) {
	EI_TRACE_ERR0("ei_connect_init","Thisalivename too long");
	return ERL_ERROR;
    }
	
    strcpy(ec->thisalivename, thisalivename);
    
    if (strlen(thisnodename) >= sizeof(ec->thisnodename)) {
	EI_TRACE_ERR0("ei_connect_init","Thisnodename too long");
	return ERL_ERROR;
    }
    strcpy(ec->thisnodename, thisnodename);

/* FIXME right now this_ipaddr is never used */    
/*    memmove(&ec->this_ipaddr, thisipaddr, sizeof(ec->this_ipaddr)); */
    
    strcpy(ec->self.node,thisnodename);
    ec->self.num = 0;
    ec->self.serial = 0;
    ec->self.creation = creation;

    if ((dbglevel = getenv("EI_TRACELEVEL")) != NULL ||
	(dbglevel = getenv("ERL_DEBUG_DIST")) != NULL)
	ei_tracelevel = atoi(dbglevel);

    return 0;
}
Пример #11
0
static int recv_name(int fd, 
		     unsigned *version,
		     unsigned *flags, ErlConnect *namebuf, unsigned ms)
{
    char dbuf[DEFBUF_SIZ];
    char *buf = dbuf;
    int is_static = 1;
    int buflen = DEFBUF_SIZ;
    int rlen;
    char *s;
    struct sockaddr_in sin;
    socklen_t sin_len = sizeof(sin);
    char tag;
    
    erl_errno = EIO;		/* Default */

    if ((rlen = read_2byte_package(fd, &buf, &buflen, &is_static, ms)) <= 0) {
	EI_TRACE_ERR1("recv_name","<- RECV_NAME socket read failed (%d)",rlen);
	goto error;
    }
    if ((rlen - 7) > MAXNODELEN) {
	EI_TRACE_ERR1("recv_name","<- RECV_NAME nodename too long (%d)",rlen-7);
	goto error;
    }
    s = buf;
    tag = get8(s);
    if (tag != 'n') {
	EI_TRACE_ERR2("recv_name","<- RECV_NAME incorrect tag, "
		      "expected 'n' got '%c' (%u)",tag,tag);
	goto error;
    }
    *version = get16be(s);
    *flags = get32be(s);

    if (!(*flags & DFLAG_EXTENDED_REFERENCES)) {
	EI_TRACE_ERR0("recv_name","<- RECV_NAME peer cannot handle"
		      "extended references");
	goto error;
    }

    if (!(*flags & DFLAG_EXTENDED_PIDS_PORTS)
	&& !ei_internal_use_r9_pids_ports()) {
	EI_TRACE_ERR0("recv_name","<- RECV_NAME peer cannot "
		      "handle extended pids and ports");
	erl_errno = EIO;
	goto error;
    }
	  
    if (getpeername(fd, (struct sockaddr *) &sin, &sin_len) < 0) {
	EI_TRACE_ERR0("recv_name","<- RECV_NAME can't get peername");
	erl_errno = errno;
	goto error;
    }
    memcpy(namebuf->ipadr, &(sin.sin_addr.s_addr), 
	sizeof(sin.sin_addr.s_addr));
    memcpy(namebuf->nodename, s, rlen - 7);
    namebuf->nodename[rlen - 7] = '\0';
    if (!is_static)
	free(buf);
    EI_TRACE_CONN3("recv_name",
		   "<- RECV_NAME (ok) node = %s, version = %u, flags = %u",
		   namebuf->nodename,*version,*flags);
    erl_errno = 0;
    return 0;
    
error:
    if (!is_static)
	free(buf);
    return -1;
}
Пример #12
0
/* this protocol is a lot more complex than the old one */
static int ei_epmd_r4_publish (int port, const char *alive, unsigned ms)
{
  char buf[EPMDBUF];
  char *s = buf;
  int fd;
  int elen = 0;
  int nlen = strlen(alive);
  int len = elen + nlen + 13; /* hard coded: be careful! */
  int n;
  int res, creation;
  
  if (len > sizeof(buf)-2)
  {
    erl_errno = ERANGE;
    return -1;
  }

  s = buf;
  put16be(s,len);

  put8(s,EI_EPMD_ALIVE2_REQ);
  put16be(s,port); /* port number */
  put8(s,'h');            /* h = r4 hidden node */
  put8(s, EI_MYPROTO);      /* protocol 0 ?? */
  put16be(s,EI_DIST_HIGH);   /* highest understood version: 1 = R4 */
  put16be(s,EI_DIST_LOW);    /* lowest:  0 = R3 */
  put16be(s,nlen);        /* length of alivename */
  strcpy(s, alive);
  s += nlen;
  put16be(s,elen);        /* length of extra string = 0 */
                          /* no extra string */

  if ((fd = ei_epmd_connect_tmo(NULL,ms)) < 0) return fd;

  if ((res = ei_write_fill_t(fd, buf, len+2, ms)) != len+2) {
    closesocket(fd);
    erl_errno = (res == -2) ? ETIMEDOUT : EIO;
    return -1;
  }

  EI_TRACE_CONN6("ei_epmd_r4_publish",
		 "-> ALIVE2_REQ alive=%s port=%d ntype=%d "
		 "proto=%d dist-high=%d dist-low=%d",
		 alive,port,'H',EI_MYPROTO,EI_DIST_HIGH,EI_DIST_LOW);
  
  if ((n = ei_read_fill_t(fd, buf, 4, ms)) != 4) {
    EI_TRACE_ERR0("ei_epmd_r4_publish","<- CLOSE");
    closesocket(fd);
    erl_errno = (n == -2) ? ETIMEDOUT : EIO;
    return -2;			/* version mismatch */
  }
  /* Don't close fd here! It keeps us registered with epmd */
  s = buf;
  if (((res=get8(s)) != EI_EPMD_ALIVE2_RESP)) {  /* response */
    EI_TRACE_ERR1("ei_epmd_r4_publish","<- unknown (%d)",res);
    EI_TRACE_ERR0("ei_epmd_r4_publish","-> CLOSE");
    closesocket(fd);
    erl_errno = EIO;
    return -1;
  }

  EI_TRACE_CONN0("ei_epmd_r4_publish","<- ALIVE2_RESP");

  if (((res=get8(s)) != 0)) {           /* 0 == success */
      EI_TRACE_ERR1("ei_epmd_r4_publish"," result=%d (fail)",res);
    closesocket(fd);
    erl_errno = EIO;
    return -1;
  }

  creation = get16be(s);

  EI_TRACE_CONN2("ei_epmd_r4_publish",
		 " result=%d (ok) creation=%d",res,creation);

  /* probably should save fd so we can close it later... */
  /* epmd_saveconn(OPEN,fd,alive); */

  /* return the creation number, for no good reason */
  /* return creation;*/

  /* no - return the descriptor */
  return fd;
}
Пример #13
0
static int ei_epmd_r4_port (struct in_addr *addr, const char *alive,
			    int *dist, unsigned ms)
{
  char buf[EPMDBUF];
  char *s = buf;
  int len = strlen(alive) + 1;
  int fd;
  int ntype;
  int port;
  int dist_high, dist_low, proto;
  int res;
#if defined(VXWORKS)
  char ntoabuf[32];
#endif

  if (len > sizeof(buf) - 3)
  {
      erl_errno = ERANGE;
      return -1;
  }
  
  put16be(s,len);
  put8(s,EI_EPMD_PORT2_REQ);
  strcpy(s,alive);
  
  /* connect to epmd */
  if ((fd = ei_epmd_connect_tmo(addr,ms)) < 0)
  {
      return -1;
  }

  if ((res = ei_write_fill_t(fd, buf, len+2, ms)) != len+2) {
    closesocket(fd);
    erl_errno = (res == -2) ? ETIMEDOUT : EIO;
    return -1;
  }

#ifdef VXWORKS
  /* FIXME use union/macro for level. Correct level? */
  if (ei_tracelevel > 2) {
    inet_ntoa_b(*addr,ntoabuf);
    EI_TRACE_CONN2("ei_epmd_r4_port",
		   "-> PORT2_REQ alive=%s ip=%s",alive,ntoabuf);
  }
#else
  EI_TRACE_CONN2("ei_epmd_r4_port",
		 "-> PORT2_REQ alive=%s ip=%s",alive,inet_ntoa(*addr));
#endif

  /* read first two bytes (response type, response) */
  if ((res = ei_read_fill_t(fd, buf, 2, ms)) != 2) {
    EI_TRACE_ERR0("ei_epmd_r4_port","<- CLOSE");
    erl_errno = (res == -2) ? ETIMEDOUT : EIO;
    closesocket(fd);
    return -2;			/* version mismatch */
  }

  s = buf;
  res = get8(s);
  
  if (res != EI_EPMD_PORT2_RESP) { /* response type */
    EI_TRACE_ERR1("ei_epmd_r4_port","<- unknown (%d)",res);
    EI_TRACE_ERR0("ei_epmd_r4_port","-> CLOSE");
    closesocket(fd);
    erl_errno = EIO;
    return -1;
  }

  

  /* got negative response */
  if ((res = get8(s))) {
    /* got negative response */
    EI_TRACE_ERR1("ei_epmd_r4_port","<- PORT2_RESP result=%d (failure)",res);
    closesocket(fd);
    erl_errno = EIO;
    return -1;
  }

  EI_TRACE_CONN1("ei_epmd_r4_port","<- PORT2_RESP result=%d (ok)",res);

  /* expecting remaining 8 bytes */
  if ((res = ei_read_fill_t(fd,buf,8,ms)) != 8) {
    EI_TRACE_ERR0("ei_epmd_r4_port","<- CLOSE");
    erl_errno = (res == -2) ? ETIMEDOUT : EIO;
    closesocket(fd);
    return -1;
  }
  
  closesocket(fd);
  s = buf;

  port = get16be(s);
  ntype = get8(s); 
  proto = get8(s);
  dist_high = get16be(s);
  dist_low = get16be(s);
  
  EI_TRACE_CONN5("ei_epmd_r4_port",
		"   port=%d ntype=%d proto=%d dist-high=%d dist-low=%d",
		port,ntype,proto,dist_high,dist_low);

  /* right network protocol? */
  if (EI_MYPROTO != proto)
  {
      erl_errno = EIO;
      return -1;
  }

  /* is there overlap in our distribution versions? */
  if ((EI_DIST_HIGH < dist_low) || (EI_DIST_LOW > dist_high)) 
  {
      erl_errno = EIO;
      return -1;
  }

  /* choose the highest common version */
  /* i.e. min(his-max, my-max) */
  *dist = (dist_high > EI_DIST_HIGH ? EI_DIST_HIGH : dist_high);
    
  /* ignore the remaining fields */
  return port;
}