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
authorTom Henderson <tomh@tomh.org>
Tue, 04 Sep 2007 21:26:54 -0700
changeset 1318 89b78e2d521e
parent 1317 82629189efff
child 1319 c258a29466e8
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
examples/csma-broadcast.cc
examples/wscript
src/internet-node/arp-ipv4-interface.cc
src/internet-node/udp-socket.cc
src/node/ipv4-address.cc
src/node/ipv4-address.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/csma-broadcast.cc	Tue Sep 04 21:26:54 2007 -0700
@@ -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 ();
+}
--- a/examples/wscript	Mon Sep 03 23:32:23 2007 -0700
+++ b/examples/wscript	Tue Sep 04 21:26:54 2007 -0700
@@ -14,6 +14,10 @@
         ['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'
--- a/src/internet-node/arp-ipv4-interface.cc	Mon Sep 03 23:32:23 2007 -0700
+++ b/src/internet-node/arp-ipv4-interface.cc	Tue Sep 04 21:26:54 2007 -0700
@@ -62,8 +62,9 @@
       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;
--- a/src/internet-node/udp-socket.cc	Mon Sep 03 23:32:23 2007 -0700
+++ b/src/internet-node/udp-socket.cc	Tue Sep 04 21:26:54 2007 -0700
@@ -153,10 +153,6 @@
   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 @@
       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 @@
       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);
--- a/src/node/ipv4-address.cc	Mon Sep 03 23:32:23 2007 -0700
+++ b/src/node/ipv4-address.cc	Tue Sep 04 21:26:54 2007 -0700
@@ -99,6 +99,11 @@
 {
   m_mask = value;
 }
+uint32_t 
+Ipv4Mask::GetInverse (void) const
+{
+  return ~m_mask;
+}
 
 void 
 Ipv4Mask::Print (std::ostream &os) const
@@ -162,6 +167,18 @@
   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
 {
--- a/src/node/ipv4-address.h	Mon Sep 03 23:32:23 2007 -0700
+++ b/src/node/ipv4-address.h	Tue Sep 04 21:26:54 2007 -0700
@@ -119,6 +119,16 @@
    * \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 @@
    */
   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;