1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/examples/tcp-2way.cc Wed Jul 09 17:04:29 2008 -0400
1.3 @@ -0,0 +1,785 @@
1.4 +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
1.5 +/*
1.6 + * Copyright 2007 University of Washington
1.7 + * Copyright 2007 Georgia Tech Research Corporation
1.8 + * Copyright 2008 Sandia Corporation
1.9 + *
1.10 + * This program is free software; you can redistribute it and/or modify
1.11 + * it under the terms of the GNU General Public License version 2 as
1.12 + * published by the Free Software Foundation;
1.13 + *
1.14 + * This program is distributed in the hope that it will be useful,
1.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.17 + * GNU General Public License for more details.
1.18 + *
1.19 + * You should have received a copy of the GNU General Public License
1.20 + * along with this program; if not, write to the Free Software
1.21 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1.22 + *
1.23 + *
1.24 + * Sandia is a multiprogram laboratory operated by Sandia
1.25 + * Corporation, a Lockheed Martin Company, for the United States
1.26 + * Department of Energy's National Nuclear Security Administration
1.27 + * under Contract DE-AC04-94AL85000.
1.28 + *
1.29 + * Author: David Evensky, Sandia National Labs
1.30 + *
1.31 + * includes GPL'ed ns-3-dev code from:
1.32 + * udp-echo, // ??, (c) U. Wash. 2007
1.33 + * tcp-large-transfer // ??
1.34 + * packet-sink // Tom Henderson, (c) U. Wash. 2007
1.35 + * onoff // George F. Riley, (c) GT Res Corp. 2007
1.36 + */
1.37 +
1.38 +
1.39 +/* NOTE
1.40 +This isn't really an example file, so don't look to closely at it as a starting
1.41 +script. It is here for validation of the TCP model.
1.42 +*/
1.43 +
1.44 +#include <iostream>
1.45 +#include <fstream>
1.46 +#include <sstream>
1.47 +#include <string>
1.48 +#include <iomanip>
1.49 +#include <map>
1.50 +
1.51 +#include "ns3/core-module.h"
1.52 +#include "ns3/helper-module.h"
1.53 +#include "ns3/node-module.h"
1.54 +#include "ns3/global-route-manager.h"
1.55 +#include "ns3/simulator-module.h"
1.56 +#include "ns3/log.h"
1.57 +
1.58 +using namespace ns3;
1.59 +
1.60 +NS_LOG_COMPONENT_DEFINE ("tcp-2way");
1.61 +
1.62 +//----------defines-------------------------------------------------------------
1.63 +//define to print more debugging info.
1.64 +#define VERBOSE_TESTING
1.65 +
1.66 +/* define to die because Socket::Recv() is told to
1.67 + * only read an "undesired" number of bytes
1.68 + * fails NS_ASSERT in HandleRead because rx_addr_tag
1.69 + * tag isn't there.
1.70 + */
1.71 +//#define TOO_SMALL_BUG
1.72 +
1.73 +//define to print this pointer in NS_LOG_FUNCTION
1.74 +//#define PRINT_THIS
1.75 +
1.76 +/*define to print packet info in HandleRead
1.77 + *expected output is of the form:
1.78 + *536:P{536} *bytes from 10.1.0.2 [02-06-0a:01:00:02:20:00] <0|536|884018>
1.79 + * ^ ^ ^ ^ ^ ^ ^ ^
1.80 + * | | | | | | | |
1.81 + * | | | | | | | +bytes left
1.82 + * | | | | | | | to read in
1.83 + * | | | | | | | sent buffer
1.84 + * | | | | | | +bytes read in
1.85 + * | | | | | | this packet if
1.86 + * | | | | | | header read,
1.87 + * | | | | | | prints size
1.88 + * | | | | | | in ()
1.89 + * | | | | | +bytes cur. packet
1.90 + * | | | | | left to process
1.91 + * | | | | +mac addr of sender
1.92 + * | | | +IP addr of sender
1.93 + * | | +print '*' while processing first chunk in a received packet.
1.94 + * | | if there are multiple small sent packets, these can appear in
1.95 + * | | a single packet, and are processed by a do {} while() loop.
1.96 + * | +rle output of packet::PeekData(), in this case filled with 536 bytes
1.97 + * | filled with the letter 'P' (brought to you by the letter 'Q' and the
1.98 + * | number '9' :-))
1.99 + * + packet::GetSize()
1.100 + *
1.101 + * If there is a header it will look more like:
1.102 + * 536:N{317}@B.{6}HELLOP{206} *bytes from 10.1.0.2 [02-06-0a:01:00:02:20:00]\
1.103 + * <219|317|0>
1.104 + * 536:N{317}@B.{6}HELLOP{206} bytes from 10.1.0.2 [02-06-0a:01:00:02:20:00]\
1.105 + * <0|206(13)|999794> (ArchHeader=HELLO:1000000)
1.106 + * where you can see that this first packet includes 317 bytes from the
1.107 + * previous send packet (filled with N) and 13 bytes of header before the 206
1.108 + * bytes of payload (filled with P).
1.109 + */
1.110 +
1.111 +#define RECV_PRINT
1.112 +
1.113 +// dcl non-method functions....
1.114 +std::string rle(const uint8_t *, int );
1.115 +std::ofstream fileOut("tcp-2way.out");
1.116 +
1.117 +//----------class ArchHeader dcl and definition---------------------------------
1.118 +/*
1.119 + * ArchHeader: A toy header that holds a string
1.120 + * and a uint32_t. The string is an abitrary label
1.121 + * and the int is used as the length of the payload.
1.122 + */
1.123 +
1.124 +class ArchHeader : public Header {
1.125 +public:
1.126 + virtual uint32_t GetSerializedSize (void) const;
1.127 + virtual void Serialize (Buffer::Iterator) const;
1.128 + virtual uint32_t Deserialize (Buffer::Iterator);
1.129 + virtual void Print (std::ostream &) const;
1.130 + static TypeId GetTypeId (void);
1.131 + virtual TypeId GetInstanceTypeId (void) const;
1.132 +
1.133 + // accessor functions.....
1.134 + void SetIntValue (uint32_t);
1.135 + uint32_t GetIntValue (void) const;
1.136 + void SetStrValue (const std::string &s);
1.137 + std::string GetStrValue (void) const;
1.138 +private:
1.139 + uint32_t int_value;
1.140 + std::string str_value;
1.141 +};
1.142 +
1.143 +
1.144 +TypeId
1.145 +ArchHeader::GetTypeId (void)
1.146 +{
1.147 + static TypeId tid = TypeId ("ns3::ArchHeader")
1.148 + .AddConstructor<ArchHeader> () // NOTE: Required for ????
1.149 + .SetParent<Header> () // ditto
1.150 + ;
1.151 + return tid;
1.152 +}
1.153 +
1.154 +TypeId
1.155 +ArchHeader::GetInstanceTypeId (void) const
1.156 +{
1.157 + return GetTypeId ();
1.158 +}
1.159 +
1.160 +uint32_t
1.161 +ArchHeader::GetSerializedSize (void) const
1.162 +{
1.163 + return 2*sizeof (uint32_t) + str_value.size (); // int, str len & bytes
1.164 +}
1.165 +
1.166 +void
1.167 +ArchHeader::Serialize (Buffer::Iterator i) const
1.168 +{
1.169 + i.WriteU32 (int_value);
1.170 + uint32_t str_len = str_value.size ();
1.171 + i.WriteU32 (str_len);
1.172 + for (uint32_t j = 0; j < str_value.size (); j++)
1.173 + i.WriteU8 (str_value[j]);
1.174 +}
1.175 +
1.176 +uint32_t
1.177 +ArchHeader::Deserialize (Buffer::Iterator i)
1.178 +{
1.179 + int_value = i.ReadU32 ();
1.180 + uint32_t str_len = i.ReadU32 ();
1.181 + str_value.reserve (str_len);
1.182 + for (uint32_t j = 0; j < str_len; j++) {
1.183 + char v = i.ReadU8 ();
1.184 + str_value.push_back (v);
1.185 + }
1.186 + return 2*sizeof (uint32_t) + str_value.size ();
1.187 +}
1.188 +
1.189 +
1.190 +void
1.191 +ArchHeader::SetIntValue (uint32_t v_)
1.192 +{
1.193 + int_value = v_;
1.194 +}
1.195 +
1.196 +uint32_t
1.197 +ArchHeader::GetIntValue (void) const
1.198 +{
1.199 + return int_value;
1.200 +}
1.201 +
1.202 +void
1.203 +ArchHeader::SetStrValue (const std::string &s)
1.204 +{
1.205 + str_value = s;
1.206 +}
1.207 +
1.208 +std::string
1.209 +ArchHeader::GetStrValue (void) const
1.210 +{
1.211 + return str_value;
1.212 +}
1.213 +
1.214 +void
1.215 +ArchHeader::Print (std::ostream &os) const
1.216 +{
1.217 + os << "(ArchHeader=" << str_value << ":" << int_value << ")";
1.218 +}
1.219 +
1.220 +//----------class TalkerApp dcl and definition----------------------------------
1.221 +/*
1.222 + * TalkerApp:
1.223 + * An an Application that can serve as both Rx and Tx side.
1.224 + * and is configured by ConfRecv/ConfSend and driven by
1.225 + * ScheduleSendPacket. Becareful not to try to send a packet
1.226 + * from the Rx side to the Tx side (back channel) before the
1.227 + * connection is setup, which has to be from the Tx to the Rx
1.228 + * (the forward channel).
1.229 + */
1.230 +
1.231 +class TalkerApp : public Application {
1.232 +public:
1.233 + TalkerApp ();
1.234 + virtual ~TalkerApp ();
1.235 + void ConfRecv (Ptr<Node>,const Address &);
1.236 + void ConfSend (Ptr<Node>,const Address &);
1.237 + void ScheduleSendPacket(const Time ,const char , const uint32_t size );
1.238 +
1.239 +protected:
1.240 + virtual void DoDispose (void);
1.241 +private:
1.242 + virtual void StartApplication (void);
1.243 + virtual void StopApplication (void);
1.244 +
1.245 + void StartApplicationRecv (void);
1.246 + void StartApplicationSend (void);
1.247 +
1.248 + void HandleRead (Ptr<Socket>);
1.249 + void SendPacket (std::string,char,uint32_t);
1.250 +
1.251 + void CloseConnection (Ptr<Socket> socket);
1.252 + void ConnectionSucceeded (Ptr<Socket>);
1.253 + void ConnectionFailed (Ptr<Socket>);
1.254 + bool ConnectionRequested (Ptr<Socket>, const Address &);
1.255 + void ConnectionCreated (Ptr<Socket>, const Address &);
1.256 +
1.257 +
1.258 + bool verbose;
1.259 + Ptr<Socket> m_socket;
1.260 + Ptr<Socket> m_servsocket;
1.261 + Address m_local;
1.262 + Address m_remote;
1.263 + int i_am_listener;
1.264 + typedef std::map<Ptr<Socket>, uint32_t>::iterator left_to_read_iterator_type;
1.265 + std::map<Ptr<Socket>, uint32_t> m_left_to_read;
1.266 +};
1.267 +
1.268 +class TalkerApp_sub : public TalkerApp {
1.269 +public:
1.270 + int foo(void);
1.271 +};
1.272 +
1.273 +int
1.274 +TalkerApp_sub::foo(void) {return 0;}
1.275 +
1.276 +TalkerApp::TalkerApp () :
1.277 + verbose (false),
1.278 + m_socket (0),
1.279 + m_servsocket (0),
1.280 + i_am_listener (0)
1.281 +{}
1.282 +
1.283 +TalkerApp::~TalkerApp ()
1.284 +{}
1.285 +
1.286 +void
1.287 +TalkerApp::DoDispose (void)
1.288 +{
1.289 + m_socket = 0;
1.290 + m_servsocket = 0;
1.291 + Application::DoDispose ();
1.292 +}
1.293 +
1.294 +
1.295 +void
1.296 +TalkerApp::CloseConnection (Ptr<Socket> sock)
1.297 +{
1.298 + NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
1.299 +#ifdef PRINT_THIS
1.300 + << this
1.301 +#endif
1.302 + << sock
1.303 + );
1.304 + sock->Close ();
1.305 +}
1.306 +
1.307 +void
1.308 +TalkerApp::ConnectionSucceeded (Ptr<Socket> sock)
1.309 +{
1.310 + NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
1.311 +#ifdef PRINT_THIS
1.312 + << this
1.313 +#endif
1.314 + << sock
1.315 +
1.316 + );
1.317 +}
1.318 +
1.319 +void
1.320 +TalkerApp::ConnectionFailed (Ptr<Socket> sock)
1.321 +{
1.322 + NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
1.323 +#ifdef PRINT_THIS
1.324 + << this
1.325 +#endif
1.326 + << sock
1.327 + );
1.328 +}
1.329 +
1.330 +bool
1.331 +TalkerApp::ConnectionRequested (Ptr<Socket> sock, const Address &addr)
1.332 +{
1.333 + NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
1.334 +#ifdef PRINT_THIS
1.335 + << this
1.336 +#endif
1.337 + << sock
1.338 + << addr
1.339 + );
1.340 + return true;
1.341 +}
1.342 +
1.343 +void
1.344 +TalkerApp::ConnectionCreated (Ptr<Socket> sock, const Address &addr)
1.345 +{
1.346 + NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
1.347 +#ifdef PRINT_THIS
1.348 + << this
1.349 +#endif
1.350 + << sock
1.351 + << addr
1.352 + );
1.353 + m_socket = sock;
1.354 + m_socket->SetRecvCallback(MakeCallback (&TalkerApp::HandleRead, this));
1.355 +}
1.356 +
1.357 +void
1.358 +TalkerApp::ScheduleSendPacket (const Time dt,const char fill,
1.359 + const uint32_t size)
1.360 +{
1.361 + NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
1.362 +#ifdef PRINT_THIS
1.363 + << this
1.364 +#endif
1.365 + << dt
1.366 + << fill
1.367 + << size
1.368 + );
1.369 + Simulator::Schedule(dt,&TalkerApp::SendPacket, this,
1.370 + std::string("HELLO"),fill,size);
1.371 +}
1.372 +
1.373 +
1.374 +void
1.375 +TalkerApp::StartApplication ()
1.376 +{
1.377 + NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
1.378 +#ifdef PRINT_THIS
1.379 + << this
1.380 +#endif
1.381 + );
1.382 + if (i_am_listener)
1.383 + StartApplicationRecv ();
1.384 + else
1.385 + StartApplicationSend ();
1.386 +}
1.387 +
1.388 +void
1.389 +TalkerApp::StartApplicationSend ()
1.390 +{
1.391 + NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
1.392 +#ifdef PRINT_THIS
1.393 + << this
1.394 +#endif
1.395 + );
1.396 +
1.397 + if (!m_socket) {
1.398 + m_socket = Socket::CreateSocket (GetNode (),
1.399 + TcpSocketFactory::GetTypeId ());
1.400 + m_socket->Bind ();
1.401 + }
1.402 +
1.403 + m_socket->Connect (m_remote);
1.404 + m_socket->SetConnectCallback
1.405 + (
1.406 + MakeCallback (&TalkerApp::ConnectionSucceeded,this),
1.407 + MakeCallback (&TalkerApp::ConnectionFailed,this)
1.408 + );
1.409 + m_socket->SetRecvCallback (MakeCallback (&TalkerApp::HandleRead, this));
1.410 +}
1.411 +
1.412 +void
1.413 +TalkerApp::StartApplicationRecv ()
1.414 +{
1.415 + NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
1.416 +#ifdef PRINT_THIS
1.417 + << this
1.418 +#endif
1.419 + );
1.420 + if (!m_servsocket) {
1.421 + m_servsocket = Socket::CreateSocket (GetNode (),
1.422 + TcpSocketFactory::GetTypeId ());
1.423 + m_servsocket->Bind (m_local);
1.424 + m_servsocket->Listen (0);
1.425 + }
1.426 +
1.427 + m_servsocket->SetAcceptCallback
1.428 + (
1.429 + MakeCallback (&TalkerApp::ConnectionRequested,this),
1.430 + MakeCallback (&TalkerApp::ConnectionCreated,this)
1.431 + );
1.432 +}
1.433 +
1.434 +void
1.435 +TalkerApp::ConfRecv (Ptr<Node> node, const Address &addr)
1.436 +{
1.437 + i_am_listener = 1;
1.438 + NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
1.439 +#ifdef PRINT_THIS
1.440 + << this
1.441 +#endif
1.442 + << node
1.443 + << addr
1.444 + );
1.445 + m_local = addr;
1.446 + node->AddApplication (this);
1.447 +}
1.448 +
1.449 +void
1.450 +TalkerApp::ConfSend (Ptr<Node> node, const Address &addr)
1.451 +{
1.452 + i_am_listener = 0;
1.453 + NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
1.454 +#ifdef PRINT_THIS
1.455 + << this
1.456 +#endif
1.457 + << node
1.458 + << addr
1.459 + );
1.460 + m_remote = addr;
1.461 + node->AddApplication (this);
1.462 +}
1.463 +
1.464 +
1.465 +void
1.466 +TalkerApp::SendPacket (std::string label,char fill,uint32_t payloadsize)
1.467 +{
1.468 + NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
1.469 +#ifdef PRINT_THIS
1.470 + << this
1.471 +#endif
1.472 + << label
1.473 + << fill
1.474 + << payloadsize
1.475 + );
1.476 +
1.477 +#if 0
1.478 + Ptr<Packet> p = Create<Packet> (payloadsize); // zero byte filled packet.
1.479 +#else
1.480 + uint8_t *buf = (uint8_t *) malloc(payloadsize*sizeof(uint8_t));
1.481 + memset(buf,fill,payloadsize);
1.482 + Ptr<Packet> p = Create<Packet> (buf,payloadsize); // filled packet.
1.483 + free(buf);
1.484 +#endif
1.485 + if (verbose) {
1.486 + p->Print (fileOut << "Before Marking|");
1.487 + fileOut << std::endl;
1.488 + }
1.489 +
1.490 + ArchHeader hdr;
1.491 + hdr.SetStrValue (label);
1.492 + hdr.SetIntValue (p->GetSize());
1.493 + p->AddHeader (hdr);
1.494 + if (verbose) {
1.495 + p->Print(fileOut << "After Header Marking|");
1.496 + fileOut << std::endl;
1.497 + }
1.498 +
1.499 + m_socket->Send (p);
1.500 +}
1.501 +
1.502 +void
1.503 +TalkerApp::StopApplication ()
1.504 +{
1.505 + NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
1.506 +#ifdef PRINT_THIS
1.507 + << this
1.508 +#endif
1.509 + );
1.510 + if (m_socket)
1.511 + m_socket->SetRecvCallback (MakeNullCallback<void, Ptr<Socket> > ());
1.512 +}
1.513 +
1.514 +void
1.515 +TalkerApp::HandleRead (Ptr<Socket> socket)
1.516 +{
1.517 + left_to_read_iterator_type iter = m_left_to_read.find (socket);
1.518 + if (iter == m_left_to_read.end ())
1.519 + m_left_to_read[socket] = 0;
1.520 +
1.521 + std::ostringstream pretty;
1.522 + pretty << (i_am_listener ? "Server" : "Client")
1.523 + << (iter == m_left_to_read.end () ?
1.524 + "(new)" : "(old)")
1.525 + << "|";
1.526 +
1.527 + NS_LOG_FUNCTION ( pretty.str ()
1.528 +#ifdef PRINT_THIS
1.529 + << this
1.530 +#endif
1.531 + << socket
1.532 + );
1.533 + /*
1.534 + * NOTE: I can crash with the # bytes == 500 rather than 536
1.535 + * which seems to be the default MTU
1.536 + */
1.537 +
1.538 +#ifdef TOO_SMALL_BUG
1.539 + const uint32_t number_of_bytes_willing_to_read = 500;
1.540 +#else
1.541 + const uint32_t number_of_bytes_willing_to_read = 536;
1.542 +#endif
1.543 + const uint32_t unused_flags = 0;
1.544 +
1.545 + Ptr<Packet> packet;
1.546 + while (packet = socket->Recv (number_of_bytes_willing_to_read,
1.547 + unused_flags) ){
1.548 + std::string raw_rle = rle(packet->PeekData(),
1.549 + packet->GetSize());
1.550 + SocketAddressTag rx_addr_tag;
1.551 + bool found;
1.552 + found = packet->FindFirstMatchingTag (rx_addr_tag);
1.553 + NS_ASSERT (found);
1.554 + Address from = rx_addr_tag.GetAddress ();
1.555 + // XXX packet->RemoveTag (tag);
1.556 + if (InetSocketAddress::IsMatchingType (from)) {
1.557 + InetSocketAddress address = InetSocketAddress::ConvertFrom (from);
1.558 +
1.559 +#ifdef VERBOSE_TESTING
1.560 + packet->Print (fileOut << "Packet Dump: ");
1.561 + fileOut << std::endl;
1.562 +#endif
1.563 +
1.564 +
1.565 + bool freshly_in_the_loop = true;
1.566 + do {
1.567 +#if defined(RECV_PRINT)
1.568 + fileOut
1.569 + << raw_rle // <length>:<rle of packet->PeekBuffer>
1.570 + << (freshly_in_the_loop ? " *" : " ") /* used to see if the do while
1.571 + * does anything */
1.572 + << "bytes from "
1.573 + << address.GetIpv4 () << " [" << address << "] ";
1.574 +#endif
1.575 + freshly_in_the_loop = false;
1.576 + int header_bytes = 0;
1.577 + ArchHeader* hdr = 0; // sadly, can't be a Ptr<>
1.578 + if (
1.579 + (m_left_to_read[socket] == 0)
1.580 + ) {
1.581 + hdr = new ArchHeader;
1.582 + if (packet->RemoveHeader (*hdr)) {
1.583 + m_left_to_read[socket] = hdr->GetIntValue ();
1.584 + header_bytes = hdr->GetSerializedSize ();
1.585 + } else {
1.586 + ; // never get here, ns3 dumps if no header is there.
1.587 + }
1.588 + }
1.589 + uint32_t num_bytes_processed = 0;
1.590 + if (m_left_to_read[socket] <= packet->GetSize ()) {
1.591 + packet->RemoveAtStart (m_left_to_read[socket]);
1.592 + num_bytes_processed = m_left_to_read[socket];
1.593 + m_left_to_read[socket] = 0;
1.594 +
1.595 + } else {
1.596 + m_left_to_read[socket] -= packet->GetSize ();
1.597 + num_bytes_processed = packet->GetSize ();
1.598 + packet->RemoveAtStart (packet->GetSize ());
1.599 + }
1.600 +
1.601 +#if defined(RECV_PRINT)
1.602 + fileOut
1.603 + << "<"
1.604 + << packet->GetSize ()
1.605 + << "|"
1.606 + << num_bytes_processed
1.607 + ;
1.608 + if (header_bytes)
1.609 + fileOut
1.610 + << "("
1.611 + << header_bytes
1.612 + << ")"
1.613 + ;
1.614 + fileOut
1.615 + << "|"
1.616 + << m_left_to_read[socket]
1.617 + << ">";
1.618 +#ifdef VERBOSE_TESTING
1.619 + if (hdr)
1.620 + hdr->Print(fileOut << " ");
1.621 +#endif
1.622 + fileOut << std::endl;
1.623 +#endif
1.624 + if (hdr)
1.625 + delete hdr; // free what we new....
1.626 + } while (
1.627 + packet->GetSize ()
1.628 + );
1.629 + } else {
1.630 + fileOut << "not a match in HandleRead" << std::endl;
1.631 + }
1.632 +
1.633 + }
1.634 +}
1.635 +
1.636 +//---------------Non-member functions-------------------------------------------
1.637 +/*
1.638 + * returns a string containing the length of the buffer,
1.639 + * followed by an run length encoded version of the buffer
1.640 + * un-printables are represented by '.' (i.e. special_marker
1.641 + * const).
1.642 + */
1.643 +std::string rle(const uint8_t *buf, int buflen) {
1.644 +
1.645 + int justify = 5;
1.646 + std::ostringstream o;
1.647 + const uint8_t min_rep = 3;
1.648 + uint8_t cur_char = 0;
1.649 + const uint8_t special_marker = '.';
1.650 + int cur_cnt = 0;
1.651 + if (justify) {
1.652 + o << std::setw(justify) << std::right << buflen << ":";
1.653 + } else {
1.654 + o << buflen << ":";
1.655 + }
1.656 +
1.657 + for (int i = 0; i < buflen; i++) {
1.658 + if (
1.659 + (!isprint(buf[i]) && cur_char == special_marker) ||
1.660 + (buf[i] == cur_char)
1.661 + )
1.662 + cur_cnt++;
1.663 + else {
1.664 + if (cur_cnt >= min_rep)
1.665 + o << (isprint(cur_char) ? static_cast<char>(cur_char) : '.') << "{"
1.666 + << cur_cnt << "}";
1.667 + else
1.668 + for (int irep=0; irep < cur_cnt; irep++)
1.669 + o << (isprint(cur_char) ? static_cast<char>(cur_char) : '.');
1.670 + if (isprint(buf[i]))
1.671 + cur_char = buf[i];
1.672 + else
1.673 + cur_char = special_marker;
1.674 + cur_cnt = 1;
1.675 + }
1.676 + }
1.677 + if (cur_cnt >= min_rep)
1.678 + o << (isprint(cur_char) ? static_cast<char>(cur_char) : '.') << "{"
1.679 + << cur_cnt << "}";
1.680 + else
1.681 + for (int irep=0; irep < cur_cnt; irep++)
1.682 + o << (isprint(cur_char) ? static_cast<char>(cur_char) : '.');
1.683 + return o.str();
1.684 +}
1.685 +
1.686 +//---------------Main-----------------------------------------------------------
1.687 +int
1.688 +main (int argc, char *argv[]) {
1.689 +
1.690 + std::clog.rdbuf (fileOut.rdbuf ()); /* till we can do this in ns3::log
1.691 + * without this ns3 logging messages
1.692 + * are far away from normal output
1.693 + */
1.694 +
1.695 +#ifdef VERBOSE_TESTING
1.696 + LogComponentEnable ("tcp-2way",LOG_LEVEL_ALL);
1.697 +#endif
1.698 +
1.699 + RandomVariable::UseGlobalSeed (1, 1, 2, 3, 5, 8);
1.700 + Packet::EnableMetadata ();
1.701 +
1.702 + // boilerplate: "c0[0]" is Tx, "c0[1]" is Rx.
1.703 + NodeContainer c0;
1.704 + c0.Create (2);
1.705 +
1.706 + // We create the channels first without any IP addressing information
1.707 + PointToPointHelper p2p;
1.708 + p2p.SetDeviceAttribute ("DataRate",DataRateValue (DataRate (10000000)));
1.709 + p2p.SetChannelAttribute ("Delay",TimeValue (MilliSeconds (10)));
1.710 + NetDeviceContainer dev0 = p2p.Install (c0);
1.711 +
1.712 + // add ip/tcp stack to nodes.
1.713 + InternetStackHelper internet;
1.714 + internet.Install (c0);
1.715 +
1.716 + // Later, we add IP addresses.
1.717 + Ipv4AddressHelper ipv4;
1.718 + ipv4.SetBase ("10.1.0.0", "255.255.255.0");
1.719 + Ipv4InterfaceContainer ifaces = ipv4.Assign (dev0);
1.720 +
1.721 + // Configure the apps.
1.722 + uint16_t servPort = 32;
1.723 +
1.724 +
1.725 + // setup Rx side using ns3::Node "c0[1]" to listen for ANY:servPort
1.726 + Ptr<TalkerApp> sink = CreateObject<TalkerApp_sub>();
1.727 + sink->ConfRecv (c0.Get (1),
1.728 + InetSocketAddress (Ipv4Address::GetAny (), servPort));
1.729 + sink->Start (Seconds (0.0)); // somehow we get by without a Stop. bad form?
1.730 +
1.731 + // setup Tx side using ns3::Node "c0[0]" to talk to "c0[1]":servPort
1.732 + Ptr<TalkerApp> source = CreateObject<TalkerApp_sub>();
1.733 + source->ConfSend (c0.Get (0),
1.734 + InetSocketAddress (ifaces.GetAddress (1),
1.735 + servPort));
1.736 + source->Start (Seconds (0.0));
1.737 +
1.738 + // 10 sec is an eternity for this case, we should be done by then.
1.739 + Simulator::Stop (Seconds (10));
1.740 +
1.741 +
1.742 + // For regression use only output ascii and pcap traces.
1.743 +#ifdef REGRESSION_MODE
1.744 + std::ofstream ascii;
1.745 + ascii.open ("tcp-2way.tr");
1.746 + PointToPointHelper::EnableAsciiAll (ascii);
1.747 + PointToPointHelper::EnablePcapAll ("tcp-2way");
1.748 +#endif
1.749 +
1.750 + /*
1.751 + * Now lets schedule some packets and go. For scheduling packets
1.752 + * we have to be careful not to do the backchannel too early or
1.753 + * we try to use a socket that doesn't yet exist since on the Rx
1.754 + * side the socket is created as part of the normal Tx->Rx connection
1.755 + * setup.
1.756 + *
1.757 + * The delay of 40ms was by trial and error and seems good enough. It
1.758 + * would be nice to know what the bounds are and why....
1.759 + */
1.760 +
1.761 + char tagchar = 'A'; // the fill character in case we fill in SendPacket.
1.762 +
1.763 + Time d2t = MilliSeconds(40); /* rate to change time offset (dt) so packets
1.764 + * are sent in order (Tx->Rx, Rx->Tx for a given
1.765 + * size over a range of sizes).*/
1.766 +
1.767 + Time dt = MilliSeconds(0); /* ns3 doesn't take absolute times, but times
1.768 + * relative to Simulator::Now() */
1.769 +
1.770 + uint32_t size = 0;
1.771 + source->ScheduleSendPacket (dt, tagchar, size);
1.772 + dt += d2t;
1.773 + ++tagchar;
1.774 + sink->ScheduleSendPacket (dt, tagchar, size);
1.775 + for (size = 1; size <= 1000000; size *= 10) {
1.776 + dt += d2t;
1.777 + ++tagchar;
1.778 + source->ScheduleSendPacket (dt, tagchar, size);
1.779 + dt += d2t;
1.780 + ++tagchar;
1.781 + sink->ScheduleSendPacket (dt, tagchar, size);
1.782 + }
1.783 +
1.784 + // Release the Hounds!!
1.785 + Simulator::Run ();
1.786 + Simulator::Destroy ();
1.787 + fileOut.close();
1.788 +}
2.1 --- a/examples/wscript Wed Jul 09 14:10:18 2008 -0400
2.2 +++ b/examples/wscript Wed Jul 09 17:04:29 2008 -0400
2.3 @@ -56,6 +56,10 @@
2.4 ['point-to-point', 'internet-stack'])
2.5 obj.source = 'tcp-errors.cc'
2.6
2.7 + obj = bld.create_ns3_program('tcp-2way',
2.8 + ['point-to-point', 'internet-stack'])
2.9 + obj.source = 'tcp-2way.cc'
2.10 +
2.11 obj = bld.create_ns3_program('tcp-star-server',
2.12 ['point-to-point', 'internet-stack'])
2.13 obj.source = 'tcp-star-server.cc'
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/regression/tests/test-tcp-2way.py Wed Jul 09 17:04:29 2008 -0400
3.3 @@ -0,0 +1,13 @@
3.4 +#! /usr/bin/env python
3.5 +
3.6 +"""Generic trace-comparison-type regression test."""
3.7 +
3.8 +import os
3.9 +import shutil
3.10 +import tracediff
3.11 +
3.12 +def run(verbose, generate, refDirName):
3.13 + """Execute a test."""
3.14 +
3.15 + return tracediff.run_test(verbose, generate, refDirName,
3.16 + "tcp-2way")