1
0
mirror of https://github.com/facebookincubator/mvfst.git synced 2025-11-25 15:43:13 +03:00
Files
mvfst/quic/common/udpsocket/FollyQuicAsyncUDPSocket.h
Joseph Beshay 58b6d8941b Add FollyQuicAsyncUDPSocket implementation
Summary: Introduces FollyQuicAsyncUDPSocket; a folly::AsyncUDPSocket wrapper that implements QuicAsyncUDPSocket that is driven by FollyQuicEventBase.

Reviewed By: mjoras, sharmafb

Differential Revision: D50809226

fbshipit-source-id: 8f4be11a48c0d5d170e9c117de12aba661cb9963
2023-12-14 00:24:12 -08:00

253 lines
7.7 KiB
C++

/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <quic/common/NetworkData.h>
#include <quic/common/events/FollyQuicEventBase.h>
#include <quic/common/udpsocket/QuicAsyncUDPSocketImpl.h>
#include <folly/io/async/AsyncUDPSocket.h>
#include <folly/net/NetworkSocket.h>
#include <cstddef>
#include <memory>
namespace quic {
// This alias is used by the server components that need functionality not yet
// exposed in the QuicAsyncUDPSocket interface.
// The alias was created to make it easier to find the occurences of
// folly::AsyncUDPSocket in the QUIC code.
using FollyAsyncUDPSocketAlias = folly::AsyncUDPSocket;
class FollyQuicAsyncUDPSocket : public QuicAsyncUDPSocketImpl {
public:
socklen_t kAddrLen = sizeof(sockaddr_storage);
FollyQuicAsyncUDPSocket(
std::shared_ptr<FollyQuicEventBase> qEvb,
folly::AsyncUDPSocket& socketToWrap)
: evb_(std::move(qEvb)), follySocket_(socketToWrap) {
CHECK_EQ(evb_->getBackingEventBase(), follySocket_.getEventBase());
}
FollyQuicAsyncUDPSocket(
std::shared_ptr<FollyQuicEventBase> qEvb,
std::unique_ptr<folly::AsyncUDPSocket> socketToWrap)
: evb_(std::move(qEvb)),
follySocketPtr(std::move(socketToWrap)),
follySocket_(*follySocketPtr) {
CHECK_EQ(evb_->getBackingEventBase(), follySocket_.getEventBase());
}
explicit FollyQuicAsyncUDPSocket(std::shared_ptr<FollyQuicEventBase> qEvb)
: evb_(std::move(qEvb)),
follySocketPtr(std::make_unique<folly::AsyncUDPSocket>(
evb_ ? evb_->getBackingEventBase() : nullptr)),
follySocket_(*follySocketPtr) {
if (evb_) {
CHECK_EQ(evb_->getBackingEventBase(), follySocket_.getEventBase());
}
}
void init(sa_family_t family) override;
void bind(const folly::SocketAddress& address) override;
[[nodiscard]] bool isBound() const override;
void connect(const folly::SocketAddress& address) override;
void close() override;
void resumeRead(ReadCallback* callback) override;
void pauseRead() override;
ssize_t write(
const folly::SocketAddress& address,
const std::unique_ptr<folly::IOBuf>& buf) override;
int writem(
folly::Range<folly::SocketAddress const*> addrs,
const std::unique_ptr<folly::IOBuf>* bufs,
size_t count) override;
ssize_t writeGSO(
const folly::SocketAddress& address,
const std::unique_ptr<folly::IOBuf>& buf,
WriteOptions options) override;
/**
* Send the data in buffers to destination. Returns the return code from
* ::sendmmsg.
* bufs is an array of std::unique_ptr<folly::IOBuf>
* of size num
* options is an array of WriteOptions or nullptr
* Before calling writeGSO with a positive value
* verify GSO is supported on this platform by calling getGSO
*/
int writemGSO(
folly::Range<folly::SocketAddress const*> addrs,
const std::unique_ptr<folly::IOBuf>* bufs,
size_t count,
const WriteOptions* options) override;
ssize_t recvmsg(struct msghdr* msg, int flags) override;
int recvmmsg(
struct mmsghdr* msgvec,
unsigned int vlen,
unsigned int flags,
struct timespec* timeout) override;
// generic segmentation offload get/set
// negative return value means GSO is not available
int getGSO() override;
// generic receive offload get/set
// negative return value means GRO is not available
int getGRO() override;
bool setGRO(bool bVal) override;
/**
* Returns the socket server is bound to
*/
[[nodiscard]] const folly::SocketAddress& address() const override;
/**
* Manage the eventbase driving this socket
*/
void attachEventBase(std::shared_ptr<QuicEventBase> evb) override;
void detachEventBase() override;
[[nodiscard]] std::shared_ptr<QuicEventBase> getEventBase() const override;
/**
* Set extra control messages to send
*/
void setCmsgs(const folly::SocketCmsgMap& cmsgs) override;
void appendCmsgs(const folly::SocketCmsgMap& cmsgs) override;
void setAdditionalCmsgsFunc(
folly::Function<folly::Optional<folly::SocketCmsgMap>()>&&
additionalCmsgsFunc) override;
/*
* Packet timestamping is currentl not supported.
*/
int getTimestamping() override;
/**
* Set SO_REUSEADDR flag on the socket. Default is OFF.
*/
void setReuseAddr(bool reuseAddr) override;
/**
* Set Dont-Fragment (DF) but ignore Path MTU.
*
* On Linux, this sets IP(V6)_MTU_DISCOVER to IP(V6)_PMTUDISC_PROBE.
* This essentially sets DF but ignores Path MTU for this socket.
* This may be desirable for apps that has its own PMTU Discovery mechanism.
* See http://man7.org/linux/man-pages/man7/ip.7.html for more info.
*/
void setDFAndTurnOffPMTU() override;
/**
* Callback for receiving errors on the UDP sockets
*/
void setErrMessageCallback(
ErrMessageCallback* /* errMessageCallback */) override;
void applyOptions(
const folly::SocketOptionMap& options,
folly::SocketOptionKey::ApplyPos pos) override;
/**
* Set reuse port mode to call bind() on the same address multiple times
*/
void setReusePort(bool reusePort) override;
/**
* Set SO_RCVBUF option on the socket, if not zero. Default is zero.
*/
void setRcvBuf(int rcvBuf) override;
/**
* Set SO_SNDBUF option on the socket, if not zero. Default is zero.
*/
void setSndBuf(int sndBuf) override;
/**
* Use an already bound file descriptor. You can either transfer ownership
* of this FD by using ownership = FDOwnership::OWNS or share it using
* FDOwnership::SHARED. In case FD is shared, it will not be `close`d in
* destructor.
*/
void setFD(int fd, FDOwnership ownership) override;
int getFD() override;
folly::AsyncUDPSocket& getFollySocket();
private:
class FollyReadCallbackWrapper : public folly::AsyncUDPSocket::ReadCallback {
public:
FollyReadCallbackWrapper(
QuicAsyncUDPSocket::ReadCallback* readCallback,
FollyQuicAsyncUDPSocket* parentSocket) {
CHECK(readCallback != nullptr);
CHECK(parentSocket != nullptr);
wrappedReadCallback_ = readCallback;
parentSocket_ = parentSocket;
}
void getReadBuffer(void** buf, size_t* len) noexcept override;
void onDataAvailable(
const folly::SocketAddress& client,
size_t len,
bool truncated,
folly::AsyncUDPSocket::ReadCallback::OnDataAvailableParams
params) noexcept override;
void onNotifyDataAvailable(folly::AsyncUDPSocket& socket) noexcept override;
bool shouldOnlyNotify() override;
void onReadError(const folly::AsyncSocketException& ex) noexcept override;
void onReadClosed() noexcept override;
private:
FollyQuicAsyncUDPSocket* parentSocket_ = nullptr;
QuicAsyncUDPSocket::ReadCallback* wrappedReadCallback_ = nullptr;
};
class FollyErrCallbackWrapper
: public folly::AsyncUDPSocket::ErrMessageCallback {
public:
explicit FollyErrCallbackWrapper(
QuicAsyncUDPSocket::ErrMessageCallback* errorCallback) {
CHECK(errorCallback != nullptr);
wrappedErrorCallback_ = errorCallback;
}
void errMessage(const cmsghdr& cmsg) noexcept override;
void errMessageError(
const folly::AsyncSocketException& ex) noexcept override;
QuicAsyncUDPSocket::ErrMessageCallback* wrappedErrorCallback_ = nullptr;
};
std::shared_ptr<FollyQuicEventBase> evb_{nullptr};
std::unique_ptr<FollyReadCallbackWrapper> readCallbackWrapper_{nullptr};
std::unique_ptr<FollyErrCallbackWrapper> errCallbackWrapper_{nullptr};
std::unique_ptr<folly::AsyncUDPSocket> follySocketPtr;
folly::AsyncUDPSocket& follySocket_;
};
} // namespace quic