• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "quiche/quic/tools/quic_client_default_network_helper.h"
6 
7 #include "absl/cleanup/cleanup.h"
8 #include "quiche/quic/core/io/quic_event_loop.h"
9 #include "quiche/quic/core/quic_default_packet_writer.h"
10 #include "quiche/quic/core/quic_packets.h"
11 #include "quiche/quic/core/quic_types.h"
12 #include "quiche/quic/core/quic_udp_socket.h"
13 #include "quiche/quic/platform/api/quic_logging.h"
14 #include "quiche/common/platform/api/quiche_logging.h"
15 #include "quiche/common/platform/api/quiche_system_event_loop.h"
16 
17 namespace quic {
18 
19 namespace {
20 
21 // For level-triggered I/O, we need to manually rearm the kSocketEventWritable
22 // listener whenever the socket gets blocked.
23 class LevelTriggeredPacketWriter : public QuicDefaultPacketWriter {
24  public:
LevelTriggeredPacketWriter(int fd,QuicEventLoop * event_loop)25   explicit LevelTriggeredPacketWriter(int fd, QuicEventLoop* event_loop)
26       : QuicDefaultPacketWriter(fd), event_loop_(event_loop) {
27     QUICHE_DCHECK(!event_loop->SupportsEdgeTriggered());
28   }
29 
WritePacket(const char * buffer,size_t buf_len,const QuicIpAddress & self_address,const QuicSocketAddress & peer_address,PerPacketOptions * options)30   WriteResult WritePacket(const char* buffer, size_t buf_len,
31                           const QuicIpAddress& self_address,
32                           const QuicSocketAddress& peer_address,
33                           PerPacketOptions* options) override {
34     WriteResult result = QuicDefaultPacketWriter::WritePacket(
35         buffer, buf_len, self_address, peer_address, options);
36     if (IsWriteBlockedStatus(result.status)) {
37       bool success = event_loop_->RearmSocket(fd(), kSocketEventWritable);
38       QUICHE_DCHECK(success);
39     }
40     return result;
41   }
42 
43  private:
44   QuicEventLoop* event_loop_;
45 };
46 
47 }  // namespace
48 
QuicClientDefaultNetworkHelper(QuicEventLoop * event_loop,QuicClientBase * client)49 QuicClientDefaultNetworkHelper::QuicClientDefaultNetworkHelper(
50     QuicEventLoop* event_loop, QuicClientBase* client)
51     : event_loop_(event_loop),
52       packets_dropped_(0),
53       overflow_supported_(false),
54       packet_reader_(new QuicPacketReader()),
55       client_(client),
56       max_reads_per_event_loop_(std::numeric_limits<int>::max()) {}
57 
~QuicClientDefaultNetworkHelper()58 QuicClientDefaultNetworkHelper::~QuicClientDefaultNetworkHelper() {
59   if (client_->connected()) {
60     client_->session()->connection()->CloseConnection(
61         QUIC_PEER_GOING_AWAY, "Client being torn down",
62         ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
63   }
64 
65   CleanUpAllUDPSockets();
66 }
67 
CreateUDPSocketAndBind(QuicSocketAddress server_address,QuicIpAddress bind_to_address,int bind_to_port)68 bool QuicClientDefaultNetworkHelper::CreateUDPSocketAndBind(
69     QuicSocketAddress server_address, QuicIpAddress bind_to_address,
70     int bind_to_port) {
71   int fd = CreateUDPSocket(server_address, &overflow_supported_);
72   if (fd < 0) {
73     return false;
74   }
75   auto closer = absl::MakeCleanup([fd] { close(fd); });
76 
77   QuicSocketAddress client_address;
78   if (bind_to_address.IsInitialized()) {
79     client_address = QuicSocketAddress(bind_to_address, client_->local_port());
80   } else if (server_address.host().address_family() == IpAddressFamily::IP_V4) {
81     client_address = QuicSocketAddress(QuicIpAddress::Any4(), bind_to_port);
82   } else {
83     client_address = QuicSocketAddress(QuicIpAddress::Any6(), bind_to_port);
84   }
85 
86   // Some platforms expect that the addrlen given to bind() exactly matches the
87   // size of the associated protocol family's sockaddr struct.
88   // TODO(b/179430548): Revert this when affected platforms are updated to
89   // to support binding with an addrelen of sizeof(sockaddr_storage)
90   socklen_t addrlen;
91   switch (client_address.host().address_family()) {
92     case IpAddressFamily::IP_V4:
93       addrlen = sizeof(sockaddr_in);
94       break;
95     case IpAddressFamily::IP_V6:
96       addrlen = sizeof(sockaddr_in6);
97       break;
98     case IpAddressFamily::IP_UNSPEC:
99       addrlen = 0;
100       break;
101   }
102 
103   sockaddr_storage addr = client_address.generic_address();
104   int rc = bind(fd, reinterpret_cast<sockaddr*>(&addr), addrlen);
105   if (rc < 0) {
106     QUIC_LOG(ERROR) << "Bind failed: " << strerror(errno)
107                     << " bind_to_address:" << bind_to_address
108                     << ", bind_to_port:" << bind_to_port
109                     << ", client_address:" << client_address;
110     return false;
111   }
112 
113   if (client_address.FromSocket(fd) != 0) {
114     QUIC_LOG(ERROR) << "Unable to get self address.  Error: "
115                     << strerror(errno);
116   }
117 
118   if (event_loop_->RegisterSocket(
119           fd, kSocketEventReadable | kSocketEventWritable, this)) {
120     fd_address_map_[fd] = client_address;
121     std::move(closer).Cancel();
122     return true;
123   }
124   return false;
125 }
126 
CleanUpUDPSocket(int fd)127 void QuicClientDefaultNetworkHelper::CleanUpUDPSocket(int fd) {
128   CleanUpUDPSocketImpl(fd);
129   fd_address_map_.erase(fd);
130 }
131 
CleanUpAllUDPSockets()132 void QuicClientDefaultNetworkHelper::CleanUpAllUDPSockets() {
133   for (std::pair<int, QuicSocketAddress> fd_address : fd_address_map_) {
134     CleanUpUDPSocketImpl(fd_address.first);
135   }
136   fd_address_map_.clear();
137 }
138 
CleanUpUDPSocketImpl(int fd)139 void QuicClientDefaultNetworkHelper::CleanUpUDPSocketImpl(int fd) {
140   if (fd > -1) {
141     bool success = event_loop_->UnregisterSocket(fd);
142     QUICHE_DCHECK(success || fds_unregistered_externally_);
143     int rc = close(fd);
144     QUICHE_DCHECK_EQ(0, rc);
145   }
146 }
147 
RunEventLoop()148 void QuicClientDefaultNetworkHelper::RunEventLoop() {
149   quiche::QuicheRunSystemEventLoopIteration();
150   event_loop_->RunEventLoopOnce(QuicTime::Delta::FromMilliseconds(50));
151 }
152 
OnSocketEvent(QuicEventLoop *,QuicUdpSocketFd fd,QuicSocketEventMask events)153 void QuicClientDefaultNetworkHelper::OnSocketEvent(
154     QuicEventLoop* /*event_loop*/, QuicUdpSocketFd fd,
155     QuicSocketEventMask events) {
156   if (events & kSocketEventReadable) {
157     QUIC_DVLOG(1) << "Read packets on kSocketEventReadable";
158     int times_to_read = max_reads_per_event_loop_;
159     bool more_to_read = true;
160     QuicPacketCount packets_dropped = 0;
161     while (client_->connected() && more_to_read && times_to_read > 0) {
162       more_to_read = packet_reader_->ReadAndDispatchPackets(
163           fd, GetLatestClientAddress().port(), *client_->helper()->GetClock(),
164           this, overflow_supported_ ? &packets_dropped : nullptr);
165       --times_to_read;
166     }
167     if (packets_dropped_ < packets_dropped) {
168       QUIC_LOG(ERROR)
169           << packets_dropped - packets_dropped_
170           << " more packets are dropped in the socket receive buffer.";
171       packets_dropped_ = packets_dropped;
172     }
173     if (client_->connected() && more_to_read) {
174       bool success =
175           event_loop_->ArtificiallyNotifyEvent(fd, kSocketEventReadable);
176       QUICHE_DCHECK(success);
177     } else if (!event_loop_->SupportsEdgeTriggered()) {
178       bool success = event_loop_->RearmSocket(fd, kSocketEventReadable);
179       QUICHE_DCHECK(success);
180     }
181   }
182   if (client_->connected() && (events & kSocketEventWritable)) {
183     client_->writer()->SetWritable();
184     client_->session()->connection()->OnCanWrite();
185   }
186 }
187 
CreateQuicPacketWriter()188 QuicPacketWriter* QuicClientDefaultNetworkHelper::CreateQuicPacketWriter() {
189   if (event_loop_->SupportsEdgeTriggered()) {
190     return new QuicDefaultPacketWriter(GetLatestFD());
191   } else {
192     return new LevelTriggeredPacketWriter(GetLatestFD(), event_loop_);
193   }
194 }
195 
SetClientPort(int port)196 void QuicClientDefaultNetworkHelper::SetClientPort(int port) {
197   fd_address_map_.back().second =
198       QuicSocketAddress(GetLatestClientAddress().host(), port);
199 }
200 
GetLatestClientAddress() const201 QuicSocketAddress QuicClientDefaultNetworkHelper::GetLatestClientAddress()
202     const {
203   if (fd_address_map_.empty()) {
204     return QuicSocketAddress();
205   }
206 
207   return fd_address_map_.back().second;
208 }
209 
GetLatestFD() const210 int QuicClientDefaultNetworkHelper::GetLatestFD() const {
211   if (fd_address_map_.empty()) {
212     return -1;
213   }
214 
215   return fd_address_map_.back().first;
216 }
217 
ProcessPacket(const QuicSocketAddress & self_address,const QuicSocketAddress & peer_address,const QuicReceivedPacket & packet)218 void QuicClientDefaultNetworkHelper::ProcessPacket(
219     const QuicSocketAddress& self_address,
220     const QuicSocketAddress& peer_address, const QuicReceivedPacket& packet) {
221   client_->session()->ProcessUdpPacket(self_address, peer_address, packet);
222 }
223 
CreateUDPSocket(QuicSocketAddress server_address,bool * overflow_supported)224 int QuicClientDefaultNetworkHelper::CreateUDPSocket(
225     QuicSocketAddress server_address, bool* overflow_supported) {
226   QuicUdpSocketApi api;
227   int fd = api.Create(server_address.host().AddressFamilyToInt(),
228                       /*receive_buffer_size =*/kDefaultSocketReceiveBuffer,
229                       /*send_buffer_size =*/kDefaultSocketReceiveBuffer);
230   if (fd < 0) {
231     return fd;
232   }
233 
234   *overflow_supported = api.EnableDroppedPacketCount(fd);
235   api.EnableReceiveTimestamp(fd);
236 
237   if (!BindInterfaceNameIfNeeded(fd)) {
238     CleanUpUDPSocket(fd);
239     return kQuicInvalidSocketFd;
240   }
241 
242   return fd;
243 }
244 
BindInterfaceNameIfNeeded(int fd)245 bool QuicClientDefaultNetworkHelper::BindInterfaceNameIfNeeded(int fd) {
246   QuicUdpSocketApi api;
247   std::string interface_name = client_->interface_name();
248   if (!interface_name.empty()) {
249     if (!api.BindInterface(fd, interface_name)) {
250       QUIC_DLOG(WARNING) << "Failed to bind socket (" << fd
251                          << ") to interface (" << interface_name << ").";
252       return false;
253     }
254   }
255   return true;
256 }
257 
258 }  // namespace quic
259