diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml
index 601091c570..d2e5b08541 100644
--- a/doc/src/sgml/libpq.sgml
+++ b/doc/src/sgml/libpq.sgml
@@ -1735,6 +1735,36 @@ char *PQhost(const PGconn *conn);
+
+
+
+ PQhostaddr
+
+ PQhostaddr
+
+
+
+
+
+ Returns the server IP address of the active connection.
+ This can be the address that a host name resolved to,
+ or an IP address provided through the hostaddr
+ parameter.
+
+char *PQhostaddr(const PGconn *conn);
+
+
+
+
+ PQhostaddr returns NULL if the
+ conn argument is NULL.
+ 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.
+
+
+
+
PQport
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index 04e227b5a6..ee88e1ca5c 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -596,14 +596,30 @@ 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 +2870,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 +2911,27 @@ 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 +2993,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 +3108,27 @@ 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..bc456fec0c 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -1471,6 +1471,39 @@ connectNoDelay(PGconn *conn)
return 1;
}
+/* ----------
+ * Write currently connected IP address into host_addr (of len host_addr_len).
+ * If unable to, set it to the empty string.
+ * ----------
+ */
+static void
+getHostaddr(PGconn *conn, char *host_addr, int host_addr_len)
+{
+ struct sockaddr_storage *addr = &conn->raddr.addr;
+
+ if (conn->connhost[conn->whichhost].type == CHT_HOST_ADDRESS)
+ strlcpy(host_addr, conn->connhost[conn->whichhost].hostaddr, host_addr_len);
+ else if (addr->ss_family == AF_INET)
+ {
+ if (inet_net_ntop(AF_INET,
+ &((struct sockaddr_in *) addr)->sin_addr.s_addr,
+ 32,
+ host_addr, host_addr_len) == NULL)
+ host_addr[0] = '\0';
+ }
+#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, host_addr_len) == NULL)
+ host_addr[0] = '\0';
+ }
+#endif
+ else
+ host_addr[0] = '\0';
+}
/* ----------
* connectFailureMessage -
@@ -1504,34 +1537,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, NI_MAXHOST);
/* To which host and port were we actually connecting? */
if (conn->connhost[conn->whichhost].type == CHT_HOST_ADDRESS)
@@ -1548,14 +1559,14 @@ connectFailureMessage(PGconn *conn, int errorno)
* looked-up IP address.
*/
if (conn->connhost[conn->whichhost].type != CHT_HOST_ADDRESS &&
+ strlen(host_addr) > 0 &&
strcmp(displayed_host, host_addr) != 0)
appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not connect to server: %s\n"
"\tIs the server running on host \"%s\" (%s) and accepting\n"
"\tTCP/IP connections on port %s?\n"),
SOCK_STRERROR(errorno, sebuf, sizeof(sebuf)),
- displayed_host,
- host_addr,
+ displayed_host, host_addr,
displayed_port);
else
appendPQExpBuffer(&conn->errorMessage,
@@ -2286,6 +2297,7 @@ keep_going: /* We will come back to here until there is
*/
{
struct addrinfo *addr_cur = conn->addr_cur;
+ char host_addr[NI_MAXHOST];
/*
* Advance to next possible host, if we've tried all of
@@ -2302,6 +2314,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;
+ }
+
+ getHostaddr(conn, host_addr, NI_MAXHOST);
+ if (strlen(host_addr) > 0)
+ conn->connip = strdup(host_addr);
+ /*
+ * purposely ignore strdup failure; not a big problem if
+ * it fails anyway.
+ */
+
conn->sock = socket(addr_cur->ai_family, SOCK_STREAM, 0);
if (conn->sock == PGINVALID_SOCKET)
{
@@ -3665,6 +3692,8 @@ freePGconn(PGconn *conn)
free(conn->sslcompression);
if (conn->requirepeer)
free(conn->requirepeer);
+ if (conn->connip)
+ free(conn->connip);
#if defined(ENABLE_GSS) || defined(ENABLE_SSPI)
if (conn->krbsrvname)
free(conn->krbsrvname);
@@ -6172,6 +6201,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