fix: Emit appropriate error messages from getaddrinfo(3). (#888)

* fix: Emit appropriate error messages from getaddrinfo(3).

This fixes an omission likely caused when switching resolver
library calls.  Fixes #846.
diff --git a/src/iperf.h b/src/iperf.h
index b8a6e58..6ce77f5 100755
--- a/src/iperf.h
+++ b/src/iperf.h
@@ -1,5 +1,5 @@
 /*
- * iperf, Copyright (c) 2014-2018, The Regents of the University of
+ * iperf, Copyright (c) 2014-2019, The Regents of the University of
  * California, through Lawrence Berkeley National Laboratory (subject
  * to receipt of any required approvals from the U.S. Dept. of
  * Energy).  All rights reserved.
@@ -385,4 +385,6 @@
 #define MAX_MSS (9 * 1024)
 #define MAX_STREAMS 128
 
+extern int gerror; /* error value from getaddrinfo(3), for use in internal error handling */
+
 #endif /* !__IPERF_H */
diff --git a/src/iperf_error.c b/src/iperf_error.c
index e6eb032..fd3cccc 100644
--- a/src/iperf_error.c
+++ b/src/iperf_error.c
@@ -33,6 +33,8 @@
 #include "iperf.h"
 #include "iperf_api.h"
 
+int gerror;
+
 /* Do a printf to stderr. */
 void
 iperf_err(struct iperf_test *test, const char *format, ...)
@@ -185,11 +187,13 @@
             break;
         case IELISTEN:
             snprintf(errstr, len, "unable to start listener for connections");
+	    herr = 1;
             perr = 1;
             break;
         case IECONNECT:
             snprintf(errstr, len, "unable to connect to server");
             perr = 1;
+	    herr = 1;
             break;
         case IEACCEPT:
             snprintf(errstr, len, "unable to accept connection from client");
@@ -317,6 +321,7 @@
             break;
         case IESTREAMLISTEN:
             snprintf(errstr, len, "unable to start stream listener");
+	    herr = 1;
             perr = 1;
             break;
         case IESTREAMCONNECT:
@@ -383,10 +388,15 @@
 	
     }
 
+    /* Append the result of strerror() or gai_strerror() if appropriate */
     if (herr || perr)
         strncat(errstr, ": ", len - strlen(errstr) - 1);
     if (errno && perr)
         strncat(errstr, strerror(errno), len - strlen(errstr) - 1);
+    else if (herr && gerror) {
+        strncat(errstr, gai_strerror(gerror), len - strlen(errstr) - 1);
+	gerror = 0;
+    }
 
     return errstr;
 }
diff --git a/src/iperf_sctp.c b/src/iperf_sctp.c
index c1cb134..06e1e23 100644
--- a/src/iperf_sctp.c
+++ b/src/iperf_sctp.c
@@ -1,5 +1,5 @@
 /*
- * iperf, Copyright (c) 2014-2018, The Regents of the University of
+ * iperf, Copyright (c) 2014-2019, The Regents of the University of
  * California, through Lawrence Berkeley National Laboratory (subject
  * to receipt of any required approvals from the U.S. Dept. of
  * Energy).  All rights reserved.
@@ -178,7 +178,7 @@
     }
     hints.ai_socktype = SOCK_STREAM;
     hints.ai_flags = AI_PASSIVE;
-    if (getaddrinfo(test->bind_address, portstr, &hints, &res) != 0) {
+    if ((gerror = getaddrinfo(test->bind_address, portstr, &hints, &res)) != 0) {
         i_errno = IESTREAMLISTEN;
         return -1;
     }
@@ -266,7 +266,7 @@
         memset(&hints, 0, sizeof(hints));
         hints.ai_family = test->settings->domain;
         hints.ai_socktype = SOCK_STREAM;
-        if (getaddrinfo(test->bind_address, NULL, &hints, &local_res) != 0) {
+        if ((gerror = getaddrinfo(test->bind_address, NULL, &hints, &local_res)) != 0) {
             i_errno = IESTREAMCONNECT;
             return -1;
         }
@@ -276,7 +276,7 @@
     hints.ai_family = test->settings->domain;
     hints.ai_socktype = SOCK_STREAM;
     snprintf(portstr, sizeof(portstr), "%d", test->server_port);
-    if (getaddrinfo(test->server_hostname, portstr, &hints, &server_res) != 0) {
+    if ((gerror = getaddrinfo(test->server_hostname, portstr, &hints, &server_res)) != 0) {
 	if (test->bind_address)
 	    freeaddrinfo(local_res);
         i_errno = IESTREAMCONNECT;
@@ -548,7 +548,7 @@
         xbe0 = TAILQ_FIRST(&test->xbind_addrs);
         TAILQ_REMOVE(&test->xbind_addrs, xbe0, link);
 
-        if (getaddrinfo(xbe0->name, servname, &hints, &xbe0->ai) != 0) {
+        if ((gerror = getaddrinfo(xbe0->name, servname, &hints, &xbe0->ai)) != 0) {
             i_errno = IESETSCTPBINDX;
             retval = -1;
             goto out;
@@ -592,7 +592,7 @@
     TAILQ_FOREACH(xbe, &test->xbind_addrs, link) {
         if (xbe->ai != NULL)
             freeaddrinfo(xbe->ai);
-        if (getaddrinfo(xbe->name, servname, &hints, &xbe->ai) != 0) {
+        if ((gerror = getaddrinfo(xbe->name, servname, &hints, &xbe->ai)) != 0) {
             i_errno = IESETSCTPBINDX;
             retval = -1;
             goto out;
diff --git a/src/iperf_tcp.c b/src/iperf_tcp.c
index f6ef78f..232aaa1 100644
--- a/src/iperf_tcp.c
+++ b/src/iperf_tcp.c
@@ -1,5 +1,5 @@
 /*
- * iperf, Copyright (c) 2014-2018, The Regents of the University of
+ * iperf, Copyright (c) 2014-2019, The Regents of the University of
  * California, through Lawrence Berkeley National Laboratory (subject
  * to receipt of any required approvals from the U.S. Dept. of
  * Energy).  All rights reserved.
@@ -184,7 +184,7 @@
 	}
         hints.ai_socktype = SOCK_STREAM;
         hints.ai_flags = AI_PASSIVE;
-        if (getaddrinfo(test->bind_address, portstr, &hints, &res) != 0) {
+        if ((gerror = getaddrinfo(test->bind_address, portstr, &hints, &res)) != 0) {
             i_errno = IESTREAMLISTEN;
             return -1;
         }
@@ -375,7 +375,7 @@
         memset(&hints, 0, sizeof(hints));
         hints.ai_family = test->settings->domain;
         hints.ai_socktype = SOCK_STREAM;
-        if (getaddrinfo(test->bind_address, NULL, &hints, &local_res) != 0) {
+        if ((gerror = getaddrinfo(test->bind_address, NULL, &hints, &local_res)) != 0) {
             i_errno = IESTREAMCONNECT;
             return -1;
         }
@@ -385,7 +385,7 @@
     hints.ai_family = test->settings->domain;
     hints.ai_socktype = SOCK_STREAM;
     snprintf(portstr, sizeof(portstr), "%d", test->server_port);
-    if (getaddrinfo(test->server_hostname, portstr, &hints, &server_res) != 0) {
+    if ((gerror = getaddrinfo(test->server_hostname, portstr, &hints, &server_res)) != 0) {
 	if (test->bind_address)
 	    freeaddrinfo(local_res);
         i_errno = IESTREAMCONNECT;
diff --git a/src/net.c b/src/net.c
index fd525ee..96fb7ed 100644
--- a/src/net.c
+++ b/src/net.c
@@ -1,5 +1,5 @@
 /*
- * iperf, Copyright (c) 2014-2018, The Regents of the University of
+ * iperf, Copyright (c) 2014-2019, The Regents of the University of
  * California, through Lawrence Berkeley National Laboratory (subject
  * to receipt of any required approvals from the U.S. Dept. of
  * Energy).  All rights reserved.
@@ -65,6 +65,13 @@
 #include "timer.h"
 
 /*
+ * Declaration of gerror in iperf_error.c.  Most other files in iperf3 can get this
+ * by including "iperf.h", but net.c lives "below" this layer.  Clearly the
+ * presence of this declaration is a sign we need to revisit this layering.
+ */
+extern int gerror;
+
+/*
  * timeout_connect adapted from netcat, via OpenBSD and FreeBSD
  * Copyright (c) 2001 Eric Jackson <ericj@monkey.org>
  */
@@ -122,14 +129,14 @@
         memset(&hints, 0, sizeof(hints));
         hints.ai_family = domain;
         hints.ai_socktype = proto;
-        if (getaddrinfo(local, NULL, &hints, &local_res) != 0)
+        if ((gerror = getaddrinfo(local, NULL, &hints, &local_res)) != 0)
             return -1;
     }
 
     memset(&hints, 0, sizeof(hints));
     hints.ai_family = domain;
     hints.ai_socktype = proto;
-    if (getaddrinfo(server, NULL, &hints, &server_res) != 0)
+    if ((gerror = getaddrinfo(server, NULL, &hints, &server_res)) != 0)
         return -1;
 
     s = socket(server_res->ai_family, proto, 0);
@@ -238,7 +245,7 @@
     }
     hints.ai_socktype = proto;
     hints.ai_flags = AI_PASSIVE;
-    if (getaddrinfo(local, portstr, &hints, &res) != 0)
+    if ((gerror = getaddrinfo(local, portstr, &hints, &res)) != 0)
         return -1; 
 
     s = socket(res->ai_family, proto, 0);