Index: net/tools/quic/quic_packet_reader.cc |
diff --git a/net/tools/quic/quic_packet_reader.cc b/net/tools/quic/quic_packet_reader.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..1982269f30bc3b47c49750d9f745a67a38507ecc |
--- /dev/null |
+++ b/net/tools/quic/quic_packet_reader.cc |
@@ -0,0 +1,143 @@ |
+// Copyright 2015 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/tools/quic/quic_packet_reader.h" |
+ |
+#include <errno.h> |
+#ifndef __APPLE__ |
+// This is a GNU header that is not present in /usr/include on MacOS |
+#include <features.h> |
+#endif |
+#include <string.h> |
+#include <sys/epoll.h> |
+ |
+#include "base/logging.h" |
+#include "net/base/ip_endpoint.h" |
+#include "net/tools/quic/quic_dispatcher.h" |
+#include "net/tools/quic/quic_socket_utils.h" |
+ |
+#define MMSG_MORE 0 |
+ |
+#ifndef SO_RXQ_OVFL |
+#define SO_RXQ_OVFL 40 |
+#endif |
+ |
+namespace net { |
+ |
+namespace tools { |
+ |
+QuicPacketReader::QuicPacketReader() { |
+ Initialize(); |
+} |
+ |
+void QuicPacketReader::Initialize() { |
+ // Zero initialize uninitialized memory. |
+ memset(cbuf_, 0, arraysize(cbuf_)); |
+ memset(buf_, 0, arraysize(buf_)); |
+ memset(raw_address_, 0, sizeof(raw_address_)); |
+ memset(mmsg_hdr_, 0, sizeof(mmsg_hdr_)); |
+ |
+ for (int i = 0; i < kNumPacketsPerReadMmsgCall; ++i) { |
+ iov_[i].iov_base = buf_ + (2 * kMaxPacketSize * i); |
+ iov_[i].iov_len = 2 * kMaxPacketSize; |
+ |
+ msghdr* hdr = &mmsg_hdr_[i].msg_hdr; |
+ hdr->msg_name = &raw_address_[i]; |
+ hdr->msg_namelen = sizeof(sockaddr_storage); |
+ hdr->msg_iov = &iov_[i]; |
+ hdr->msg_iovlen = 1; |
+ |
+ hdr->msg_control = cbuf_ + kSpaceForOverflowAndIp * i; |
+ hdr->msg_controllen = kSpaceForOverflowAndIp; |
+ } |
+} |
+ |
+QuicPacketReader::~QuicPacketReader() { |
+} |
+ |
+bool QuicPacketReader::ReadAndDispatchPackets( |
+ int fd, |
+ int port, |
+ ProcessPacketInterface* processor, |
+ QuicPacketCount* packets_dropped) { |
+#if MMSG_MORE |
+ // Re-set the length fields in case recvmmsg has changed them. |
+ for (int i = 0; i < kNumPacketsPerReadMmsgCall; ++i) { |
+ iov_[i].iov_len = 2 * kMaxPacketSize; |
+ mmsg_hdr_[i].msg_len = 0; |
+ msghdr* hdr = &mmsg_hdr_[i].msg_hdr; |
+ hdr->msg_namelen = sizeof(sockaddr_storage); |
+ hdr->msg_iovlen = 1; |
+ hdr->msg_controllen = kSpaceForOverflowAndIp; |
+ } |
+ |
+ int packets_read = |
+ recvmmsg(fd, mmsg_hdr_, kNumPacketsPerReadMmsgCall, 0, nullptr); |
+ |
+ if (packets_read <= 0) { |
+ return false; // recvmmsg failed. |
+ } |
+ |
+ for (int i = 0; i < packets_read; ++i) { |
+ if (mmsg_hdr_[i].msg_len == 0) { |
+ continue; |
+ } |
+ |
+ IPEndPoint client_address = IPEndPoint(raw_address_[i]); |
+ IPAddressNumber server_ip = |
+ QuicSocketUtils::GetAddressFromMsghdr(&mmsg_hdr_[i].msg_hdr); |
+ if (!IsInitializedAddress(server_ip)) { |
+ LOG(DFATAL) << "Unable to get server address."; |
+ continue; |
+ } |
+ |
+ QuicEncryptedPacket packet(reinterpret_cast<char*>(iov_[i].iov_base), |
+ mmsg_hdr_[i].msg_len, false); |
+ IPEndPoint server_address(server_ip, port); |
+ processor->ProcessPacket(server_address, client_address, packet); |
+ } |
+ |
+ if (packets_dropped != nullptr) { |
+ QuicSocketUtils::GetOverflowFromMsghdr(&mmsg_hdr_[0].msg_hdr, |
+ packets_dropped); |
+ } |
+ |
+ return true; |
+#else |
+ LOG(FATAL) << "Unsupported"; |
+ return false; |
+#endif |
+} |
+ |
+/* static */ |
+bool QuicPacketReader::ReadAndDispatchSinglePacket( |
+ int fd, |
+ int port, |
+ ProcessPacketInterface* processor, |
+ QuicPacketCount* packets_dropped) { |
+ // Allocate some extra space so we can send an error if the packet is larger |
+ // than kMaxPacketSize. |
+ char buf[2 * kMaxPacketSize]; |
+ |
+ IPEndPoint client_address; |
+ IPAddressNumber server_ip; |
+ int bytes_read = QuicSocketUtils::ReadPacket( |
+ fd, buf, arraysize(buf), packets_dropped, &server_ip, &client_address); |
+ |
+ if (bytes_read < 0) { |
+ return false; // ReadPacket failed. |
+ } |
+ |
+ QuicEncryptedPacket packet(buf, bytes_read, false); |
+ IPEndPoint server_address(server_ip, port); |
+ processor->ProcessPacket(server_address, client_address, packet); |
+ |
+ // The socket read was successful, so return true even if packet dispatch |
+ // failed. |
+ return true; |
+} |
+ |
+} // namespace tools |
+ |
+} // namespace net |