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