Add SSL_has_pending.

This was added in OpenSSL 1.1.x. It is slightly different from
SSL_pending in that it also reports buffered transport data.

Change-Id: I81e217aad1ceb6f4c31c36634a546e12b6dc8dfc
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/50445
Commit-Queue: David Benjamin <davidben@google.com>
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 057fbc0..ca7ae14 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -362,10 +362,31 @@
 // SSL_peek behaves like |SSL_read| but does not consume any bytes returned.
 OPENSSL_EXPORT int SSL_peek(SSL *ssl, void *buf, int num);
 
-// SSL_pending returns the number of bytes available in |ssl|. It does not read
-// from the transport.
+// SSL_pending returns the number of buffered, decrypted bytes available for
+// read in |ssl|. It does not read from the transport.
+//
+// In DTLS, it is possible for this function to return zero while there is
+// buffered, undecrypted data from the transport in |ssl|. For example,
+// |SSL_read| may read a datagram with two records, decrypt the first, and leave
+// the second buffered for a subsequent call to |SSL_read|. Callers that wish to
+// detect this case can use |SSL_has_pending|.
 OPENSSL_EXPORT int SSL_pending(const SSL *ssl);
 
+// SSL_has_pending returns one if |ssl| has buffered, decrypted bytes available
+// for read, or if |ssl| has buffered data from the transport that has not yet
+// been decrypted. If |ssl| has neither, this function returns zero.
+//
+// In TLS, BoringSSL does not implement read-ahead, so this function returns one
+// if and only if |SSL_pending| would return a non-zero value. In DTLS, it is
+// possible for this function to return one while |SSL_pending| returns zero.
+// For example, |SSL_read| may read a datagram with two records, decrypt the
+// first, and leave the second buffered for a subsequent call to |SSL_read|.
+//
+// As a result, if this function returns one, the next call to |SSL_read| may
+// still fail, read from the transport, or both. The buffered, undecrypted data
+// may be invalid or incomplete.
+OPENSSL_EXPORT int SSL_has_pending(const SSL *ssl);
+
 // SSL_write writes up to |num| bytes from |buf| into |ssl|. It implicitly runs
 // any pending handshakes, including renegotiations when enabled. On success, it
 // returns the number of bytes written. Otherwise, it returns <= 0. The caller
diff --git a/ssl/ssl_lib.cc b/ssl/ssl_lib.cc
index 03864e1..e2e2436 100644
--- a/ssl/ssl_lib.cc
+++ b/ssl/ssl_lib.cc
@@ -1697,6 +1697,10 @@
   return static_cast<int>(ssl->s3->pending_app_data.size());
 }
 
+int SSL_has_pending(const SSL *ssl) {
+  return SSL_pending(ssl) != 0 || !ssl->s3->read_buffer.empty();
+}
+
 int SSL_CTX_check_private_key(const SSL_CTX *ctx) {
   return ssl_cert_check_private_key(ctx->cert.get(),
                                     ctx->cert->privatekey.get());
diff --git a/ssl/ssl_test.cc b/ssl/ssl_test.cc
index a2ca07a..4169671 100644
--- a/ssl/ssl_test.cc
+++ b/ssl/ssl_test.cc
@@ -4966,23 +4966,43 @@
 
   ASSERT_TRUE(Connect());
   EXPECT_EQ(0, SSL_pending(client_.get()));
+  EXPECT_EQ(0, SSL_has_pending(client_.get()));
 
   ASSERT_EQ(5, SSL_write(server_.get(), "hello", 5));
   ASSERT_EQ(5, SSL_write(server_.get(), "world", 5));
   EXPECT_EQ(0, SSL_pending(client_.get()));
+  EXPECT_EQ(0, SSL_has_pending(client_.get()));
 
   char buf[10];
   ASSERT_EQ(1, SSL_peek(client_.get(), buf, 1));
   EXPECT_EQ(5, SSL_pending(client_.get()));
+  EXPECT_EQ(1, SSL_has_pending(client_.get()));
 
   ASSERT_EQ(1, SSL_read(client_.get(), buf, 1));
   EXPECT_EQ(4, SSL_pending(client_.get()));
+  EXPECT_EQ(1, SSL_has_pending(client_.get()));
 
   ASSERT_EQ(4, SSL_read(client_.get(), buf, 10));
   EXPECT_EQ(0, SSL_pending(client_.get()));
+  if (is_dtls()) {
+    // In DTLS, the two records would have been read as a single datagram and
+    // buffered inside |client_|. Thus, |SSL_has_pending| should return true.
+    //
+    // This test is slightly unrealistic. It relies on |ConnectClientAndServer|
+    // using a |BIO| pair, which does not preserve datagram boundaries. Reading
+    // 1 byte, then 4 bytes, from the first record also relies on
+    // https://crbug.com/boringssl/65. But it does test the codepaths. When
+    // fixing either of these bugs, this test may need to be redone.
+    EXPECT_EQ(1, SSL_has_pending(client_.get()));
+  } else {
+    // In TLS, we do not overread, so |SSL_has_pending| should report no data is
+    // buffered.
+    EXPECT_EQ(0, SSL_has_pending(client_.get()));
+  }
 
   ASSERT_EQ(2, SSL_read(client_.get(), buf, 2));
   EXPECT_EQ(3, SSL_pending(client_.get()));
+  EXPECT_EQ(1, SSL_has_pending(client_.get()));
 }
 
 // Test that post-handshake tickets consumed by |SSL_shutdown| are ignored.