1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
3 * Copyright 2007 University of Washington
4 * Copyright 2007 Georgia Tech Research Corporation
5 * Copyright 2008 Sandia Corporation
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation;
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * Sandia is a multiprogram laboratory operated by Sandia
22 * Corporation, a Lockheed Martin Company, for the United States
23 * Department of Energy's National Nuclear Security Administration
24 * under Contract DE-AC04-94AL85000.
26 * Author: David Evensky, Sandia National Labs
28 * includes GPL'ed ns-3-dev code from:
29 * udp-echo, // ??, (c) U. Wash. 2007
30 * tcp-large-transfer // ??
31 * packet-sink // Tom Henderson, (c) U. Wash. 2007
32 * onoff // George F. Riley, (c) GT Res Corp. 2007
37 This isn't really an example file, so don't look to closely at it as a starting
38 script. It is here for validation of the TCP model.
48 #include "ns3/core-module.h"
49 #include "ns3/helper-module.h"
50 #include "ns3/node-module.h"
51 #include "ns3/global-route-manager.h"
52 #include "ns3/simulator-module.h"
57 NS_LOG_COMPONENT_DEFINE ("tcp-2way");
59 //----------defines-------------------------------------------------------------
60 //define to print more debugging info.
61 #define VERBOSE_TESTING
63 /* define to die because Socket::Recv() is told to
64 * only read an "undesired" number of bytes
65 * fails NS_ASSERT in HandleRead because rx_addr_tag
68 //#define TOO_SMALL_BUG
70 //define to print this pointer in NS_LOG_FUNCTION
73 /*define to print packet info in HandleRead
74 *expected output is of the form:
75 *536:P{536} *bytes from 10.1.0.2 [02-06-0a:01:00:02:20:00] <0|536|884018>
78 * | | | | | | | +bytes left
79 * | | | | | | | to read in
80 * | | | | | | | sent buffer
81 * | | | | | | +bytes read in
82 * | | | | | | this packet if
83 * | | | | | | header read,
84 * | | | | | | prints size
86 * | | | | | +bytes cur. packet
87 * | | | | | left to process
88 * | | | | +mac addr of sender
89 * | | | +IP addr of sender
90 * | | +print '*' while processing first chunk in a received packet.
91 * | | if there are multiple small sent packets, these can appear in
92 * | | a single packet, and are processed by a do {} while() loop.
93 * | +rle output of packet::PeekData(), in this case filled with 536 bytes
94 * | filled with the letter 'P' (brought to you by the letter 'Q' and the
98 * If there is a header it will look more like:
99 * 536:N{317}@B.{6}HELLOP{206} *bytes from 10.1.0.2 [02-06-0a:01:00:02:20:00]\
101 * 536:N{317}@B.{6}HELLOP{206} bytes from 10.1.0.2 [02-06-0a:01:00:02:20:00]\
102 * <0|206(13)|999794> (ArchHeader=HELLO:1000000)
103 * where you can see that this first packet includes 317 bytes from the
104 * previous send packet (filled with N) and 13 bytes of header before the 206
105 * bytes of payload (filled with P).
110 // dcl non-method functions....
111 std::string rle(const uint8_t *, int );
112 std::ofstream fileOut("tcp-2way.out");
114 //----------class ArchHeader dcl and definition---------------------------------
116 * ArchHeader: A toy header that holds a string
117 * and a uint32_t. The string is an abitrary label
118 * and the int is used as the length of the payload.
121 class ArchHeader : public Header {
123 virtual uint32_t GetSerializedSize (void) const;
124 virtual void Serialize (Buffer::Iterator) const;
125 virtual uint32_t Deserialize (Buffer::Iterator);
126 virtual void Print (std::ostream &) const;
127 static TypeId GetTypeId (void);
128 virtual TypeId GetInstanceTypeId (void) const;
130 // accessor functions.....
131 void SetIntValue (uint32_t);
132 uint32_t GetIntValue (void) const;
133 void SetStrValue (const std::string &s);
134 std::string GetStrValue (void) const;
137 std::string str_value;
142 ArchHeader::GetTypeId (void)
144 static TypeId tid = TypeId ("ns3::ArchHeader")
145 .AddConstructor<ArchHeader> () // NOTE: Required for ????
146 .SetParent<Header> () // ditto
152 ArchHeader::GetInstanceTypeId (void) const
158 ArchHeader::GetSerializedSize (void) const
160 return 2*sizeof (uint32_t) + str_value.size (); // int, str len & bytes
164 ArchHeader::Serialize (Buffer::Iterator i) const
166 i.WriteU32 (int_value);
167 uint32_t str_len = str_value.size ();
168 i.WriteU32 (str_len);
169 for (uint32_t j = 0; j < str_value.size (); j++)
170 i.WriteU8 (str_value[j]);
174 ArchHeader::Deserialize (Buffer::Iterator i)
176 int_value = i.ReadU32 ();
177 uint32_t str_len = i.ReadU32 ();
178 str_value.reserve (str_len);
179 for (uint32_t j = 0; j < str_len; j++) {
180 char v = i.ReadU8 ();
181 str_value.push_back (v);
183 return 2*sizeof (uint32_t) + str_value.size ();
188 ArchHeader::SetIntValue (uint32_t v_)
194 ArchHeader::GetIntValue (void) const
200 ArchHeader::SetStrValue (const std::string &s)
206 ArchHeader::GetStrValue (void) const
212 ArchHeader::Print (std::ostream &os) const
214 os << "(ArchHeader=" << str_value << ":" << int_value << ")";
217 //----------class TalkerApp dcl and definition----------------------------------
220 * An an Application that can serve as both Rx and Tx side.
221 * and is configured by ConfRecv/ConfSend and driven by
222 * ScheduleSendPacket. Becareful not to try to send a packet
223 * from the Rx side to the Tx side (back channel) before the
224 * connection is setup, which has to be from the Tx to the Rx
225 * (the forward channel).
228 class TalkerApp : public Application {
231 virtual ~TalkerApp ();
232 void ConfRecv (Ptr<Node>,const Address &);
233 void ConfSend (Ptr<Node>,const Address &);
234 void ScheduleSendPacket(const Time ,const char , const uint32_t size );
237 virtual void DoDispose (void);
239 virtual void StartApplication (void);
240 virtual void StopApplication (void);
242 void StartApplicationRecv (void);
243 void StartApplicationSend (void);
245 void HandleRead (Ptr<Socket>);
246 void SendPacket (std::string,char,uint32_t);
248 void CloseConnection (Ptr<Socket> socket);
249 void ConnectionSucceeded (Ptr<Socket>);
250 void ConnectionFailed (Ptr<Socket>);
251 bool ConnectionRequested (Ptr<Socket>, const Address &);
252 void ConnectionCreated (Ptr<Socket>, const Address &);
256 Ptr<Socket> m_socket;
257 Ptr<Socket> m_servsocket;
261 typedef std::map<Ptr<Socket>, uint32_t>::iterator left_to_read_iterator_type;
262 std::map<Ptr<Socket>, uint32_t> m_left_to_read;
265 class TalkerApp_sub : public TalkerApp {
271 TalkerApp_sub::foo(void) {return 0;}
273 TalkerApp::TalkerApp () :
280 TalkerApp::~TalkerApp ()
284 TalkerApp::DoDispose (void)
288 Application::DoDispose ();
293 TalkerApp::CloseConnection (Ptr<Socket> sock)
295 NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
305 TalkerApp::ConnectionSucceeded (Ptr<Socket> sock)
307 NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
317 TalkerApp::ConnectionFailed (Ptr<Socket> sock)
319 NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
328 TalkerApp::ConnectionRequested (Ptr<Socket> sock, const Address &addr)
330 NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
341 TalkerApp::ConnectionCreated (Ptr<Socket> sock, const Address &addr)
343 NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
351 m_socket->SetRecvCallback(MakeCallback (&TalkerApp::HandleRead, this));
355 TalkerApp::ScheduleSendPacket (const Time dt,const char fill,
358 NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
366 Simulator::Schedule(dt,&TalkerApp::SendPacket, this,
367 std::string("HELLO"),fill,size);
372 TalkerApp::StartApplication ()
374 NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
380 StartApplicationRecv ();
382 StartApplicationSend ();
386 TalkerApp::StartApplicationSend ()
388 NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
395 m_socket = Socket::CreateSocket (GetNode (),
396 TcpSocketFactory::GetTypeId ());
400 m_socket->Connect (m_remote);
401 m_socket->SetConnectCallback
403 MakeCallback (&TalkerApp::ConnectionSucceeded,this),
404 MakeCallback (&TalkerApp::ConnectionFailed,this)
406 m_socket->SetRecvCallback (MakeCallback (&TalkerApp::HandleRead, this));
410 TalkerApp::StartApplicationRecv ()
412 NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
418 m_servsocket = Socket::CreateSocket (GetNode (),
419 TcpSocketFactory::GetTypeId ());
420 m_servsocket->Bind (m_local);
421 m_servsocket->Listen (0);
424 m_servsocket->SetAcceptCallback
426 MakeCallback (&TalkerApp::ConnectionRequested,this),
427 MakeCallback (&TalkerApp::ConnectionCreated,this)
432 TalkerApp::ConfRecv (Ptr<Node> node, const Address &addr)
435 NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
443 node->AddApplication (this);
447 TalkerApp::ConfSend (Ptr<Node> node, const Address &addr)
450 NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
458 node->AddApplication (this);
463 TalkerApp::SendPacket (std::string label,char fill,uint32_t payloadsize)
465 NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
475 Ptr<Packet> p = Create<Packet> (payloadsize); // zero byte filled packet.
477 uint8_t *buf = (uint8_t *) malloc(payloadsize*sizeof(uint8_t));
478 memset(buf,fill,payloadsize);
479 Ptr<Packet> p = Create<Packet> (buf,payloadsize); // filled packet.
483 p->Print (fileOut << "Before Marking|");
484 fileOut << std::endl;
488 hdr.SetStrValue (label);
489 hdr.SetIntValue (p->GetSize());
492 p->Print(fileOut << "After Header Marking|");
493 fileOut << std::endl;
500 TalkerApp::StopApplication ()
502 NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
508 m_socket->SetRecvCallback (MakeNullCallback<void, Ptr<Socket> > ());
512 TalkerApp::HandleRead (Ptr<Socket> socket)
514 left_to_read_iterator_type iter = m_left_to_read.find (socket);
515 if (iter == m_left_to_read.end ())
516 m_left_to_read[socket] = 0;
518 std::ostringstream pretty;
519 pretty << (i_am_listener ? "Server" : "Client")
520 << (iter == m_left_to_read.end () ?
524 NS_LOG_FUNCTION ( pretty.str ()
531 * NOTE: I can crash with the # bytes == 500 rather than 536
532 * which seems to be the default MTU
536 const uint32_t number_of_bytes_willing_to_read = 500;
538 const uint32_t number_of_bytes_willing_to_read = 536;
540 const uint32_t unused_flags = 0;
543 while (packet = socket->Recv (number_of_bytes_willing_to_read,
545 std::string raw_rle = rle(packet->PeekData(),
547 SocketAddressTag rx_addr_tag;
549 found = packet->FindFirstMatchingTag (rx_addr_tag);
551 Address from = rx_addr_tag.GetAddress ();
552 // XXX packet->RemoveTag (tag);
553 if (InetSocketAddress::IsMatchingType (from)) {
554 InetSocketAddress address = InetSocketAddress::ConvertFrom (from);
556 #ifdef VERBOSE_TESTING
557 packet->Print (fileOut << "Packet Dump: ");
558 fileOut << std::endl;
562 bool freshly_in_the_loop = true;
564 #if defined(RECV_PRINT)
566 << raw_rle // <length>:<rle of packet->PeekBuffer>
567 << (freshly_in_the_loop ? " *" : " ") /* used to see if the do while
570 << address.GetIpv4 () << " [" << address << "] ";
572 freshly_in_the_loop = false;
573 int header_bytes = 0;
574 ArchHeader* hdr = 0; // sadly, can't be a Ptr<>
576 (m_left_to_read[socket] == 0)
578 hdr = new ArchHeader;
579 if (packet->RemoveHeader (*hdr)) {
580 m_left_to_read[socket] = hdr->GetIntValue ();
581 header_bytes = hdr->GetSerializedSize ();
583 ; // never get here, ns3 dumps if no header is there.
586 uint32_t num_bytes_processed = 0;
587 if (m_left_to_read[socket] <= packet->GetSize ()) {
588 packet->RemoveAtStart (m_left_to_read[socket]);
589 num_bytes_processed = m_left_to_read[socket];
590 m_left_to_read[socket] = 0;
593 m_left_to_read[socket] -= packet->GetSize ();
594 num_bytes_processed = packet->GetSize ();
595 packet->RemoveAtStart (packet->GetSize ());
598 #if defined(RECV_PRINT)
601 << packet->GetSize ()
603 << num_bytes_processed
613 << m_left_to_read[socket]
615 #ifdef VERBOSE_TESTING
617 hdr->Print(fileOut << " ");
619 fileOut << std::endl;
622 delete hdr; // free what we new....
627 fileOut << "not a match in HandleRead" << std::endl;
633 //---------------Non-member functions-------------------------------------------
635 * returns a string containing the length of the buffer,
636 * followed by an run length encoded version of the buffer
637 * un-printables are represented by '.' (i.e. special_marker
640 std::string rle(const uint8_t *buf, int buflen) {
643 std::ostringstream o;
644 const uint8_t min_rep = 3;
645 uint8_t cur_char = 0;
646 const uint8_t special_marker = '.';
649 o << std::setw(justify) << std::right << buflen << ":";
654 for (int i = 0; i < buflen; i++) {
656 (!isprint(buf[i]) && cur_char == special_marker) ||
661 if (cur_cnt >= min_rep)
662 o << (isprint(cur_char) ? static_cast<char>(cur_char) : '.') << "{"
665 for (int irep=0; irep < cur_cnt; irep++)
666 o << (isprint(cur_char) ? static_cast<char>(cur_char) : '.');
670 cur_char = special_marker;
674 if (cur_cnt >= min_rep)
675 o << (isprint(cur_char) ? static_cast<char>(cur_char) : '.') << "{"
678 for (int irep=0; irep < cur_cnt; irep++)
679 o << (isprint(cur_char) ? static_cast<char>(cur_char) : '.');
683 //---------------Main-----------------------------------------------------------
685 main (int argc, char *argv[]) {
687 std::clog.rdbuf (fileOut.rdbuf ()); /* till we can do this in ns3::log
688 * without this ns3 logging messages
689 * are far away from normal output
692 #ifdef VERBOSE_TESTING
693 LogComponentEnable ("tcp-2way",LOG_LEVEL_ALL);
696 RandomVariable::UseGlobalSeed (1, 1, 2, 3, 5, 8);
697 Packet::EnableMetadata ();
699 // boilerplate: "c0[0]" is Tx, "c0[1]" is Rx.
703 // We create the channels first without any IP addressing information
704 PointToPointHelper p2p;
705 p2p.SetDeviceAttribute ("DataRate",DataRateValue (DataRate (10000000)));
706 p2p.SetChannelAttribute ("Delay",TimeValue (MilliSeconds (10)));
707 NetDeviceContainer dev0 = p2p.Install (c0);
709 // add ip/tcp stack to nodes.
710 InternetStackHelper internet;
711 internet.Install (c0);
713 // Later, we add IP addresses.
714 Ipv4AddressHelper ipv4;
715 ipv4.SetBase ("10.1.0.0", "255.255.255.0");
716 Ipv4InterfaceContainer ifaces = ipv4.Assign (dev0);
718 // Configure the apps.
719 uint16_t servPort = 32;
722 // setup Rx side using ns3::Node "c0[1]" to listen for ANY:servPort
723 Ptr<TalkerApp> sink = CreateObject<TalkerApp_sub>();
724 sink->ConfRecv (c0.Get (1),
725 InetSocketAddress (Ipv4Address::GetAny (), servPort));
726 sink->Start (Seconds (0.0)); // somehow we get by without a Stop. bad form?
728 // setup Tx side using ns3::Node "c0[0]" to talk to "c0[1]":servPort
729 Ptr<TalkerApp> source = CreateObject<TalkerApp_sub>();
730 source->ConfSend (c0.Get (0),
731 InetSocketAddress (ifaces.GetAddress (1),
733 source->Start (Seconds (0.0));
735 // 10 sec is an eternity for this case, we should be done by then.
736 Simulator::Stop (Seconds (10));
739 // For regression use only output ascii and pcap traces.
740 #ifdef REGRESSION_MODE
742 ascii.open ("tcp-2way.tr");
743 PointToPointHelper::EnableAsciiAll (ascii);
744 PointToPointHelper::EnablePcapAll ("tcp-2way");
748 * Now lets schedule some packets and go. For scheduling packets
749 * we have to be careful not to do the backchannel too early or
750 * we try to use a socket that doesn't yet exist since on the Rx
751 * side the socket is created as part of the normal Tx->Rx connection
754 * The delay of 40ms was by trial and error and seems good enough. It
755 * would be nice to know what the bounds are and why....
758 char tagchar = 'A'; // the fill character in case we fill in SendPacket.
760 Time d2t = MilliSeconds(40); /* rate to change time offset (dt) so packets
761 * are sent in order (Tx->Rx, Rx->Tx for a given
762 * size over a range of sizes).*/
764 Time dt = MilliSeconds(0); /* ns3 doesn't take absolute times, but times
765 * relative to Simulator::Now() */
768 source->ScheduleSendPacket (dt, tagchar, size);
771 sink->ScheduleSendPacket (dt, tagchar, size);
772 for (size = 1; size <= 1000000; size *= 10) {
775 source->ScheduleSendPacket (dt, tagchar, size);
778 sink->ScheduleSendPacket (dt, tagchar, size);
781 // Release the Hounds!!
783 Simulator::Destroy ();