diff --git a/p2p/base/dtls_transport.cc b/p2p/base/dtls_transport.cc index 172d06188f..ce2793cb46 100644 --- a/p2p/base/dtls_transport.cc +++ b/p2p/base/dtls_transport.cc @@ -93,12 +93,17 @@ rtc::StreamResult StreamInterfaceChannel::Write(const void* data, size_t* written, int* error) { RTC_DCHECK_RUN_ON(&sequence_checker_); - // Always succeeds, since this is an unreliable transport anyway. - // TODO(zhihuang): Should this block if ice_transport_'s temporarily - // unwritable? rtc::PacketOptions packet_options; - ice_transport_->SendPacket(static_cast(data), data_len, - packet_options); + int sent = ice_transport_->SendPacket(static_cast(data), + data_len, packet_options); + if (sent < 0) { + if (written) { + *written = 0; + } + return rtc::IsBlockingError(ice_transport_->GetError()) ? rtc::SR_BLOCK + : rtc::SR_ERROR; + } + if (written) { *written = data_len; } diff --git a/p2p/base/dtls_transport_unittest.cc b/p2p/base/dtls_transport_unittest.cc index 851c1ea131..4957b46a50 100644 --- a/p2p/base/dtls_transport_unittest.cc +++ b/p2p/base/dtls_transport_unittest.cc @@ -421,6 +421,16 @@ TEST_F(DtlsTransportTest, TestTransferDtls) { TestTransfer(1000, 100, /*srtp=*/false); } +// Connect with DTLS, and fail to write, to ensure errors are propagated. +TEST_F(DtlsTransportTest, TestWriteFailsOverDtls) { + PrepareDtls(rtc::KT_DEFAULT); + ASSERT_TRUE(Connect()); + client1_.fake_ice_transport()->SetError(EAGAIN); + int res = client1_.dtls_transport()->SendPacket("hello", 5, + rtc::PacketOptions(), 0); + EXPECT_EQ(res, -1); +} + // Connect with DTLS, combine multiple DTLS records into one packet. // Our DTLS implementation doesn't do this, but other implementations may; // see https://tools.ietf.org/html/rfc6347#section-4.1.1. diff --git a/p2p/base/fake_ice_transport.h b/p2p/base/fake_ice_transport.h index 8b52fe934c..7f934446e4 100644 --- a/p2p/base/fake_ice_transport.h +++ b/p2p/base/fake_ice_transport.h @@ -302,6 +302,10 @@ class FakeIceTransport : public IceTransportInternal { return -1; } + if (error_ != 0) { + return -1; + } + send_packet_.AppendData(data, len); if (!combine_outgoing_packets_ || send_packet_.size() > len) { rtc::CopyOnWriteBuffer packet(std::move(send_packet_)); @@ -338,7 +342,17 @@ class FakeIceTransport : public IceTransportInternal { } } - int GetError() override { return 0; } + // Sets the error that is returned by `GetError`. If an error is set (i.e. + // non-zero), `SendPacket` will return -1. + void SetError(int error) { + RTC_DCHECK_RUN_ON(network_thread_); + error_ = error; + } + + int GetError() override { + RTC_DCHECK_RUN_ON(network_thread_); + return error_; + } rtc::CopyOnWriteBuffer last_sent_packet() { RTC_DCHECK_RUN_ON(network_thread_); @@ -421,6 +435,7 @@ class FakeIceTransport : public IceTransportInternal { rtc::CopyOnWriteBuffer last_sent_packet_ RTC_GUARDED_BY(network_thread_); rtc::Thread* const network_thread_; webrtc::ScopedTaskSafetyDetached task_safety_; + int error_ RTC_GUARDED_BY(network_thread_) = 0; }; class FakeIceTransportWrapper : public webrtc::IceTransportInterface {