From 4f0eae4a6df114e66ac23f76d613896b095a41de Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 13 Jun 2007 16:37:04 +0200 Subject: [PATCH 01/21] add a rationale for the way Trailers work --- src/common/trailer.h | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/common/trailer.h b/src/common/trailer.h index 7ad1e7c31..9919df89d 100644 --- a/src/common/trailer.h +++ b/src/common/trailer.h @@ -36,6 +36,32 @@ namespace ns3 { * - ns3::Trailer::DeserializeFrom * - ns3::Trailer::GetSerializedSize * - ns3::Trailer::PrintTo + * + * Note that the SerializeTo and DeserializeFrom methods behave + * in a way which might seem surprising to users: the input iterator + * really points to the end of the buffer to which and from which + * the user is expected to write and read respectively. This means that + * if the trailer has a fixed size and if the user wishes to read or + * write that trailer from front to back, the user must rewind the + * iterator by hand to go to the start of the trailer. Typical code + * looks like this: + * \code + * void CrcTrailer::SerializeTo (Buffer::Iterator end) + * { + * end.Prev (4); + * end.WriteHtonU32 (m_crc); + * } + * \endcode + * + * Some users would have expected that the iterator would be rewinded + * to the "start" of the trailer before calling SerializeTo and DeserializeFrom. + * However, this behavior was not implemented because it cannot be made to + * work reliably for trailers which have a variable size. i.e., if the trailer + * contains options, the code which calls DeserializeFrom cannot rewind + * to the start of the trailer because it does not know the real size of the + * trailer. Hence, to make this legitimate use-case work (variable-sized + * trailers), the input iterator to DeserializeFrom and SerializeTo points + * to the end of the trailer, and not its start. */ class Trailer : public Chunk { public: @@ -56,6 +82,9 @@ private: * \param end the buffer iterator in which the protocol trailer * must serialize itself. This iterator identifies * the end of the buffer. + * + * This iterator must be typically moved with the Buffer::Iterator::Prev + * method before writing any byte in the buffer. */ virtual void SerializeTo (Buffer::Iterator end) const = 0; /** @@ -63,6 +92,9 @@ private: * deserialize itself. This iterator identifies * the end of the buffer. * \returns the number of bytes read from the buffer + * + * This iterator must be typically moved with the Buffer::Iterator::Prev + * method before reading any byte in the buffer. */ virtual uint32_t DeserializeFrom (Buffer::Iterator end) = 0; }; From e38244e7c0af8a70067535b9ba65a5fe63557d5d Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Wed, 13 Jun 2007 18:34:05 +0100 Subject: [PATCH 02/21] WAF: add -Wall and -Werror to CXXFLAGS, like in the SCons build. --- wscript | 1 + 1 file changed, 1 insertion(+) diff --git a/wscript b/wscript index 75bca783c..779c3c136 100644 --- a/wscript +++ b/wscript @@ -79,6 +79,7 @@ def configure(conf): conf.setenv(variant_name) variant_env.append_value('CXXDEFINES', 'RUN_SELF_TESTS') + variant_env.append_value('CXXFLAGS', ['-Wall', '-Werror']) if 'debug' in Params.g_options.debug_level.lower(): variant_env.append_value('CXXDEFINES', 'NS3_DEBUG_ENABLE') variant_env.append_value('CXXDEFINES', 'NS3_ASSERT_ENABLE') From 50037ae6112cec74ca395829e54f6d0c5b467e6c Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Wed, 13 Jun 2007 18:40:38 +0100 Subject: [PATCH 03/21] Fix compilier warning/error: src/simulator/cairo-wideint.c:789: warning: comparison between signed and unsigned integer expressions. --- src/simulator/cairo-wideint.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/simulator/cairo-wideint.c b/src/simulator/cairo-wideint.c index 354183fe7..1b2ffe1b4 100644 --- a/src/simulator/cairo-wideint.c +++ b/src/simulator/cairo-wideint.c @@ -786,7 +786,7 @@ _cairo_int_96by64_32x64_divrem (cairo_int128_t num, cairo_int64_t den) nonneg_den = _cairo_int64_negate (den); uqr = _cairo_uint_96by64_32x64_divrem (num, nonneg_den); - if (_cairo_uint64_eq (uqr.rem, nonneg_den)) { + if (_cairo_uint64_eq (uqr.rem, _cairo_int64_to_uint64 (nonneg_den))) { /* bail on overflow. */ qr.quo = _cairo_uint32s_to_uint64 (0x7FFFFFFF, -1U);; qr.rem = den; From cdf13df87d8561868706926386817f4d1d0ab431 Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Wed, 13 Jun 2007 23:13:21 -0700 Subject: [PATCH 04/21] Add main-query-interface.cc sample file --- SConstruct | 6 + samples/main-query-interface.cc | 280 ++++++++++++++++++++++++++++++++ 2 files changed, 286 insertions(+) create mode 100644 samples/main-query-interface.cc diff --git a/SConstruct b/SConstruct index 210ebca0b..44f168c6b 100644 --- a/SConstruct +++ b/SConstruct @@ -411,6 +411,12 @@ sample_trace.add_dep('common') sample_trace.set_executable() sample_trace.add_source('main-trace.cc') +sample_query_interface = build.Ns3Module('sample-query-interface', 'samples') +ns3.add(sample_query_interface) +sample_query_interface.add_dep('common') +sample_query_interface.set_executable() +sample_query_interface.add_source('main-query-interface.cc') + sample_simu = build.Ns3Module('sample-simulator', 'samples') ns3.add(sample_simu) sample_simu.set_executable() diff --git a/samples/main-query-interface.cc b/samples/main-query-interface.cc new file mode 100644 index 000000000..20da36ff3 --- /dev/null +++ b/samples/main-query-interface.cc @@ -0,0 +1,280 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2007 University of Washington + * Authors: Tom Henderson, Craig Dowell + * + * 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 + */ + +#include "ns3/debug.h" +#include "ns3/object.h" +#include "ns3/component-manager.h" + +using namespace ns3; + +// +// This sample file shows examples of how to use QueryInterface. +// +// QueryInterface is a templated method of class Object, defined in +// src/core/object.h. ns-3 objects that derive from class Object +// can have QueryInterface invoked on them. +// +// QueryInterface is a type-safe way to ask an object, at run-time, +// "Do you support the interface identified by the given InterfaceId?" +// It avoids deprecated techniques of having to downcast pointers to +// an object to ask questions about its type. One or more interfaces +// may be associated with a given object. +// +// QueryInterface is of most use when working with base class +// pointers of objects that may be subclassed. For instance, +// one may have a pointer to a Node, but not know whether it has +// an IPv4 stack. Another example might be to determine whether +// a Node has an EnergyModel, to which calls to decrement energy +// from the node's battery might be made. +// + + +// +// Object is the base class for ns-3 node-related objects used at +// the public API. Object provides reference counting implementations +// and the QueryInterface. +// +// A common design paradigm for an ns-3 node object, such as a Queue, +// is that we provide an abstract base class that inherits from +// Object. This class is assigned an interface ID (iid) and +// contains the basic API for objects in this class and subclasses. +// This base class is specialized to provide implementations of +// the object in question (such as a DropTailQueue). +// +// The design pattern commonly used is known as the "non-virtual +// public interface" pattern, whereby the public API for this +// object is a set of public non-virtual functions that forward +// to private virtual functions. The forwarding functions can +// impose pre- and post-conditions on the forwarding call at +// the base class level. +// +// We'll call this base class "AnInterface" in the example below. +// +// +class AnInterface : public Object +{ +public: + static const InterfaceId iid; + void methodA (void); +private: + virtual void domethodA (void) = 0; +}; + +void +AnInterface::methodA (void) +{ + // pre-dispatch asserts + NS_DEBUG_UNCOND("AnInterface pre-condition::methodA"); + domethodA (); + NS_DEBUG_UNCOND("AnInterface post-condition::methodA\n"); + // post-dispatch asserts +} + +// +// The below assignment assigns the InterfaceId of the class AnInterface, +// and declares that the parent iid is that of class Object. +// +const InterfaceId AnInterface::iid = MakeInterfaceId ("AnInterface", Object::iid); + +// +// AnImplementation is an implementation of the abstract base class +// defined above. It provides implementation for the virtual functions +// in the base class. It defines one ClassId for each constructor, +// and can also provide an interface itself (in this example, +// a methodImpl is available) +// +class AnImplementation : public AnInterface +{ +public: + static const InterfaceId iid; + static const ClassId cid; + + AnImplementation (); + void methodImpl (void); +private: + virtual void domethodA (void); +}; + +void +AnImplementation::methodImpl (void) +{ + NS_DEBUG_UNCOND("AnImplementation::methodImpl\n"); +} + + +AnImplementation::AnImplementation (void) +{ + // enable our interface + SetInterfaceId (AnImplementation::iid); +} + +void +AnImplementation::domethodA () +{ + NS_DEBUG_UNCOND("AnImplementation::domethodA"); +} + +// +// The below assignment assigns the InterfaceId of the class AnImplementation, +// and declares that the parent iid is that of class Object. +// +const InterfaceId AnImplementation::iid = + MakeInterfaceId ("AnImplementation", AnInterface::iid); + +// +// The next few lines are used by the component manager. They +// state that the component manager can create a new object +// AnImplementation and return an interface corresponding to +// the AnImplementation iid. +// +const ClassId AnImplementation::cid = + MakeClassId + ("AnImplementation", AnImplementation::iid); + + +// +// Extending interfaces +// ================== +// What if AnInterface doesn't provide enough API for your +// object type? +// - if you aren't concerned about backward compatibility and +// don't mind recompiling, you just add new methods to AnInterface +// and recompile. +// - if you want to address backward compatibiliy, or allow part +// of the system to use the old interface, you have to do more. +// You have to declare a new interface with the new functionality. +// + +class AnExtendedInterface : public AnInterface +{ +public: + static const InterfaceId iid; + void methodB (void); +private: + virtual void domethodB (void) = 0; +}; + +const InterfaceId AnExtendedInterface::iid = + MakeInterfaceId ("AnExtendedInterface", AnInterface::iid); + +// +// Then you need provide an implementation for the virtual +// methods. If you are providing a new implementation for +// everything, the answer is straightforward +// + +class ANewImplementation : public AnExtendedInterface +{ +public: + static const InterfaceId iid; + static const ClassId cid; + + ANewImplementation (); + void methodImpl (void); +private: + virtual void domethodA (void) { /* new-implementation-behavior (); */} + virtual void domethodB (void) { /* new-implementation-behavior (); */} +}; + +ANewImplementation::ANewImplementation (void) +{ + // enable our interface + SetInterfaceId (ANewImplementation::iid); +} + +void +ANewImplementation::methodImpl (void) +{ + NS_DEBUG_UNCOND("ANewImplementation::methodImpl\n"); +} + +const InterfaceId ANewImplementation::iid = + MakeInterfaceId ("ANewImplementation", AnExtendedInterface::iid); + +// +// If you want to extend an existing implementation, you can use +// the existing class to instantiate an implementation of its +// methods (hasa) and do the following if you can use stuff from +// the existing class. +// + +class AnExtendedImplementation : public AnExtendedInterface +{ +public: + static const InterfaceId iid; + static const ClassId cid; + + AnExtendedImplementation (); + void methodImpl (void) { /* pImpl->methodImpl (); */ } + void methodExtendedImpl (void); +private: + virtual void domethodA (void) { /* new-implementation-behavior (); */} + virtual void domethodB (void) { /* new-implementation-behavior (); */} + Ptr pImpl; +}; + +AnExtendedImplementation::AnExtendedImplementation (void) +{ + pImpl = Create (); + SetInterfaceId (AnExtendedImplementation::iid); +} + +void +AnExtendedImplementation::methodExtendedImpl (void) +{ + NS_DEBUG_UNCOND("AnExtendedImplementation::methodExtendedImpl\n"); +} + +const InterfaceId AnExtendedImplementation::iid = + MakeInterfaceId ("AnExtendedImplementation", AnExtendedInterface::iid); + +// +// Inheriting from an existing implementation (isa) and an extended +// interface is tricky, because of the diamond multiple inheritance +// problem. If the pImpl method above is not desirable, it may +// be that the implementation extension could be aggregated. +// +// The extension will not have access to the base implementation, +// so this design pattern may be more appropriate if the extension +// is very modular (e.g., add an EnergyModel to a wireless interface) +// +// EXAMPLE NOT YET PROVIDED + +int main (int argc, char *argv[]) +{ + + Ptr aBase = ComponentManager::Create + (AnImplementation::cid, AnInterface::iid); + NS_ASSERT (aBase != 0); + + aBase->methodA (); + //aBase->methodImpl (); // XXX won't compile, aBase not right ptr type + + Ptr aBaseImplPtr = + aBase-> QueryInterface (AnImplementation::iid); + aBaseImplPtr->methodImpl (); + aBaseImplPtr->methodA(); + + // Test symmetric property of QueryInterface + Ptr aBase2 = + aBaseImplPtr-> QueryInterface (AnInterface::iid); + aBase2->methodA (); + + return 0; +} From 4042681e83f0bcb038432ac2b228a3ce4891bc56 Mon Sep 17 00:00:00 2001 From: "George F. Riley" Date: Thu, 14 Jun 2007 10:41:47 +0200 Subject: [PATCH 05/21] Simplification to p2p-net-device and p2p-channel (work in progress) --- src/devices/p2p/p2p-channel.cc | 6 +- src/devices/p2p/p2p-net-device.cc | 150 +++++++----------------------- src/devices/p2p/p2p-net-device.h | 59 ++++++------ src/node/mac-address.cc | 21 +++++ src/node/mac-address.h | 15 +++ 5 files changed, 104 insertions(+), 147 deletions(-) diff --git a/src/devices/p2p/p2p-channel.cc b/src/devices/p2p/p2p-channel.cc index 2833c8bb1..be4851553 100644 --- a/src/devices/p2p/p2p-channel.cc +++ b/src/devices/p2p/p2p-channel.cc @@ -135,12 +135,14 @@ PointToPointChannel::TransmitEnd(Packet& p, Ptr src) // The sender is going to free the packet as soon as it has been transmitted. // We need to copy it to get a reference so it won't e deleted. // - Packet packet = p; +// Above is not correct (GFR). The event scheduler makes a copy +// of the packet +// Packet packet = p; NS_DEBUG ("PointToPointChannel::TransmitEnd (): Schedule event in " << m_delay.GetSeconds () << "sec"); Simulator::Schedule (m_delay, &PointToPointChannel::PropagationCompleteEvent, - this, packet, src); + this, p, src); return true; } diff --git a/src/devices/p2p/p2p-net-device.cc b/src/devices/p2p/p2p-net-device.cc index 9542d951b..2667e388f 100644 --- a/src/devices/p2p/p2p-net-device.cc +++ b/src/devices/p2p/p2p-net-device.cc @@ -16,7 +16,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * Author: Mathieu Lacage + * Author: Craig Dowell + * Revised: George Riley */ #include @@ -32,11 +33,17 @@ NS_DEBUG_COMPONENT_DEFINE ("PointToPointNetDevice"); namespace ns3 { -PointToPointNetDevice::PointToPointNetDevice (Ptr node) +DataRateDefaultValue PointToPointNetDevice::g_defaultRate( + "PointToPointLinkDataRate", + "The default data rate for point to point links", + DataRate ("10Mb/s")); + + PointToPointNetDevice::PointToPointNetDevice (Ptr node, + const DataRate& rate) : - NetDevice(node, MacAddress ("00:00:00:00:00:00")), + NetDevice(node, MacAddress (6)), m_txMachineState (READY), - m_bps (DataRate (0xffffffff)), + m_bps (rate), m_tInterframeGap (Seconds(0)), m_channel (0), m_queue (0), @@ -101,26 +108,25 @@ void PointToPointNetDevice::DoDispose() // // Assignment operator for PointToPointNetDevice. // -// This uses the non-obvious trick of taking the source net device passed by -// value instead of by reference. This causes the copy constructor to be -// invoked (where the real work is done -- see above). All we have to do -// here is to return the newly constructed net device. // - PointToPointNetDevice& -PointToPointNetDevice::operator= (const PointToPointNetDevice nd) +PointToPointNetDevice& +PointToPointNetDevice::operator= (const PointToPointNetDevice& nd) { NS_DEBUG ("PointToPointNetDevice::operator= (" << &nd << ")"); + // FIXME. Not sure what to do here + // GFR Note. I would suggest dis-allowing netdevice assignment, + // as well as pass-by-value (ie. copy constructor). return *this; } void -PointToPointNetDevice::SetDataRate(DataRate bps) +PointToPointNetDevice::SetDataRate(const DataRate& bps) { m_bps = bps; } void -PointToPointNetDevice::SetInterframeGap(Time t) +PointToPointNetDevice::SetInterframeGap(const Time& t) { m_tInterframeGap = t; } @@ -133,68 +139,23 @@ PointToPointNetDevice::SendTo (Packet& p, const MacAddress& dest) NS_ASSERT (IsLinkUp ()); -#ifdef NOTYET - struct NetDevicePacketDestAddress tag; - tag.address = address; - p.AddTag (tag); -#endif - // // This class simulates a point to point device. In the case of a serial // link, this means that we're simulating something like a UART. This is // not a requirement for a point-to-point link, but it's a typical model for // the device. // -// Generally, a real device will have a list of pending packets to transmit. -// An on-device CPU frees the main CPU(s) of the details of what is happening -// in the device and feeds the USART. The main CPU basically just sees the -// list of packets -- it puts packets into the list, and the device frees the -// packets when they are transmitted. -// -// In the case of our virtual device here, the queue pointed to by m_queue -// corresponds to this list. The main CPU adds packets to the list by -// calling this method and when the device completes a send, the packets are -// freed in an "interrupt" service routine. -// -// We're going to do the same thing here. So first of all, the incoming packet -// goes onto our queue if possible. If the queue can't handle it, there's -// nothing to be done. -// - if (m_queue->Enqueue(p) == false ) - { - return false; - } -// -// If there's a transmission in progress, the "interrupt" will keep the -// transmission process going. If the device is idle, we need to start a -// transmission. -// -// In the real world, the USART runs until it finishes sending bits, and then -// pulls on the device's transmit complete interrupt wire. At the same time, -// the electrons from the last wiggle of the wire are busy propagating down -// the wire. In the case of a long speed-of-light delay in the wire, we could -// conceivably start transmitting the next packet before the end of the -// previously sent data has even reached the end of the wire. This situation -// is usually avoided (like the plague) and an "interframe gap" is introduced. -// This is usually the round-trip delay on the channel plus some hard-to- -// quantify receiver turn-around time (the time required for the receiver -// to process the last frame and prepare for reception of the next). -// -// So, if the transmit machine is ready, we need to schedule a transmit -// complete event (at which time we tell the channel we're no longer sending -// bits). A separate transmit ready event (at which time the transmitter -// becomes ready to start sending bits again is scheduled there). Finally, -// we tell the channel (via TransmitStart ()) that we've started wiggling the -// wire and bits are coming out. -// -// If the transmit machine is not ready, we just leave and the transmit ready -// event we know is coming will kick-start the transmit process. // +// If there's a transmission in progress, we enque the packet for later +// trnsmission; otherwise we send it now. if (m_txMachineState == READY) { return TransmitStart (p); } - return true; + else + { + return m_queue->Enqueue(p); + } } bool @@ -206,25 +167,25 @@ PointToPointNetDevice::TransmitStart (Packet &p) // // This function is called to start the process of transmitting a packet. // We need to tell the channel that we've started wiggling the wire and -// schedule an event that will be executed when it's time to tell the -// channel that we're done wiggling the wire. +// schedule an event that will be executed when the transmission is complete. // NS_ASSERT_MSG(m_txMachineState == READY, "Must be READY to transmit"); m_txMachineState = BUSY; - Time tEvent = Seconds (m_bps.CalculateTxTime(p.GetSize())); + Time txCompleteTime = Seconds (m_bps.CalculateTxTime(p.GetSize())) + + m_tInterframeGap; NS_DEBUG ("PointToPointNetDevice::TransmitStart (): " << "Schedule TransmitCompleteEvent in " << - tEvent.GetSeconds () << "sec"); - - Simulator::Schedule (tEvent, - &PointToPointNetDevice::TransmitCompleteEvent, + txCompleteTime.GetSeconds () << "sec"); + // Schedule the tx complete event + Simulator::Schedule (txCompleteTime, + &PointToPointNetDevice::TransmitComplete, this); - return m_channel->TransmitStart (p, this); + return m_channel->TransmitStart(p, this); } void -PointToPointNetDevice::TransmitCompleteEvent (void) +PointToPointNetDevice::TransmitComplete (void) { NS_DEBUG ("PointToPointNetDevice::TransmitCompleteEvent ()"); // @@ -234,49 +195,10 @@ PointToPointNetDevice::TransmitCompleteEvent (void) // the transmitter after the interframe gap. // NS_ASSERT_MSG(m_txMachineState == BUSY, "Must be BUSY if transmitting"); - m_txMachineState = GAP; - Packet p; - bool found; - found = m_queue->Dequeue (p); - NS_ASSERT_MSG(found, "Packet must be on queue if transmitted"); - NS_DEBUG ("PointToPointNetDevice::TransmitCompleteEvent (): Pkt UID is " << - p.GetUid () << ")"); - m_channel->TransmitEnd (p, this); - - NS_DEBUG ( - "PointToPointNetDevice::TransmitCompleteEvent (): " << - "Schedule TransmitReadyEvent in " - << m_tInterframeGap.GetSeconds () << "sec"); - - Simulator::Schedule (m_tInterframeGap, - &PointToPointNetDevice::TransmitReadyEvent, - this); -} - - void -PointToPointNetDevice::TransmitReadyEvent (void) -{ - NS_DEBUG ("PointToPointNetDevice::TransmitReadyEvent ()"); -// -// This function is called to enable the transmitter after the interframe -// gap has passed. If there are pending transmissions, we use this opportunity -// to start the next transmit. -// - NS_ASSERT_MSG(m_txMachineState == GAP, "Must be in interframe gap"); m_txMachineState = READY; - - if (m_queue->IsEmpty()) - { - return; - } - else - { - Packet p; - bool found; - found = m_queue->Peek (p); - NS_ASSERT_MSG(found, "IsEmpty false but no Packet on queue?"); - TransmitStart (p); - } + Packet p; + if (!m_queue->Dequeue(p)) return; // Nothing to do at this point + TransmitStart(p); } TraceResolver * diff --git a/src/devices/p2p/p2p-net-device.h b/src/devices/p2p/p2p-net-device.h index e1eb8a666..5fb3e8016 100644 --- a/src/devices/p2p/p2p-net-device.h +++ b/src/devices/p2p/p2p-net-device.h @@ -30,6 +30,7 @@ #include "ns3/callback-trace-source.h" #include "ns3/nstime.h" #include "ns3/data-rate.h" +#include "ns3/default-value.h" #include "ns3/ptr.h" namespace ns3 { @@ -80,7 +81,8 @@ public: * @see PointToPointTopology::AddPointToPointLink () * @param node the Node to which this device is connected. */ - PointToPointNetDevice (Ptr node); + PointToPointNetDevice (Ptr node, + const DataRate& = g_defaultRate.GetValue()); /** * Copy Construct a PointToPointNetDevice * @@ -105,7 +107,7 @@ public: * * @param nd the object to be copied */ - PointToPointNetDevice& operator= (PointToPointNetDevice nd); + PointToPointNetDevice& operator= (const PointToPointNetDevice& nd); /** * Set the Data Rate used for transmission of packets. The data rate is * set in the Attach () method from the corresponding field in the channel @@ -114,7 +116,7 @@ public: * @see Attach () * @param bps the data rate at which this object operates */ - void SetDataRate(DataRate bps); + void SetDataRate(const DataRate& bps); /** * Set the inteframe gap used to separate packets. The interframe gap * defines the minimum space required between packets sent by this device. @@ -125,7 +127,7 @@ public: * @see Attach () * @param t the interframe gap time */ - void SetInterframeGap(Time t); + void SetInterframeGap(const Time& t); /** * Attach the device to a channel. * @@ -190,6 +192,19 @@ protected: * @returns a pointer to the channel */ virtual Ptr DoGetChannel(void) const; + /** + * Set a new default data rate + * @param Data rate to set for new default + */ + static void SetDefaultRate(const DataRate&); + + /** + * Get the current default rate. + * @returns a const reference to current default + */ + + static const DataRate& GetDefaultRate(); + private: /** * Send a Packet Down the Wire. @@ -223,33 +238,11 @@ private: /** * Stop Sending a Packet Down the Wire and Begin the Interframe Gap. * - * The TransmitCompleteEvent method is used internally to finish the process - * of sending a packet out on the channel. During execution of this method - * the TransmitEnd method is called on the channel to let it know that the - * physical device this class represents has virually finished sending - * signals. The channel uses this event to begin its speed of light delay - * timer after which it notifies the Net Device at the other end of the - * link that the bits have arrived. During this method, the net device - * also schedules the TransmitReadyEvent at which time the transmitter - * becomes ready to send the next packet. + * The TransmitComplete method is used internally to finish the process + * of sending a packet out on the channel. * - * @see PointToPointChannel::TransmitEnd () - * @see TransmitReadyEvent () - * @returns true if success, false on failure */ - void TransmitCompleteEvent (void); - /** - * Cause the Transmitter to Become Ready to Send Another Packet. - * - * The TransmitReadyEvent method is used internally to re-enable the - * transmit machine of the net device. It is scheduled after a suitable - * interframe gap after the completion of the previous transmission. - * The queue is checked at this time, and if there is a packet waiting on - * the queue, the transmission process is begun. - * - * @see TransmitStart () - */ - void TransmitReadyEvent (void); + void TransmitComplete(void); /** * Create a Trace Resolver for events in the net device. * @@ -263,8 +256,7 @@ private: enum TxMachineState { READY, /**< The transmitter is ready to begin transmission of a packet */ - BUSY, /**< The transmitter is busy transmitting a packet */ - GAP /**< The transmitter is in the interframe gap time */ + BUSY /**< The transmitter is busy transmitting a packet */ }; /** * The state of the Net Device transmit state machine. @@ -305,6 +297,11 @@ private: * @see class TraceResolver */ CallbackTraceSource m_rxTrace; + /** + * Default data rate. Used for all newly created p2p net devices + */ + static DataRateDefaultValue g_defaultRate; + }; }; // namespace ns3 diff --git a/src/node/mac-address.cc b/src/node/mac-address.cc index be455a8a3..9dcf9bdd6 100644 --- a/src/node/mac-address.cc +++ b/src/node/mac-address.cc @@ -33,6 +33,9 @@ namespace ns3 { +// Static variables +uint8_t MacAddress::g_nextAddress[MacAddress::MAX_LEN]; + static char AsciiToLowCase (char c) { @@ -54,6 +57,13 @@ MacAddress::MacAddress () : m_len(0) } } +MacAddress::MacAddress(uint8_t len) : m_len(len) +{ + NS_ASSERT (len <= MacAddress::MAX_LEN); + AdvanceAddress(); + memcpy(m_address, g_nextAddress, len); +} + MacAddress::MacAddress (uint8_t const *address, uint8_t len) { NS_ASSERT (len <= MacAddress::MAX_LEN); @@ -148,6 +158,17 @@ MacAddress::Set (uint8_t const ad[MacAddress::MAX_LEN], uint8_t len) m_len = len; } +// Static methods +void MacAddress::AdvanceAddress() + { + // Advance to next address, little end first + for(size_t i = 0; i < MAX_LEN; ++i) + { + if (++g_nextAddress[i] != 0) break; + } + } + +// Non-member operators bool operator == (MacAddress const&a, MacAddress const&b) { return a.IsEqual (b); diff --git a/src/node/mac-address.h b/src/node/mac-address.h index 75a80b700..76c5a6ae0 100644 --- a/src/node/mac-address.h +++ b/src/node/mac-address.h @@ -46,6 +46,13 @@ public: * This MacAddress has length of zero, and is internally all zeros */ MacAddress (void); + /** + * \brief Construct a MacAddress using the next available + * address. + * \see MacAddres::Next + * \param len length, in bytes, of the desired address + */ + MacAddress(uint8_t len); /** * \brief Construct a MacAddress from a byte-array * @@ -97,6 +104,14 @@ public: */ void Set (uint8_t const ad[MAX_LEN], uint8_t len); + // Static methods/members + /** + * + * Advance the global to the next available mac address. + */ + static void AdvanceAddress(); + static uint8_t g_nextAddress[MAX_LEN]; + private: uint8_t m_address[MAX_LEN]; uint8_t m_len; From 96418f577d8b2f89c002543e796f1f96f9666d24 Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Thu, 14 Jun 2007 13:09:56 +0100 Subject: [PATCH 06/21] re-sync cairo-wideint.c with upstream cairo's version (also fixes the recent compiler warning, but in a different way) --- src/simulator/cairo-wideint.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/simulator/cairo-wideint.c b/src/simulator/cairo-wideint.c index 1b2ffe1b4..957de8e51 100644 --- a/src/simulator/cairo-wideint.c +++ b/src/simulator/cairo-wideint.c @@ -658,7 +658,7 @@ _cairo_int128_divrem (cairo_int128_t num, cairo_int128_t den) * Compute a 32 bit quotient and 64 bit remainder of a 96 bit unsigned * dividend and 64 bit divisor. If the quotient doesn't fit into 32 * bits then the returned remainder is equal to the divisor, and the - * qoutient is the largest representable 64 bit integer. It is an + * quotient is the largest representable 64 bit integer. It is an * error to call this function with the high 32 bits of @num being * non-zero. */ cairo_uquorem64_t @@ -776,7 +776,7 @@ _cairo_int_96by64_32x64_divrem (cairo_int128_t num, cairo_int64_t den) { int num_neg = _cairo_int128_negative (num); int den_neg = _cairo_int64_negative (den); - cairo_int64_t nonneg_den = den; + cairo_uint64_t nonneg_den; cairo_uquorem64_t uqr; cairo_quorem64_t qr; @@ -784,6 +784,8 @@ _cairo_int_96by64_32x64_divrem (cairo_int128_t num, cairo_int64_t den) num = _cairo_int128_negate (num); if (den_neg) nonneg_den = _cairo_int64_negate (den); + else + nonneg_den = den; uqr = _cairo_uint_96by64_32x64_divrem (num, nonneg_den); if (_cairo_uint64_eq (uqr.rem, _cairo_int64_to_uint64 (nonneg_den))) { From 65aca43f3ffe04af77177220b999b9e1a2deb7b7 Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Fri, 15 Jun 2007 15:19:38 +0100 Subject: [PATCH 07/21] WAF: make all ns3 modules register themselves in the environment; link the run-tests program with all ns3 modules, not with a hardcoded list. --- src/applications/wscript | 4 ++++ src/common/wscript | 2 ++ src/core/wscript | 2 ++ src/devices/p2p/wscript | 4 ++++ src/internet-node/wscript | 4 ++++ src/node/wscript | 3 +++ src/simulator/wscript | 2 ++ src/wscript | 1 + utils/wscript | 13 +++++++------ 9 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/applications/wscript b/src/applications/wscript index e6f9582bd..85fa0513b 100644 --- a/src/applications/wscript +++ b/src/applications/wscript @@ -1,6 +1,10 @@ ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- +def configure(conf): + conf.env.append_value('NS3_MODULES', 'ns3-applications') + + def build(bld): obj = bld.create_obj('cpp', 'shlib') obj.name = 'ns3-applications' diff --git a/src/common/wscript b/src/common/wscript index b62e204b2..65753d930 100644 --- a/src/common/wscript +++ b/src/common/wscript @@ -1,5 +1,7 @@ ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- +def configure(conf): + conf.env.append_value('NS3_MODULES', 'ns3-common') def build(bld): common = bld.create_obj('cpp', 'shlib') diff --git a/src/core/wscript b/src/core/wscript index 222539171..ce9795c8e 100644 --- a/src/core/wscript +++ b/src/core/wscript @@ -3,6 +3,8 @@ import sys def configure(conf): + conf.env.append_value('NS3_MODULES', 'ns3-core') + e = conf.create_header_configurator() e.mandatory = False e.name = 'stdlib.h' diff --git a/src/devices/p2p/wscript b/src/devices/p2p/wscript index 73b27d061..c4c0f7952 100644 --- a/src/devices/p2p/wscript +++ b/src/devices/p2p/wscript @@ -1,6 +1,10 @@ ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- +def configure(conf): + conf.env.append_value('NS3_MODULES', 'ns3-p2p') + + def build(bld): p2p = bld.create_obj('cpp', 'shlib') p2p.name = 'ns3-p2p' diff --git a/src/internet-node/wscript b/src/internet-node/wscript index bf3236159..806861fd3 100644 --- a/src/internet-node/wscript +++ b/src/internet-node/wscript @@ -1,6 +1,10 @@ ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- +def configure(conf): + conf.env.append_value('NS3_MODULES', 'ns3-internet-node') + + def build(bld): obj = bld.create_obj('cpp', 'shlib') obj.name = 'ns3-internet-node' diff --git a/src/node/wscript b/src/node/wscript index b39d6fa1e..c608945c7 100644 --- a/src/node/wscript +++ b/src/node/wscript @@ -1,5 +1,8 @@ ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- +def configure(conf): + conf.env.append_value('NS3_MODULES', 'ns3-node') + def build(bld): node = bld.create_obj('cpp', 'shlib') diff --git a/src/simulator/wscript b/src/simulator/wscript index b18ec3802..3f038d813 100644 --- a/src/simulator/wscript +++ b/src/simulator/wscript @@ -13,6 +13,8 @@ def set_options(opt): def configure(conf): + conf.env.append_value('NS3_MODULES', 'ns3-simulator') + if Params.g_options.high_precision_as_double: conf.add_define('USE_HIGH_PRECISION_DOUBLE', 1) conf.env['USE_HIGH_PRECISION_DOUBLE'] = 1 diff --git a/src/wscript b/src/wscript index ae5647577..2e2349f10 100644 --- a/src/wscript +++ b/src/wscript @@ -29,6 +29,7 @@ def configure(conf): blddir = os.path.abspath(os.path.join(conf.m_blddir, conf.env.variant())) for module in all_modules: + conf.sub_config(module) conf.env.append_value('NS3_MODULE_PATH', os.path.join(blddir, 'src', module)) diff --git a/utils/wscript b/utils/wscript index cc0755526..fb9857559 100644 --- a/utils/wscript +++ b/utils/wscript @@ -1,23 +1,24 @@ ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- -import sys -import Params def build(bld): + env = bld.env_of_name('default') def create_ns_prog(name, source): obj = bld.create_obj('cpp', 'program') obj.target = name - obj.uselib_local = "ns3-core ns3-common ns3-simulator" obj.source = source return obj unit_tests = create_ns_prog('run-tests', 'run-tests.cc') unit_tests.install_var = 0 # do not install unit_tests.unit_test = 1 # runs on 'waf check' + ## link unit test program with all ns3 modules + unit_tests.uselib_local = env['NS3_MODULES'] + print env['NS3_MODULES'] - #if sys.platform != 'win32': obj = create_ns_prog('bench-simulator', 'bench-simulator.cc') + obj.uselib_local = "ns3-core ns3-common ns3-simulator" + obj = create_ns_prog('replay-simulation', 'replay-simulation.cc') - ## bench-packets requires missing header files - #obj = create_ns_prog('bench-packets', 'bench-packets.cc') + obj.uselib_local = "ns3-core ns3-common ns3-simulator" From ce155b4d353e5913b0616e9383bab377f6a37899 Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Fri, 15 Jun 2007 15:25:01 +0100 Subject: [PATCH 08/21] WAF: remove debugging print accidentally left in. --- utils/wscript | 1 - 1 file changed, 1 deletion(-) diff --git a/utils/wscript b/utils/wscript index fb9857559..27c509c01 100644 --- a/utils/wscript +++ b/utils/wscript @@ -15,7 +15,6 @@ def build(bld): unit_tests.unit_test = 1 # runs on 'waf check' ## link unit test program with all ns3 modules unit_tests.uselib_local = env['NS3_MODULES'] - print env['NS3_MODULES'] obj = create_ns_prog('bench-simulator', 'bench-simulator.cc') obj.uselib_local = "ns3-core ns3-common ns3-simulator" From d5260811dcdd63e72284499b2f4b79d938efb010 Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Fri, 15 Jun 2007 18:10:40 +0100 Subject: [PATCH 09/21] Add a Packet::AddAtEnd unit test. --- src/common/packet.cc | 55 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/src/common/packet.cc b/src/common/packet.cc index 459cdae39..4acc7fe0e 100644 --- a/src/common/packet.cc +++ b/src/common/packet.cc @@ -119,3 +119,58 @@ Packet::Print (std::ostream &os) const {} }; // namespace ns3 + + + +#ifdef RUN_SELF_TESTS + +#include "ns3/test.h" +#include + +namespace ns3 { + +class PacketTest: public Test { +public: + virtual bool RunTests (void); + PacketTest (); +}; + + +PacketTest::PacketTest () + : Test ("Packet") {} + + +bool +PacketTest::RunTests (void) +{ + bool ok = true; + + Packet pkt1 (reinterpret_cast ("hello"), 5); + Packet pkt2 (reinterpret_cast (" world"), 6); + Packet packet; + packet.AddAtEnd (pkt1); + packet.AddAtEnd (pkt2); + + if (packet.GetSize () != 11) + { + Failure () << "expected size 11, got " << packet.GetSize () << std::endl; + ok = false; + } + + std::string msg = std::string (reinterpret_cast(packet.PeekData ()), + packet.GetSize ()); + if (msg != "hello world") + { + Failure () << "expected size 'hello world', got " << msg << std::endl; + ok = false; + } + + return ok; +} + + +static PacketTest gPacketTest; + +}; // namespace ns3 + +#endif /* RUN_SELF_TESTS */ From d1c6c9a348101466aaf94772b0f633881321aef1 Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Fri, 15 Jun 2007 13:19:57 -0700 Subject: [PATCH 10/21] back out unfinished p2p changes --- src/devices/p2p/p2p-channel.cc | 6 +- src/devices/p2p/p2p-net-device.cc | 150 +++++++++++++++++++++++------- src/devices/p2p/p2p-net-device.h | 59 ++++++------ src/node/mac-address.cc | 21 ----- src/node/mac-address.h | 15 --- 5 files changed, 147 insertions(+), 104 deletions(-) diff --git a/src/devices/p2p/p2p-channel.cc b/src/devices/p2p/p2p-channel.cc index be4851553..2833c8bb1 100644 --- a/src/devices/p2p/p2p-channel.cc +++ b/src/devices/p2p/p2p-channel.cc @@ -135,14 +135,12 @@ PointToPointChannel::TransmitEnd(Packet& p, Ptr src) // The sender is going to free the packet as soon as it has been transmitted. // We need to copy it to get a reference so it won't e deleted. // -// Above is not correct (GFR). The event scheduler makes a copy -// of the packet -// Packet packet = p; + Packet packet = p; NS_DEBUG ("PointToPointChannel::TransmitEnd (): Schedule event in " << m_delay.GetSeconds () << "sec"); Simulator::Schedule (m_delay, &PointToPointChannel::PropagationCompleteEvent, - this, p, src); + this, packet, src); return true; } diff --git a/src/devices/p2p/p2p-net-device.cc b/src/devices/p2p/p2p-net-device.cc index 2667e388f..9542d951b 100644 --- a/src/devices/p2p/p2p-net-device.cc +++ b/src/devices/p2p/p2p-net-device.cc @@ -16,8 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * Author: Craig Dowell - * Revised: George Riley + * Author: Mathieu Lacage */ #include @@ -33,17 +32,11 @@ NS_DEBUG_COMPONENT_DEFINE ("PointToPointNetDevice"); namespace ns3 { -DataRateDefaultValue PointToPointNetDevice::g_defaultRate( - "PointToPointLinkDataRate", - "The default data rate for point to point links", - DataRate ("10Mb/s")); - - PointToPointNetDevice::PointToPointNetDevice (Ptr node, - const DataRate& rate) +PointToPointNetDevice::PointToPointNetDevice (Ptr node) : - NetDevice(node, MacAddress (6)), + NetDevice(node, MacAddress ("00:00:00:00:00:00")), m_txMachineState (READY), - m_bps (rate), + m_bps (DataRate (0xffffffff)), m_tInterframeGap (Seconds(0)), m_channel (0), m_queue (0), @@ -108,25 +101,26 @@ void PointToPointNetDevice::DoDispose() // // Assignment operator for PointToPointNetDevice. // +// This uses the non-obvious trick of taking the source net device passed by +// value instead of by reference. This causes the copy constructor to be +// invoked (where the real work is done -- see above). All we have to do +// here is to return the newly constructed net device. // -PointToPointNetDevice& -PointToPointNetDevice::operator= (const PointToPointNetDevice& nd) + PointToPointNetDevice& +PointToPointNetDevice::operator= (const PointToPointNetDevice nd) { NS_DEBUG ("PointToPointNetDevice::operator= (" << &nd << ")"); - // FIXME. Not sure what to do here - // GFR Note. I would suggest dis-allowing netdevice assignment, - // as well as pass-by-value (ie. copy constructor). return *this; } void -PointToPointNetDevice::SetDataRate(const DataRate& bps) +PointToPointNetDevice::SetDataRate(DataRate bps) { m_bps = bps; } void -PointToPointNetDevice::SetInterframeGap(const Time& t) +PointToPointNetDevice::SetInterframeGap(Time t) { m_tInterframeGap = t; } @@ -139,23 +133,68 @@ PointToPointNetDevice::SendTo (Packet& p, const MacAddress& dest) NS_ASSERT (IsLinkUp ()); +#ifdef NOTYET + struct NetDevicePacketDestAddress tag; + tag.address = address; + p.AddTag (tag); +#endif + // // This class simulates a point to point device. In the case of a serial // link, this means that we're simulating something like a UART. This is // not a requirement for a point-to-point link, but it's a typical model for // the device. // +// Generally, a real device will have a list of pending packets to transmit. +// An on-device CPU frees the main CPU(s) of the details of what is happening +// in the device and feeds the USART. The main CPU basically just sees the +// list of packets -- it puts packets into the list, and the device frees the +// packets when they are transmitted. +// +// In the case of our virtual device here, the queue pointed to by m_queue +// corresponds to this list. The main CPU adds packets to the list by +// calling this method and when the device completes a send, the packets are +// freed in an "interrupt" service routine. +// +// We're going to do the same thing here. So first of all, the incoming packet +// goes onto our queue if possible. If the queue can't handle it, there's +// nothing to be done. +// + if (m_queue->Enqueue(p) == false ) + { + return false; + } +// +// If there's a transmission in progress, the "interrupt" will keep the +// transmission process going. If the device is idle, we need to start a +// transmission. +// +// In the real world, the USART runs until it finishes sending bits, and then +// pulls on the device's transmit complete interrupt wire. At the same time, +// the electrons from the last wiggle of the wire are busy propagating down +// the wire. In the case of a long speed-of-light delay in the wire, we could +// conceivably start transmitting the next packet before the end of the +// previously sent data has even reached the end of the wire. This situation +// is usually avoided (like the plague) and an "interframe gap" is introduced. +// This is usually the round-trip delay on the channel plus some hard-to- +// quantify receiver turn-around time (the time required for the receiver +// to process the last frame and prepare for reception of the next). +// +// So, if the transmit machine is ready, we need to schedule a transmit +// complete event (at which time we tell the channel we're no longer sending +// bits). A separate transmit ready event (at which time the transmitter +// becomes ready to start sending bits again is scheduled there). Finally, +// we tell the channel (via TransmitStart ()) that we've started wiggling the +// wire and bits are coming out. +// +// If the transmit machine is not ready, we just leave and the transmit ready +// event we know is coming will kick-start the transmit process. // -// If there's a transmission in progress, we enque the packet for later -// trnsmission; otherwise we send it now. if (m_txMachineState == READY) { return TransmitStart (p); } - else - { - return m_queue->Enqueue(p); - } + return true; } bool @@ -167,25 +206,25 @@ PointToPointNetDevice::TransmitStart (Packet &p) // // This function is called to start the process of transmitting a packet. // We need to tell the channel that we've started wiggling the wire and -// schedule an event that will be executed when the transmission is complete. +// schedule an event that will be executed when it's time to tell the +// channel that we're done wiggling the wire. // NS_ASSERT_MSG(m_txMachineState == READY, "Must be READY to transmit"); m_txMachineState = BUSY; - Time txCompleteTime = Seconds (m_bps.CalculateTxTime(p.GetSize())) + - m_tInterframeGap; + Time tEvent = Seconds (m_bps.CalculateTxTime(p.GetSize())); NS_DEBUG ("PointToPointNetDevice::TransmitStart (): " << "Schedule TransmitCompleteEvent in " << - txCompleteTime.GetSeconds () << "sec"); - // Schedule the tx complete event - Simulator::Schedule (txCompleteTime, - &PointToPointNetDevice::TransmitComplete, + tEvent.GetSeconds () << "sec"); + + Simulator::Schedule (tEvent, + &PointToPointNetDevice::TransmitCompleteEvent, this); - return m_channel->TransmitStart(p, this); + return m_channel->TransmitStart (p, this); } void -PointToPointNetDevice::TransmitComplete (void) +PointToPointNetDevice::TransmitCompleteEvent (void) { NS_DEBUG ("PointToPointNetDevice::TransmitCompleteEvent ()"); // @@ -195,10 +234,49 @@ PointToPointNetDevice::TransmitComplete (void) // the transmitter after the interframe gap. // NS_ASSERT_MSG(m_txMachineState == BUSY, "Must be BUSY if transmitting"); - m_txMachineState = READY; + m_txMachineState = GAP; Packet p; - if (!m_queue->Dequeue(p)) return; // Nothing to do at this point - TransmitStart(p); + bool found; + found = m_queue->Dequeue (p); + NS_ASSERT_MSG(found, "Packet must be on queue if transmitted"); + NS_DEBUG ("PointToPointNetDevice::TransmitCompleteEvent (): Pkt UID is " << + p.GetUid () << ")"); + m_channel->TransmitEnd (p, this); + + NS_DEBUG ( + "PointToPointNetDevice::TransmitCompleteEvent (): " << + "Schedule TransmitReadyEvent in " + << m_tInterframeGap.GetSeconds () << "sec"); + + Simulator::Schedule (m_tInterframeGap, + &PointToPointNetDevice::TransmitReadyEvent, + this); +} + + void +PointToPointNetDevice::TransmitReadyEvent (void) +{ + NS_DEBUG ("PointToPointNetDevice::TransmitReadyEvent ()"); +// +// This function is called to enable the transmitter after the interframe +// gap has passed. If there are pending transmissions, we use this opportunity +// to start the next transmit. +// + NS_ASSERT_MSG(m_txMachineState == GAP, "Must be in interframe gap"); + m_txMachineState = READY; + + if (m_queue->IsEmpty()) + { + return; + } + else + { + Packet p; + bool found; + found = m_queue->Peek (p); + NS_ASSERT_MSG(found, "IsEmpty false but no Packet on queue?"); + TransmitStart (p); + } } TraceResolver * diff --git a/src/devices/p2p/p2p-net-device.h b/src/devices/p2p/p2p-net-device.h index 5fb3e8016..e1eb8a666 100644 --- a/src/devices/p2p/p2p-net-device.h +++ b/src/devices/p2p/p2p-net-device.h @@ -30,7 +30,6 @@ #include "ns3/callback-trace-source.h" #include "ns3/nstime.h" #include "ns3/data-rate.h" -#include "ns3/default-value.h" #include "ns3/ptr.h" namespace ns3 { @@ -81,8 +80,7 @@ public: * @see PointToPointTopology::AddPointToPointLink () * @param node the Node to which this device is connected. */ - PointToPointNetDevice (Ptr node, - const DataRate& = g_defaultRate.GetValue()); + PointToPointNetDevice (Ptr node); /** * Copy Construct a PointToPointNetDevice * @@ -107,7 +105,7 @@ public: * * @param nd the object to be copied */ - PointToPointNetDevice& operator= (const PointToPointNetDevice& nd); + PointToPointNetDevice& operator= (PointToPointNetDevice nd); /** * Set the Data Rate used for transmission of packets. The data rate is * set in the Attach () method from the corresponding field in the channel @@ -116,7 +114,7 @@ public: * @see Attach () * @param bps the data rate at which this object operates */ - void SetDataRate(const DataRate& bps); + void SetDataRate(DataRate bps); /** * Set the inteframe gap used to separate packets. The interframe gap * defines the minimum space required between packets sent by this device. @@ -127,7 +125,7 @@ public: * @see Attach () * @param t the interframe gap time */ - void SetInterframeGap(const Time& t); + void SetInterframeGap(Time t); /** * Attach the device to a channel. * @@ -192,19 +190,6 @@ protected: * @returns a pointer to the channel */ virtual Ptr DoGetChannel(void) const; - /** - * Set a new default data rate - * @param Data rate to set for new default - */ - static void SetDefaultRate(const DataRate&); - - /** - * Get the current default rate. - * @returns a const reference to current default - */ - - static const DataRate& GetDefaultRate(); - private: /** * Send a Packet Down the Wire. @@ -238,11 +223,33 @@ private: /** * Stop Sending a Packet Down the Wire and Begin the Interframe Gap. * - * The TransmitComplete method is used internally to finish the process - * of sending a packet out on the channel. + * The TransmitCompleteEvent method is used internally to finish the process + * of sending a packet out on the channel. During execution of this method + * the TransmitEnd method is called on the channel to let it know that the + * physical device this class represents has virually finished sending + * signals. The channel uses this event to begin its speed of light delay + * timer after which it notifies the Net Device at the other end of the + * link that the bits have arrived. During this method, the net device + * also schedules the TransmitReadyEvent at which time the transmitter + * becomes ready to send the next packet. * + * @see PointToPointChannel::TransmitEnd () + * @see TransmitReadyEvent () + * @returns true if success, false on failure */ - void TransmitComplete(void); + void TransmitCompleteEvent (void); + /** + * Cause the Transmitter to Become Ready to Send Another Packet. + * + * The TransmitReadyEvent method is used internally to re-enable the + * transmit machine of the net device. It is scheduled after a suitable + * interframe gap after the completion of the previous transmission. + * The queue is checked at this time, and if there is a packet waiting on + * the queue, the transmission process is begun. + * + * @see TransmitStart () + */ + void TransmitReadyEvent (void); /** * Create a Trace Resolver for events in the net device. * @@ -256,7 +263,8 @@ private: enum TxMachineState { READY, /**< The transmitter is ready to begin transmission of a packet */ - BUSY /**< The transmitter is busy transmitting a packet */ + BUSY, /**< The transmitter is busy transmitting a packet */ + GAP /**< The transmitter is in the interframe gap time */ }; /** * The state of the Net Device transmit state machine. @@ -297,11 +305,6 @@ private: * @see class TraceResolver */ CallbackTraceSource m_rxTrace; - /** - * Default data rate. Used for all newly created p2p net devices - */ - static DataRateDefaultValue g_defaultRate; - }; }; // namespace ns3 diff --git a/src/node/mac-address.cc b/src/node/mac-address.cc index 9dcf9bdd6..be455a8a3 100644 --- a/src/node/mac-address.cc +++ b/src/node/mac-address.cc @@ -33,9 +33,6 @@ namespace ns3 { -// Static variables -uint8_t MacAddress::g_nextAddress[MacAddress::MAX_LEN]; - static char AsciiToLowCase (char c) { @@ -57,13 +54,6 @@ MacAddress::MacAddress () : m_len(0) } } -MacAddress::MacAddress(uint8_t len) : m_len(len) -{ - NS_ASSERT (len <= MacAddress::MAX_LEN); - AdvanceAddress(); - memcpy(m_address, g_nextAddress, len); -} - MacAddress::MacAddress (uint8_t const *address, uint8_t len) { NS_ASSERT (len <= MacAddress::MAX_LEN); @@ -158,17 +148,6 @@ MacAddress::Set (uint8_t const ad[MacAddress::MAX_LEN], uint8_t len) m_len = len; } -// Static methods -void MacAddress::AdvanceAddress() - { - // Advance to next address, little end first - for(size_t i = 0; i < MAX_LEN; ++i) - { - if (++g_nextAddress[i] != 0) break; - } - } - -// Non-member operators bool operator == (MacAddress const&a, MacAddress const&b) { return a.IsEqual (b); diff --git a/src/node/mac-address.h b/src/node/mac-address.h index 76c5a6ae0..75a80b700 100644 --- a/src/node/mac-address.h +++ b/src/node/mac-address.h @@ -46,13 +46,6 @@ public: * This MacAddress has length of zero, and is internally all zeros */ MacAddress (void); - /** - * \brief Construct a MacAddress using the next available - * address. - * \see MacAddres::Next - * \param len length, in bytes, of the desired address - */ - MacAddress(uint8_t len); /** * \brief Construct a MacAddress from a byte-array * @@ -104,14 +97,6 @@ public: */ void Set (uint8_t const ad[MAX_LEN], uint8_t len); - // Static methods/members - /** - * - * Advance the global to the next available mac address. - */ - static void AdvanceAddress(); - static uint8_t g_nextAddress[MAX_LEN]; - private: uint8_t m_address[MAX_LEN]; uint8_t m_len; From c329d7dd4e8c306c0a0554735e005df6e14d41c8 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Sat, 16 Jun 2007 17:15:58 +0200 Subject: [PATCH 11/21] improve Packet Header/Trailer API dox --- src/common/header.h | 8 ++++++++ src/common/trailer.h | 8 +++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/common/header.h b/src/common/header.h index b51b520ba..0a8eb9643 100644 --- a/src/common/header.h +++ b/src/common/header.h @@ -49,6 +49,10 @@ private: /** * \returns the size of the serialized Header. + * + * This method is used by Packet::AddHeader to reserve + * enough room in the packet byte buffer prior to calling + * Header::Serialize. */ virtual uint32_t GetSerializedSize (void) const = 0; @@ -63,6 +67,10 @@ private: * deserialize itself. This iterator identifies * the start of the buffer. * \returns the number of bytes read from the buffer + * + * The value returned is used to trim the packet byte buffer of the + * corresponding amount when this method is invoked from + * Packet::RemoveHeader */ virtual uint32_t DeserializeFrom (Buffer::Iterator start) = 0; }; diff --git a/src/common/trailer.h b/src/common/trailer.h index 9919df89d..a2f9589ae 100644 --- a/src/common/trailer.h +++ b/src/common/trailer.h @@ -75,6 +75,10 @@ private: /** * \returns the size of the serialized Trailer. + * + * This method is used by Packet::AddTrailer to reserve + * enough room in the packet byte buffer prior to calling + * Trailer::Serialize. */ virtual uint32_t GetSerializedSize (void) const = 0; @@ -94,7 +98,9 @@ private: * \returns the number of bytes read from the buffer * * This iterator must be typically moved with the Buffer::Iterator::Prev - * method before reading any byte in the buffer. + * method before reading any byte in the buffer. The value returned + * is used to trim the packet byte buffer of the corresponding + * amount when this method is invoked from Packet::RemoveTrailer */ virtual uint32_t DeserializeFrom (Buffer::Iterator end) = 0; }; From 396c76892c2261e76523ae97615e086888fde333 Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Sun, 17 Jun 2007 14:17:22 -0700 Subject: [PATCH 12/21] release_steps.txt document --- doc/release_steps.txt | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 doc/release_steps.txt diff --git a/doc/release_steps.txt b/doc/release_steps.txt new file mode 100644 index 000000000..e5c17ddfc --- /dev/null +++ b/doc/release_steps.txt @@ -0,0 +1,19 @@ +Steps in doing an ns-3 release + +1. prepare the source files + - revise and check in AUTHORS, if needed + - revise and check in RELEASE_NOTES + - update and check in VERSION to the latest release number +2. make a new "architecture.pdf" document and place it in the doc/ directory +3. scons dist +4. test tarball on release platforms (run-tests and simple-p2p) +5. tag ns-3-dev with "release ns-3.0.X" +6. clone the ns-3-dev and place it on the repository +7. upload "ns-3.0.x.tar.gz" to the releases/ directory on the server +8. update web page + - add link to news.html + - update download.html + - update roadmap.html + - build and update Doxygen directory on the server + - update and upload software architecture document (PDF, HTML) +9. announce to ns-developers, with summary of release notes From e9ae18f809a42ead853b68865da7357bb069397d Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Sun, 17 Jun 2007 16:04:12 -0700 Subject: [PATCH 13/21] bump VERSION number --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index b50214693..75a22a26a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.0.2 +3.0.3 From 5e703c70f7fffa061dde175ff3ede08fe5178714 Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Sun, 17 Jun 2007 16:04:52 -0700 Subject: [PATCH 14/21] Added tag release ns-3.0.3 for changeset 38099dd26e94 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index b812011d2..6ffe67f46 100644 --- a/.hgtags +++ b/.hgtags @@ -1,2 +1,3 @@ 56928998e05c9c11f5f3aefe79be8d2843e0db88 release ns-3.0.1 7ac5a4b0969b255c4824c926c2b37ef450136ce9 release ns-3.0.2 +38099dd26e9467b8f49f8632f22789858149a6e7 release ns-3.0.3 From 5f48c4e7f3067d6c45042dd938a51c2523f7bc1a Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Mon, 18 Jun 2007 10:53:48 +0100 Subject: [PATCH 15/21] add waf.bat for convenience (waf itself still has to be manually copied from outside, though) --- waf.bat | 1 + 1 file changed, 1 insertion(+) create mode 100755 waf.bat diff --git a/waf.bat b/waf.bat new file mode 100755 index 000000000..bc191a5ee --- /dev/null +++ b/waf.bat @@ -0,0 +1 @@ +@python -x waf %* & exit /b From 0dfdcfbdc37166dc1772737d8167a82d4f9ffeeb Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Fri, 1 Jun 2007 12:42:29 +0200 Subject: [PATCH 16/21] add test and fix buggy assert --- src/common/buffer.cc | 8 ++++++++ src/common/buffer.h | 3 ++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/common/buffer.cc b/src/common/buffer.cc index e725ecd2a..2c64f8920 100644 --- a/src/common/buffer.cc +++ b/src/common/buffer.cc @@ -655,6 +655,14 @@ BufferTest::RunTests (void) i.Prev (1); i.WriteU8 (1, 1); + buffer = Buffer (6); + buffer.AddAtStart (3); + buffer.RemoveAtEnd (8); + buffer.AddAtEnd (4); + i = buffer.End (); + i.Prev (4); + i.WriteU8 (1, 4); + return ok; } diff --git a/src/common/buffer.h b/src/common/buffer.h index 500e11f7c..4986d4998 100644 --- a/src/common/buffer.h +++ b/src/common/buffer.h @@ -522,7 +522,8 @@ Buffer::Iterator::GetIndex (uint32_t n) NS_ASSERT ( (m_current + n <= m_dataEnd) && ((m_current + n <= m_zeroStart) || - (m_current >= m_zeroEnd)) + (m_current >= m_zeroEnd) || + m_zeroStart == m_zeroEnd) ); uint32_t index; if (m_current < m_zeroStart) From 3b96881ba2b9b575f06f6899a20f15c3460ca97a Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Mon, 18 Jun 2007 15:55:47 +0100 Subject: [PATCH 17/21] Bug 37: NS_TEST_ASSERT_EQUAL --- src/core/test.h | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/core/test.h b/src/core/test.h index aa7766f42..982cb989c 100644 --- a/src/core/test.h +++ b/src/core/test.h @@ -101,6 +101,41 @@ private: }; }; // namespace ns3 +/** + * Convenience macro to check that a value returned by a test is what + * is expected. Note: this macro assumes a 'bool result = true' + * declaration exists in the test function body, and that the function + * returns that value. + * + * \param got value obtained from the test + * \param expected value that the test is expected to return + */ +#define NS_TEST_ASSERT_EQUAL(got, expected) \ + if ((got) != (expected)) \ + { \ + Failure () << __FILE__ << ":" <<__LINE__ \ + << ": expected " << (expected) \ + << ", got " << (got) << std::endl; \ + result = false; \ + } +/** + * Convenience macro to check an assertion is held during an unit + * test. Note: this macro assumes a 'bool result = true' declaration + * exists in the test function body, and that the function returns + * that value. + * + * \param assertion expression that must be true if the test did not fail + */ +#define NS_TEST_ASSERT(assertion) \ + if (!(assertion)) \ + { \ + Failure () << __FILE__ << ":" <<__LINE__ \ + << ": assertion `" << (assertion) \ + << "'failed." << std::endl; \ + result = false; \ + } + + #endif /* RUN_SELF_TESTS */ #endif /* TEST_H */ From 67454b117b1de87acbefc44a375fa6d1939d0713 Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Mon, 18 Jun 2007 18:01:28 +0100 Subject: [PATCH 18/21] Add Ipv4Mask == and != operators, similarly to Ipv4Address. --- src/node/ipv4-address.cc | 8 ++++++++ src/node/ipv4-address.h | 4 +++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/node/ipv4-address.cc b/src/node/ipv4-address.cc index 86d02792a..ca36d8083 100644 --- a/src/node/ipv4-address.cc +++ b/src/node/ipv4-address.cc @@ -230,6 +230,14 @@ std::ostream& operator<< (std::ostream& os, Ipv4Mask const& mask) mask.Print (os); return os; } +bool operator == (Ipv4Mask const &a, Ipv4Mask const &b) +{ + return a.IsEqual (b); +} +bool operator != (Ipv4Mask const &a, Ipv4Mask const &b) +{ + return !a.IsEqual (b); +} }; // namespace ns3 diff --git a/src/node/ipv4-address.h b/src/node/ipv4-address.h index f99ad9ed4..a0714ac26 100644 --- a/src/node/ipv4-address.h +++ b/src/node/ipv4-address.h @@ -126,7 +126,9 @@ class Ipv4AddressHash : public std::unary_function { public: size_t operator()(Ipv4Address const &x) const; }; -bool operator != (Ipv4Address const &a, Ipv4Address const &b); + +bool operator == (Ipv4Mask const &a, Ipv4Mask const &b); +bool operator != (Ipv4Mask const &a, Ipv4Mask const &b); }; // namespace ns3 From 75d762c0b973c85d386578f48f65eb78d20bf457 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Mon, 18 Jun 2007 19:31:27 +0200 Subject: [PATCH 19/21] fix small typos --- README | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README b/README index cb6dd3366..fc44e69cd 100644 --- a/README +++ b/README @@ -23,7 +23,7 @@ will be contributed by the community in an open collaboration process. Contributing to the ns-3 project is still a very informal -process because that process depends heavily on the personality +process because that process depends heavily on the background of the people involved, the amount of time they can invest and the type of model they want to work on. @@ -34,7 +34,7 @@ project. These steps are described in doc/contributing.txt 2) An overview of the ns-3 project ---------------------------------- -This package contains the latest version of ns-3 which is aims +This package contains the latest version of ns-3 which aims at being a replacement for ns-2. Currently, ns-3 provides a number of very simple network simulation models: - an ipv4 and udp stack @@ -93,6 +93,7 @@ The current codebase is expected to fail to build on the following platforms: - gcc 3.3 and earlier - optimized builds on linux x86 gcc 4.0 + - cygwin Other platforms may or may not work: we welcome patches to improve the portability of the code to these From 91aa5250de170bd5683e87c1ef5cd22f3bf75e11 Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Tue, 19 Jun 2007 16:59:44 +0100 Subject: [PATCH 20/21] Add Ipv4Address operator <, to allow Ipv4Address to be used in std::set; Closes #39. --- src/node/ipv4-address.cc | 5 +++++ src/node/ipv4-address.h | 2 ++ 2 files changed, 7 insertions(+) diff --git a/src/node/ipv4-address.cc b/src/node/ipv4-address.cc index ca36d8083..f8ff9f7a6 100644 --- a/src/node/ipv4-address.cc +++ b/src/node/ipv4-address.cc @@ -215,6 +215,11 @@ bool operator != (Ipv4Address const &a, Ipv4Address const &b) { return !a.IsEqual (b); } +bool operator < (Ipv4Address const &addrA, Ipv4Address const &addrB) +{ + return (addrA.GetHostOrder () < addrB.GetHostOrder ()); +} + size_t Ipv4AddressHash::operator()(Ipv4Address const &x) const { return x.GetHostOrder (); diff --git a/src/node/ipv4-address.h b/src/node/ipv4-address.h index a0714ac26..dc834052a 100644 --- a/src/node/ipv4-address.h +++ b/src/node/ipv4-address.h @@ -122,6 +122,8 @@ std::ostream& operator<< (std::ostream& os, Ipv4Mask const& mask); bool operator == (Ipv4Address const &a, Ipv4Address const &b); bool operator != (Ipv4Address const &a, Ipv4Address const &b); +bool operator < (Ipv4Address const &addrA, Ipv4Address const &addrB); + class Ipv4AddressHash : public std::unary_function { public: size_t operator()(Ipv4Address const &x) const; From 3012f74206c517e8260dda8982c6d661bee81079 Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Thu, 21 Jun 2007 00:38:58 +0100 Subject: [PATCH 21/21] WAF: configure dynamic path for the cygwin platform. --- wscript | 3 +++ 1 file changed, 3 insertions(+) diff --git a/wscript b/wscript index 779c3c136..d67039a54 100644 --- a/wscript +++ b/wscript @@ -142,6 +142,9 @@ def _run_argv(argv): elif sys.platform == 'win32': pathvar = 'PATH' pathsep = ';' + elif sys.platform == 'cygwin': + pathvar = 'PATH' + pathsep = ':' else: Params.warning(("Don't know how to configure " "dynamic library path for the platform '%s'") % (sys.platform,))