diff --git a/BUILD.gn b/BUILD.gn index 34c0c30716..baf8b0951d 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -608,6 +608,7 @@ if (rtc_include_tests && !build_with_chromium) { "p2p:libstunprober_unittests", "p2p:rtc_p2p_unittests", "rtc_base:async_dns_resolver_unittests", + "rtc_base:async_packet_socket_unittest", "rtc_base:callback_list_unittests", "rtc_base:rtc_base_approved_unittests", "rtc_base:rtc_base_unittests", diff --git a/p2p/base/port_unittest.cc b/p2p/base/port_unittest.cc index 1d482c4e26..f3a01d08cd 100644 --- a/p2p/base/port_unittest.cc +++ b/p2p/base/port_unittest.cc @@ -266,14 +266,14 @@ static void SendPingAndReceiveResponse(Connection* lconn, lconn->Ping(rtc::TimeMillis()); ASSERT_TRUE_WAIT(lport->last_stun_msg(), kDefaultTimeout); ASSERT_GT(lport->last_stun_buf().size(), 0u); - rconn->OnReadPacket( - rtc::ReceivedPacket(lport->last_stun_buf(), absl::nullopt)); + rconn->OnReadPacket(rtc::ReceivedPacket(lport->last_stun_buf(), + rtc::SocketAddress(), absl::nullopt)); clock->AdvanceTime(webrtc::TimeDelta::Millis(ms)); ASSERT_TRUE_WAIT(rport->last_stun_msg(), kDefaultTimeout); ASSERT_GT(rport->last_stun_buf().size(), 0u); - lconn->OnReadPacket( - rtc::ReceivedPacket(rport->last_stun_buf(), absl::nullopt)); + lconn->OnReadPacket(rtc::ReceivedPacket(rport->last_stun_buf(), + rtc::SocketAddress(), absl::nullopt)); } class TestChannel : public sigslot::has_slots<> { @@ -1494,8 +1494,8 @@ TEST_F(PortTest, TestLoopbackCall) { ASSERT_TRUE_WAIT(lport->last_stun_msg() != NULL, kDefaultTimeout); IceMessage* msg = lport->last_stun_msg(); EXPECT_EQ(STUN_BINDING_REQUEST, msg->type()); - conn->OnReadPacket( - rtc::ReceivedPacket(lport->last_stun_buf(), absl::nullopt)); + conn->OnReadPacket(rtc::ReceivedPacket(lport->last_stun_buf(), + rtc::SocketAddress(), absl::nullopt)); ASSERT_TRUE_WAIT(lport->last_stun_msg() != NULL, kDefaultTimeout); msg = lport->last_stun_msg(); EXPECT_EQ(STUN_BINDING_RESPONSE, msg->type()); @@ -1528,10 +1528,8 @@ TEST_F(PortTest, TestLoopbackCall) { lport->Reset(); auto buf = std::make_unique(); WriteStunMessage(*modified_req, buf.get()); - conn1->OnReadPacket( - rtc::ReceivedPacket(rtc::reinterpret_array_view( - rtc::MakeArrayView(buf->Data(), buf->Length())), - absl::nullopt)); + conn1->OnReadPacket(rtc::ReceivedPacket::CreateFromLegacy( + buf->Data(), buf->Length(), /*packet_time_us=*/-1)); ASSERT_TRUE_WAIT(lport->last_stun_msg() != NULL, kDefaultTimeout); msg = lport->last_stun_msg(); EXPECT_EQ(STUN_BINDING_ERROR_RESPONSE, msg->type()); @@ -1564,8 +1562,8 @@ TEST_F(PortTest, TestIceRoleConflict) { IceMessage* msg = rport->last_stun_msg(); EXPECT_EQ(STUN_BINDING_REQUEST, msg->type()); // Send rport binding request to lport. - lconn->OnReadPacket( - rtc::ReceivedPacket(rport->last_stun_buf(), absl::nullopt)); + lconn->OnReadPacket(rtc::ReceivedPacket(rport->last_stun_buf(), + rtc::SocketAddress(), absl::nullopt)); ASSERT_TRUE_WAIT(lport->last_stun_msg() != NULL, kDefaultTimeout); EXPECT_EQ(STUN_BINDING_RESPONSE, lport->last_stun_msg()->type()); @@ -1897,14 +1895,14 @@ TEST_F(PortTest, TestSendStunMessage) { std::unique_ptr request = CopyStunMessage(*msg); // Receive the BINDING-REQUEST and respond with BINDING-RESPONSE. - rconn->OnReadPacket( - rtc::ReceivedPacket(lport->last_stun_buf(), absl::nullopt)); + rconn->OnReadPacket(rtc::ReceivedPacket(lport->last_stun_buf(), + rtc::SocketAddress(), absl::nullopt)); msg = rport->last_stun_msg(); ASSERT_TRUE(msg != NULL); EXPECT_EQ(STUN_BINDING_RESPONSE, msg->type()); // Received a BINDING-RESPONSE. - lconn->OnReadPacket( - rtc::ReceivedPacket(rport->last_stun_buf(), absl::nullopt)); + lconn->OnReadPacket(rtc::ReceivedPacket(rport->last_stun_buf(), + rtc::SocketAddress(), absl::nullopt)); // Verify the STUN Stats. EXPECT_EQ(1U, lconn->stats().sent_ping_requests_total); @@ -1984,12 +1982,12 @@ TEST_F(PortTest, TestSendStunMessage) { // Respond with a BINDING-RESPONSE. request = CopyStunMessage(*msg); - lconn->OnReadPacket( - rtc::ReceivedPacket(rport->last_stun_buf(), absl::nullopt)); + lconn->OnReadPacket(rtc::ReceivedPacket(rport->last_stun_buf(), + rtc::SocketAddress(), absl::nullopt)); msg = lport->last_stun_msg(); // Receive the BINDING-RESPONSE. - rconn->OnReadPacket( - rtc::ReceivedPacket(lport->last_stun_buf(), absl::nullopt)); + rconn->OnReadPacket(rtc::ReceivedPacket(lport->last_stun_buf(), + rtc::SocketAddress(), absl::nullopt)); // Verify the Stun ping stats. EXPECT_EQ(3U, rconn->stats().sent_ping_requests_total); @@ -2040,8 +2038,8 @@ TEST_F(PortTest, TestNomination) { lconn->Ping(0); ASSERT_TRUE_WAIT(lport->last_stun_msg(), kDefaultTimeout); ASSERT_GT(lport->last_stun_buf().size(), 0u); - rconn->OnReadPacket( - rtc::ReceivedPacket(lport->last_stun_buf(), absl::nullopt)); + rconn->OnReadPacket(rtc::ReceivedPacket(lport->last_stun_buf(), + rtc::SocketAddress(), absl::nullopt)); EXPECT_EQ(nomination, rconn->remote_nomination()); EXPECT_FALSE(lconn->nominated()); @@ -2053,8 +2051,8 @@ TEST_F(PortTest, TestNomination) { // updating the acknowledged nomination of `lconn`. ASSERT_TRUE_WAIT(rport->last_stun_msg(), kDefaultTimeout); ASSERT_GT(rport->last_stun_buf().size(), 0u); - lconn->OnReadPacket( - rtc::ReceivedPacket(rport->last_stun_buf(), absl::nullopt)); + lconn->OnReadPacket(rtc::ReceivedPacket(rport->last_stun_buf(), + rtc::SocketAddress(), absl::nullopt)); EXPECT_EQ(nomination, lconn->acked_nomination()); EXPECT_TRUE(lconn->nominated()); @@ -2181,8 +2179,8 @@ TEST_F(PortTest, TestNetworkCostChange) { IceMessage* msg = lport->last_stun_msg(); EXPECT_EQ(STUN_BINDING_REQUEST, msg->type()); // Pass the binding request to rport. - rconn->OnReadPacket( - rtc::ReceivedPacket(lport->last_stun_buf(), absl::nullopt)); + rconn->OnReadPacket(rtc::ReceivedPacket(lport->last_stun_buf(), + rtc::SocketAddress(), absl::nullopt)); // Wait until rport sends the response and then check the remote network cost. ASSERT_TRUE_WAIT(rport->last_stun_msg() != NULL, kDefaultTimeout); @@ -2512,8 +2510,8 @@ TEST_F(PortTest, // Send request. lconn->Ping(0); ASSERT_TRUE_WAIT(lport->last_stun_msg() != NULL, kDefaultTimeout); - rconn->OnReadPacket( - rtc::ReceivedPacket(lport->last_stun_buf(), absl::nullopt)); + rconn->OnReadPacket(rtc::ReceivedPacket(lport->last_stun_buf(), + rtc::SocketAddress(), absl::nullopt)); // Intercept request and add comprehension required attribute. ASSERT_TRUE_WAIT(rport->last_stun_msg() != NULL, kDefaultTimeout); @@ -2523,10 +2521,8 @@ TEST_F(PortTest, modified_response->AddFingerprint(); ByteBufferWriter buf; WriteStunMessage(*modified_response, &buf); - lconn->OnReadPacket( - rtc::ReceivedPacket(rtc::reinterpret_array_view( - rtc::MakeArrayView(buf.Data(), buf.Length())), - absl::nullopt)); + lconn->OnReadPacket(rtc::ReceivedPacket::CreateFromLegacy( + buf.Data(), buf.Length(), /*packet_time_us=*/-1)); // Response should have been ignored, leaving us unwritable still. EXPECT_FALSE(lconn->writable()); } @@ -2554,10 +2550,8 @@ TEST_F(PortTest, in_msg->AddFingerprint(); ByteBufferWriter buf; WriteStunMessage(*in_msg, &buf); - lconn->OnReadPacket( - rtc::ReceivedPacket(rtc::reinterpret_array_view( - rtc::MakeArrayView(buf.Data(), buf.Length())), - absl::nullopt)); + lconn->OnReadPacket(rtc::ReceivedPacket::CreateFromLegacy( + buf.Data(), buf.Length(), /*packet_time_us=*/-1)); EXPECT_EQ(0u, lconn->last_ping_received()); } @@ -2603,8 +2597,8 @@ TEST_F(PortTest, TestHandleStunBindingIndication) { IceMessage* msg = rport->last_stun_msg(); EXPECT_EQ(STUN_BINDING_REQUEST, msg->type()); // Send rport binding request to lport. - lconn->OnReadPacket( - rtc::ReceivedPacket(rport->last_stun_buf(), absl::nullopt)); + lconn->OnReadPacket(rtc::ReceivedPacket(rport->last_stun_buf(), + rtc::SocketAddress(), absl::nullopt)); ASSERT_TRUE_WAIT(lport->last_stun_msg() != NULL, kDefaultTimeout); EXPECT_EQ(STUN_BINDING_RESPONSE, lport->last_stun_msg()->type()); @@ -2613,10 +2607,8 @@ TEST_F(PortTest, TestHandleStunBindingIndication) { // Adding a delay of 100ms. rtc::Thread::Current()->ProcessMessages(100); // Pinging lconn using stun indication message. - lconn->OnReadPacket( - rtc::ReceivedPacket(rtc::reinterpret_array_view( - rtc::MakeArrayView(buf->Data(), buf->Length())), - absl::nullopt)); + lconn->OnReadPacket(rtc::ReceivedPacket::CreateFromLegacy( + buf->Data(), buf->Length(), /*packet_time_us=*/-1)); int64_t last_ping_received2 = lconn->last_ping_received(); EXPECT_GT(last_ping_received2, last_ping_received1); } @@ -3113,8 +3105,8 @@ TEST_F(PortTest, TestIceLiteConnectivity) { con->SendStunBindingResponse(request.get()); // Feeding the respone message from litemode to the full mode connection. - ch1.conn()->OnReadPacket( - rtc::ReceivedPacket(ice_lite_port->last_stun_buf(), absl::nullopt)); + ch1.conn()->OnReadPacket(rtc::ReceivedPacket( + ice_lite_port->last_stun_buf(), rtc::SocketAddress(), absl::nullopt)); // Verifying full mode connection becomes writable from the response. EXPECT_EQ_WAIT(Connection::STATE_WRITABLE, ch1.conn()->write_state(), @@ -3231,8 +3223,8 @@ TEST_P(GoogPingTest, TestGoogPingAnnounceEnable) { GetSupportedGoogPingVersion(response) >= kGoogPingVersion); // Feeding the respone message back. - ch1.conn()->OnReadPacket( - rtc::ReceivedPacket(port2->last_stun_buf(), absl::nullopt)); + ch1.conn()->OnReadPacket(rtc::ReceivedPacket( + port2->last_stun_buf(), rtc::SocketAddress(), absl::nullopt)); port1->Reset(); port2->Reset(); @@ -3415,10 +3407,8 @@ TEST_F(PortTest, TestGoogPingUnsupportedVersionInStunBindingResponse) { modified_response->Write(&buf); // Feeding the modified respone message back. - ch1.conn()->OnReadPacket( - rtc::ReceivedPacket(rtc::reinterpret_array_view( - rtc::MakeArrayView(buf.Data(), buf.Length())), - absl::nullopt)); + ch1.conn()->OnReadPacket(rtc::ReceivedPacket::CreateFromLegacy( + buf.Data(), buf.Length(), /*packet_time_us=*/-1)); port1->Reset(); port2->Reset(); @@ -3490,8 +3480,8 @@ TEST_F(PortTest, TestChangeInAttributeMakesGoogPingFallsbackToStunBinding) { ASSERT_TRUE(GetSupportedGoogPingVersion(response) >= kGoogPingVersion); // Feeding the respone message back. - ch1.conn()->OnReadPacket( - rtc::ReceivedPacket(port2->last_stun_buf(), absl::nullopt)); + ch1.conn()->OnReadPacket(rtc::ReceivedPacket( + port2->last_stun_buf(), rtc::SocketAddress(), absl::nullopt)); port1->Reset(); port2->Reset(); @@ -3575,8 +3565,8 @@ TEST_F(PortTest, TestErrorResponseMakesGoogPingFallBackToStunBinding) { ASSERT_TRUE(GetSupportedGoogPingVersion(response) >= kGoogPingVersion); // Feeding the respone message back. - ch1.conn()->OnReadPacket( - rtc::ReceivedPacket(port2->last_stun_buf(), absl::nullopt)); + ch1.conn()->OnReadPacket(rtc::ReceivedPacket( + port2->last_stun_buf(), rtc::SocketAddress(), absl::nullopt)); port1->Reset(); port2->Reset(); @@ -3602,10 +3592,8 @@ TEST_F(PortTest, TestErrorResponseMakesGoogPingFallBackToStunBinding) { rtc::ByteBufferWriter buf; error_response.Write(&buf); - ch1.conn()->OnReadPacket( - rtc::ReceivedPacket(rtc::reinterpret_array_view( - rtc::MakeArrayView(buf.Data(), buf.Length())), - absl::nullopt)); + ch1.conn()->OnReadPacket(rtc::ReceivedPacket::CreateFromLegacy( + buf.Data(), buf.Length(), /*packet_time_us=*/-1)); // And now the third ping...this should be a binding. port1->Reset(); @@ -3842,8 +3830,8 @@ class ConnectionTest : public PortTest { lconn->Ping(rtc::TimeMillis()); ASSERT_TRUE_WAIT(lport->last_stun_msg(), kDefaultTimeout); ASSERT_GT(lport->last_stun_buf().size(), 0u); - rconn->OnReadPacket( - rtc::ReceivedPacket(lport->last_stun_buf(), absl::nullopt)); + rconn->OnReadPacket(rtc::ReceivedPacket( + lport->last_stun_buf(), rtc::SocketAddress(), absl::nullopt)); clock_.AdvanceTime(webrtc::TimeDelta::Millis(ms)); ASSERT_TRUE_WAIT(rport->last_stun_msg(), kDefaultTimeout); @@ -3857,7 +3845,8 @@ class ConnectionTest : public PortTest { rtc::BufferT reply; SendPingAndCaptureReply(lconn, rconn, ms, &reply); - lconn->OnReadPacket(rtc::ReceivedPacket(reply, absl::nullopt)); + lconn->OnReadPacket( + rtc::ReceivedPacket(reply, rtc::SocketAddress(), absl::nullopt)); } void OnConnectionStateChange(Connection* connection) { num_state_changes_++; } @@ -3918,7 +3907,8 @@ TEST_F(ConnectionTest, ConnectionForgetLearnedStateDiscardsPendingPings) { EXPECT_FALSE(lconn->writable()); EXPECT_FALSE(lconn->receiving()); - lconn->OnReadPacket(rtc::ReceivedPacket(reply, absl::nullopt)); + lconn->OnReadPacket( + rtc::ReceivedPacket(reply, rtc::SocketAddress(), absl::nullopt)); // That reply was discarded due to the ForgetLearnedState() while it was // outstanding. @@ -3990,15 +3980,15 @@ TEST_F(ConnectionTest, SendReceiveGoogDelta) { lconn->Ping(rtc::TimeMillis(), std::move(delta)); ASSERT_TRUE_WAIT(lport_->last_stun_msg(), kDefaultTimeout); ASSERT_GT(lport_->last_stun_buf().size(), 0u); - rconn->OnReadPacket( - rtc::ReceivedPacket(lport_->last_stun_buf(), absl::nullopt)); + rconn->OnReadPacket(rtc::ReceivedPacket(lport_->last_stun_buf(), + rtc::SocketAddress(), absl::nullopt)); EXPECT_TRUE(received_goog_delta); clock_.AdvanceTime(webrtc::TimeDelta::Millis(ms)); ASSERT_TRUE_WAIT(rport_->last_stun_msg(), kDefaultTimeout); ASSERT_GT(rport_->last_stun_buf().size(), 0u); - lconn->OnReadPacket( - rtc::ReceivedPacket(rport_->last_stun_buf(), absl::nullopt)); + lconn->OnReadPacket(rtc::ReceivedPacket(rport_->last_stun_buf(), + rtc::SocketAddress(), absl::nullopt)); EXPECT_TRUE(received_goog_delta_ack); } @@ -4028,14 +4018,14 @@ TEST_F(ConnectionTest, SendGoogDeltaNoReply) { lconn->Ping(rtc::TimeMillis(), std::move(delta)); ASSERT_TRUE_WAIT(lport_->last_stun_msg(), kDefaultTimeout); ASSERT_GT(lport_->last_stun_buf().size(), 0u); - rconn->OnReadPacket( - rtc::ReceivedPacket(lport_->last_stun_buf(), absl::nullopt)); + rconn->OnReadPacket(rtc::ReceivedPacket(lport_->last_stun_buf(), + rtc::SocketAddress(), absl::nullopt)); clock_.AdvanceTime(webrtc::TimeDelta::Millis(ms)); ASSERT_TRUE_WAIT(rport_->last_stun_msg(), kDefaultTimeout); ASSERT_GT(rport_->last_stun_buf().size(), 0u); - lconn->OnReadPacket( - rtc::ReceivedPacket(rport_->last_stun_buf(), absl::nullopt)); + lconn->OnReadPacket(rtc::ReceivedPacket(rport_->last_stun_buf(), + rtc::SocketAddress(), absl::nullopt)); EXPECT_TRUE(received_goog_delta_ack_error); } diff --git a/rtc_base/BUILD.gn b/rtc_base/BUILD.gn index ac237ed4c8..9cf0522164 100644 --- a/rtc_base/BUILD.gn +++ b/rtc_base/BUILD.gn @@ -1369,10 +1369,12 @@ rtc_library("async_packet_socket") { ] deps = [ ":callback_list", + ":checks", ":dscp", ":socket", ":timeutils", "../api:sequence_checker", + "network:received_packet", "network:sent_packet", "system:no_unique_address", "system:rtc_export", @@ -1380,6 +1382,21 @@ rtc_library("async_packet_socket") { ] } +if (rtc_include_tests) { + rtc_library("async_packet_socket_unittest") { + testonly = true + visibility = [ "*" ] + sources = [ "async_packet_socket_unittest.cc" ] + deps = [ + ":async_packet_socket", + ":gunit_helpers", + "../test:test_support", + "network:received_packet", + "third_party/sigslot", + ] + } +} + rtc_library("mdns_responder_interface") { sources = [ "mdns_responder_interface.h" ] deps = [ ":ip_address" ] diff --git a/rtc_base/async_packet_socket.cc b/rtc_base/async_packet_socket.cc index f50138cb62..3721366099 100644 --- a/rtc_base/async_packet_socket.cc +++ b/rtc_base/async_packet_socket.cc @@ -10,6 +10,8 @@ #include "rtc_base/async_packet_socket.h" +#include "rtc_base/checks.h" + namespace rtc { PacketTimeUpdateParams::PacketTimeUpdateParams() = default; @@ -38,6 +40,41 @@ void AsyncPacketSocket::UnsubscribeCloseEvent(const void* removal_tag) { on_close_.RemoveReceivers(removal_tag); } +void AsyncPacketSocket::RegisterReceivedPacketCallback( + absl::AnyInvocable + received_packet_callback) { + RTC_DCHECK_RUN_ON(&network_checker_); + RTC_CHECK(!received_packet_callback_); + SignalReadPacket.connect(this, &AsyncPacketSocket::NotifyPacketReceived); + received_packet_callback_ = std::move(received_packet_callback); +} + +void AsyncPacketSocket::DeregisterReceivedPacketCallback() { + RTC_DCHECK_RUN_ON(&network_checker_); + SignalReadPacket.disconnect(this); + received_packet_callback_ = nullptr; +} + +void AsyncPacketSocket::NotifyPacketReceived( + const rtc::ReceivedPacket& packet) { + RTC_DCHECK_RUN_ON(&network_checker_); + if (received_packet_callback_) { + received_packet_callback_(this, packet); + return; + } + if (SignalReadPacket.is_empty()) { + RTC_DCHECK_NOTREACHED() << " No listener registered"; + return; + } + // TODO(bugs.webrtc.org:15368): Remove. This code path is only used if + // SignalReadyPacket is used by clients to get notification of received + // packets but actual socket implementation use NotifyPacketReceived to + // trigger the notification. + SignalReadPacket(this, reinterpret_cast(packet.payload().data()), + packet.payload().size(), packet.source_address(), + packet.arrival_time() ? packet.arrival_time()->us() : -1); +} + void CopySocketInformationToPacketInfo(size_t packet_size_bytes, const AsyncPacketSocket& socket_from, bool is_connectionless, diff --git a/rtc_base/async_packet_socket.h b/rtc_base/async_packet_socket.h index 0d3ceb94e7..768fcd446b 100644 --- a/rtc_base/async_packet_socket.h +++ b/rtc_base/async_packet_socket.h @@ -11,11 +11,13 @@ #ifndef RTC_BASE_ASYNC_PACKET_SOCKET_H_ #define RTC_BASE_ASYNC_PACKET_SOCKET_H_ +#include #include #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/system/no_unique_address.h" @@ -115,8 +117,14 @@ class RTC_EXPORT AsyncPacketSocket : public sigslot::has_slots<> { std::function callback); void UnsubscribeCloseEvent(const void* removal_tag); + void RegisterReceivedPacketCallback( + absl::AnyInvocable + received_packet_callback); + void DeregisterReceivedPacketCallback(); + // Emitted each time a packet is read. Used only for UDP and // connected TCP sockets. + // TODO(bugs.webrtc.org:15368): Deprecate and remove. sigslot::signal5 { on_close_.Send(this, err); } + // TODO(bugs.webrtc.org:15368): Deprecate and remove. + void NotifyPacketReceived(AsyncPacketSocket*, + const char* data, + size_t size, + const SocketAddress& address, + const int64_t& packet_time_us) { + NotifyPacketReceived( + ReceivedPacket::CreateFromLegacy(data, size, packet_time_us, address)); + } + + void NotifyPacketReceived(const rtc::ReceivedPacket& packet); + RTC_NO_UNIQUE_ADDRESS webrtc::SequenceChecker network_checker_{ webrtc::SequenceChecker::kDetached}; private: webrtc::CallbackList on_close_ RTC_GUARDED_BY(&network_checker_); + absl::AnyInvocable + received_packet_callback_ RTC_GUARDED_BY(&network_checker_); }; // Listen socket, producing an AsyncPacketSocket when a peer connects. diff --git a/rtc_base/async_packet_socket_unittest.cc b/rtc_base/async_packet_socket_unittest.cc new file mode 100644 index 0000000000..6cd4f09459 --- /dev/null +++ b/rtc_base/async_packet_socket_unittest.cc @@ -0,0 +1,110 @@ +/* + * Copyright 2023 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. + */ + +#include "rtc_base/async_packet_socket.h" + +#include "rtc_base/third_party/sigslot/sigslot.h" +#include "test/gmock.h" +#include "test/gtest.h" + +namespace rtc { +namespace { + +using ::testing::MockFunction; + +class MockAsyncPacketSocket : public rtc::AsyncPacketSocket { + public: + ~MockAsyncPacketSocket() = default; + + MOCK_METHOD(SocketAddress, GetLocalAddress, (), (const, override)); + MOCK_METHOD(SocketAddress, GetRemoteAddress, (), (const, override)); + MOCK_METHOD(int, + Send, + (const void* pv, size_t cb, const rtc::PacketOptions& options), + (override)); + + MOCK_METHOD(int, + SendTo, + (const void* pv, + size_t cb, + const SocketAddress& addr, + const rtc::PacketOptions& options), + (override)); + MOCK_METHOD(int, Close, (), (override)); + MOCK_METHOD(State, GetState, (), (const, override)); + MOCK_METHOD(int, + GetOption, + (rtc::Socket::Option opt, int* value), + (override)); + MOCK_METHOD(int, SetOption, (rtc::Socket::Option opt, int value), (override)); + MOCK_METHOD(int, GetError, (), (const, override)); + MOCK_METHOD(void, SetError, (int error), (override)); + + void NotifyPacketReceived() { + char data[1] = {'a'}; + AsyncPacketSocket::NotifyPacketReceived(this, data, 1, SocketAddress(), -1); + } +}; + +TEST(AsyncPacketSocket, RegisteredCallbackReceivePacketsFromNotify) { + MockAsyncPacketSocket mock_socket; + MockFunction + received_packet; + + EXPECT_CALL(received_packet, Call); + mock_socket.RegisterReceivedPacketCallback(received_packet.AsStdFunction()); + mock_socket.NotifyPacketReceived(); +} + +TEST(AsyncPacketSocket, RegisteredCallbackReceivePacketsFromSignalReadPacket) { + MockAsyncPacketSocket mock_socket; + MockFunction + received_packet; + + EXPECT_CALL(received_packet, Call); + mock_socket.RegisterReceivedPacketCallback(received_packet.AsStdFunction()); + char data[1] = {'a'}; + mock_socket.SignalReadPacket(&mock_socket, data, 1, SocketAddress(), -1); +} + +TEST(AsyncPacketSocket, SignalReadPacketTriggeredByNotifyPacketReceived) { + class SigslotPacketReceiver : public sigslot::has_slots<> { + public: + explicit SigslotPacketReceiver(rtc::AsyncPacketSocket& socket) { + socket.SignalReadPacket.connect(this, + &SigslotPacketReceiver::OnPacketReceived); + } + + bool packet_received() const { return packet_received_; } + + private: + void OnPacketReceived(AsyncPacketSocket*, + const char*, + size_t, + const SocketAddress&, + // TODO(bugs.webrtc.org/9584): Change to passing the + // int64_t timestamp by value. + const int64_t&) { + packet_received_ = true; + } + + bool packet_received_ = false; + }; + + MockAsyncPacketSocket mock_socket; + SigslotPacketReceiver receiver(mock_socket); + ASSERT_FALSE(receiver.packet_received()); + + mock_socket.NotifyPacketReceived(); + EXPECT_TRUE(receiver.packet_received()); +} + +} // namespace +} // namespace rtc diff --git a/rtc_base/network/BUILD.gn b/rtc_base/network/BUILD.gn index a42745a4c0..263bfcc282 100644 --- a/rtc_base/network/BUILD.gn +++ b/rtc_base/network/BUILD.gn @@ -23,6 +23,7 @@ rtc_library("received_packet") { "received_packet.h", ] deps = [ + "..:socket_address", "../../api:array_view", "../../api/units:timestamp", ] diff --git a/rtc_base/network/received_packet.cc b/rtc_base/network/received_packet.cc index f27f01ff65..40d6e1142c 100644 --- a/rtc_base/network/received_packet.cc +++ b/rtc_base/network/received_packet.cc @@ -17,16 +17,22 @@ namespace rtc { ReceivedPacket::ReceivedPacket(rtc::ArrayView payload, + const SocketAddress& source_address, absl::optional arrival_time) - : payload_(payload), arrival_time_(std::move(arrival_time)) {} + : payload_(payload), + arrival_time_(std::move(arrival_time)), + source_address_(source_address) {} // static -ReceivedPacket ReceivedPacket::CreateFromLegacy(const char* data, - size_t size, - int64_t packet_time_us) { +ReceivedPacket ReceivedPacket::CreateFromLegacy( + const char* data, + size_t size, + int64_t packet_time_us, + const rtc::SocketAddress& source_address) { RTC_DCHECK(packet_time_us == -1 || packet_time_us >= 0); return ReceivedPacket(rtc::reinterpret_array_view( rtc::MakeArrayView(data, size)), + source_address, (packet_time_us >= 0) ? absl::optional( webrtc::Timestamp::Micros(packet_time_us)) diff --git a/rtc_base/network/received_packet.h b/rtc_base/network/received_packet.h index bcaf2a3766..9b10099e9d 100644 --- a/rtc_base/network/received_packet.h +++ b/rtc_base/network/received_packet.h @@ -15,6 +15,7 @@ #include "absl/types/optional.h" #include "api/array_view.h" #include "api/units/timestamp.h" +#include "rtc_base/socket_address.h" namespace rtc { @@ -24,12 +25,15 @@ namespace rtc { // example it may contains STUN, SCTP, SRTP, RTP, RTCP.... etc. class ReceivedPacket { public: - // Caller must keep memory pointed to by payload valid for the lifetime of - // this ReceivedPacket. + // Caller must keep memory pointed to by payload and address valid for the + // lifetime of this ReceivedPacket. ReceivedPacket( rtc::ArrayView payload, + const SocketAddress& source_address, absl::optional arrival_time = absl::nullopt); + // Address/port of the packet sender. + const SocketAddress& source_address() const { return source_address_; } rtc::ArrayView payload() const { return payload_; } // Timestamp when this packet was received. Not available on all socket @@ -38,13 +42,16 @@ class ReceivedPacket { return arrival_time_; } - static ReceivedPacket CreateFromLegacy(const char* data, - size_t size, - int64_t packet_time_us); + static ReceivedPacket CreateFromLegacy( + const char* data, + size_t size, + int64_t packet_time_us, + const rtc::SocketAddress& = rtc::SocketAddress()); private: rtc::ArrayView payload_; absl::optional arrival_time_; + const SocketAddress& source_address_; }; } // namespace rtc