Hi

pá 26. 10. 2018 v 15:55 odesílatel Fabien COELHO <coe...@cri.ensmp.fr>
napsal:

>
> 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...).
>
>
I checked this patch, and it looks well. The documentation is correct, all
tests passed. It does what is proposed.

I think so some redundant messages can be reduced - see function
printConnInfo - attached patch

If there are no be a objection, I'll mark this patch as ready for commiters

Regards

Pavel


> --
> Fabien.
diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml
index 601091c570..a7c9f2b400 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 0dea54d3ce..5b361c9484 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -158,6 +158,7 @@ static void print_with_linenumbers(FILE *output, char *lines,
 					   const char *header_keyword);
 static void minimal_error_message(PGresult *res);
 
+static void printConnInfo(void);
 static void printSSLInfo(void);
 static bool printPsetInfo(const char *param, struct printQueryOpt *popt);
 static char *pset_value_string(const char *param, struct printQueryOpt *popt);
@@ -595,15 +596,7 @@ exec_command_conninfo(PsqlScanState scan_state, bool active_branch)
 			printf(_("You are currently not connected to a database.\n"));
 		else
 		{
-			char	   *host = PQhost(pset.db);
-
-			/* If the host is an absolute path, the connection is via socket */
-			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));
-			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));
+			printConnInfo();
 			printSSLInfo();
 		}
 	}
@@ -2854,6 +2847,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 +2888,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 +2965,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";
@@ -3070,15 +3079,7 @@ do_connect(enum trivalue reuse_previous_specification,
 			param_is_newly_set(PQhost(o_conn), PQhost(pset.db)) ||
 			param_is_newly_set(PQport(o_conn), PQport(pset.db)))
 		{
-			char	   *host = PQhost(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));
-			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));
+			printConnInfo();
 		}
 		else
 			printf(_("You are now connected to database \"%s\" as user \"%s\".\n"),
@@ -3138,6 +3139,35 @@ connection_warnings(bool in_startup)
 }
 
 
+/*
+ * printConnInfo
+ *
+ * Print information about current connection.
+ */
+static void
+printConnInfo(void)
+{
+	char	   *host = PQhost(pset.db);
+	char	   *hostaddr = PQhostaddr(pset.db);
+	char	   *db = PQdb(pset.db);
+
+	/* If the host is an absolute path, the connection is via socket unless overriden by hostaddr */
+	if (is_absolute_path(host))
+		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
+		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
  *
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