Lift BIO above SSL_PROTOCOL_METHOD.

This gets us closer to exposing BIO-free APIs. The next step is probably
to make the experimental bssl::OpenRecord function call a split out core
of ssl_read_impl.

Change-Id: I4acebb43f708df8c52eb4e328da8ae3551362fb9
Reviewed-on: https://boringssl-review.googlesource.com/21865
Commit-Queue: Steven Valdez <svaldez@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Steven Valdez <svaldez@google.com>
diff --git a/ssl/d1_pkt.cc b/ssl/d1_pkt.cc
index 5b1cce5..7e329e3 100644
--- a/ssl/d1_pkt.cc
+++ b/ssl/d1_pkt.cc
@@ -128,84 +128,29 @@
 
 namespace bssl {
 
-int dtls1_get_record(SSL *ssl) {
-  for (;;) {
-    Span<uint8_t> body;
-    uint8_t type, alert;
-    size_t consumed;
-    enum ssl_open_record_t open_ret = dtls_open_record(
-        ssl, &type, &body, &consumed, &alert, ssl_read_buffer(ssl));
-    if (open_ret != ssl_open_record_partial) {
-      ssl_read_buffer_consume(ssl, consumed);
-    }
-    switch (open_ret) {
-      case ssl_open_record_partial: {
-        assert(ssl_read_buffer(ssl).empty());
-        int read_ret = ssl_read_buffer_extend_to(ssl, 0 /* unused */);
-        if (read_ret <= 0) {
-          return read_ret;
-        }
-        continue;
-      }
-
-      case ssl_open_record_success: {
-        if (body.size() > 0xffff) {
-          OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW);
-          return -1;
-        }
-
-        SSL3_RECORD *rr = &ssl->s3->rrec;
-        rr->type = type;
-        rr->length = static_cast<uint16_t>(body.size());
-        rr->data = body.data();
-        return 1;
-      }
-
-      case ssl_open_record_discard:
-        continue;
-
-      case ssl_open_record_close_notify:
-        return 0;
-
-      case ssl_open_record_error:
-        if (alert != 0) {
-          ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
-        }
-        return -1;
-    }
-
-    assert(0);
-    OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
-    return -1;
-  }
-}
-
-int dtls1_read_app_data(SSL *ssl, bool *out_got_handshake, uint8_t *buf,
-                        int len, int peek) {
+ssl_open_record_t dtls1_open_app_data(SSL *ssl, Span<uint8_t> *out,
+                                      size_t *out_consumed, uint8_t *out_alert,
+                                      Span<uint8_t> in) {
   assert(!SSL_in_init(ssl));
 
-  *out_got_handshake = false;
-  SSL3_RECORD *rr = &ssl->s3->rrec;
-
-again:
-  if (rr->length == 0) {
-    int ret = dtls1_get_record(ssl);
-    if (ret <= 0) {
-      return ret;
-    }
+  uint8_t type;
+  Span<uint8_t> record;
+  auto ret = dtls_open_record(ssl, &type, &record, out_consumed, out_alert, in);
+  if (ret != ssl_open_record_success) {
+    return ret;
   }
 
-  if (rr->type == SSL3_RT_HANDSHAKE) {
+  if (type == SSL3_RT_HANDSHAKE) {
     // Parse the first fragment header to determine if this is a pre-CCS or
     // post-CCS handshake record. DTLS resets handshake message numbers on each
     // handshake, so renegotiations and retransmissions are ambiguous.
     CBS cbs, body;
     struct hm_header_st msg_hdr;
-    CBS_init(&cbs, rr->data, rr->length);
+    CBS_init(&cbs, record.data(), record.size());
     if (!dtls1_parse_fragment(&cbs, &msg_hdr, &body)) {
-      ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
       OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_HANDSHAKE_RECORD);
-      return -1;
+      *out_alert = SSL_AD_DECODE_ERROR;
+      return ssl_open_record_error;
     }
 
     if (msg_hdr.type == SSL3_MT_FINISHED &&
@@ -215,62 +160,52 @@
         // Finished, they may not have received ours. Only do this for the
         // first fragment, in case the Finished was fragmented.
         if (!dtls1_check_timeout_num(ssl)) {
-          return -1;
+          *out_alert = 0;  // TODO(davidben): Send an alert?
+          return ssl_open_record_error;
         }
 
         dtls1_retransmit_outgoing_messages(ssl);
       }
-
-      rr->length = 0;
-      goto again;
+      return ssl_open_record_discard;
     }
 
     // Otherwise, this is a pre-CCS handshake message from an unsupported
     // renegotiation attempt. Fall through to the error path.
   }
 
-  if (rr->type != SSL3_RT_APPLICATION_DATA) {
-    ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
+  if (type != SSL3_RT_APPLICATION_DATA) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD);
-    return -1;
+    *out_alert = SSL_AD_UNEXPECTED_MESSAGE;
+    return ssl_open_record_error;
   }
 
-  // Discard empty records.
-  if (rr->length == 0) {
-    goto again;
+  if (record.empty()) {
+    return ssl_open_record_discard;
   }
 
-  if (len <= 0) {
-    return len;
-  }
-
-  if ((unsigned)len > rr->length) {
-    len = rr->length;
-  }
-
-  OPENSSL_memcpy(buf, rr->data, len);
-  if (!peek) {
-    // TODO(davidben): Should the record be truncated instead? This is a
-    // datagram transport. See https://crbug.com/boringssl/65.
-    rr->length -= len;
-    rr->data += len;
-    if (rr->length == 0) {
-      // The record has been consumed, so we may now clear the buffer.
-      ssl_read_buffer_discard(ssl);
-    }
-  }
-
-  return len;
+  *out = record;
+  return ssl_open_record_success;
 }
 
-void dtls1_read_close_notify(SSL *ssl) {
-  // Bidirectional shutdown doesn't make sense for an unordered transport. DTLS
-  // alerts also aren't delivered reliably, so we may even time out because the
-  // peer never received our close_notify. Report to the caller that the channel
-  // has fully shut down.
-  if (ssl->s3->read_shutdown == ssl_shutdown_none) {
-    ssl->s3->read_shutdown = ssl_shutdown_close_notify;
+ssl_open_record_t dtls1_open_close_notify(SSL *ssl, size_t *out_consumed,
+                                          uint8_t *out_alert,
+                                          bssl::Span<uint8_t> in) {
+  switch (ssl->s3->read_shutdown) {
+    // Bidirectional shutdown doesn't make sense for an unordered transport.
+    // DTLS alerts also aren't delivered reliably, so we may even time out
+    // because the peer never received our close_notify. Report to the caller
+    // that the channel has fully shut down.
+    case ssl_shutdown_none:
+    case ssl_shutdown_close_notify:
+      ssl->s3->read_shutdown = ssl_shutdown_close_notify;
+      return ssl_open_record_close_notify;
+    case ssl_shutdown_error:
+      ERR_restore_state(ssl->s3->read_error);
+      *out_alert = 0;
+      return ssl_open_record_error;
   }
+  assert(0);
+  return ssl_open_record_error;
 }
 
 int dtls1_write_app_data(SSL *ssl, bool *out_needs_handshake,