diff options
Diffstat (limited to 'lib/erl_interface/src/connect')
-rw-r--r-- | lib/erl_interface/src/connect/ei_connect.c | 127 | ||||
-rw-r--r-- | lib/erl_interface/src/connect/ei_resolve.c | 5 |
2 files changed, 103 insertions, 29 deletions
diff --git a/lib/erl_interface/src/connect/ei_connect.c b/lib/erl_interface/src/connect/ei_connect.c index 6dc51adee1..be228ab853 100644 --- a/lib/erl_interface/src/connect/ei_connect.c +++ b/lib/erl_interface/src/connect/ei_connect.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2000-2016. All Rights Reserved. + * Copyright Ericsson AB 2000-2017. 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. @@ -423,7 +423,7 @@ int ei_connect_xinit(ei_cnode* ec, const char *thishostname, } #endif /* _REENTRANT */ - ec->creation = creation; + ec->creation = creation & 0x3; /* 2 bits */ if (cookie) { if (strlen(cookie) >= sizeof(ec->ei_connect_cookie)) { @@ -462,7 +462,7 @@ int ei_connect_xinit(ei_cnode* ec, const char *thishostname, strcpy(ec->self.node,thisnodename); ec->self.num = 0; ec->self.serial = 0; - ec->self.creation = creation; + ec->self.creation = creation & 0x3; /* 2 bits */ if ((dbglevel = getenv("EI_TRACELEVEL")) != NULL || (dbglevel = getenv("ERL_DEBUG_DIST")) != NULL) @@ -497,7 +497,8 @@ int ei_connect_init(ei_cnode* ec, const char* this_node_name, } #endif /* _REENTRANT */ - if (gethostname(thishostname, EI_MAXHOSTNAMELEN) == -1) { + /* gethostname requires len to be max(hostname) + 1 */ + if (gethostname(thishostname, EI_MAXHOSTNAMELEN+1) == -1) { #ifdef __WIN32__ EI_TRACE_ERR1("ei_connect_init","Failed to get host name: %d", WSAGetLastError()); @@ -582,6 +583,54 @@ static int cnct(uint16 port, struct in_addr *ip_addr, int addr_len, unsigned ms) return s; } /* cnct */ + +/* + * Same as ei_gethostbyname_r, but also handles ERANGE error + * and may allocate larger buffer with malloc. + */ +static +struct hostent *dyn_gethostbyname_r(const char *name, + struct hostent *hostp, + char **buffer_p, + int buflen, + int *h_errnop) +{ + char* buf = *buffer_p; + struct hostent *hp; + + while (1) { + hp = ei_gethostbyname_r(name, hostp, buf, buflen, h_errnop); + if (hp) { + *buffer_p = buf; + break; + } + + if (*h_errnop != ERANGE) { + if (buf != *buffer_p) + free(buf); + break; + } + + buflen *= 2; + if (buf == *buffer_p) + buf = malloc(buflen); + else { + char* buf2 = realloc(buf, buflen); + if (buf2) + buf = buf2; + else { + free(buf); + buf = NULL; + } + } + if (!buf) { + *h_errnop = ENOMEM; + break; + } + } + return hp; +} + /* * Set up a connection to a given Node, and * interchange hand shake messages with it. @@ -596,8 +645,10 @@ int ei_connect_tmo(ei_cnode* ec, char *nodename, unsigned ms) /* these are needed for the call to gethostbyname_r */ struct hostent host; char buffer[1024]; + char *buf = buffer; int ei_h_errno; #endif /* !win32 */ + int res; /* extract the host and alive parts from nodename */ if (!(hostname = strchr(nodename,'@'))) { @@ -610,10 +661,11 @@ int ei_connect_tmo(ei_cnode* ec, char *nodename, unsigned ms) } #ifndef __WIN32__ - hp = ei_gethostbyname_r(hostname,&host,buffer,1024,&ei_h_errno); + hp = dyn_gethostbyname_r(hostname,&host,&buf,sizeof(buffer),&ei_h_errno); if (hp == NULL) { char thishostname[EI_MAXHOSTNAMELEN+1]; - if (gethostname(thishostname,EI_MAXHOSTNAMELEN) < 0) { + /* gethostname requies len to be max(hostname) + 1*/ + if (gethostname(thishostname,EI_MAXHOSTNAMELEN+1) < 0) { EI_TRACE_ERR0("ei_connect_tmo", "Failed to get name of this host"); erl_errno = EHOSTUNREACH; @@ -625,7 +677,7 @@ int ei_connect_tmo(ei_cnode* ec, char *nodename, unsigned ms) } if (strcmp(hostname,thishostname) == 0) /* Both nodes on same standalone host, use loopback */ - hp = ei_gethostbyname_r("localhost",&host,buffer,1024,&ei_h_errno); + hp = dyn_gethostbyname_r("localhost",&host,&buf,sizeof(buffer),&ei_h_errno); if (hp == NULL) { EI_TRACE_ERR2("ei_connect", "Can't find host for %s: %d\n",nodename,ei_h_errno); @@ -636,7 +688,8 @@ int ei_connect_tmo(ei_cnode* ec, char *nodename, unsigned ms) #else /* __WIN32__ */ if ((hp = ei_gethostbyname(hostname)) == NULL) { char thishostname[EI_MAXHOSTNAMELEN+1]; - if (gethostname(thishostname,EI_MAXHOSTNAMELEN) < 0) { + /* gethostname requires len to be max(hostname) + 1 */ + if (gethostname(thishostname,EI_MAXHOSTNAMELEN+1) < 0) { EI_TRACE_ERR1("ei_connect_tmo", "Failed to get name of this host: %d", WSAGetLastError()); @@ -660,7 +713,14 @@ int ei_connect_tmo(ei_cnode* ec, char *nodename, unsigned ms) } } #endif /* win32 */ - return ei_xconnect_tmo(ec, (Erl_IpAddr) *hp->h_addr_list, alivename, ms); + + res = ei_xconnect_tmo(ec, (Erl_IpAddr) *hp->h_addr_list, alivename, ms); + +#ifndef __WIN32__ + if (buf != buffer) + free(buf); +#endif + return res; } /* ei_connect */ int ei_connect(ei_cnode* ec, char *nodename) @@ -1297,11 +1357,14 @@ static int recv_status(int fd, unsigned ms) "<- RECV_STATUS socket read failed (%d)", rlen); goto error; } - if (rlen == 3 && buf[0] == 's' && buf[1] == 'o' && - buf[2] == 'k') { + + EI_TRACE_CONN2("recv_status", + "<- RECV_STATUS (%.*s)", (rlen>20 ? 20 : rlen), buf); + + if (rlen >= 3 && buf[0] == 's' && buf[1] == 'o' && buf[2] == 'k') { + /* Expecting "sok" or "sok_simultaneous" */ if (!is_static) free(buf); - EI_TRACE_CONN0("recv_status","<- RECV_STATUS (ok)"); return 0; } error: @@ -1708,28 +1771,36 @@ error: static int get_home(char *buf, int size) { - char* homedrive; - char* homepath; - #ifdef __WIN32__ - homedrive = getenv("HOMEDRIVE"); - homepath = getenv("HOMEPATH"); -#else - homedrive = ""; - homepath = getenv("HOME"); -#endif + char* homedrive = getenv("HOMEDRIVE"); + char* homepath = getenv("HOMEPATH"); - if (!homedrive || !homepath) { - buf[0] = '.'; - buf[1] = '\0'; - return 1; - } else if (strlen(homedrive)+strlen(homepath) < size-1) { + if (homedrive && homepath) { + if (strlen(homedrive)+strlen(homepath) >= size) + return 0; strcpy(buf, homedrive); strcat(buf, homepath); return 1; } - - return 0; + else { + int len = GetWindowsDirectory(buf, size); + if (len) { + return (len < size); + } + } +#else + char* homepath = getenv("HOME"); + if (homepath) { + if (strlen(homepath) >= size) + return 0; + strcpy(buf, homepath); + return 1; + } +#endif + + buf[0] = '.'; + buf[1] = '\0'; + return 1; } diff --git a/lib/erl_interface/src/connect/ei_resolve.c b/lib/erl_interface/src/connect/ei_resolve.c index fd0c659373..2757735d39 100644 --- a/lib/erl_interface/src/connect/ei_resolve.c +++ b/lib/erl_interface/src/connect/ei_resolve.c @@ -645,8 +645,11 @@ struct hostent *ei_gethostbyname_r(const char *name, #else #if (defined(__GLIBC__) || defined(__linux__) || (__FreeBSD_version >= 602000) || defined(__DragonFly__) || defined(__ANDROID__)) struct hostent *result; + int err; - gethostbyname_r(name, hostp, buffer, buflen, &result, h_errnop); + err = gethostbyname_r(name, hostp, buffer, buflen, &result, h_errnop); + if (err == ERANGE) + *h_errnop = err; return result; #else |