// Copyright (c) 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "quiche/quic/qbone/qbone_packet_exchanger.h"

#include <utility>

namespace quic {

bool QbonePacketExchanger::ReadAndDeliverPacket(
    QboneClientInterface* qbone_client) {
  bool blocked = false;
  std::string error;
  std::unique_ptr<QuicData> packet = ReadPacket(&blocked, &error);
  if (packet == nullptr) {
    if (!blocked && visitor_) {
      visitor_->OnReadError(error);
    }
    return false;
  }
  qbone_client->ProcessPacketFromNetwork(packet->AsStringPiece());
  return true;
}

void QbonePacketExchanger::WritePacketToNetwork(const char* packet,
                                                size_t size) {
  bool blocked = false;
  std::string error;
  if (packet_queue_.empty() && !write_blocked_) {
    if (WritePacket(packet, size, &blocked, &error)) {
      return;
    }
    if (blocked) {
      write_blocked_ = true;
    } else {
      QUIC_LOG_EVERY_N_SEC(ERROR, 60) << "Packet write failed: " << error;
      if (visitor_) {
        visitor_->OnWriteError(error);
      }
    }
  }

  // Drop the packet on the floor if the queue if full.
  if (packet_queue_.size() >= max_pending_packets_) {
    return;
  }

  auto data_copy = new char[size];
  memcpy(data_copy, packet, size);
  packet_queue_.push_back(
      std::make_unique<QuicData>(data_copy, size, /* owns_buffer = */ true));
}

void QbonePacketExchanger::SetWritable() {
  write_blocked_ = false;
  while (!packet_queue_.empty()) {
    bool blocked = false;
    std::string error;
    if (WritePacket(packet_queue_.front()->data(),
                    packet_queue_.front()->length(), &blocked, &error)) {
      packet_queue_.pop_front();
    } else {
      if (!blocked && visitor_) {
        visitor_->OnWriteError(error);
      }
      write_blocked_ = blocked;
      return;
    }
  }
}

}  // namespace quic
