diff --git a/samples/main-header.cc b/samples/main-header.cc new file mode 100644 index 000000000..27126b8cf --- /dev/null +++ b/samples/main-header.cc @@ -0,0 +1,123 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +#include "ns3/packet.h" +#include "ns3/header.h" +#include + +using namespace ns3; + +/* A sample Header implementation + */ +class MyHeader : public Header +{ +public: + static const char *GetUid (void); + + MyHeader (); + virtual ~MyHeader (); + + void SetData (uint16_t data); + uint16_t GetData (void) const; +private: + virtual std::string DoGetName (void) const; + virtual void PrintTo (std::ostream &os) const; + virtual void SerializeTo (Buffer::Iterator start) const; + virtual uint32_t DeserializeFrom (Buffer::Iterator start); + virtual uint32_t GetSerializedSize (void) const; + + uint16_t m_data; +}; + +MyHeader::MyHeader () +{ + // we must provide a public default constructor, + // implicit or explicit, but never private. +} +MyHeader::~MyHeader () +{} + +const char * +MyHeader::GetUid (void) +{ + // This string is used by the internals of the packet + // code to keep track of the packet metadata. + // You need to make sure that this string is absolutely + // unique. The code will detect any duplicate string. + return "MyHeader.test.nsnam.org"; +} + +std::string +MyHeader::DoGetName (void) const +{ + // This string is used to identify the type of + // my header by the packet printing routines. + return "MYHEADER"; +} +void +MyHeader::PrintTo (std::ostream &os) const +{ + // This method is invoked by the packet printing + // routines to print the content of my header. + os << "data=" << m_data << std::endl; +} +uint32_t +MyHeader::GetSerializedSize (void) const +{ + // we reserve 2 bytes for our header. + return 2; +} +void +MyHeader::SerializeTo (Buffer::Iterator start) const +{ + // we can serialize two bytes at the start of the buffer. + // we write them in network byte order. + start.WriteHtonU16 (m_data); +} +uint32_t +MyHeader::DeserializeFrom (Buffer::Iterator start) +{ + // we can deserialize two bytes from the start of the buffer. + // we read them in network byte order and store them + // in host byte order. + m_data = start.ReadNtohU16 (); + + // we return the number of bytes effectively read. + return 2; +} + +void +MyHeader::SetData (uint16_t data) +{ + m_data = data; +} +uint16_t +MyHeader::GetData (void) const +{ + return m_data; +} + + + +int main (int argc, char *argv[]) +{ + // instantiate a header. + MyHeader sourceHeader; + sourceHeader.SetData (2); + + // instantiate a packet + Packet p; + // and store my header into the packet. + p.AddHeader (sourceHeader); + + // print the content of my packet on the standard output. + p.Print (std::cout); + + // you can now remove the header from the packet: + MyHeader destinationHeader; + p.RemoveHeader (destinationHeader); + + // and check that the destination and source + // headers contain the same values. + NS_ASSERT (sourceHeader.GetData () == destinationHeader.GetData ()); + + return 0; +} diff --git a/samples/main-packet.cc b/samples/main-packet.cc deleted file mode 100644 index d0796a90b..000000000 --- a/samples/main-packet.cc +++ /dev/null @@ -1,118 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -#include "ns3/packet.h" -#include "ns3/header.h" -#include - -using namespace ns3; - -/* A sample Header implementation - */ -class MyHeader : public Header -{ -public: - static const char *GetUid (void); - - MyHeader (); - virtual ~MyHeader (); - - void SetData (uint16_t data); - uint16_t GetData (void) const; -private: - virtual std::string DoGetName (void) const; - virtual void PrintTo (std::ostream &os) const; - virtual void SerializeTo (Buffer::Iterator start) const; - virtual uint32_t DeserializeFrom (Buffer::Iterator start); - virtual uint32_t GetSerializedSize (void) const; - - uint16_t m_data; -}; - -const char * -MyHeader::GetUid (void) -{ - // make sure the string is really unique. - return "MyHeader.test.nsnam.org"; -} - -MyHeader::MyHeader () -{} -MyHeader::~MyHeader () -{} -std::string -MyHeader::DoGetName (void) const -{ - return "MyHeader"; -} -void -MyHeader::PrintTo (std::ostream &os) const -{ - os << "MyHeader data=" << m_data << std::endl; -} -uint32_t -MyHeader::GetSerializedSize (void) const -{ - return 2; -} -void -MyHeader::SerializeTo (Buffer::Iterator start) const -{ - // serialize in head of buffer - start.WriteHtonU16 (m_data); -} -uint32_t -MyHeader::DeserializeFrom (Buffer::Iterator start) -{ - // deserialize from head of buffer - m_data = start.ReadNtohU16 (); - return GetSerializedSize (); -} - -void -MyHeader::SetData (uint16_t data) -{ - m_data = data; -} -uint16_t -MyHeader::GetData (void) const -{ - return m_data; -} - -/* A sample Tag implementation - */ -class MyTag -{ -public: - static const char *GetUid (void) {return "MyTag.test.nsnam.org";} - void Print (std::ostream &os) const {} - uint32_t GetSerializedSize (void) const {return 0;} - void Serialize (Buffer::Iterator i) const {} - uint32_t Deserialize (Buffer::Iterator i) {return 0;} - - uint16_t m_streamId; -}; - -static void -Receive (Packet p) -{ - MyHeader my; - p.RemoveHeader (my); - std::cout << "received data=" << my.GetData () << std::endl; - struct MyTag myTag; - p.PeekTag (myTag); -} - - -int main (int argc, char *argv[]) -{ - Packet p; - MyHeader my; - my.SetData (2); - std::cout << "send data=2" << std::endl; - p.AddHeader (my); - struct MyTag myTag; - myTag.m_streamId = 5; - p.AddTag (myTag); - Receive (p); - return 0; -} diff --git a/samples/wscript b/samples/wscript index 30c825555..eb4e4f208 100644 --- a/samples/wscript +++ b/samples/wscript @@ -14,7 +14,7 @@ def build(bld): obj = create_ns_prog('main-ptr', 'main-ptr.cc') #obj = create_ns_prog('main-trace', 'main-trace.cc') obj = create_ns_prog('main-simulator', 'main-simulator.cc') - obj = create_ns_prog('main-packet', 'main-packet.cc') + obj = create_ns_prog('main-header', 'main-header.cc') obj = create_ns_prog('main-test', 'main-test.cc') obj = create_ns_prog('main-simple', 'main-simple.cc', deps=['node', 'internet-node', 'applications']) diff --git a/src/common/header.h b/src/common/header.h index 609729b26..b70b1d731 100644 --- a/src/common/header.h +++ b/src/common/header.h @@ -36,6 +36,29 @@ namespace ns3 { * - ns3::Header::DeserializeFrom * - ns3::Header::GetSerializedSize * - ns3::Header::PrintTo + * - ns3::Header::DoGetName + * + * Each header must also make sure that: + * - it defines a public default constructor + * - it defines a public static method named GetUid which returns a string. + * + * The latter should look like the following to ensure that + * every header returns a unique string. + * \code + * class MyHeader : public Header + * { + * public: + * static const char *GetUid (void); + * }; + * + * const char *MyHeader::GetUid (void) + * { + * return "MyHeader.unique.prefix"; + * } + * \endcode + * + * Sample code which shows how to create a new Header, and how to use it, + * is shown in the sample file samples/main-header.cc */ class Header : public Chunk { public: diff --git a/src/common/packet.h b/src/common/packet.h index 807dbaaca..3e305fa3d 100644 --- a/src/common/packet.h +++ b/src/common/packet.h @@ -58,21 +58,19 @@ class PacketPrinter; * were serialized in the byte buffer. The maintenance of metadata is * optional and disabled by default. To enable it, you must call * Packet::EnableMetadata and this will allow you to get non-empty - * output from Packet::Print and Packet::PrintDefault. + * output from Packet::Print and Packet::Print. * * Implementing a new type of Header or Trailer for a new protocol is * pretty easy and is a matter of creating a subclass of the ns3::Header - * or of the ns3::Trailer base class, and implementing the 4 pure virtual + * or of the ns3::Trailer base class, and implementing the 5 pure virtual * methods defined in either of the two base classes. Users _must_ - * also implement a static public method named GetUid which is - * expected to return a unique string which uniquely identifies the - * user's new header or trailer. - * - * Sample code which shows how to create a new Header, and how to use it, - * is shown in the sample file samples/main-header.cc + * also make sure that they class defines a public default constructor and + * a public method named GetUid, as documented in the ns3::Header and ns::Trailer + * API documentations. * * Implementing a new type of Tag requires roughly the same amount of - * work: + * work: users must implement a total of 6 methods which are described in + * the ns3::Tags API documentation. * * The current implementation of the byte buffers and tag list is based * on COW (Copy On Write. An introduction to COW can be found in Scott diff --git a/src/common/trailer.h b/src/common/trailer.h index 92aef295f..457c13ccc 100644 --- a/src/common/trailer.h +++ b/src/common/trailer.h @@ -36,6 +36,26 @@ namespace ns3 { * - ns3::Trailer::DeserializeFrom * - ns3::Trailer::GetSerializedSize * - ns3::Trailer::PrintTo + * - ns3::Trailer::DoGetName + * + * Each trailer must also make sure that: + * - it defines a public default constructor + * - it defines a public static method named GetUid which returns a string. + * + * The latter should look like the following to ensure that + * every trailer returns a unique string. + * \code + * class MyTrailer : public Header + * { + * public: + * static const char *GetUid (void); + * }; + * + * const char *MyTrailer::GetUid (void) + * { + * return "MyTrailer.unique.prefix"; + * } + * \endcode * * Note that the SerializeTo and DeserializeFrom methods behave * in a way which might seem surprising to users: the input iterator