Fix for bug69: set local address correctly upon UDP connect; apply correct UDP connect() semantics (that sendto cannot override addresses on a connected socket); if destination is IPv4 limited broadcast address, convert to subnet-directed broadcast and send out on each interface; provide example csma-broadcast.cc script

This commit is contained in:
Tom Henderson
2007-09-04 21:26:54 -07:00
parent 5e7e0d7b2a
commit 929e23b74e
6 changed files with 229 additions and 16 deletions

159
examples/csma-broadcast.cc Normal file
View File

@@ -0,0 +1,159 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
//
// Example of the sending of a datagram to a broadcast address
//
// Network topology
// ==============
// | |
// n0 n1 n2
// | |
// ==========
//
// n0 originates UDP broadcast to 255.255.255.255, which is replicated
// and received on both n1 and n2
#include <iostream>
#include <fstream>
#include <string>
#include <cassert>
#include "ns3/command-line.h"
#include "ns3/default-value.h"
#include "ns3/ptr.h"
#include "ns3/random-variable.h"
#include "ns3/debug.h"
#include "ns3/simulator.h"
#include "ns3/nstime.h"
#include "ns3/data-rate.h"
#include "ns3/ascii-trace.h"
#include "ns3/pcap-trace.h"
#include "ns3/internet-node.h"
#include "ns3/csma-channel.h"
#include "ns3/csma-net-device.h"
#include "ns3/csma-topology.h"
#include "ns3/csma-ipv4-topology.h"
#include "ns3/eui48-address.h"
#include "ns3/ipv4-address.h"
#include "ns3/inet-socket-address.h"
#include "ns3/ipv4.h"
#include "ns3/socket.h"
#include "ns3/ipv4-route.h"
#include "ns3/onoff-application.h"
using namespace ns3;
int main (int argc, char *argv[])
{
// Users may find it convenient to turn on explicit debugging
// for selected modules; the below lines suggest how to do this
#if 0
DebugComponentEnable("CsmaNetDevice");
DebugComponentEnable("Ipv4L3Protocol");
DebugComponentEnable("NetDevice");
DebugComponentEnable("Channel");
DebugComponentEnable("CsmaChannel");
DebugComponentEnable("PacketSocket");
#endif
// Set up some default values for the simulation. Use the Bind()
// technique to tell the system what subclass of Queue to use,
// and what the queue limit is
// The below Bind command tells the queue factory which class to
// instantiate, when the queue factory is invoked in the topology code
DefaultValue::Bind ("Queue", "DropTailQueue");
// Allow the user to override any of the defaults and the above
// Bind()s at run-time, via command-line arguments
CommandLine::Parse (argc, argv);
// Here, we will explicitly create four nodes. In more sophisticated
// topologies, we could configure a node factory.
Ptr<Node> n0 = Create<InternetNode> ();
Ptr<Node> n1 = Create<InternetNode> ();
Ptr<Node> n2 = Create<InternetNode> ();
// We create the channels first without any IP addressing information
Ptr<CsmaChannel> channel0 =
CsmaTopology::CreateCsmaChannel(
DataRate(5000000), MilliSeconds(2));
// We create the channels first without any IP addressing information
Ptr<CsmaChannel> channel1 =
CsmaTopology::CreateCsmaChannel(
DataRate(5000000), MilliSeconds(2));
uint32_t n0ifIndex0 = CsmaIpv4Topology::AddIpv4CsmaNode (n0, channel0,
Eui48Address("10:54:23:54:0:50"));
uint32_t n0ifIndex1 = CsmaIpv4Topology::AddIpv4CsmaNode (n0, channel1,
Eui48Address("10:54:23:54:0:51"));
uint32_t n1ifIndex = CsmaIpv4Topology::AddIpv4CsmaNode (n1, channel0,
Eui48Address("10:54:23:54:23:51"));
uint32_t n2ifIndex = CsmaIpv4Topology::AddIpv4CsmaNode (n2, channel1,
Eui48Address("10:54:23:54:23:52"));
// Later, we add IP addresses.
CsmaIpv4Topology::AddIpv4Address (
n0, n0ifIndex0, Ipv4Address("10.1.0.1"), Ipv4Mask("255.255.0.0"));
CsmaIpv4Topology::AddIpv4Address (
n1, n1ifIndex, Ipv4Address("10.1.0.2"), Ipv4Mask("255.255.0.0"));
CsmaIpv4Topology::AddIpv4Address (
n0, n0ifIndex1, Ipv4Address("192.168.1.1"), Ipv4Mask("255.255.255.0"));
CsmaIpv4Topology::AddIpv4Address (
n2, n2ifIndex, Ipv4Address("192.168.1.2"), Ipv4Mask("255.255.255.0"));
// Create the OnOff application to send UDP datagrams of size
// 210 bytes at a rate of 448 Kb/s
// from n0 to n1
Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
n0,
InetSocketAddress ("255.255.255.255", 80),
"Udp",
ConstantVariable(1),
ConstantVariable(0));
// Start the application
ooff->Start(Seconds(1.0));
ooff->Stop (Seconds(10.0));
// Configure tracing of all enqueue, dequeue, and NetDevice receive events
// Trace output will be sent to the csma-broadcast.tr file
AsciiTrace asciitrace ("csma-broadcast.tr");
asciitrace.TraceAllNetDeviceRx ();
asciitrace.TraceAllQueues ();
// Also configure some tcpdump traces; each interface will be traced
// The output files will be named
// simple-point-to-point.pcap-<nodeId>-<interfaceId>
// and can be read by the "tcpdump -r" command (use "-tt" option to
// display timestamps correctly)
PcapTrace pcaptrace ("csma-broadcast.pcap");
pcaptrace.TraceAllIp ();
Simulator::Run ();
Simulator::Destroy ();
}

View File

@@ -14,6 +14,10 @@ def build(bld):
['csma', 'internet-node'])
obj.source = 'csma-one-subnet.cc'
obj = bld.create_ns3_program('csma-broadcast',
['csma', 'internet-node'])
obj.source = 'csma-broadcast.cc'
obj = bld.create_ns3_program('csma-packet-socket',
['csma', 'internet-node'])
obj.source = 'csma-packet-socket.cc'

View File

@@ -62,8 +62,9 @@ ArpIpv4Interface::SendTo (Packet p, Ipv4Address dest)
Ptr<ArpL3Protocol> arp = m_node->QueryInterface<ArpL3Protocol> (ArpL3Protocol::iid);
Address hardwareDestination;
bool found;
if (dest.IsBroadcast ())
if (dest.IsBroadcast () ||
dest.IsSubnetDirectedBroadcast (GetNetworkMask ()) )
{
hardwareDestination = GetDevice ()->GetBroadcast ();
found = true;

View File

@@ -153,10 +153,6 @@ UdpSocket::Connect(const Address & address)
InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
m_defaultAddress = transport.GetIpv4 ();
m_defaultPort = transport.GetPort ();
if (m_defaultAddress.IsBroadcast () )
{
NS_ASSERT_MSG(false, "UdpSocket::Connect, can't connect to broadcast");
}
NotifyConnectionSucceeded ();
m_connected = true;
if (GetIpv4RouteToDestination (m_node, routeToDest, m_defaultAddress) )
@@ -196,24 +192,31 @@ UdpSocket::DoSend (const Packet &p)
m_errno = ERROR_SHUTDOWN;
return -1;
}
m_udp->Send (p, m_endPoint->GetLocalAddress (), m_defaultAddress,
m_endPoint->GetLocalPort (), m_defaultPort);
NotifyDataSent (p.GetSize ());
return 0;
return DoSendTo (p, m_defaultAddress, m_defaultPort);
}
int
UdpSocket::DoSendTo (const Packet &p, const Address &address)
{
InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
Ipv4Address ipv4 = transport.GetIpv4 ();
uint16_t port = transport.GetPort ();
return DoSendTo (p, ipv4, port);
if (!m_connected)
{
InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
Ipv4Address ipv4 = transport.GetIpv4 ();
uint16_t port = transport.GetPort ();
return DoSendTo (p, ipv4, port);
}
else
{
// connected UDP socket must use default addresses
return DoSendTo (p, m_defaultAddress, m_defaultPort);
}
}
int
UdpSocket::DoSendTo (const Packet &p, Ipv4Address dest, uint16_t port)
{
Ipv4Route routeToDest;
if (m_endPoint == 0)
{
if (Bind () == -1)
@@ -228,8 +231,23 @@ UdpSocket::DoSendTo (const Packet &p, Ipv4Address dest, uint16_t port)
m_errno = ERROR_SHUTDOWN;
return -1;
}
Ipv4Route routeToDest;
if (GetIpv4RouteToDestination (m_node, routeToDest, dest) )
//
// If dest is sent to the limited broadcast address (all ones),
// convert it to send a copy of the packet out of every interface
//
if (dest.IsBroadcast ())
{
Ptr<Ipv4> ipv4 = m_node->QueryInterface<Ipv4> (Ipv4::iid);
for (uint32_t i = 0; i < ipv4->GetNInterfaces (); i++ )
{
Ipv4Address addri = ipv4->GetAddress (i);
Ipv4Mask maski = ipv4->GetNetworkMask (i);
m_udp->Send (p, addri, addri.GetSubnetDirectedBroadcast (maski),
m_endPoint->GetLocalPort (), port);
NotifyDataSent (p.GetSize ());
}
}
else if (GetIpv4RouteToDestination (m_node, routeToDest, dest) )
{
uint32_t localIfIndex = routeToDest.GetInterface ();
Ptr<Ipv4> ipv4 = m_node->QueryInterface<Ipv4> (Ipv4::iid);

View File

@@ -99,6 +99,11 @@ Ipv4Mask::SetHostOrder (uint32_t value)
{
m_mask = value;
}
uint32_t
Ipv4Mask::GetInverse (void) const
{
return ~m_mask;
}
void
Ipv4Mask::Print (std::ostream &os) const
@@ -162,6 +167,18 @@ Ipv4Address::CombineMask (Ipv4Mask const &mask) const
return Ipv4Address (GetHostOrder () & mask.GetHostOrder ());
}
Ipv4Address
Ipv4Address::GetSubnetDirectedBroadcast (Ipv4Mask const &mask) const
{
return Ipv4Address (GetHostOrder () | mask.GetInverse ());
}
bool
Ipv4Address::IsSubnetDirectedBroadcast (Ipv4Mask const &mask) const
{
return ( (GetHostOrder () | mask.GetInverse ()) == GetHostOrder () );
}
bool
Ipv4Address::IsBroadcast (void) const
{

View File

@@ -119,6 +119,16 @@ public:
* \param mask a network mask
*/
Ipv4Address CombineMask (Ipv4Mask const &mask) const;
/**
* \brief Generate subnet-directed broadcast address corresponding to mask
*
* The subnet-directed broadcast address has the host bits set to all
* ones.
*
* \param mask a network mask
*/
Ipv4Address GetSubnetDirectedBroadcast (Ipv4Mask const &mask) const;
bool IsSubnetDirectedBroadcast (Ipv4Mask const &mask) const;
static bool IsMatchingType (const Address &address);
operator Address ();
@@ -151,6 +161,10 @@ public:
*/
uint32_t GetHostOrder (void) const;
void SetHostOrder (uint32_t value);
/**
* \brief Return the inverse mask in host order.
*/
uint32_t GetInverse (void) const;
void Print (std::ostream &os) const;