Hi
pá 26. 10. 2018 v 15:55 odesílatel Fabien COELHO <[email protected]>
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