mirror of
https://github.com/postgres/postgres.git
synced 2025-05-02 11:44:50 +03:00
Add support for abstract Unix-domain sockets
This is a variant of the normal Unix-domain sockets that don't use the file system but a separate "abstract" namespace. At the user interface, such sockets are represented by names starting with "@". Supported on Linux and Windows right now. Reviewed-by: Michael Paquier <michael@paquier.xyz> Discussion: https://www.postgresql.org/message-id/flat/6dee8574-b0ad-fc49-9c8c-2edc796f0033@2ndquadrant.com
This commit is contained in:
parent
a7e65dc88b
commit
c9f0624bc2
@ -749,6 +749,21 @@ include_dir 'conf.d'
|
|||||||
An empty value
|
An empty value
|
||||||
specifies not listening on any Unix-domain sockets, in which case
|
specifies not listening on any Unix-domain sockets, in which case
|
||||||
only TCP/IP sockets can be used to connect to the server.
|
only TCP/IP sockets can be used to connect to the server.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
A value that starts with <literal>@</literal> specifies that a
|
||||||
|
Unix-domain socket in the abstract namespace should be created
|
||||||
|
(currently supported on Linux and Windows). In that case, this value
|
||||||
|
does not specify a <quote>directory</quote> but a prefix from which
|
||||||
|
the actual socket name is computed in the same manner as for the
|
||||||
|
file-system namespace. While the abstract socket name prefix can be
|
||||||
|
chosen freely, since it is not a file-system location, the convention
|
||||||
|
is to nonetheless use file-system-like values such as
|
||||||
|
<literal>@/tmp</literal>.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
The default value is normally
|
The default value is normally
|
||||||
<filename>/tmp</filename>, but that can be changed at build time.
|
<filename>/tmp</filename>, but that can be changed at build time.
|
||||||
On Windows, the default is empty, which means no Unix-domain socket is
|
On Windows, the default is empty, which means no Unix-domain socket is
|
||||||
@ -763,6 +778,7 @@ include_dir 'conf.d'
|
|||||||
named <literal>.s.PGSQL.<replaceable>nnnn</replaceable>.lock</literal> will be
|
named <literal>.s.PGSQL.<replaceable>nnnn</replaceable>.lock</literal> will be
|
||||||
created in each of the <varname>unix_socket_directories</varname> directories.
|
created in each of the <varname>unix_socket_directories</varname> directories.
|
||||||
Neither file should ever be removed manually.
|
Neither file should ever be removed manually.
|
||||||
|
For sockets in the abstract namespace, no lock file is created.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
@ -787,7 +803,8 @@ include_dir 'conf.d'
|
|||||||
|
|
||||||
<para>
|
<para>
|
||||||
This parameter is not supported on Windows. Any setting will be
|
This parameter is not supported on Windows. Any setting will be
|
||||||
ignored.
|
ignored. Also, sockets in the abstract namespace have no file owner,
|
||||||
|
so this setting is also ignored in that case.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
@ -834,6 +851,11 @@ include_dir 'conf.d'
|
|||||||
similar effect by pointing <varname>unix_socket_directories</varname> to a
|
similar effect by pointing <varname>unix_socket_directories</varname> to a
|
||||||
directory having search permission limited to the desired audience.
|
directory having search permission limited to the desired audience.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Sockets in the abstract namespace have no file permissions, so this
|
||||||
|
setting is also ignored in that case.
|
||||||
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
@ -1031,7 +1031,10 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname
|
|||||||
communication; the value is the name of the directory in which the
|
communication; the value is the name of the directory in which the
|
||||||
socket file is stored. (On Unix, an absolute path name begins with a
|
socket file is stored. (On Unix, an absolute path name begins with a
|
||||||
slash. On Windows, paths starting with drive letters are also
|
slash. On Windows, paths starting with drive letters are also
|
||||||
recognized.) The default behavior when <literal>host</literal> is not
|
recognized.) If the host name starts with <literal>@</literal>, it is
|
||||||
|
taken as a Unix-domain socket in the abstract namespace (currently
|
||||||
|
supported on Linux and Windows).
|
||||||
|
The default behavior when <literal>host</literal> is not
|
||||||
specified, or is empty, is to connect to a Unix-domain
|
specified, or is empty, is to connect to a Unix-domain
|
||||||
socket<indexterm><primary>Unix domain socket</primary></indexterm> in
|
socket<indexterm><primary>Unix domain socket</primary></indexterm> in
|
||||||
<filename>/tmp</filename> (or whatever socket directory was specified
|
<filename>/tmp</filename> (or whatever socket directory was specified
|
||||||
|
@ -611,6 +611,10 @@ StreamServerPort(int family, const char *hostName, unsigned short portNumber,
|
|||||||
static int
|
static int
|
||||||
Lock_AF_UNIX(const char *unixSocketDir, const char *unixSocketPath)
|
Lock_AF_UNIX(const char *unixSocketDir, const char *unixSocketPath)
|
||||||
{
|
{
|
||||||
|
/* no lock file for abstract sockets */
|
||||||
|
if (unixSocketPath[0] == '@')
|
||||||
|
return STATUS_OK;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Grab an interlock file associated with the socket file.
|
* Grab an interlock file associated with the socket file.
|
||||||
*
|
*
|
||||||
@ -642,6 +646,10 @@ Lock_AF_UNIX(const char *unixSocketDir, const char *unixSocketPath)
|
|||||||
static int
|
static int
|
||||||
Setup_AF_UNIX(const char *sock_path)
|
Setup_AF_UNIX(const char *sock_path)
|
||||||
{
|
{
|
||||||
|
/* no file system permissions for abstract sockets */
|
||||||
|
if (sock_path[0] == '@')
|
||||||
|
return STATUS_OK;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fix socket ownership/permission if requested. Note we must do this
|
* Fix socket ownership/permission if requested. Note we must do this
|
||||||
* before we listen() to avoid a window where unwanted connections could
|
* before we listen() to avoid a window where unwanted connections could
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "large_obj.h"
|
#include "large_obj.h"
|
||||||
#include "libpq-fe.h"
|
#include "libpq-fe.h"
|
||||||
|
#include "libpq/pqcomm.h"
|
||||||
#include "mainloop.h"
|
#include "mainloop.h"
|
||||||
#include "portability/instr_time.h"
|
#include "portability/instr_time.h"
|
||||||
#include "pqexpbuffer.h"
|
#include "pqexpbuffer.h"
|
||||||
@ -604,12 +605,9 @@ exec_command_conninfo(PsqlScanState scan_state, bool active_branch)
|
|||||||
char *host = PQhost(pset.db);
|
char *host = PQhost(pset.db);
|
||||||
char *hostaddr = PQhostaddr(pset.db);
|
char *hostaddr = PQhostaddr(pset.db);
|
||||||
|
|
||||||
/*
|
if (is_unixsock_path(host))
|
||||||
* If the host is an absolute path, the connection is via socket
|
|
||||||
* unless overridden by hostaddr
|
|
||||||
*/
|
|
||||||
if (is_absolute_path(host))
|
|
||||||
{
|
{
|
||||||
|
/* hostaddr overrides host */
|
||||||
if (hostaddr && *hostaddr)
|
if (hostaddr && *hostaddr)
|
||||||
printf(_("You are connected to database \"%s\" as user \"%s\" on address \"%s\" at port \"%s\".\n"),
|
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));
|
db, PQuser(pset.db), hostaddr, PQport(pset.db));
|
||||||
@ -3407,12 +3405,9 @@ do_connect(enum trivalue reuse_previous_specification,
|
|||||||
char *host = PQhost(pset.db);
|
char *host = PQhost(pset.db);
|
||||||
char *hostaddr = PQhostaddr(pset.db);
|
char *hostaddr = PQhostaddr(pset.db);
|
||||||
|
|
||||||
/*
|
if (is_unixsock_path(host))
|
||||||
* If the host is an absolute path, the connection is via socket
|
|
||||||
* unless overridden by hostaddr
|
|
||||||
*/
|
|
||||||
if (is_absolute_path(host))
|
|
||||||
{
|
{
|
||||||
|
/* hostaddr overrides host */
|
||||||
if (hostaddr && *hostaddr)
|
if (hostaddr && *hostaddr)
|
||||||
printf(_("You are now connected to database \"%s\" as user \"%s\" on address \"%s\" at port \"%s\".\n"),
|
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));
|
PQdb(pset.db), PQuser(pset.db), hostaddr, PQport(pset.db));
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "common/string.h"
|
#include "common/string.h"
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
|
#include "libpq/pqcomm.h"
|
||||||
#include "prompt.h"
|
#include "prompt.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
|
||||||
@ -136,7 +137,7 @@ get_prompt(promptStatus_t status, ConditionalStack cstack)
|
|||||||
const char *host = PQhost(pset.db);
|
const char *host = PQhost(pset.db);
|
||||||
|
|
||||||
/* INET socket */
|
/* INET socket */
|
||||||
if (host && host[0] && !is_absolute_path(host))
|
if (host && host[0] && !is_unixsock_path(host))
|
||||||
{
|
{
|
||||||
strlcpy(buf, host, sizeof(buf));
|
strlcpy(buf, host, sizeof(buf));
|
||||||
if (*p == 'm')
|
if (*p == 'm')
|
||||||
|
@ -217,6 +217,21 @@ getaddrinfo_unix(const char *path, const struct addrinfo *hintsp,
|
|||||||
|
|
||||||
strcpy(unp->sun_path, path);
|
strcpy(unp->sun_path, path);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the supplied path starts with @, replace that with a zero byte for
|
||||||
|
* the internal representation. In that mode, the entire sun_path is the
|
||||||
|
* address, including trailing zero bytes. But we set the address length
|
||||||
|
* to only include the length of the original string. That way the
|
||||||
|
* trailing zero bytes won't show up in any network or socket lists of the
|
||||||
|
* operating system. This is just a convention, also followed by other
|
||||||
|
* packages.
|
||||||
|
*/
|
||||||
|
if (path[0] == '@')
|
||||||
|
{
|
||||||
|
unp->sun_path[0] = '\0';
|
||||||
|
aip->ai_addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(path);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN
|
#ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN
|
||||||
unp->sun_len = sizeof(struct sockaddr_un);
|
unp->sun_len = sizeof(struct sockaddr_un);
|
||||||
#endif
|
#endif
|
||||||
@ -249,7 +264,14 @@ getnameinfo_unix(const struct sockaddr_un *sa, int salen,
|
|||||||
|
|
||||||
if (service)
|
if (service)
|
||||||
{
|
{
|
||||||
ret = snprintf(service, servicelen, "%s", sa->sun_path);
|
/*
|
||||||
|
* Check whether it looks like an abstract socket, but it could also
|
||||||
|
* just be an empty string.
|
||||||
|
*/
|
||||||
|
if (sa->sun_path[0] == '\0' && sa->sun_path[1] != '\0')
|
||||||
|
ret = snprintf(service, servicelen, "@%s", sa->sun_path + 1);
|
||||||
|
else
|
||||||
|
ret = snprintf(service, servicelen, "%s", sa->sun_path);
|
||||||
if (ret < 0 || ret >= servicelen)
|
if (ret < 0 || ret >= servicelen)
|
||||||
return EAI_MEMORY;
|
return EAI_MEMORY;
|
||||||
}
|
}
|
||||||
|
@ -85,6 +85,15 @@ typedef struct
|
|||||||
*/
|
*/
|
||||||
#define UNIXSOCK_PATH_BUFLEN sizeof(((struct sockaddr_un *) NULL)->sun_path)
|
#define UNIXSOCK_PATH_BUFLEN sizeof(((struct sockaddr_un *) NULL)->sun_path)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A host that looks either like an absolute path or starts with @ is
|
||||||
|
* interpreted as a Unix-domain socket address.
|
||||||
|
*/
|
||||||
|
static inline bool
|
||||||
|
is_unixsock_path(const char *path)
|
||||||
|
{
|
||||||
|
return is_absolute_path(path) || path[0] == '@';
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These manipulate the frontend/backend protocol version number.
|
* These manipulate the frontend/backend protocol version number.
|
||||||
|
@ -1093,7 +1093,7 @@ connectOptions2(PGconn *conn)
|
|||||||
{
|
{
|
||||||
ch->type = CHT_HOST_NAME;
|
ch->type = CHT_HOST_NAME;
|
||||||
#ifdef HAVE_UNIX_SOCKETS
|
#ifdef HAVE_UNIX_SOCKETS
|
||||||
if (is_absolute_path(ch->host))
|
if (is_unixsock_path(ch->host))
|
||||||
ch->type = CHT_UNIX_SOCKET;
|
ch->type = CHT_UNIX_SOCKET;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -6945,7 +6945,7 @@ passwordFromFile(const char *hostname, const char *port, const char *dbname,
|
|||||||
/* 'localhost' matches pghost of '' or the default socket directory */
|
/* 'localhost' matches pghost of '' or the default socket directory */
|
||||||
if (hostname == NULL || hostname[0] == '\0')
|
if (hostname == NULL || hostname[0] == '\0')
|
||||||
hostname = DefaultHost;
|
hostname = DefaultHost;
|
||||||
else if (is_absolute_path(hostname))
|
else if (is_unixsock_path(hostname))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We should probably use canonicalize_path(), but then we have to
|
* We should probably use canonicalize_path(), but then we have to
|
||||||
|
Loading…
x
Reference in New Issue
Block a user