text: // Copyright 2021 gRPC authors.
  //
  // Licensed under the Apache License, Version 2.0 (the "License");
  // you may not use this file except in compliance with the License.
  // You may obtain a copy of the License at
  //
  //     http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing, software
  // distributed under the License is distributed on an "AS IS" BASIS,
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  // See the License for the specific language governing permissions and
  // limitations under the License.
  
  #ifndef GRPC_TEST_CORE_TRANSPORT_BINDER_END2END_FUZZERS_FUZZER_UTILS_H
  #define GRPC_TEST_CORE_TRANSPORT_BINDER_END2END_FUZZERS_FUZZER_UTILS_H
  
  #include <memory>
  #include <queue>
  #include <string>
  #include <thread>
  #include <vector>
  
  #include "absl/memory/memory.h"
  #include "absl/status/status.h"
  
  #include <grpc/support/log.h>
  
  #include "src/core/ext/transport/binder/wire_format/binder.h"
  #include "src/core/ext/transport/binder/wire_format/wire_reader.h"
  #include "test/core/transport/binder/end2end/fuzzers/binder_transport_fuzzer.pb.h"
  
  namespace grpc_binder {
  namespace fuzzing {
  
  // A WritableParcel implementation that simply does nothing. Don't use
  // MockWritableParcel here since capturing calls is expensive.
  class NoOpWritableParcel : public WritableParcel {
   public:
    int32_t GetDataSize() const override { return 0; }
    absl::Status WriteInt32(int32_t /*data*/) override {
      return absl::OkStatus();
    }
    absl::Status WriteInt64(int64_t /*data*/) override {
      return absl::OkStatus();
    }
    absl::Status WriteBinder(HasRawBinder* /*binder*/) override {
      return absl::OkStatus();
    }
    absl::Status WriteString(absl::string_view /*s*/) override {
      return absl::OkStatus();
    }
    absl::Status WriteByteArray(const int8_t* /*buffer*/,
                                int32_t /*length*/) override {
      return absl::OkStatus();
    }
  };
  
  // Binder implementation used in fuzzing.
  //
  // Most of its the functionalities are no-op, except ConstructTxReceiver now
  // returns a TransactionReceiverForFuzzing.
  class BinderForFuzzing : public Binder {
   public:
    BinderForFuzzing() : input_(absl::make_unique<NoOpWritableParcel>()) {}
  
    explicit BinderForFuzzing(const binder_transport_fuzzer::IncomingParcels& p)
        : incoming_parcels_(p), input_(absl::make_unique<NoOpWritableParcel>()) {}
  
    void Initialize() override {}
    absl::Status PrepareTransaction() override { return absl::OkStatus(); }
  
    absl::Status Transact(BinderTransportTxCode /*tx_code*/) override {
      return absl::OkStatus();
    }
  
    std::unique_ptr<TransactionReceiver> ConstructTxReceiver(
        grpc_core::RefCountedPtr<WireReader> wire_reader_ref,
        TransactionReceiver::OnTransactCb cb) const override;
  
    WritableParcel* GetWritableParcel() const override { return input_.get(); }
    void* GetRawBinder() override { return nullptr; }
  
   private:
    binder_transport_fuzzer::IncomingParcels incoming_parcels_;
    std::unique_ptr<WritableParcel> input_;
  };
  
  // ReadableParcel implementation used in fuzzing.
  //
  // It consumes a Parcel generated by mutator, and returns the data in the Parcel
  // upon user's requests.
  class ReadableParcelForFuzzing : public ReadableParcel {
   public:
    explicit ReadableParcelForFuzzing(const binder_transport_fuzzer::Parcel& p)
        : parcel_data_size_(p.data_size()), consumed_data_size_(0) {
      for (const auto& v : p.values()) {
        values_.push(v);
      }
    }
  
    // Construct from SetupTransportParcel, which have fixed types of data in it.
    explicit ReadableParcelForFuzzing(
        const binder_transport_fuzzer::SetupTransportParcel& p)
        : parcel_data_size_(p.data_size()), consumed_data_size_(0) {
      // Creates value for protocol version and put it into the queue
      binder_transport_fuzzer::Value version_value;
      version_value.set_i32(p.version());
      values_.push(version_value);
  
      // Creates a binder value and put it into the queue
      binder_transport_fuzzer::Value binder_value;
      binder_value.mutable_binder();  // sets one-of field
      values_.push(binder_value);
    }
  
    int32_t GetDataSize() const override;
    absl::Status ReadInt32(int32_t* data) override;
    absl::Status ReadInt64(int64_t* data) override;
    absl::Status ReadBinder(std::unique_ptr<Binder>* binder) override;
    absl::Status ReadByteArray(std::string* data) override;
    absl::Status ReadString(std::string* data) override;
  
   private:
    // Stores data/objects in binder in their order. Since we don't support random
    // access using a std::queue is enough here.
    std::queue<binder_transport_fuzzer::Value> values_;
  
    const int32_t parcel_data_size_;
  
    static constexpr size_t kParcelDataSizeLimit = 1024 * 1024;
    size_t consumed_data_size_;
  };
  
  void JoinFuzzingThread();
  
  // TransactionReceiver implementation used in fuzzing.
  //
  // When constructed, start sending fuzzed requests to the client. When all the
  // bytes are consumed, the reference to WireReader will be released.
  class TransactionReceiverForFuzzing : public TransactionReceiver {
   public:
    TransactionReceiverForFuzzing(
        binder_transport_fuzzer::IncomingParcels incoming_parcels,
        grpc_core::RefCountedPtr<WireReader> wire_reader_ref,
        TransactionReceiver::OnTransactCb cb);
  
    void* GetRawBinder() override { return nullptr; }
  };
  
  }  // namespace fuzzing
  }  // namespace grpc_binder
  
  #endif  // GRPC_TEST_CORE_TRANSPORT_BINDER_END2END_FUZZERS_FUZZER_UTILS_H
  