/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef RTC_BASE_ASYNC_PACKET_SOCKET_H_
#define RTC_BASE_ASYNC_PACKET_SOCKET_H_
#include <cstddef>
#include <cstdint>
#include <functional>
#include <span>
#include <utility>
#include <vector>
#include "absl/functional/any_invocable.h"
#include "api/sequence_checker.h"
#include "rtc_base/callback_list.h"
#include "rtc_base/dscp.h"
#include "rtc_base/network/received_packet.h"
#include "rtc_base/network/sent_packet.h"
#include "rtc_base/socket.h"
#include "rtc_base/socket_address.h"
#include "rtc_base/system/no_unique_address.h"
#include "rtc_base/system/rtc_export.h"
#include "rtc_base/thread_annotations.h"
namespace webrtc {
// This structure holds the info needed to update the packet send time header
// extension, including the information needed to update the authentication tag
// after changing the value.
struct PacketTimeUpdateParams {
PacketTimeUpdateParams();
PacketTimeUpdateParams(
const PacketTimeUpdateParams& other);
~PacketTimeUpdateParams();
int rtp_sendtime_extension_id = -
1;
// extension header id present in packet.
std::vector<
char> srtp_auth_key;
// Authentication key.
int srtp_auth_tag_len = -
1;
// Authentication tag length.
int64_t srtp_packet_index = -
1;
// Required for Rtp Packet authentication.
};
// This structure holds meta information for the packet which is about to send
// over network.
struct RTC_EXPORT AsyncSocketPacketOptions {
AsyncSocketPacketOptions();
explicit AsyncSocketPacketOptions(DiffServCodePoint dscp);
AsyncSocketPacketOptions(
const AsyncSocketPacketOptions& other);
~AsyncSocketPacketOptions();
DiffServCodePoint dscp = DSCP_NO_CHANGE;
// Packet will be sent with ECT(1), RFC-3168, Section 5.
// Intended to be used with L4S
// https://www.rfc-editor.org/rfc/rfc9331.html
bool ect_1 =
false;
// When used with RTP packets (for example, PacketOptions), the value
// should be 16 bits. A value of -1 represents "not set".
int64_t packet_id = -
1;
PacketTimeUpdateParams packet_time_params;
// PacketInfo is passed to SentPacket when signaling this packet is sent.
PacketInfo info_signaled_after_sent;
// True if this is a batchable packet. Batchable packets are collected at low
// levels and sent first when their AsyncPacketSocket receives a
// OnSendBatchComplete call.
bool batchable =
false;
// True if this is the last packet of a batch.
bool last_packet_in_batch =
false;
};
// Provides the ability to receive packets asynchronously. Sends are not
// buffered since it is acceptable to drop packets under high load.
class RTC_EXPORT AsyncPacketSocket {
public:
enum State {
STATE_CLOSED,
STATE_BINDING,
STATE_BOUND,
STATE_CONNECTING,
STATE_CONNECTED
};
AsyncPacketSocket() =
default;
virtual ~AsyncPacketSocket();
AsyncPacketSocket(
const AsyncPacketSocket&) =
delete;
AsyncPacketSocket&
operator=(
const AsyncPacketSocket&) =
delete;
// Returns current local address. Address may be set to null if the
// socket is not bound yet (GetState() returns STATE_BINDING).
virtual SocketAddress GetLocalAddress()
const =
0;
// Returns remote address. Returns zeroes if this is not a client TCP socket.
virtual SocketAddress GetRemoteAddress()
const =
0;
// Send a packet.
virtual int Send(
const void* pv,
size_t cb,
const AsyncSocketPacketOptions& options) =
0;
int Send(std::span<
const uint8_t> data,
const AsyncSocketPacketOptions& options) {
return Send(data.data(), data.size(), options);
}
virtual int SendTo(
const void* pv,
size_t cb,
const SocketAddress& addr,
const AsyncSocketPacketOptions& options) =
0;
int SendTo(std::span<
const uint8_t> data,
const SocketAddress& addr,
const AsyncSocketPacketOptions& options) {
return SendTo(data.data(), data.size(), addr, options);
}
// Close the socket.
virtual int Close() =
0;
// Returns current state of the socket.
virtual State GetState()
const =
0;
// Get/set options.
virtual int GetOption(Socket::Option opt,
int* value) =
0;
virtual int SetOption(Socket::Option opt,
int value) =
0;
// Get/Set current error.
// TODO: Remove SetError().
virtual int GetError()
const =
0;
virtual void SetError(
int error) =
0;
// Register a callback to be called when the socket is closed.
void SubscribeCloseEvent(
const void* removal_tag,
std::function<
void(AsyncPacketSocket*,
int)> callback);
void UnsubscribeCloseEvent(
const void* removal_tag);
void RegisterReceivedPacketCallback(
absl::AnyInvocable<
void(AsyncPacketSocket*,
const ReceivedIpPacket&)>
received_packet_callback);
void DeregisterReceivedPacketCallback();
// Emitted each time a packet is sent.
void SubscribeSentPacket(
void* tag,
absl::AnyInvocable<
void(AsyncPacketSocket*,
const SentPacketInfo&)>
callback);
void UnsubscribeSentPacket(
void* tag) {
sent_packet_callbacks_.RemoveReceivers(tag);
}
void NotifySentPacket(AsyncPacketSocket* socket,
const SentPacketInfo& info) {
sent_packet_callbacks_.Send(socket, info);
}
// Emitted when the socket is currently able to send.
void SubscribeReadyToSend(
void* tag,
absl::AnyInvocable<
void(AsyncPacketSocket*)> callback) {
ready_to_send_callbacks_.AddReceiver(tag, std::move(callback));
}
void UnsubscribeReadyToSend(
void* tag) {
ready_to_send_callbacks_.RemoveReceivers(tag);
}
void NotifyReadyToSend(AsyncPacketSocket* socket) {
ready_to_send_callbacks_.Send(socket);
}
// Emitted after address for the socket is allocated, i.e. binding
// is finished. State of the socket is changed from BINDING to BOUND
// (for UDP sockets).
void SubscribeAddressReady(
void* tag,
absl::AnyInvocable<
void(AsyncPacketSocket*,
const SocketAddress&)>
callback) {
address_ready_callbacks_.AddReceiver(tag, std::move(callback));
}
void UnsubscribeAddressReady(
void* tag) {
address_ready_callbacks_.RemoveReceivers(tag);
}
void NotifyAddressReady(AsyncPacketSocket* socket,
const SocketAddress& address) {
address_ready_callbacks_.Send(socket, address);
}
// Emitted for client TCP sockets when state is changed from
// CONNECTING to CONNECTED.
void NotifyConnect(AsyncPacketSocket* socket) {
connect_callbacks_.Send(socket);
}
[[deprecated]]
void SubscribeConnect(
absl::AnyInvocable<
void(AsyncPacketSocket*)> callback) {
connect_callbacks_.AddReceiver(std::move(callback));
}
void SubscribeConnect(
void* tag,
absl::AnyInvocable<
void(AsyncPacketSocket*)> callback) {
connect_callbacks_.AddReceiver(tag, std::move(callback));
}
void UnsubscribeConnect(
void* tag) {
connect_callbacks_.RemoveReceivers(tag);
}
void NotifyClosedForTest(
int err) { NotifyClosed(err); }
protected:
void NotifyClosed(
int err) {
RTC_DCHECK_RUN_ON(&network_checker_);
on_close_.Send(
this, err);
}
void NotifyPacketReceived(
const ReceivedIpPacket& packet);
RTC_NO_UNIQUE_ADDRESS SequenceChecker network_checker_{
SequenceChecker::kDetached};
private:
CallbackList<AsyncPacketSocket*,
int> on_close_
RTC_GUARDED_BY(&network_checker_);
absl::AnyInvocable<
void(AsyncPacketSocket*,
const ReceivedIpPacket&)>
received_packet_callback_ RTC_GUARDED_BY(&network_checker_);
CallbackList<AsyncPacketSocket*> connect_callbacks_;
CallbackList<AsyncPacketSocket*,
const SentPacketInfo&>
sent_packet_callbacks_;
CallbackList<AsyncPacketSocket*> ready_to_send_callbacks_;
CallbackList<AsyncPacketSocket*,
const SocketAddress&>
address_ready_callbacks_;
};
// Listen socket, producing an AsyncPacketSocket when a peer connects.
class RTC_EXPORT AsyncListenSocket {
public:
enum class State {
kClosed,
kBound,
};
AsyncListenSocket() =
default;
virtual ~AsyncListenSocket() =
default;
// Returns current state of the socket.
virtual State GetState()
const =
0;
// Returns current local address. Address may be set to null if the
// socket is not bound yet (GetState() returns kBinding).
virtual SocketAddress GetLocalAddress()
const =
0;
void SubscribeNewConnection(
void* tag,
absl::AnyInvocable<
void(AsyncListenSocket*, AsyncPacketSocket*)>
callback) {
new_connection_callbacks_.AddReceiver(tag, std::move(callback));
}
void UnsubscribeNewConnection(
void* tag) {
new_connection_callbacks_.RemoveReceivers(tag);
}
void NotifyNewConnection(AsyncListenSocket* listen_socket,
AsyncPacketSocket* packet_socket) {
new_connection_callbacks_.Send(listen_socket, packet_socket);
}
private:
CallbackList<AsyncListenSocket*, AsyncPacketSocket*>
new_connection_callbacks_;
};
void CopySocketInformationToPacketInfo(size_t packet_size_bytes,
const AsyncPacketSocket& socket_from,
PacketInfo* info);
}
// namespace webrtc
#endif // RTC_BASE_ASYNC_PACKET_SOCKET_H_