From 5b459b24696419c8747c506c26a813288ef899f5 Mon Sep 17 00:00:00 2001
From: Jacob Champion <jacob.champion@enterprisedb.com>
Date: Fri, 18 Jul 2025 10:06:13 -0700
Subject: [PATCH 1/2] WIP: extend "TLS read pending" concept to GSS too

pgtls_read_pending() is renamed to pgtls_read_is_pending(), to avoid
conflation with the forthcoming pgtls_drain_pending().
---
 src/interfaces/libpq/fe-misc.c           |  6 ++----
 src/interfaces/libpq/fe-secure-gssapi.c  |  6 ++++++
 src/interfaces/libpq/fe-secure-openssl.c |  2 +-
 src/interfaces/libpq/fe-secure.c         | 19 +++++++++++++++++++
 src/interfaces/libpq/libpq-int.h         |  4 +++-
 5 files changed, 31 insertions(+), 6 deletions(-)

diff --git a/src/interfaces/libpq/fe-misc.c b/src/interfaces/libpq/fe-misc.c
index dca44fdc5d2..434216ff89f 100644
--- a/src/interfaces/libpq/fe-misc.c
+++ b/src/interfaces/libpq/fe-misc.c
@@ -1099,14 +1099,12 @@ pqSocketCheck(PGconn *conn, int forRead, int forWrite, pg_usec_time_t end_time)
 			return -1;
 		}
 
-#ifdef USE_SSL
-		/* Check for SSL library buffering read bytes */
-		if (forRead && conn->ssl_in_use && pgtls_read_pending(conn))
+		/* Check for SSL/GSS library buffering read bytes */
+		if (forRead && pqsecure_read_is_pending(conn))
 		{
 			/* short-circuit the select */
 			return 1;
 		}
-#endif
 	}
 
 	/* We will retry as long as we get EINTR */
diff --git a/src/interfaces/libpq/fe-secure-gssapi.c b/src/interfaces/libpq/fe-secure-gssapi.c
index bc9e1ce06fa..7c88e64cfd2 100644
--- a/src/interfaces/libpq/fe-secure-gssapi.c
+++ b/src/interfaces/libpq/fe-secure-gssapi.c
@@ -469,6 +469,12 @@ gss_read(PGconn *conn, void *recv_buffer, size_t length, ssize_t *ret)
 	return PGRES_POLLING_OK;
 }
 
+bool
+pg_GSS_read_is_pending(PGconn *conn)
+{
+	return PqGSSResultLength > PqGSSResultNext;
+}
+
 /*
  * Negotiate GSSAPI transport for a connection.  When complete, returns
  * PGRES_POLLING_OK.  Will return PGRES_POLLING_READING or
diff --git a/src/interfaces/libpq/fe-secure-openssl.c b/src/interfaces/libpq/fe-secure-openssl.c
index 51dd7b9fec0..8f975561e51 100644
--- a/src/interfaces/libpq/fe-secure-openssl.c
+++ b/src/interfaces/libpq/fe-secure-openssl.c
@@ -231,7 +231,7 @@ rloop:
 }
 
 bool
-pgtls_read_pending(PGconn *conn)
+pgtls_read_is_pending(PGconn *conn)
 {
 	return SSL_pending(conn->ssl) > 0;
 }
diff --git a/src/interfaces/libpq/fe-secure.c b/src/interfaces/libpq/fe-secure.c
index e686681ba15..94c97ec26fb 100644
--- a/src/interfaces/libpq/fe-secure.c
+++ b/src/interfaces/libpq/fe-secure.c
@@ -243,6 +243,25 @@ pqsecure_raw_read(PGconn *conn, void *ptr, size_t len)
 	return n;
 }
 
+/*
+ * Returns true if there are any bytes available in the transport buffer.
+ */
+bool
+pqsecure_read_is_pending(PGconn *conn)
+{
+#ifdef USE_SSL
+	if (conn->ssl_in_use)
+		return pgtls_read_is_pending(conn);
+#endif
+#ifdef ENABLE_GSS
+	if (conn->gssenc)
+		return pg_GSS_read_is_pending(conn);
+#endif
+
+	/* Plaintext connections have no transport buffer. */
+	return 0;
+}
+
 /*
  *	Write data to a secure connection.
  *
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 70c28f2ffca..51bc2d3b740 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -809,6 +809,7 @@ extern int	pqWriteReady(PGconn *conn);
 extern PostgresPollingStatusType pqsecure_open_client(PGconn *);
 extern void pqsecure_close(PGconn *);
 extern ssize_t pqsecure_read(PGconn *, void *ptr, size_t len);
+extern bool pqsecure_read_is_pending(PGconn *);
 extern ssize_t pqsecure_write(PGconn *, const void *ptr, size_t len);
 extern ssize_t pqsecure_raw_read(PGconn *, void *ptr, size_t len);
 extern ssize_t pqsecure_raw_write(PGconn *, const void *ptr, size_t len);
@@ -847,7 +848,7 @@ extern ssize_t pgtls_read(PGconn *conn, void *ptr, size_t len);
 /*
  *	Is there unread data waiting in the SSL read buffer?
  */
-extern bool pgtls_read_pending(PGconn *conn);
+extern bool pgtls_read_is_pending(PGconn *conn);
 
 /*
  *	Write data to a secure connection.
@@ -895,6 +896,7 @@ extern PostgresPollingStatusType pqsecure_open_gss(PGconn *conn);
  */
 extern ssize_t pg_GSS_write(PGconn *conn, const void *ptr, size_t len);
 extern ssize_t pg_GSS_read(PGconn *conn, void *ptr, size_t len);
+extern bool pg_GSS_read_is_pending(PGconn *conn);
 #endif
 
 /* === in fe-trace.c === */
-- 
2.34.1

