File 0212-erl_interface-Fix-ei_connect.patch of Package erlang

From 3c8c8158de1b0f1880d588c1169be6a2f727c379 Mon Sep 17 00:00:00 2001
From: Sverker Eriksson <sverker@erlang.org>
Date: Wed, 18 Apr 2018 11:31:53 +0200
Subject: [PATCH] erl_interface: Fix ei_connect

when ei_gethostbyname_r returns ERANGE.
---
 lib/erl_interface/src/connect/ei_connect.c | 63 ++++++++++++++++++++++++++++--
 lib/erl_interface/src/connect/ei_resolve.c |  5 ++-
 2 files changed, 64 insertions(+), 4 deletions(-)

diff --git a/lib/erl_interface/src/connect/ei_connect.c b/lib/erl_interface/src/connect/ei_connect.c
index ea9ecb31d5..5c01223e3d 100644
--- a/lib/erl_interface/src/connect/ei_connect.c
+++ b/lib/erl_interface/src/connect/ei_connect.c
@@ -583,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.
@@ -597,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,'@'))) {
@@ -611,7 +661,7 @@ 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) {
@@ -627,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);
@@ -663,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)
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
-- 
2.16.3

openSUSE Build Service is sponsored by