/* 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; }
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); }
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; }
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; }
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; }
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 */
/* 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 */
/* * 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 */
/* * 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); }
/* * 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; }
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; }
/* 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; }
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; }