From 3f889136a609c57a39813f28414b0a31ad1ecec8 Mon Sep 17 00:00:00 2001
From: Heikki Linnakangas <heikki.linnakangas@iki.fi>
Date: Mon, 4 Mar 2024 10:48:46 +0200
Subject: [PATCH v12 3/8] Move initialization of Port struct to child process

In postmaster, use a more lightweight ClientSocket struct that
encapsulates just the socket itself and the endpoint addresses that
you get from accept() call. ClientSocket is passed to the child
process, which initializes the bigger Port struct. This makes it more
clear what information postmaster initializes, and what is left to the
child process.

Rename the StreamServerPort, StreamConnection functions to make it
more clear what they do. Remove StreamClose, replacing it with plain
closesocket() calls.

Reviewed-by: Tristan Partin, Andres Freund
Discussion: https://www.postgresql.org/message-id/7a59b073-5b5b-151e-7ed3-8b01ff7ce9ef@iki.fi
---
 src/backend/libpq/pqcomm.c          |  95 ++++++++--------
 src/backend/postmaster/postmaster.c | 165 ++++++++++++++++------------
 src/backend/tcop/postgres.c         |   5 +-
 src/include/libpq/libpq-be.h        |  21 +++-
 src/include/libpq/libpq.h           |   6 +-
 src/tools/pgindent/typedefs.list    |   1 +
 6 files changed, 163 insertions(+), 130 deletions(-)

diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c
index c606bf34473..0769995eef0 100644
--- a/src/backend/libpq/pqcomm.c
+++ b/src/backend/libpq/pqcomm.c
@@ -29,11 +29,11 @@
  * INTERFACE ROUTINES
  *
  * setup/teardown:
- *		StreamServerPort	- Open postmaster's server port
- *		StreamConnection	- Create new connection with client
- *		StreamClose			- Close a client/backend connection
+ *		ListenServerPort	- Open postmaster's server port
+ *		AcceptClientConnection - Accept new connection with client
+ *		InitClientConnection - Initialize a client connection
  *		TouchSocketFiles	- Protect socket files against /tmp cleaners
- *		pq_init			- initialize libpq at backend startup
+ *		pq_init				- initialize libpq at backend startup
  *		socket_comm_reset	- reset libpq during error recovery
  *		socket_close		- shutdown libpq at backend exit
  *
@@ -304,7 +304,7 @@ socket_close(int code, Datum arg)
 
 
 /*
- * StreamServerPort -- open a "listening" port to accept connections.
+ * ListenServerPort -- open a "listening" port to accept connections.
  *
  * family should be AF_UNIX or AF_UNSPEC; portNumber is the port number.
  * For AF_UNIX ports, hostName should be NULL and unixSocketDir must be
@@ -319,7 +319,7 @@ socket_close(int code, Datum arg)
  * RETURNS: STATUS_OK or STATUS_ERROR
  */
 int
-StreamServerPort(int family, const char *hostName, unsigned short portNumber,
+ListenServerPort(int family, const char *hostName, unsigned short portNumber,
 				 const char *unixSocketDir,
 				 pgsocket ListenSockets[], int *NumListenSockets, int MaxListen)
 {
@@ -685,8 +685,9 @@ Setup_AF_UNIX(const char *sock_path)
 
 
 /*
- * StreamConnection -- create a new connection with client using
- *		server port.  Set port->sock to the FD of the new connection.
+ * AcceptClientConnection -- accept a new connection with client using
+ *		server port.  Fills *client_sock with the FD and endpoint info
+ *		of the new connection.
  *
  * ASSUME: that this doesn't need to be non-blocking because
  *		the Postmaster waits for the socket to be ready to accept().
@@ -694,13 +695,13 @@ Setup_AF_UNIX(const char *sock_path)
  * RETURNS: STATUS_OK or STATUS_ERROR
  */
 int
-StreamConnection(pgsocket server_fd, Port *port)
+AcceptClientConnection(pgsocket server_fd, ClientSocket *client_sock)
 {
 	/* accept connection and fill in the client (remote) address */
-	port->raddr.salen = sizeof(port->raddr.addr);
-	if ((port->sock = accept(server_fd,
-							 (struct sockaddr *) &port->raddr.addr,
-							 &port->raddr.salen)) == PGINVALID_SOCKET)
+	client_sock->raddr.salen = sizeof(client_sock->raddr.addr);
+	if ((client_sock->sock = accept(server_fd,
+									(struct sockaddr *) &client_sock->raddr.addr,
+									&client_sock->raddr.salen)) == PGINVALID_SOCKET)
 	{
 		ereport(LOG,
 				(errcode_for_socket_access(),
@@ -718,10 +719,10 @@ StreamConnection(pgsocket server_fd, Port *port)
 	}
 
 	/* fill in the server (local) address */
-	port->laddr.salen = sizeof(port->laddr.addr);
-	if (getsockname(port->sock,
-					(struct sockaddr *) &port->laddr.addr,
-					&port->laddr.salen) < 0)
+	client_sock->laddr.salen = sizeof(client_sock->laddr.addr);
+	if (getsockname(client_sock->sock,
+					(struct sockaddr *) &client_sock->laddr.addr,
+					&client_sock->laddr.salen) < 0)
 	{
 		ereport(LOG,
 				(errmsg("%s() failed: %m", "getsockname")));
@@ -729,7 +730,7 @@ StreamConnection(pgsocket server_fd, Port *port)
 	}
 
 	/* select NODELAY and KEEPALIVE options if it's a TCP connection */
-	if (port->laddr.addr.ss_family != AF_UNIX)
+	if (client_sock->laddr.addr.ss_family != AF_UNIX)
 	{
 		int			on;
 #ifdef WIN32
@@ -740,7 +741,7 @@ StreamConnection(pgsocket server_fd, Port *port)
 
 #ifdef	TCP_NODELAY
 		on = 1;
-		if (setsockopt(port->sock, IPPROTO_TCP, TCP_NODELAY,
+		if (setsockopt(client_sock->sock, IPPROTO_TCP, TCP_NODELAY,
 					   (char *) &on, sizeof(on)) < 0)
 		{
 			ereport(LOG,
@@ -749,7 +750,7 @@ StreamConnection(pgsocket server_fd, Port *port)
 		}
 #endif
 		on = 1;
-		if (setsockopt(port->sock, SOL_SOCKET, SO_KEEPALIVE,
+		if (setsockopt(client_sock->sock, SOL_SOCKET, SO_KEEPALIVE,
 					   (char *) &on, sizeof(on)) < 0)
 		{
 			ereport(LOG,
@@ -781,7 +782,7 @@ StreamConnection(pgsocket server_fd, Port *port)
 		 * https://msdn.microsoft.com/en-us/library/bb736549%28v=vs.85%29.aspx
 		 */
 		optlen = sizeof(oldopt);
-		if (getsockopt(port->sock, SOL_SOCKET, SO_SNDBUF, (char *) &oldopt,
+		if (getsockopt(client_sock->sock, SOL_SOCKET, SO_SNDBUF, (char *) &oldopt,
 					   &optlen) < 0)
 		{
 			ereport(LOG,
@@ -791,7 +792,7 @@ StreamConnection(pgsocket server_fd, Port *port)
 		newopt = PQ_SEND_BUFFER_SIZE * 4;
 		if (oldopt < newopt)
 		{
-			if (setsockopt(port->sock, SOL_SOCKET, SO_SNDBUF, (char *) &newopt,
+			if (setsockopt(client_sock->sock, SOL_SOCKET, SO_SNDBUF, (char *) &newopt,
 						   sizeof(newopt)) < 0)
 			{
 				ereport(LOG,
@@ -800,13 +801,34 @@ StreamConnection(pgsocket server_fd, Port *port)
 			}
 		}
 #endif
+	}
+	return STATUS_OK;
+}
+
+/*
+ * InitClientConnection -- create a new connection from the given socket.
+ *
+ * This runs in the backend process.
+ */
+Port *
+InitClientConnection(ClientSocket *client_sock)
+{
+	Port	   *port;
+
+	port = palloc0(sizeof(Port));
+	port->sock = client_sock->sock;
+	port->laddr = client_sock->laddr;
+	port->raddr = client_sock->raddr;
 
+	/* Apply the current keepalive parameters if it's a TCP connection */
+	if (port->laddr.addr.ss_family != AF_UNIX)
+	{
 		/*
-		 * Also apply the current keepalive parameters.  If we fail to set a
-		 * parameter, don't error out, because these aren't universally
-		 * supported.  (Note: you might think we need to reset the GUC
-		 * variables to 0 in such a case, but it's not necessary because the
-		 * show hooks for these variables report the truth anyway.)
+		 * If we fail to set a parameter, don't error out, because these
+		 * aren't universally supported.  (Note: you might think we need to
+		 * reset the GUC variables to 0 in such a case, but it's not necessary
+		 * because the show hooks for these variables report the truth
+		 * anyway.)
 		 */
 		(void) pq_setkeepalivesidle(tcp_keepalives_idle, port);
 		(void) pq_setkeepalivesinterval(tcp_keepalives_interval, port);
@@ -814,24 +836,7 @@ StreamConnection(pgsocket server_fd, Port *port)
 		(void) pq_settcpusertimeout(tcp_user_timeout, port);
 	}
 
-	return STATUS_OK;
-}
-
-/*
- * StreamClose -- close a client/backend connection
- *
- * NOTE: this is NOT used to terminate a session; it is just used to release
- * the file descriptor in a process that should no longer have the socket
- * open.  (For example, the postmaster calls this after passing ownership
- * of the connection to a child process.)  It is expected that someone else
- * still has the socket open.  So, we only want to close the descriptor,
- * we do NOT want to send anything to the far end.
- */
-void
-StreamClose(pgsocket sock)
-{
-	if (closesocket(sock) != 0)
-		elog(LOG, "could not close client or listen socket: %m");
+	return port;
 }
 
 /*
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 2cf5e228186..446dc738d97 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -430,15 +430,15 @@ typedef enum CAC_state
 	CAC_TOOMANY,
 } CAC_state;
 
-static void BackendInitialize(Port *port, CAC_state cac);
-static void BackendRun(Port *port) pg_attribute_noreturn();
+static void BackendInitialize(ClientSocket *client_sock, CAC_state cac);
+static void BackendRun(void) pg_attribute_noreturn();
 static void ExitPostmaster(int status) pg_attribute_noreturn();
 static int	ServerLoop(void);
-static int	BackendStartup(Port *port);
+static int	BackendStartup(ClientSocket *client_sock);
 static int	ProcessStartupPacket(Port *port, bool ssl_done, bool gss_done);
 static void SendNegotiateProtocolVersion(List *unrecognized_protocol_options);
 static void processCancelRequest(Port *port, void *pkt);
-static void report_fork_failure_to_client(Port *port, int errnum);
+static void report_fork_failure_to_client(ClientSocket *client_sock, int errnum);
 static CAC_state canAcceptConnections(int backend_type);
 static bool RandomCancelKey(int32 *cancel_key);
 static void signal_child(pid_t pid, int signal);
@@ -489,8 +489,8 @@ typedef struct
 } win32_deadchild_waitinfo;
 #endif							/* WIN32 */
 
-static pid_t backend_forkexec(Port *port, CAC_state cac);
-static pid_t internal_forkexec(int argc, char *argv[], Port *port, BackgroundWorker *worker);
+static pid_t backend_forkexec(ClientSocket *client_sock, CAC_state cac);
+static pid_t internal_forkexec(int argc, char *argv[], ClientSocket *client_sock, BackgroundWorker *worker);
 
 /* Type for a socket that can be inherited to a client process */
 #ifdef WIN32
@@ -509,9 +509,9 @@ typedef int InheritableSocket;
  */
 typedef struct
 {
-	bool		has_port;
-	Port		port;
-	InheritableSocket portsocket;
+	bool		has_client_sock;
+	ClientSocket client_sock;
+	InheritableSocket inh_sock;
 
 	bool		has_bgworker;
 	BackgroundWorker bgworker;
@@ -560,13 +560,13 @@ typedef struct
 	char		pkglib_path[MAXPGPATH];
 } BackendParameters;
 
-static void read_backend_variables(char *id, Port **port, BackgroundWorker **worker);
-static void restore_backend_variables(BackendParameters *param, Port **port, BackgroundWorker **worker);
+static void read_backend_variables(char *id, ClientSocket **client_sock, BackgroundWorker **worker);
+static void restore_backend_variables(BackendParameters *param, ClientSocket **client_sock, BackgroundWorker **worker);
 
 #ifndef WIN32
-static bool save_backend_variables(BackendParameters *param, Port *port, BackgroundWorker *worker);
+static bool save_backend_variables(BackendParameters *param, ClientSocket *client_sock, BackgroundWorker *worker);
 #else
-static bool save_backend_variables(BackendParameters *param, Port *port, BackgroundWorker *worker,
+static bool save_backend_variables(BackendParameters *param, ClientSocket *client_sock, BackgroundWorker *worker,
 								   HANDLE childProcess, pid_t childPid);
 #endif
 
@@ -1222,14 +1222,14 @@ PostmasterMain(int argc, char *argv[])
 			char	   *curhost = (char *) lfirst(l);
 
 			if (strcmp(curhost, "*") == 0)
-				status = StreamServerPort(AF_UNSPEC, NULL,
+				status = ListenServerPort(AF_UNSPEC, NULL,
 										  (unsigned short) PostPortNumber,
 										  NULL,
 										  ListenSockets,
 										  &NumListenSockets,
 										  MAXLISTEN);
 			else
-				status = StreamServerPort(AF_UNSPEC, curhost,
+				status = ListenServerPort(AF_UNSPEC, curhost,
 										  (unsigned short) PostPortNumber,
 										  NULL,
 										  ListenSockets,
@@ -1323,7 +1323,7 @@ PostmasterMain(int argc, char *argv[])
 		{
 			char	   *socketdir = (char *) lfirst(l);
 
-			status = StreamServerPort(AF_UNIX, NULL,
+			status = ListenServerPort(AF_UNIX, NULL,
 									  (unsigned short) PostPortNumber,
 									  socketdir,
 									  ListenSockets,
@@ -1503,7 +1503,10 @@ CloseServerPorts(int status, Datum arg)
 	 * condition if a new postmaster wants to re-use the TCP port number.
 	 */
 	for (i = 0; i < NumListenSockets; i++)
-		StreamClose(ListenSockets[i]);
+	{
+		if (closesocket(ListenSockets[i]) != 0)
+			elog(LOG, "could not close listen socket: %m");
+	}
 	NumListenSockets = 0;
 
 	/*
@@ -1773,18 +1776,20 @@ ServerLoop(void)
 
 			if (events[i].events & WL_SOCKET_ACCEPT)
 			{
-				Port		port;
+				ClientSocket s;
 
-				memset(&port, 0, sizeof(port));
-				if (StreamConnection(events[i].fd, &port) == STATUS_OK)
-					BackendStartup(&port);
+				if (AcceptClientConnection(events[i].fd, &s) == STATUS_OK)
+					BackendStartup(&s);
 
 				/*
 				 * We no longer need the open socket or port structure in this
 				 * process
 				 */
-				if (port.sock != PGINVALID_SOCKET)
-					StreamClose(port.sock);
+				if (s.sock != PGINVALID_SOCKET)
+				{
+					if (closesocket(s.sock) != 0)
+						elog(LOG, "could not close client socket: %m");
+				}
 			}
 		}
 
@@ -2155,11 +2160,7 @@ retry1:
 
 	/*
 	 * Now fetch parameters out of startup packet and save them into the Port
-	 * structure.  All data structures attached to the Port struct must be
-	 * allocated in TopMemoryContext so that they will remain available in a
-	 * running backend (even after PostmasterContext is destroyed).  We need
-	 * not worry about leaking this storage on failure, since we aren't in the
-	 * postmaster process anymore.
+	 * structure.
 	 */
 	oldcontext = MemoryContextSwitchTo(TopMemoryContext);
 
@@ -2295,7 +2296,7 @@ retry1:
 		port->database_name[0] = '\0';
 
 	/*
-	 * Done putting stuff in TopMemoryContext.
+	 * Done filling the Port structure
 	 */
 	MemoryContextSwitchTo(oldcontext);
 
@@ -2499,7 +2500,10 @@ ClosePostmasterPorts(bool am_syslogger)
 	if (ListenSockets)
 	{
 		for (int i = 0; i < NumListenSockets; i++)
-			StreamClose(ListenSockets[i]);
+		{
+			if (closesocket(ListenSockets[i]) != 0)
+				elog(LOG, "could not close listen socket: %m");
+		}
 		pfree(ListenSockets);
 	}
 	NumListenSockets = 0;
@@ -4049,7 +4053,7 @@ TerminateChildren(int signal)
  * Note: if you change this code, also consider StartAutovacuumWorker.
  */
 static int
-BackendStartup(Port *port)
+BackendStartup(ClientSocket *client_sock)
 {
 	Backend    *bn;				/* for backend cleanup */
 	pid_t		pid;
@@ -4100,7 +4104,7 @@ BackendStartup(Port *port)
 	bn->bgworker_notify = false;
 
 #ifdef EXEC_BACKEND
-	pid = backend_forkexec(port, cac);
+	pid = backend_forkexec(client_sock, cac);
 #else							/* !EXEC_BACKEND */
 	pid = fork_process();
 	if (pid == 0)				/* child */
@@ -4112,10 +4116,10 @@ BackendStartup(Port *port)
 		ClosePostmasterPorts(false);
 
 		/* Perform additional initialization and collect startup packet */
-		BackendInitialize(port, cac);
+		BackendInitialize(client_sock, cac);
 
 		/* And run the backend */
-		BackendRun(port);
+		BackendRun();
 	}
 #endif							/* EXEC_BACKEND */
 
@@ -4130,14 +4134,14 @@ BackendStartup(Port *port)
 		errno = save_errno;
 		ereport(LOG,
 				(errmsg("could not fork new process for connection: %m")));
-		report_fork_failure_to_client(port, save_errno);
+		report_fork_failure_to_client(client_sock, save_errno);
 		return STATUS_ERROR;
 	}
 
 	/* in parent, successful fork */
 	ereport(DEBUG2,
 			(errmsg_internal("forked new backend, pid=%d socket=%d",
-							 (int) pid, (int) port->sock)));
+							 (int) pid, (int) client_sock->sock)));
 
 	/*
 	 * Everything's been successful, it's safe to add this backend to our list
@@ -4164,7 +4168,7 @@ BackendStartup(Port *port)
  * it's not up and running.
  */
 static void
-report_fork_failure_to_client(Port *port, int errnum)
+report_fork_failure_to_client(ClientSocket *client_sock, int errnum)
 {
 	char		buffer[1000];
 	int			rc;
@@ -4175,13 +4179,13 @@ report_fork_failure_to_client(Port *port, int errnum)
 			 strerror(errnum));
 
 	/* Set port to non-blocking.  Don't do send() if this fails */
-	if (!pg_set_noblock(port->sock))
+	if (!pg_set_noblock(client_sock->sock))
 		return;
 
 	/* We'll retry after EINTR, but ignore all other failures */
 	do
 	{
-		rc = send(port->sock, buffer, strlen(buffer) + 1, 0);
+		rc = send(client_sock->sock, buffer, strlen(buffer) + 1, 0);
 	} while (rc < 0 && errno == EINTR);
 }
 
@@ -4199,18 +4203,30 @@ report_fork_failure_to_client(Port *port, int errnum)
  * but have not yet set up most of our local pointers to shmem structures.
  */
 static void
-BackendInitialize(Port *port, CAC_state cac)
+BackendInitialize(ClientSocket *client_sock, CAC_state cac)
 {
 	int			status;
 	int			ret;
+	Port	   *port;
 	char		remote_host[NI_MAXHOST];
 	char		remote_port[NI_MAXSERV];
 	StringInfoData ps_data;
+	MemoryContext oldcontext;
 
-	/* Save port etc. for ps status */
+	/*
+	 * Create the Port structure.
+	 *
+	 * The Port structure and all data structures attached to it are allocated
+	 * in TopMemoryContext, so that they survive into PostgresMain execution.
+	 * We need not worry about leaking this storage on failure, since we
+	 * aren't in the postmaster process anymore.
+	 */
+	oldcontext = MemoryContextSwitchTo(TopMemoryContext);
+	port = InitClientConnection(client_sock);
 	MyProcPort = port;
+	MemoryContextSwitchTo(oldcontext);
 
-	/* Tell fd.c about the long-lived FD associated with the port */
+	/* Tell fd.c about the long-lived FD associated with the client_sock */
 	ReserveExternalFD();
 
 	/*
@@ -4269,8 +4285,9 @@ BackendInitialize(Port *port, CAC_state cac)
 	 * Save remote_host and remote_port in port structure (after this, they
 	 * will appear in log_line_prefix data for log messages).
 	 */
-	port->remote_host = strdup(remote_host);
-	port->remote_port = strdup(remote_port);
+	oldcontext = MemoryContextSwitchTo(TopMemoryContext);
+	port->remote_host = pstrdup(remote_host);
+	port->remote_port = pstrdup(remote_port);
 
 	/* And now we can issue the Log_connections message, if wanted */
 	if (Log_connections)
@@ -4301,7 +4318,10 @@ BackendInitialize(Port *port, CAC_state cac)
 		ret == 0 &&
 		strspn(remote_host, "0123456789.") < strlen(remote_host) &&
 		strspn(remote_host, "0123456789ABCDEFabcdef:") < strlen(remote_host))
-		port->remote_hostname = strdup(remote_host);
+	{
+		port->remote_hostname = pstrdup(remote_host);
+	}
+	MemoryContextSwitchTo(oldcontext);
 
 	/*
 	 * Ready to begin client interaction.  We will give up and _exit(1) after
@@ -4425,7 +4445,7 @@ BackendInitialize(Port *port, CAC_state cac)
  *		Doesn't return at all.
  */
 static void
-BackendRun(Port *port)
+BackendRun(void)
 {
 	/*
 	 * Create a per-backend PGPROC struct in shared memory.  We must do this
@@ -4439,7 +4459,7 @@ BackendRun(Port *port)
 	 */
 	MemoryContextSwitchTo(TopMemoryContext);
 
-	PostgresMain(port->database_name, port->user_name);
+	PostgresMain(MyProcPort->database_name, MyProcPort->user_name);
 }
 
 
@@ -4473,7 +4493,7 @@ postmaster_forkexec(int argc, char *argv[])
  * returns the pid of the fork/exec'd process, or -1 on failure
  */
 static pid_t
-backend_forkexec(Port *port, CAC_state cac)
+backend_forkexec(ClientSocket *client_sock, CAC_state cac)
 {
 	char	   *av[5];
 	int			ac = 0;
@@ -4489,7 +4509,7 @@ backend_forkexec(Port *port, CAC_state cac)
 	av[ac] = NULL;
 	Assert(ac < lengthof(av));
 
-	return internal_forkexec(ac, av, port, NULL);
+	return internal_forkexec(ac, av, client_sock, NULL);
 }
 
 #ifndef WIN32
@@ -4501,7 +4521,7 @@ backend_forkexec(Port *port, CAC_state cac)
  * - fork():s, and then exec():s the child process
  */
 static pid_t
-internal_forkexec(int argc, char *argv[], Port *port, BackgroundWorker *worker)
+internal_forkexec(int argc, char *argv[], ClientSocket *client_sock, BackgroundWorker *worker)
 {
 	static unsigned long tmpBackendFileNum = 0;
 	pid_t		pid;
@@ -4517,7 +4537,7 @@ internal_forkexec(int argc, char *argv[], Port *port, BackgroundWorker *worker)
 	 */
 	memset(&param, 0, sizeof(BackendParameters));
 
-	if (!save_backend_variables(&param, port, worker))
+	if (!save_backend_variables(&param, client_sock, worker))
 		return -1;				/* log made by save_backend_variables */
 
 	/* Calculate name for temp file */
@@ -4815,7 +4835,7 @@ retry:
 void
 SubPostmasterMain(int argc, char *argv[])
 {
-	Port	   *port;
+	ClientSocket *client_sock;
 	BackgroundWorker *worker;
 
 	/* In EXEC_BACKEND case we will not have inherited these settings */
@@ -4830,7 +4850,7 @@ SubPostmasterMain(int argc, char *argv[])
 		elog(FATAL, "invalid subpostmaster invocation");
 
 	/* Read in the variables file */
-	read_backend_variables(argv[2], &port, &worker);
+	read_backend_variables(argv[2], &client_sock, &worker);
 
 	/* Close the postmaster's sockets (as soon as we know them) */
 	ClosePostmasterPorts(strcmp(argv[1], "--forklog") == 0);
@@ -4929,13 +4949,14 @@ SubPostmasterMain(int argc, char *argv[])
 		 * PGPROC slots, we have already initialized libpq and are able to
 		 * report the error to the client.
 		 */
-		BackendInitialize(port, cac);
+		BackendInitialize(client_sock, cac);
 
 		/* Restore basic shared memory pointers */
 		InitShmemAccess(UsedShmemSegAddr);
 
 		/* And run the backend */
-		BackendRun(port);		/* does not return */
+		BackendRun();			/* does not return */
+
 	}
 	if (strcmp(argv[1], "--forkaux") == 0)
 	{
@@ -6055,24 +6076,24 @@ static void read_inheritable_socket(SOCKET *dest, InheritableSocket *src);
 /* Save critical backend variables into the BackendParameters struct */
 #ifndef WIN32
 static bool
-save_backend_variables(BackendParameters *param, Port *port, BackgroundWorker *worker)
+save_backend_variables(BackendParameters *param, ClientSocket *client_sock, BackgroundWorker *worker)
 #else
 static bool
-save_backend_variables(BackendParameters *param, Port *port, BackgroundWorker *worker,
+save_backend_variables(BackendParameters *param, ClientSocket *client_sock, BackgroundWorker *worker,
 					   HANDLE childProcess, pid_t childPid)
 #endif
 {
-	if (port)
+	if (client_sock)
 	{
-		memcpy(&param->port, port, sizeof(Port));
-		if (!write_inheritable_socket(&param->portsocket, port->sock, childPid))
+		memcpy(&param->client_sock, client_sock, sizeof(ClientSocket));
+		if (!write_inheritable_socket(&param->inh_sock, client_sock->sock, childPid))
 			return false;
-		param->has_port = true;
+		param->has_client_sock = true;
 	}
 	else
 	{
-		memset(&param->port, 0, sizeof(Port));
-		param->has_port = false;
+		memset(&param->client_sock, 0, sizeof(ClientSocket));
+		param->has_client_sock = false;
 	}
 
 	if (worker)
@@ -6239,7 +6260,7 @@ read_inheritable_socket(SOCKET *dest, InheritableSocket *src)
 #endif
 
 static void
-read_backend_variables(char *id, Port **port, BackgroundWorker **worker)
+read_backend_variables(char *id, ClientSocket **client_sock, BackgroundWorker **worker)
 {
 	BackendParameters param;
 
@@ -6306,21 +6327,21 @@ read_backend_variables(char *id, Port **port, BackgroundWorker **worker)
 	}
 #endif
 
-	restore_backend_variables(&param, port, worker);
+	restore_backend_variables(&param, client_sock, worker);
 }
 
 /* Restore critical backend variables from the BackendParameters struct */
 static void
-restore_backend_variables(BackendParameters *param, Port **port, BackgroundWorker **worker)
+restore_backend_variables(BackendParameters *param, ClientSocket **client_sock, BackgroundWorker **worker)
 {
-	if (param->has_port)
+	if (param->has_client_sock)
 	{
-		*port = (Port *) MemoryContextAlloc(TopMemoryContext, sizeof(Port));
-		memcpy(*port, &param->port, sizeof(Port));
-		read_inheritable_socket(&(*port)->sock, &param->portsocket);
+		*client_sock = (ClientSocket *) MemoryContextAlloc(TopMemoryContext, sizeof(ClientSocket));
+		memcpy(*client_sock, &param->client_sock, sizeof(ClientSocket));
+		read_inheritable_socket(&(*client_sock)->sock, &param->inh_sock);
 	}
 	else
-		*port = NULL;
+		*client_sock = NULL;
 
 	if (param->has_bgworker)
 	{
@@ -6386,7 +6407,7 @@ restore_backend_variables(BackendParameters *param, Port **port, BackgroundWorke
 	/*
 	 * We need to restore fd.c's counts of externally-opened FDs; to avoid
 	 * confusion, be sure to do this after restoring max_safe_fds.  (Note:
-	 * BackendInitialize will handle this for port->sock.)
+	 * BackendInitialize will handle this for (*client_sock)->sock.)
 	 */
 #ifndef WIN32
 	if (postmaster_alive_fds[0] >= 0)
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 43f05a35a2d..6b7903314ab 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -4233,10 +4233,7 @@ PostgresMain(const char *dbname, const char *username)
 
 	/*
 	 * If the PostmasterContext is still around, recycle the space; we don't
-	 * need it anymore after InitPostgres completes.  Note this does not trash
-	 * *MyProcPort, because that space is allocated in stack ... else we'd
-	 * need to copy the Port data first.  Also, subsidiary data such as the
-	 * username isn't lost either; see ProcessStartupPacket().
+	 * need it anymore after InitPostgres completes.
 	 */
 	if (PostmasterContext)
 	{
diff --git a/src/include/libpq/libpq-be.h b/src/include/libpq/libpq-be.h
index 59c2a1d874f..c35c23001eb 100644
--- a/src/include/libpq/libpq-be.h
+++ b/src/include/libpq/libpq-be.h
@@ -110,12 +110,9 @@ typedef struct ClientConnectionInfo
 } ClientConnectionInfo;
 
 /*
- * This is used by the postmaster in its communication with frontends.  It
- * contains all state information needed during this communication before the
- * backend is run.  The Port structure is kept in malloc'd memory and is
- * still available when a backend is running (see MyProcPort).  The data
- * it points to must also be malloc'd, or else palloc'd in TopMemoryContext,
- * so that it survives into PostgresMain execution!
+ * The Port structure holds state information about a client connection in a
+ * backend process.  It is available in the global variable MyProcPort.  The
+ * struct and all the data it points are kept in TopMemoryContext.
  *
  * remote_hostname is set if we did a successful reverse lookup of the
  * client's IP address during connection setup.
@@ -217,6 +214,18 @@ typedef struct Port
 #endif
 } Port;
 
+/*
+ * ClientSocket holds a socket for an accepted connection, along with the
+ * information about the endpoints.  This is passed from postmaster to
+ * the backend process.
+ */
+typedef struct ClientSocket
+{
+	pgsocket	sock;			/* File descriptor */
+	SockAddr	laddr;			/* local addr (postmaster) */
+	SockAddr	raddr;			/* remote addr (client) */
+} ClientSocket;
+
 #ifdef USE_SSL
 /*
  *	Hardcoded DH parameters, used in ephemeral DH keying.  (See also
diff --git a/src/include/libpq/libpq.h b/src/include/libpq/libpq.h
index 6171a0d17a5..45c219844a4 100644
--- a/src/include/libpq/libpq.h
+++ b/src/include/libpq/libpq.h
@@ -64,11 +64,11 @@ extern PGDLLIMPORT WaitEventSet *FeBeWaitSet;
 #define FeBeWaitSetLatchPos 1
 #define FeBeWaitSetNEvents 3
 
-extern int	StreamServerPort(int family, const char *hostName,
+extern int	ListenServerPort(int family, const char *hostName,
 							 unsigned short portNumber, const char *unixSocketDir,
 							 pgsocket ListenSocket[], int *NumListenSockets, int MaxListen);
-extern int	StreamConnection(pgsocket server_fd, Port *port);
-extern void StreamClose(pgsocket sock);
+extern int	AcceptClientConnection(pgsocket server_fd, ClientSocket *client_sock);
+extern Port *InitClientConnection(ClientSocket *client_sock);
 extern void TouchSocketFiles(void);
 extern void RemoveSocketFiles(void);
 extern void pq_init(void);
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 95ae7845d86..da465602ea1 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -388,6 +388,7 @@ ClientCertMode
 ClientCertName
 ClientConnectionInfo
 ClientData
+ClientSocket
 ClonePtrType
 ClosePortalStmt
 ClosePtrType
-- 
2.39.2

