Hello,

This is a follow-up to another patch I posted about libpq confusing documentation & psql resulting behavior under host/hostaddr settings.

Although the first mostly documentation patch did not gather much enthousiasm, I still think both issues deserve a fix.

About updating psql's behavior, without this patch:

  sh> psql "host=foo hostaddr=127.0.0.1"

  psql> \conninfo
  You are connected to database "fabien" as user "fabien" on host "foo" at port 
"5432".
   # NOPE, I'm really connected to localhost, foo does not even exist
   # Other apparent inconsistencies are possible when hostaddr overrides
   # "host" which is an socket directory or an IP.

  psql> \c template1
  could not translate host name "foo" to address: Name or service not known
  Previous connection kept
   # hmmm.... what is the meaning of reusing a connection?
   # this issue was pointed out by Arthur Zakirov

After the patch:

  sh> psql "host=foo hostaddr=127.0.0.1"

  psql> \conninfo
  You are connected to database "fabien" as user "fabien" on host "foo" (address 
"127.0.0.1") at port "5432".
  # better

  psql> \c template1
  You are now connected to database "template1" as user "fabien".
  # thanks

The patch adds a PQhostaddr() function to libpq which reports the "hostaddr" setting or the current server ip. The function is used by psql for \conninfo and when reusing parameters for \connect.

The messages are slightly more verbose because the IP is output. I think that user asking for conninfo should survive to the more precise data. This also comes handy if a host name resolves to several IPs (eg IPv6 and IPv4, or several IPs...).

--
Fabien.
diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml
index 82a440531b..310792e58d 100644
--- a/doc/src/sgml/libpq.sgml
+++ b/doc/src/sgml/libpq.sgml
@@ -1735,6 +1735,35 @@ char *PQhost(const PGconn *conn);
      </listitem>
     </varlistentry>
 
+
+    <varlistentry id="libpq-pqhostaddr">
+     <term>
+      <function>PQhostaddr</function>
+      <indexterm>
+       <primary>PQhostaddr</primary>
+      </indexterm>
+     </term>
+
+     <listitem>
+      <para>
+       Returns the actual server IP address of the active connection.
+       This can be the address a host name resolved to, or an IP address
+       provided through the <literal>hostaddr</literal> parameter.
+<synopsis>
+char *PQhostaddr(const PGconn *conn);
+</synopsis>
+      </para>
+
+      <para>
+       <function>PQhostaddr</function> returns <symbol>NULL</symbol> if the
+       <parameter>conn</parameter> argument is <symbol>NULL</symbol>.
+       Otherwise, if there is an error producing the host information (perhaps
+       if the connection has not been fully established or there was an
+       error), it returns an empty string.
+      </para>
+     </listitem>
+    </varlistentry>
+
     <varlistentry id="libpq-pqport">
      <term>
       <function>PQport</function>
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index 5b4d54a442..d6f3a981b3 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -596,14 +596,23 @@ exec_command_conninfo(PsqlScanState scan_state, bool active_branch)
 		else
 		{
 			char	   *host = PQhost(pset.db);
+			char	   *hostaddr = PQhostaddr(pset.db);
 
-			/* If the host is an absolute path, the connection is via socket */
+			/* If the host is an absolute path, the connection is via socket unless overriden by hostaddr */
 			if (is_absolute_path(host))
-				printf(_("You are connected to database \"%s\" as user \"%s\" via socket in \"%s\" at port \"%s\".\n"),
-					   db, PQuser(pset.db), host, PQport(pset.db));
+				if (hostaddr && *hostaddr)
+					printf(_("You are connected to database \"%s\" as user \"%s\" on address \"%s\" at port \"%s\".\n"),
+						   db, PQuser(pset.db), hostaddr, PQport(pset.db));
+				else
+					printf(_("You are connected to database \"%s\" as user \"%s\" via socket in \"%s\" at port \"%s\".\n"),
+						   db, PQuser(pset.db), host, PQport(pset.db));
 			else
-				printf(_("You are connected to database \"%s\" as user \"%s\" on host \"%s\" at port \"%s\".\n"),
-					   db, PQuser(pset.db), host, PQport(pset.db));
+				if (hostaddr && *hostaddr && strcmp(host, hostaddr) != 0)
+					printf(_("You are connected to database \"%s\" as user \"%s\" on host \"%s\" (address \"%s\") at port \"%s\".\n"),
+						   db, PQuser(pset.db), host, hostaddr, PQport(pset.db));
+				else
+					printf(_("You are connected to database \"%s\" as user \"%s\" on host \"%s\" at port \"%s\".\n"),
+						   db, PQuser(pset.db), host, PQport(pset.db));
 			printSSLInfo();
 		}
 	}
@@ -2854,6 +2863,7 @@ do_connect(enum trivalue reuse_previous_specification,
 	PGconn	   *o_conn = pset.db,
 			   *n_conn;
 	char	   *password = NULL;
+	char	   *hostaddr = NULL;
 	bool		keep_password;
 	bool		has_connection_string;
 	bool		reuse_previous;
@@ -2894,12 +2904,22 @@ do_connect(enum trivalue reuse_previous_specification,
 	}
 
 	/* grab missing values from the old connection */
-	if (!user && reuse_previous)
-		user = PQuser(o_conn);
-	if (!host && reuse_previous)
-		host = PQhost(o_conn);
-	if (!port && reuse_previous)
-		port = PQport(o_conn);
+	if (reuse_previous)
+	{
+		if (!user)
+			user = PQuser(o_conn);
+		if (host && strcmp(host, PQhost(o_conn)) == 0)
+			/* if we are targetting the same host, reuse its hostaddr for consistency */
+			hostaddr = PQhostaddr(o_conn);
+		if (!host)
+		{
+			host = PQhost(o_conn);
+			/* also set hostaddr for consistency */
+			hostaddr = PQhostaddr(o_conn);
+		}
+		if (!port)
+			port = PQport(o_conn);
+	}
 
 	/*
 	 * Any change in the parameters read above makes us discard the password.
@@ -2961,13 +2981,18 @@ do_connect(enum trivalue reuse_previous_specification,
 
 	while (true)
 	{
-#define PARAMS_ARRAY_SIZE	8
+#define PARAMS_ARRAY_SIZE	9
 		const char **keywords = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*keywords));
 		const char **values = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*values));
 		int			paramnum = -1;
 
 		keywords[++paramnum] = "host";
 		values[paramnum] = host;
+		if (hostaddr && *hostaddr)
+		{
+			keywords[++paramnum] = "hostaddr";
+			values[paramnum] = hostaddr;
+		}
 		keywords[++paramnum] = "port";
 		values[paramnum] = port;
 		keywords[++paramnum] = "user";
@@ -3071,14 +3096,23 @@ do_connect(enum trivalue reuse_previous_specification,
 			param_is_newly_set(PQport(o_conn), PQport(pset.db)))
 		{
 			char	   *host = PQhost(pset.db);
+			char	   *hostaddr = PQhostaddr(pset.db);
 
 			/* If the host is an absolute path, the connection is via socket */
 			if (is_absolute_path(host))
-				printf(_("You are now connected to database \"%s\" as user \"%s\" via socket in \"%s\" at port \"%s\".\n"),
-					   PQdb(pset.db), PQuser(pset.db), host, PQport(pset.db));
+				if (hostaddr && *hostaddr)
+					printf(_("You are now connected to database \"%s\" as user \"%s\" on address \"%s\" at port \"%s\".\n"),
+						   PQdb(pset.db), PQuser(pset.db), hostaddr, PQport(pset.db));
+				else
+					printf(_("You are now connected to database \"%s\" as user \"%s\" via socket in \"%s\" at port \"%s\".\n"),
+						   PQdb(pset.db), PQuser(pset.db), host, PQport(pset.db));
 			else
-				printf(_("You are now connected to database \"%s\" as user \"%s\" on host \"%s\" at port \"%s\".\n"),
-					   PQdb(pset.db), PQuser(pset.db), host, PQport(pset.db));
+				if (hostaddr && *hostaddr && strcmp(host, hostaddr) != 0)
+					printf(_("You are now connected to database \"%s\" as user \"%s\" on host \"%s\" (address \"%s\") at port \"%s\".\n"),
+						   PQdb(pset.db), PQuser(pset.db), host, hostaddr, PQport(pset.db));
+				else
+					printf(_("You are now connected to database \"%s\" as user \"%s\" on host \"%s\" at port \"%s\".\n"),
+						   PQdb(pset.db), PQuser(pset.db), host, PQport(pset.db));
 		}
 		else
 			printf(_("You are now connected to database \"%s\" as user \"%s\".\n"),
diff --git a/src/interfaces/libpq/exports.txt b/src/interfaces/libpq/exports.txt
index 4359fae30d..cc9ee9ce6b 100644
--- a/src/interfaces/libpq/exports.txt
+++ b/src/interfaces/libpq/exports.txt
@@ -173,3 +173,4 @@ PQsetErrorContextVisibility 170
 PQresultVerboseErrorMessage 171
 PQencryptPasswordConn     172
 PQresultMemorySize        173
+PQhostaddr                174
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index d001bc513d..8e3acaf05d 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -1471,6 +1471,34 @@ connectNoDelay(PGconn *conn)
 	return 1;
 }
 
+static void
+getHostaddr(PGconn *conn, char host_addr[NI_MAXHOST])
+{
+	struct sockaddr_storage *addr = &conn->raddr.addr;
+
+	if (conn->connhost[conn->whichhost].type == CHT_HOST_ADDRESS)
+		strlcpy(host_addr, conn->connhost[conn->whichhost].hostaddr, NI_MAXHOST);
+	else if (addr->ss_family == AF_INET)
+	{
+		if (inet_net_ntop(AF_INET,
+						  &((struct sockaddr_in *) addr)->sin_addr.s_addr,
+						  32,
+						  host_addr, NI_MAXHOST) == NULL)
+			strcpy(host_addr, "???");
+	}
+#ifdef HAVE_IPV6
+	else if (addr->ss_family == AF_INET6)
+	{
+		if (inet_net_ntop(AF_INET6,
+						  &((struct sockaddr_in6 *) addr)->sin6_addr.s6_addr,
+						  128,
+						  host_addr, NI_MAXHOST) == NULL)
+			strcpy(host_addr, "???");
+	}
+#endif
+	else
+		strcpy(host_addr, "???");
+}
 
 /* ----------
  * connectFailureMessage -
@@ -1504,34 +1532,12 @@ connectFailureMessage(PGconn *conn, int errorno)
 		char		host_addr[NI_MAXHOST];
 		const char *displayed_host;
 		const char *displayed_port;
-		struct sockaddr_storage *addr = &conn->raddr.addr;
 
 		/*
 		 * Optionally display the network address with the hostname. This is
 		 * useful to distinguish between IPv4 and IPv6 connections.
 		 */
-		if (conn->connhost[conn->whichhost].type == CHT_HOST_ADDRESS)
-			strlcpy(host_addr, conn->connhost[conn->whichhost].hostaddr, NI_MAXHOST);
-		else if (addr->ss_family == AF_INET)
-		{
-			if (inet_net_ntop(AF_INET,
-							  &((struct sockaddr_in *) addr)->sin_addr.s_addr,
-							  32,
-							  host_addr, sizeof(host_addr)) == NULL)
-				strcpy(host_addr, "???");
-		}
-#ifdef HAVE_IPV6
-		else if (addr->ss_family == AF_INET6)
-		{
-			if (inet_net_ntop(AF_INET6,
-							  &((struct sockaddr_in6 *) addr)->sin6_addr.s6_addr,
-							  128,
-							  host_addr, sizeof(host_addr)) == NULL)
-				strcpy(host_addr, "???");
-		}
-#endif
-		else
-			strcpy(host_addr, "???");
+		getHostaddr(conn, host_addr);
 
 		/* To which host and port were we actually connecting? */
 		if (conn->connhost[conn->whichhost].type == CHT_HOST_ADDRESS)
@@ -2302,6 +2308,21 @@ keep_going:						/* We will come back to here until there is
 						   addr_cur->ai_addrlen);
 					conn->raddr.salen = addr_cur->ai_addrlen;
 
+
+					/* set connip */
+					if (conn->connip != NULL)
+					{
+						free(conn->connip);
+						conn->connip = NULL;
+					}
+
+					{
+						char		host_addr[NI_MAXHOST];
+						getHostaddr(conn, host_addr);
+						if (strcmp(host_addr, "???") != 0)
+							conn->connip = strdup(host_addr);
+					}
+
 					conn->sock = socket(addr_cur->ai_family, SOCK_STREAM, 0);
 					if (conn->sock == PGINVALID_SOCKET)
 					{
@@ -6172,6 +6193,25 @@ PQhost(const PGconn *conn)
 	return "";
 }
 
+char *
+PQhostaddr(const PGconn *conn)
+{
+	if (!conn)
+		return NULL;
+
+	if (conn->connhost != NULL)
+	{
+		if (conn->connhost[conn->whichhost].hostaddr != NULL &&
+			conn->connhost[conn->whichhost].hostaddr[0] != '\0')
+			return conn->connhost[conn->whichhost].hostaddr;
+
+		if (conn->connip != NULL)
+			return conn->connip;
+	}
+
+	return "";
+}
+
 char *
 PQport(const PGconn *conn)
 {
diff --git a/src/interfaces/libpq/libpq-fe.h b/src/interfaces/libpq/libpq-fe.h
index 52bd5d2cd8..3f13ddf092 100644
--- a/src/interfaces/libpq/libpq-fe.h
+++ b/src/interfaces/libpq/libpq-fe.h
@@ -312,6 +312,7 @@ extern char *PQdb(const PGconn *conn);
 extern char *PQuser(const PGconn *conn);
 extern char *PQpass(const PGconn *conn);
 extern char *PQhost(const PGconn *conn);
+extern char *PQhostaddr(const PGconn *conn);
 extern char *PQport(const PGconn *conn);
 extern char *PQtty(const PGconn *conn);
 extern char *PQoptions(const PGconn *conn);
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 975ab33d02..66fd317b94 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -397,6 +397,7 @@ struct pg_conn
 	int			nconnhost;		/* # of hosts named in conn string */
 	int			whichhost;		/* host we're currently trying/connected to */
 	pg_conn_host *connhost;		/* details about each named host */
+	char	   *connip;			/* IP address for current network connection */
 
 	/* Connection data */
 	pgsocket	sock;			/* FD for socket, PGINVALID_SOCKET if

Reply via email to