| // 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 "net/third_party/quiche/src/quic/qbone/bonnet/tun_device_packet_exchanger.h" | 
 |  | 
 | #include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" | 
 | #include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h" | 
 |  | 
 | namespace quic { | 
 |  | 
 | TunDevicePacketExchanger::TunDevicePacketExchanger( | 
 |     int fd, | 
 |     size_t mtu, | 
 |     KernelInterface* kernel, | 
 |     QbonePacketExchanger::Visitor* visitor, | 
 |     size_t max_pending_packets, | 
 |     StatsInterface* stats) | 
 |     : QbonePacketExchanger(visitor, max_pending_packets), | 
 |       fd_(fd), | 
 |       mtu_(mtu), | 
 |       kernel_(kernel), | 
 |       stats_(stats) {} | 
 |  | 
 | bool TunDevicePacketExchanger::WritePacket(const char* packet, | 
 |                                            size_t size, | 
 |                                            bool* blocked, | 
 |                                            string* error) { | 
 |   *blocked = false; | 
 |   if (fd_ < 0) { | 
 |     *error = QuicStrCat("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 = QuicStrCat("Write to the TUN device was blocked: ", errno); | 
 |       *blocked = true; | 
 |       stats_->OnWriteError(error); | 
 |     } | 
 |     return false; | 
 |   } | 
 |   stats_->OnPacketWritten(); | 
 |  | 
 |   return true; | 
 | } | 
 |  | 
 | std::unique_ptr<QuicData> TunDevicePacketExchanger::ReadPacket(bool* blocked, | 
 |                                                                string* error) { | 
 |   *blocked = false; | 
 |   if (fd_ < 0) { | 
 |     *error = QuicStrCat("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 = QuicStrCat("Read from the TUN device was blocked: ", errno); | 
 |       *blocked = true; | 
 |       stats_->OnReadError(error); | 
 |     } | 
 |     return nullptr; | 
 |   } | 
 |   stats_->OnPacketRead(); | 
 |   return std::make_unique<QuicData>(read_buffer.release(), result, true); | 
 | } | 
 |  | 
 | int TunDevicePacketExchanger::file_descriptor() const { | 
 |   return fd_; | 
 | } | 
 |  | 
 | }  // namespace quic |