folly::Optional<Buf> EncryptedReadRecordLayer::getDecryptedBuf(
    folly::IOBufQueue& buf) {
  while (true) {
    // Cache the front buffer, calling front may invoke and update
    // of the tail cache.
    auto frontBuf = buf.front();
    folly::io::Cursor cursor(frontBuf);

    if (buf.empty() || !cursor.canAdvance(kEncryptedHeaderSize)) {
      return folly::none;
    }

    std::array<uint8_t, kEncryptedHeaderSize> ad;
    folly::io::Cursor adCursor(cursor);
    adCursor.pull(ad.data(), ad.size());
    folly::IOBuf adBuf{folly::IOBuf::wrapBufferAsValue(folly::range(ad))};

    auto contentType =
        static_cast<ContentType>(cursor.readBE<ContentTypeType>());
    cursor.skip(sizeof(ProtocolVersion));

    auto length = cursor.readBE<uint16_t>();
    if (length == 0) {
      throw std::runtime_error("received 0 length encrypted record");
    }
    if (length > kMaxEncryptedRecordSize) {
      throw std::runtime_error("received too long encrypted record");
    }
    auto consumedBytes = cursor - frontBuf;
    if (buf.chainLength() < consumedBytes + length) {
      return folly::none;
    }

    if (contentType == ContentType::alert && length == 2) {
      auto alert = decode<Alert>(cursor);
      throw std::runtime_error(folly::to<std::string>(
          "received plaintext alert in encrypted record: ",
          toString(alert.description)));
    }

    // If we already know that the length of the buffer is the
    // same as the number of bytes we need, move the entire buffer.
    std::unique_ptr<folly::IOBuf> encrypted;
    if (buf.chainLength() == consumedBytes + length) {
      encrypted = buf.move();
    } else {
      encrypted = buf.split(consumedBytes + length);
    }
    trimStart(*encrypted, consumedBytes);

    if (contentType == ContentType::change_cipher_spec) {
      encrypted->coalesce();
      if (encrypted->length() == 1 && *encrypted->data() == 0x01) {
        continue;
      } else {
        throw FizzException(
            "received ccs", AlertDescription::illegal_parameter);
      }
    }

    TLSMessage msg;
    if (seqNum_ == std::numeric_limits<uint64_t>::max()) {
      throw std::runtime_error("max read seq num");
    }
    if (skipFailedDecryption_) {
      auto decryptAttempt = aead_->tryDecrypt(
          std::move(encrypted), useAdditionalData_ ? &adBuf : nullptr, seqNum_);
      if (decryptAttempt) {
        seqNum_++;
        skipFailedDecryption_ = false;
        return decryptAttempt;
      } else {
        continue;
      }
    } else {
      return aead_->decrypt(
          std::move(encrypted),
          useAdditionalData_ ? &adBuf : nullptr,
          seqNum_++);
    }
  }
}
folly::Optional<Buf> EncryptedReadRecordLayer::getDecryptedBuf(
    folly::IOBufQueue& buf) {
  while (true) {
     
     
    auto frontBuf = buf.front();
    folly::io::Cursor cursor(frontBuf);

    if (buf.empty() || !cursor.canAdvance(kEncryptedHeaderSize)) {
      return folly::none;
    }

    std::array<uint8_t, kEncryptedHeaderSize> ad;
    folly::io::Cursor adCursor(cursor);
    adCursor.pull(ad.data(), ad.size());
    folly::IOBuf adBuf{folly::IOBuf::wrapBufferAsValue(folly::range(ad))};

    auto contentType =
        static_cast<ContentType>(cursor.readBE<ContentTypeType>());
    cursor.skip(sizeof(ProtocolVersion));

    auto length = cursor.readBE<uint16_t>();
    if (length == 0) {
      throw std::runtime_error("received 0 length encrypted record");
    }
    if (length > kMaxEncryptedRecordSize) {
      throw std::runtime_error("received too long encrypted record");
    }
    auto consumedBytes = cursor - frontBuf;
    if (buf.chainLength() < consumedBytes + length) {
      return folly::none;
    }

    if (contentType == ContentType::alert && length == 2) {
      auto alert = decode<Alert>(cursor);
      throw std::runtime_error(folly::to<std::string>(
          "received plaintext alert in encrypted record: ",
          toString(alert.description)));
    }

     
     
    std::unique_ptr<folly::IOBuf> encrypted;
    if (buf.chainLength() == consumedBytes + length) {
      encrypted = buf.move();
    } else {
      encrypted = buf.split(consumedBytes + length);
    }
    trimStart(*encrypted, consumedBytes);

    if (contentType == ContentType::change_cipher_spec) {
      encrypted->coalesce();
      if (encrypted->length() == 1 && *encrypted->data() == 0x01) {
        continue;
      } else {
        throw FizzException(
            "received ccs", AlertDescription::illegal_parameter);
      }
    }

    TLSMessage msg;
    if (seqNum_ == std::numeric_limits<uint64_t>::max()) {
      throw std::runtime_error("max read seq num");
    }
    if (skipFailedDecryption_) {
      auto decryptAttempt = aead_->tryDecrypt(
          std::move(encrypted), useAdditionalData_ ? &adBuf : nullptr, seqNum_);
      if (decryptAttempt) {
        seqNum_++;
        skipFailedDecryption_ = false;
        return decryptAttempt;
      } else {
        continue;
      }
    } else {
      return aead_->decrypt(
          std::move(encrypted),
          useAdditionalData_ ? &adBuf : nullptr,
          seqNum_++);
    }
  }
}