blob: 7ebd15bca1de2532af040f16c9cea334e614bb1e [file] [log] [blame]
/*
* Copyright 2019 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 PC_DATAGRAM_DTLS_ADAPTOR_H_
#define PC_DATAGRAM_DTLS_ADAPTOR_H_
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "api/crypto/crypto_options.h"
#include "api/datagram_transport_interface.h"
#include "modules/rtp_rtcp/include/rtp_header_extension_map.h"
#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
#include "p2p/base/dtls_transport_internal.h"
#include "p2p/base/ice_transport_internal.h"
#include "p2p/base/packet_transport_internal.h"
#include "rtc_base/buffer.h"
#include "rtc_base/buffer_queue.h"
#include "rtc_base/constructor_magic.h"
#include "rtc_base/ssl_stream_adapter.h"
#include "rtc_base/stream.h"
#include "rtc_base/strings/string_builder.h"
#include "rtc_base/thread_checker.h"
namespace cricket {
constexpr int kDatagramDtlsAdaptorComponent = -1;
// DTLS wrapper around DatagramTransportInterface.
// Does not encrypt.
// Owns Datagram and Ice transports.
class DatagramDtlsAdaptor : public DtlsTransportInternal,
public webrtc::DatagramSinkInterface,
public webrtc::MediaTransportStateCallback {
public:
// TODO(sukhanov): Taking crypto options, because DtlsTransportInternal
// has a virtual getter crypto_options(). Consider removing getter and
// removing crypto_options from DatagramDtlsAdaptor.
DatagramDtlsAdaptor(
const std::vector<webrtc::RtpExtension>& rtp_header_extensions,
IceTransportInternal* ice_transport,
webrtc::DatagramTransportInterface* datagram_transport,
const webrtc::CryptoOptions& crypto_options,
webrtc::RtcEventLog* event_log);
~DatagramDtlsAdaptor() override;
// Connects to ICE transport callbacks.
void ConnectToIceTransport();
// =====================================================
// Overrides for webrtc::DatagramTransportSinkInterface
// and MediaTransportStateCallback
// =====================================================
void OnDatagramReceived(rtc::ArrayView<const uint8_t> data) override;
void OnDatagramSent(webrtc::DatagramId datagram_id) override;
void OnDatagramAcked(const webrtc::DatagramAck& ack) override;
void OnDatagramLost(webrtc::DatagramId datagram_id) override;
void OnStateChanged(webrtc::MediaTransportState state) override;
// =====================================================
// DtlsTransportInternal overrides
// =====================================================
const webrtc::CryptoOptions& crypto_options() const override;
DtlsTransportState dtls_state() const override;
int component() const override;
bool IsDtlsActive() const override;
bool GetDtlsRole(rtc::SSLRole* role) const override;
bool SetDtlsRole(rtc::SSLRole role) override;
bool GetSrtpCryptoSuite(int* cipher) override;
bool GetSslCipherSuite(int* cipher) override;
rtc::scoped_refptr<rtc::RTCCertificate> GetLocalCertificate() const override;
bool SetLocalCertificate(
const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) override;
std::unique_ptr<rtc::SSLCertChain> GetRemoteSSLCertChain() const override;
bool ExportKeyingMaterial(const std::string& label,
const uint8_t* context,
size_t context_len,
bool use_context,
uint8_t* result,
size_t result_len) override;
bool SetRemoteFingerprint(const std::string& digest_alg,
const uint8_t* digest,
size_t digest_len) override;
bool SetSslMaxProtocolVersion(rtc::SSLProtocolVersion version) override;
IceTransportInternal* ice_transport() override;
const std::string& transport_name() const override;
bool writable() const override;
bool receiving() const override;
private:
// RTP/RTCP packet info stored for each sent packet.
struct SentPacketInfo {
// RTP packet info with ssrc and transport sequence number.
SentPacketInfo(int64_t packet_id,
uint32_t ssrc,
uint16_t transport_sequence_number)
: ssrc(ssrc),
transport_sequence_number(transport_sequence_number),
packet_id(packet_id) {}
// Packet info without SSRC and transport sequence number used for RTCP
// packets, RTP packets when transport sequence number is not provided or
// when feedback translation is disabled.
explicit SentPacketInfo(int64_t packet_id) : packet_id(packet_id) {}
SentPacketInfo() = default;
absl::optional<uint32_t> ssrc;
// Transport sequence number (if it was provided in outgoing RTP packet).
// It is used to re-create RTCP feedback packets from datagram ACKs.
absl::optional<uint16_t> transport_sequence_number;
// Packet id from rtc::PacketOptions. It is required to propagage sent
// notification up the stack (SignalSentPacket).
int64_t packet_id = 0;
};
// Finds SentPacketInfo for given |datagram_id| and removes map entry.
// Returns false if entry was not found.
bool GetAndRemoveSentPacketInfo(webrtc::DatagramId datagram_id,
SentPacketInfo* sent_packet_info);
// Sends datagram to datagram_transport.
int SendDatagram(rtc::ArrayView<const uint8_t> data,
webrtc::DatagramId datagram_id);
void set_receiving(bool receiving);
void set_writable(bool writable);
void set_dtls_state(DtlsTransportState state);
// Forwards incoming packet up the stack.
void PropagateReadPacket(rtc::ArrayView<const uint8_t> data,
const int64_t& packet_time_us);
// Signals SentPacket notification.
void PropagateOnSentNotification(const rtc::SentPacket& sent_packet);
// Listens to read packet notifications from ICE (only used in bypass mode).
void OnReadPacket(rtc::PacketTransportInternal* transport,
const char* data,
size_t size,
const int64_t& packet_time_us,
int flags);
void OnReadyToSend(rtc::PacketTransportInternal* transport);
void OnWritableState(rtc::PacketTransportInternal* transport);
void OnNetworkRouteChanged(absl::optional<rtc::NetworkRoute> network_route);
void OnReceivingState(rtc::PacketTransportInternal* transport);
int SendPacket(const char* data,
size_t len,
const rtc::PacketOptions& options,
int flags) override;
int SetOption(rtc::Socket::Option opt, int value) override;
int GetError() override;
void OnSentPacket(rtc::PacketTransportInternal* transport,
const rtc::SentPacket& sent_packet);
rtc::ThreadChecker thread_checker_;
webrtc::CryptoOptions crypto_options_;
IceTransportInternal* ice_transport_;
webrtc::DatagramTransportInterface* datagram_transport_;
// Current ICE writable state. Must be modified by calling set_ice_writable(),
// which propagates change notifications.
bool writable_ = false;
// Current receiving state. Must be modified by calling set_receiving(), which
// propagates change notifications.
bool receiving_ = false;
// Current DTLS state. Must be modified by calling set_dtls_state(), which
// propagates change notifications.
DtlsTransportState dtls_state_ = DTLS_TRANSPORT_NEW;
webrtc::RtcEventLog* const event_log_;
// Extension map for parsing transport sequence numbers.
webrtc::RtpHeaderExtensionMap rtp_header_extension_map_;
// Keeps information about sent RTP packet until they are Acked or Lost.
std::map<webrtc::DatagramId, SentPacketInfo> sent_rtp_packet_map_;
// Current datagram_id, incremented after each sent RTP packets.
// Datagram id is passed to datagram transport when we send datagram and we
// get it back in notifications about Sent, Acked and Lost datagrams.
int64_t current_datagram_id_ = 0;
// TODO(sukhanov): Previous nonzero timestamp is required for workaround for
// zero timestamps received, which sometimes are received from datagram
// transport. Investigate if we can eliminate zero timestamps.
int64_t previous_nonzero_timestamp_us_ = 0;
// Disable datagram to RTCP feedback translation and enable RTCP feedback
// loop (note that having both RTCP and datagram feedback loops is
// inefficient, but can be useful in tests and experiments).
const bool disable_datagram_to_rtcp_feeback_translation_;
};
} // namespace cricket
#endif // PC_DATAGRAM_DTLS_ADAPTOR_H_