blob: 08a259578d071b42959080bb960aa8b96ec3c120 [file] [log] [blame]
// Copyright 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.
#ifndef QUICHE_QUIC_CORE_QUIC_UDP_SOCKET_H_
#define QUICHE_QUIC_CORE_QUIC_UDP_SOCKET_H_
#include <cstddef>
#include <cstdint>
#include <type_traits>
#include "quiche/quic/core/io/socket.h"
#include "quiche/quic/core/quic_types.h"
#include "quiche/quic/core/quic_utils.h"
#include "quiche/quic/platform/api/quic_ip_address.h"
#include "quiche/quic/platform/api/quic_socket_address.h"
#ifndef UDP_GRO
#define UDP_GRO 104
#endif
namespace quic {
using QuicUdpSocketFd = SocketFd;
inline constexpr QuicUdpSocketFd kQuicInvalidSocketFd = kInvalidSocketFd;
inline constexpr size_t kDefaultUdpPacketControlBufferSize = 512;
enum class QuicUdpPacketInfoBit : uint8_t {
DROPPED_PACKETS = 0, // Read
V4_SELF_IP, // Read
V6_SELF_IP, // Read
PEER_ADDRESS, // Read & Write
RECV_TIMESTAMP, // Read
TTL, // Read & Write
ECN, // Read
GOOGLE_PACKET_HEADER, // Read
NUM_BITS,
IS_GRO, // Read
};
static_assert(static_cast<size_t>(QuicUdpPacketInfoBit::NUM_BITS) <=
BitMask64::NumBits(),
"BitMask64 not wide enough to hold all bits.");
// BufferSpan points to an unowned buffer, copying this structure only copies
// the pointer and length, not the buffer itself.
struct QUIC_EXPORT_PRIVATE BufferSpan {
BufferSpan(char* buffer, size_t buffer_len)
: buffer(buffer), buffer_len(buffer_len) {}
BufferSpan() = default;
BufferSpan(const BufferSpan& other) = default;
BufferSpan& operator=(const BufferSpan& other) = default;
char* buffer = nullptr;
size_t buffer_len = 0;
};
// QuicUdpPacketInfo contains per-packet information used for sending and
// receiving.
class QUIC_EXPORT_PRIVATE QuicUdpPacketInfo {
public:
BitMask64 bitmask() const { return bitmask_; }
void Reset() { bitmask_.ClearAll(); }
bool HasValue(QuicUdpPacketInfoBit bit) const { return bitmask_.IsSet(bit); }
QuicPacketCount dropped_packets() const {
QUICHE_DCHECK(HasValue(QuicUdpPacketInfoBit::DROPPED_PACKETS));
return dropped_packets_;
}
void SetDroppedPackets(QuicPacketCount dropped_packets) {
dropped_packets_ = dropped_packets;
bitmask_.Set(QuicUdpPacketInfoBit::DROPPED_PACKETS);
}
void set_gso_size(size_t gso_size) {
gso_size_ = gso_size;
bitmask_.Set(QuicUdpPacketInfoBit::IS_GRO);
}
size_t gso_size() { return gso_size_; }
const QuicIpAddress& self_v4_ip() const {
QUICHE_DCHECK(HasValue(QuicUdpPacketInfoBit::V4_SELF_IP));
return self_v4_ip_;
}
void SetSelfV4Ip(QuicIpAddress self_v4_ip) {
self_v4_ip_ = self_v4_ip;
bitmask_.Set(QuicUdpPacketInfoBit::V4_SELF_IP);
}
const QuicIpAddress& self_v6_ip() const {
QUICHE_DCHECK(HasValue(QuicUdpPacketInfoBit::V6_SELF_IP));
return self_v6_ip_;
}
void SetSelfV6Ip(QuicIpAddress self_v6_ip) {
self_v6_ip_ = self_v6_ip;
bitmask_.Set(QuicUdpPacketInfoBit::V6_SELF_IP);
}
void SetSelfIp(QuicIpAddress self_ip) {
if (self_ip.IsIPv4()) {
SetSelfV4Ip(self_ip);
} else {
SetSelfV6Ip(self_ip);
}
}
const QuicSocketAddress& peer_address() const {
QUICHE_DCHECK(HasValue(QuicUdpPacketInfoBit::PEER_ADDRESS));
return peer_address_;
}
void SetPeerAddress(QuicSocketAddress peer_address) {
peer_address_ = peer_address;
bitmask_.Set(QuicUdpPacketInfoBit::PEER_ADDRESS);
}
QuicWallTime receive_timestamp() const {
QUICHE_DCHECK(HasValue(QuicUdpPacketInfoBit::RECV_TIMESTAMP));
return receive_timestamp_;
}
void SetReceiveTimestamp(QuicWallTime receive_timestamp) {
receive_timestamp_ = receive_timestamp;
bitmask_.Set(QuicUdpPacketInfoBit::RECV_TIMESTAMP);
}
int ttl() const {
QUICHE_DCHECK(HasValue(QuicUdpPacketInfoBit::TTL));
return ttl_;
}
void SetTtl(int ttl) {
ttl_ = ttl;
bitmask_.Set(QuicUdpPacketInfoBit::TTL);
}
BufferSpan google_packet_headers() const {
QUICHE_DCHECK(HasValue(QuicUdpPacketInfoBit::GOOGLE_PACKET_HEADER));
return google_packet_headers_;
}
void SetGooglePacketHeaders(BufferSpan google_packet_headers) {
google_packet_headers_ = google_packet_headers;
bitmask_.Set(QuicUdpPacketInfoBit::GOOGLE_PACKET_HEADER);
}
QuicEcnCodepoint ecn_codepoint() const { return ecn_codepoint_; }
void SetEcnCodepoint(const QuicEcnCodepoint ecn_codepoint) {
ecn_codepoint_ = ecn_codepoint;
bitmask_.Set(QuicUdpPacketInfoBit::ECN);
}
private:
BitMask64 bitmask_;
QuicPacketCount dropped_packets_;
QuicIpAddress self_v4_ip_;
QuicIpAddress self_v6_ip_;
QuicSocketAddress peer_address_;
QuicWallTime receive_timestamp_ = QuicWallTime::Zero();
int ttl_;
BufferSpan google_packet_headers_;
size_t gso_size_ = 0;
QuicEcnCodepoint ecn_codepoint_ = ECN_NOT_ECT;
};
// QuicUdpSocketApi provides a minimal set of apis for sending and receiving
// udp packets. The low level udp socket apis differ between kernels and kernel
// versions, the goal of QuicUdpSocketApi is to hide such differences.
// We use non-static functions because it is easier to be mocked in tests when
// needed.
class QUIC_EXPORT_PRIVATE QuicUdpSocketApi {
public:
// Creates a non-blocking udp socket, sets the receive/send buffer and enable
// receiving of self ip addresses on read.
// If address_family == AF_INET6 and ipv6_only is true, receiving of IPv4 self
// addresses is disabled. This is only necessary for IPv6 sockets on iOS - all
// other platforms can ignore this parameter. Return kQuicInvalidSocketFd if
// failed.
QuicUdpSocketFd Create(int address_family, int receive_buffer_size,
int send_buffer_size, bool ipv6_only = false);
// Closes |fd|. No-op if |fd| equals to kQuicInvalidSocketFd.
void Destroy(QuicUdpSocketFd fd);
// Bind |fd| to |address|. If |address|'s port number is 0, kernel will choose
// a random port to bind to. Caller can use QuicSocketAddress::FromSocket(fd)
// to get the bound random port.
bool Bind(QuicUdpSocketFd fd, QuicSocketAddress address);
// Bind |fd| to |interface_name|. Returns true if the setsockopt call
// succeeded. Returns false if |interface_name| is empty, its length exceeds
// IFNAMSIZ, or setsockopt experienced an error. Only implemented for
// non-Android Linux.
bool BindInterface(QuicUdpSocketFd fd, const std::string& interface_name);
// Enable receiving of various per-packet information. Return true if the
// corresponding information can be received on read.
bool EnableDroppedPacketCount(QuicUdpSocketFd fd);
bool EnableReceiveTimestamp(QuicUdpSocketFd fd);
bool EnableReceiveTtlForV4(QuicUdpSocketFd fd);
bool EnableReceiveTtlForV6(QuicUdpSocketFd fd);
// Wait for |fd| to become readable, up to |timeout|.
// Return true if |fd| is readable upon return.
bool WaitUntilReadable(QuicUdpSocketFd fd, QuicTime::Delta timeout);
struct QUIC_EXPORT_PRIVATE ReadPacketResult {
bool ok = false;
QuicUdpPacketInfo packet_info;
BufferSpan packet_buffer;
BufferSpan control_buffer;
void Reset(size_t packet_buffer_length) {
ok = false;
packet_info.Reset();
packet_buffer.buffer_len = packet_buffer_length;
}
};
// Read a packet from |fd|:
// packet_info_interested: Bitmask indicating what information caller wants to
// receive into |result->packet_info|.
// result->packet_info: Received per packet information.
// result->packet_buffer: The packet buffer, to be filled with packet data.
// |result->packet_buffer.buffer_len| is set to the
// packet length on a successful return.
// result->control_buffer: The control buffer, used by ReadPacket internally.
// It is recommended to be
// |kDefaultUdpPacketControlBufferSize| bytes.
// result->ok: True iff a packet is successfully received.
//
// If |*result| is reused for subsequent ReadPacket() calls, caller needs to
// call result->Reset() before each ReadPacket().
void ReadPacket(QuicUdpSocketFd fd, BitMask64 packet_info_interested,
ReadPacketResult* result);
using ReadPacketResults = std::vector<ReadPacketResult>;
// Read up to |results->size()| packets from |fd|. The meaning of each element
// in |*results| has been documented on top of |ReadPacket|.
// Return the number of elements populated into |*results|, note it is
// possible for some of the populated elements to have ok=false.
size_t ReadMultiplePackets(QuicUdpSocketFd fd,
BitMask64 packet_info_interested,
ReadPacketResults* results);
// Write a packet to |fd|.
// packet_buffer, packet_buffer_len: The packet buffer to write.
// packet_info: The per packet information to set.
WriteResult WritePacket(QuicUdpSocketFd fd, const char* packet_buffer,
size_t packet_buffer_len,
const QuicUdpPacketInfo& packet_info);
protected:
bool SetupSocket(QuicUdpSocketFd fd, int address_family,
int receive_buffer_size, int send_buffer_size,
bool ipv6_only);
bool EnableReceiveSelfIpAddressForV4(QuicUdpSocketFd fd);
bool EnableReceiveSelfIpAddressForV6(QuicUdpSocketFd fd);
};
} // namespace quic
#endif // QUICHE_QUIC_CORE_QUIC_UDP_SOCKET_H_