diff --git a/src/applications/helper/udp-echo-helper.cc b/src/applications/helper/udp-echo-helper.cc index d740f3d04..9bb2ee7f1 100644 --- a/src/applications/helper/udp-echo-helper.cc +++ b/src/applications/helper/udp-echo-helper.cc @@ -22,6 +22,12 @@ UdpEchoServerHelper::UdpEchoServerHelper(uint16_t port) SetAttribute("Port", UintegerValue(port)); } +UdpEchoServerHelper::UdpEchoServerHelper(const Address& address) + : ApplicationHelper(UdpEchoServer::GetTypeId()) +{ + SetAttribute("Local", AddressValue(address)); +} + UdpEchoClientHelper::UdpEchoClientHelper(const Address& address, uint16_t port) : UdpEchoClientHelper(addressUtils::ConvertToSocketAddress(address, port)) { diff --git a/src/applications/helper/udp-echo-helper.h b/src/applications/helper/udp-echo-helper.h index 9d0d1d99c..6a87a65e8 100644 --- a/src/applications/helper/udp-echo-helper.h +++ b/src/applications/helper/udp-echo-helper.h @@ -31,6 +31,14 @@ class UdpEchoServerHelper : public ApplicationHelper * \param port The port the server will wait on for incoming packets */ UdpEchoServerHelper(uint16_t port); + + /** + * Create UdpEchoServerHelper which will make life easier for people trying + * to set up simulations with echos. + * + * \param address The address the server will bind to + */ + UdpEchoServerHelper(const Address& address); }; /** diff --git a/src/applications/model/udp-echo-server.cc b/src/applications/model/udp-echo-server.cc index 67be5d9de..5b5a6ab45 100644 --- a/src/applications/model/udp-echo-server.cc +++ b/src/applications/model/udp-echo-server.cc @@ -35,6 +35,12 @@ UdpEchoServer::GetTypeId() .SetParent() .SetGroupName("Applications") .AddConstructor() + .AddAttribute("Local", + "The Address on which to Bind the rx socket. " + "If it is not specified, it will listen to any address.", + AddressValue(), + MakeAddressAccessor(&UdpEchoServer::m_local), + MakeAddressChecker()) .AddAttribute("Port", "Port on which we listen for incoming packets.", UintegerValue(9), @@ -58,6 +64,8 @@ UdpEchoServer::GetTypeId() } UdpEchoServer::UdpEchoServer() + : m_socket{nullptr}, + m_socket6{nullptr} { NS_LOG_FUNCTION(this); } @@ -76,9 +84,13 @@ UdpEchoServer::StartApplication() if (!m_socket) { - TypeId tid = TypeId::LookupByName("ns3::UdpSocketFactory"); + auto tid = TypeId::LookupByName("ns3::UdpSocketFactory"); m_socket = Socket::CreateSocket(GetNode(), tid); - InetSocketAddress local = InetSocketAddress(Ipv4Address::GetAny(), m_port); + auto local = m_local; + if (local.IsInvalid()) + { + local = InetSocketAddress(Ipv4Address::GetAny(), m_port); + } if (m_socket->Bind(local) == -1) { NS_FATAL_ERROR("Failed to bind socket"); @@ -96,35 +108,36 @@ UdpEchoServer::StartApplication() NS_FATAL_ERROR("Error: Failed to join multicast group"); } } + m_socket->SetIpTos(m_tos); // Affects only IPv4 sockets. + m_socket->SetRecvCallback(MakeCallback(&UdpEchoServer::HandleRead, this)); } - if (!m_socket6) + if (m_local.IsInvalid() && !m_socket6) { - TypeId tid = TypeId::LookupByName("ns3::UdpSocketFactory"); + // local address is not specified, so create another socket to also listen to all IPv6 + // addresses + auto tid = TypeId::LookupByName("ns3::UdpSocketFactory"); m_socket6 = Socket::CreateSocket(GetNode(), tid); - Inet6SocketAddress local6 = Inet6SocketAddress(Ipv6Address::GetAny(), m_port); - if (m_socket6->Bind(local6) == -1) + auto local = Inet6SocketAddress(Ipv6Address::GetAny(), m_port); + if (m_socket6->Bind(local) == -1) { NS_FATAL_ERROR("Failed to bind socket"); } - if (addressUtils::IsMulticast(local6)) + if (addressUtils::IsMulticast(local)) { Ptr udpSocket = DynamicCast(m_socket6); if (udpSocket) { // equivalent to setsockopt (MCAST_JOIN_GROUP) - udpSocket->MulticastJoinGroup(0, local6); + udpSocket->MulticastJoinGroup(0, local); } else { NS_FATAL_ERROR("Error: Failed to join multicast group"); } } + m_socket6->SetRecvCallback(MakeCallback(&UdpEchoServer::HandleRead, this)); } - - m_socket->SetIpTos(m_tos); // Affects only IPv4 sockets. - m_socket->SetRecvCallback(MakeCallback(&UdpEchoServer::HandleRead, this)); - m_socket6->SetRecvCallback(MakeCallback(&UdpEchoServer::HandleRead, this)); } void @@ -149,11 +162,10 @@ UdpEchoServer::HandleRead(Ptr socket) { NS_LOG_FUNCTION(this << socket); - Ptr packet; Address from; - Address localAddress; - while ((packet = socket->RecvFrom(from))) + while (auto packet = socket->RecvFrom(from)) { + Address localAddress; socket->GetSockName(localAddress); m_rxTrace(packet); m_rxTraceWithAddresses(packet, from, localAddress); diff --git a/src/applications/model/udp-echo-server.h b/src/applications/model/udp-echo-server.h index a549d4c4e..5a41aa325 100644 --- a/src/applications/model/udp-echo-server.h +++ b/src/applications/model/udp-echo-server.h @@ -54,11 +54,12 @@ class UdpEchoServer : public Application */ void HandleRead(Ptr socket); - uint16_t m_port; //!< Port on which we listen for incoming packets. + uint16_t + m_port; //!< Port on which we listen for incoming packets if local address is not specified uint8_t m_tos; //!< The packets Type of Service - Ptr m_socket; //!< IPv4 Socket - Ptr m_socket6; //!< IPv6 Socket - Address m_local; //!< local multicast address + Ptr m_socket; //!< Socket + Ptr m_socket6; //!< IPv6 Socket (used if only port is specified) + Address m_local; //!< Local address to bind to (address and port) /// Callbacks for tracing the packet Rx events TracedCallback> m_rxTrace; diff --git a/src/applications/test/udp-client-server-test.cc b/src/applications/test/udp-client-server-test.cc index 2dfa54053..8228895e6 100644 --- a/src/applications/test/udp-client-server-test.cc +++ b/src/applications/test/udp-client-server-test.cc @@ -310,7 +310,7 @@ UdpEchoClientSetFillTestCase::DoRun() Ipv4InterfaceContainer interfaces = ipv4.Assign(d); uint16_t port = 5000; - UdpEchoServerHelper echoServer(port); + UdpEchoServerHelper echoServer(InetSocketAddress(Ipv4Address::GetAny(), port)); ApplicationContainer serverApps = echoServer.Install(nodes.Get(1)); serverApps.Start(Seconds(1.0)); serverApps.Stop(Seconds(10.0));