| // 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 "quic/qbone/bonnet/tun_device_packet_exchanger.h" |
| |
| #include <utility> |
| |
| #include "absl/strings/str_cat.h" |
| |
| namespace quic { |
| |
| TunDevicePacketExchanger::TunDevicePacketExchanger( |
| size_t mtu, |
| KernelInterface* kernel, |
| QbonePacketExchanger::Visitor* visitor, |
| size_t max_pending_packets, |
| StatsInterface* stats) |
| : QbonePacketExchanger(visitor, max_pending_packets), |
| mtu_(mtu), |
| kernel_(kernel), |
| stats_(stats) {} |
| |
| bool TunDevicePacketExchanger::WritePacket(const char* packet, |
| size_t size, |
| bool* blocked, |
| std::string* error) { |
| *blocked = false; |
| if (fd_ < 0) { |
| *error = absl::StrCat("Invalid file descriptor of the TUN device: ", fd_); |
| stats_->OnWriteError(error); |
| return false; |
| } |
| |
| int result = kernel_->write(fd_, packet, size); |
| if (result == -1) { |
| if (errno == EWOULDBLOCK || errno == EAGAIN) { |
| // The tunnel is blocked. Note that this does not mean the receive buffer |
| // of a TCP connection is filled. This simply means the TUN device itself |
| // is blocked on handing packets to the rest part of the kernel. |
| *error = absl::StrCat("Write to the TUN device was blocked: ", errno); |
| *blocked = true; |
| stats_->OnWriteError(error); |
| } |
| return false; |
| } |
| stats_->OnPacketWritten(result); |
| |
| return true; |
| } |
| |
| std::unique_ptr<QuicData> TunDevicePacketExchanger::ReadPacket( |
| bool* blocked, |
| std::string* error) { |
| *blocked = false; |
| if (fd_ < 0) { |
| *error = absl::StrCat("Invalid file descriptor of the TUN device: ", fd_); |
| stats_->OnReadError(error); |
| return nullptr; |
| } |
| // Reading on a TUN device returns a packet at a time. If the packet is longer |
| // than the buffer, it's truncated. |
| auto read_buffer = std::make_unique<char[]>(mtu_); |
| int result = kernel_->read(fd_, read_buffer.get(), mtu_); |
| // Note that 0 means end of file, but we're talking about a TUN device - there |
| // is no end of file. Therefore 0 also indicates error. |
| if (result <= 0) { |
| if (errno == EAGAIN || errno == EWOULDBLOCK) { |
| *error = absl::StrCat("Read from the TUN device was blocked: ", errno); |
| *blocked = true; |
| stats_->OnReadError(error); |
| } |
| return nullptr; |
| } |
| stats_->OnPacketRead(result); |
| return std::make_unique<QuicData>(read_buffer.release(), result, true); |
| } |
| |
| void TunDevicePacketExchanger::set_file_descriptor(int fd) { |
| fd_ = fd; |
| } |
| |
| const TunDevicePacketExchanger::StatsInterface* |
| TunDevicePacketExchanger::stats_interface() const { |
| return stats_; |
| } |
| |
| } // namespace quic |