Push read_shutdown logic down a layer.

We'll probably want to either move or add additional checks later, but
meanwhile this gets more code on the BIO-free side of the divide.

Change-Id: I3e2b570cdf1d70a262d952c20fd2d76ff4f70dd0
Reviewed-on: https://boringssl-review.googlesource.com/21365
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 c2cbd7e..5b1cce5 100644
--- a/ssl/d1_pkt.cc
+++ b/ssl/d1_pkt.cc
@@ -129,64 +129,55 @@
 namespace bssl {
 
 int dtls1_get_record(SSL *ssl) {
-again:
-  switch (ssl->s3->read_shutdown) {
-    case ssl_shutdown_none:
-      break;
-    case ssl_shutdown_fatal_alert:
-      OPENSSL_PUT_ERROR(SSL, SSL_R_PROTOCOL_IS_SHUTDOWN);
-      return -1;
-    case ssl_shutdown_close_notify:
-      return 0;
-  }
-
-  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;
-      }
-      goto again;
+  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);
+      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;
-      }
-
-      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:
-      goto again;
-
-    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;
   }
-
-  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,
diff --git a/ssl/dtls_record.cc b/ssl/dtls_record.cc
index c06a62d..2bf1d42 100644
--- a/ssl/dtls_record.cc
+++ b/ssl/dtls_record.cc
@@ -179,6 +179,17 @@
                                         size_t *out_consumed,
                                         uint8_t *out_alert, Span<uint8_t> in) {
   *out_consumed = 0;
+  switch (ssl->s3->read_shutdown) {
+    case ssl_shutdown_none:
+      break;
+    case ssl_shutdown_fatal_alert:
+      OPENSSL_PUT_ERROR(SSL, SSL_R_PROTOCOL_IS_SHUTDOWN);
+      *out_alert = 0;
+      return ssl_open_record_error;
+    case ssl_shutdown_close_notify:
+      return ssl_open_record_close_notify;
+  }
+
   if (in.empty()) {
     return ssl_open_record_partial;
   }
diff --git a/ssl/s3_pkt.cc b/ssl/s3_pkt.cc
index b182826..71e1a08 100644
--- a/ssl/s3_pkt.cc
+++ b/ssl/s3_pkt.cc
@@ -127,63 +127,54 @@
 static int do_ssl3_write(SSL *ssl, int type, const uint8_t *buf, unsigned len);
 
 int ssl3_get_record(SSL *ssl) {
-again:
-  switch (ssl->s3->read_shutdown) {
-    case ssl_shutdown_none:
-      break;
-    case ssl_shutdown_fatal_alert:
-      OPENSSL_PUT_ERROR(SSL, SSL_R_PROTOCOL_IS_SHUTDOWN);
-      return -1;
-    case ssl_shutdown_close_notify:
-      return 0;
-  }
-
-  Span<uint8_t> body;
-  uint8_t type, alert = SSL_AD_DECODE_ERROR;
-  size_t consumed;
-  enum ssl_open_record_t open_ret = tls_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: {
-      int read_ret = ssl_read_buffer_extend_to(ssl, consumed);
-      if (read_ret <= 0) {
-        return read_ret;
-      }
-      goto again;
+  for (;;) {
+    Span<uint8_t> body;
+    uint8_t type, alert = SSL_AD_DECODE_ERROR;
+    size_t consumed;
+    enum ssl_open_record_t open_ret = tls_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: {
+        int read_ret = ssl_read_buffer_extend_to(ssl, consumed);
+        if (read_ret <= 0) {
+          return read_ret;
+        }
+        continue;
+      }
 
-    case ssl_open_record_success: {
-      if (body.size() > 0xffff) {
-        OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW);
+      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;
-      }
-
-      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:
-      goto again;
-
-    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;
   }
-
-  assert(0);
-  OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
-  return -1;
 }
 
 int ssl3_write_app_data(SSL *ssl, bool *out_needs_handshake, const uint8_t *buf,
diff --git a/ssl/tls_record.cc b/ssl/tls_record.cc
index ba38bc9..44a04d9 100644
--- a/ssl/tls_record.cc
+++ b/ssl/tls_record.cc
@@ -191,6 +191,16 @@
                                        Span<uint8_t> *out, size_t *out_consumed,
                                        uint8_t *out_alert, Span<uint8_t> in) {
   *out_consumed = 0;
+  switch (ssl->s3->read_shutdown) {
+    case ssl_shutdown_none:
+      break;
+    case ssl_shutdown_fatal_alert:
+      OPENSSL_PUT_ERROR(SSL, SSL_R_PROTOCOL_IS_SHUTDOWN);
+      *out_alert = 0;
+      return ssl_open_record_error;
+    case ssl_shutdown_close_notify:
+      return ssl_open_record_close_notify;
+  }
 
   CBS cbs = CBS(in);