Recv callback does not get called on packet reception

362 views
Skip to first unread message

Giacomo Scaparrotti

unread,
Oct 14, 2019, 4:58:15 PM10/14/19
to ns-3-users
Hi, I am new to ns-3 and I am trying to understand it modifying the script in the tutorials.

I wanted to create a simple network with two nodes (a client which only sends data and a server which only receives). In order to keep the server's buffer free,  I need to read all the packets sent by the client. To do so, I registered a callback on the client's socket calling SetRecvCallback. Using a debugger, I can see that the m_receivedData field in the socket class gets populated with my callback. I then proceed to send my data, but when the first packet arrives, the callback does not get triggered, and the m_receivedData field is set to 0x0. I cannot understand why, can someone explain it to me? Thank you in advance.

#include "jack.h"
#include <fstream>
#include "ns3/core-module.h"
#include "ns3/network-module.h"
#include "ns3/internet-module.h"
#include "ns3/point-to-point-module.h"
#include "ns3/applications-module.h"
#include <unistd.h>
#include <thread>
#include <iostream>

using namespace ns3;

NS_LOG_COMPONENT_DEFINE
("FifthScriptExample");

class MyApp : public Application
{
public:

 
MyApp ();
 
virtual ~MyApp();

 
void Setup (Ptr<Socket> socket, Address address, uint32_t packetSize, uint32_t nPackets, DataRate dataRate);

 
void Setup(Ptr<Socket> socket, int incoming);

private:
 
virtual void StartApplication (void);
 
virtual void StopApplication (void);

 
void ScheduleTx (void);
 
void SendPacket (void);
 
void onReceive (Ptr<Socket> socket);
 
void onAccept (Ptr<Socket> s, const Address& from);

 
Ptr<Socket>     m_socket;
 
Address         m_peer;
  uint32_t        m_packetSize
;
  uint32_t        m_nPackets
;
 
DataRate        m_dataRate;
 
EventId         m_sendEvent;
 
bool            m_running;
  uint32_t        m_packetsSent
;
 
bool              m_isServer;
 
int              m_incoming;
};

MyApp::MyApp ()
 
: m_socket (0),
    m_peer
(),
    m_packetSize
(0),
    m_nPackets
(0),
    m_dataRate
(0),
    m_sendEvent
(),
    m_running
(false),
    m_packetsSent
(0),
    m_isServer
(false),
    m_incoming
(0)
{
}

MyApp::~MyApp()
{
  m_socket
= 0;
}

void
MyApp::Setup (Ptr<Socket> socket, Address address, uint32_t packetSize, uint32_t nPackets, DataRate dataRate)
{
  m_socket
= socket;
  m_peer
= address;
  m_packetSize
= packetSize;
  m_nPackets
= nPackets;
  m_dataRate
= dataRate;
}

void
MyApp::Setup(Ptr<Socket> socket, int incoming)
{
    m_socket
= socket;
    m_isServer
= true;
    m_incoming
= incoming;
}

void
MyApp::StartApplication (void)
{
  m_running
= true;
 
if (!m_isServer) {
      m_packetsSent
= 0;
      m_socket
->Connect (m_peer);
     
SendPacket ();
 
} else {
      m_socket
->Listen();
      m_socket
->SetAcceptCallback (
         
MakeNullCallback<bool, Ptr<Socket>, const Address &> (),
         
MakeCallback (&MyApp::onAccept, this));
 
}
}

void
MyApp::StopApplication (void)
{
  m_running
= false;

 
if (m_sendEvent.IsRunning ())
   
{
     
Simulator::Cancel (m_sendEvent);
   
}

 
if (m_socket)
   
{
      m_socket
->Close ();
   
}
}

void
MyApp::SendPacket (void)
{
 
if (++m_packetsSent < m_nPackets)
   
{
     
Ptr<Packet> packet = Create<Packet> (m_packetSize);
      m_socket
->Send (packet);
     
ScheduleTx ();
   
}
}

void
MyApp::ScheduleTx (void)
{
 
if (m_running)
   
{
     
Time tNext (Seconds (m_packetSize * 8 / static_cast<double> (m_dataRate.GetBitRate ())));
      m_sendEvent
= Simulator::Schedule (tNext, &MyApp::SendPacket, this);
   
}
}

void MyApp::onReceive(Ptr<Socket> socket) {
     
Ptr<Packet> packet;
       
while ((packet = socket->Recv()))
         
{
           
if (packet->GetSize () == 0)
             
{ //EOF
               
break;
             
}
         
}
}

void MyApp::onAccept(Ptr<Socket> s, const Address& from) {
   
//THIS IS WHERE THE CALLBACK GETS SET

    m_socket
->SetRecvCallback(MakeCallback(&MyApp::onReceive, this));
}

static void
CwndChange (uint32_t oldCwnd, uint32_t newCwnd)
{
  NS_LOG_UNCOND
(Simulator::Now ().GetSeconds () << "\t" << newCwnd);
}

static void
RxDrop (Ptr<const Packet> p)
{
  NS_LOG_UNCOND
("RxDrop at " << Simulator::Now ().GetSeconds ());
}

void (*my_callback)(unsigned int, unsigned int) = &CwndChange;

void AddTcpCongestionWindowCallback(void (*callback)(unsigned int, unsigned int)) {
    my_callback
= callback;
}

int
RunSimulation ()
{
 
Ptr<DefaultSimulatorImpl> s = CreateObject<DefaultSimulatorImpl> ();
 
Simulator::SetImplementation(s);

 
NodeContainer nodes;
  nodes
.Create (2);

 
PointToPointHelper pointToPoint;
  pointToPoint
.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
  pointToPoint
.SetChannelAttribute ("Delay", StringValue ("2ms"));

 
NetDeviceContainer devices;
  devices
= pointToPoint.Install (nodes);

 
Ptr<RateErrorModel> em = CreateObject<RateErrorModel> ();
  em
->SetAttribute ("ErrorRate", DoubleValue (0.00001));
  devices
.Get (1)->SetAttribute ("ReceiveErrorModel", PointerValue (em));

 
InternetStackHelper stack;
  stack
.Install (nodes);

 
Ipv4AddressHelper address;
  address
.SetBase ("10.1.1.0", "255.255.255.252");
 
Ipv4InterfaceContainer interfaces = address.Assign (devices);



 
//ASERVER
 
Ptr<Socket> ns3TcpSocket1 = Socket::CreateSocket (nodes.Get (1), TcpSocketFactory::GetTypeId ());
  ns3TcpSocket1
->Bind (InetSocketAddress (interfaces.GetAddress (1), 8080));
 
Ptr<MyApp> app1 = CreateObject<MyApp> ();
  app1
->Setup (ns3TcpSocket1, 1000000000);
  nodes
.Get (1)->AddApplication (app1);
  app1
->SetStartTime (Seconds (1.));
  app1
->SetStopTime (Seconds (20.));

 
//CLIENT
 
Ptr<Socket> ns3TcpSocket = Socket::CreateSocket (nodes.Get (0), TcpSocketFactory::GetTypeId ());
  ns3TcpSocket
->TraceConnectWithoutContext ("CongestionWindow", MakeCallback (my_callback));
  ns3TcpSocket
->Bind( InetSocketAddress (interfaces.GetAddress (0), 8080));
 
Ptr<MyApp> app = CreateObject<MyApp> ();
  app
->Setup (ns3TcpSocket, InetSocketAddress (interfaces.GetAddress (1), 8080), 1040, 1000, DataRate ("1Mbps"));
  nodes
.Get (0)->AddApplication (app);
  app
->SetStartTime (Seconds (2.));
  app
->SetStopTime (Seconds (20.));


  devices
.Get (1)->TraceConnectWithoutContext ("PhyRxDrop", MakeCallback (&RxDrop));

 
Simulator::Stop (Seconds (20));
 
Simulator::Run ();
 
Simulator::Destroy ();

 
return 0;
}




Giacomo Scaparrotti

unread,
Oct 15, 2019, 11:49:30 AM10/15/19
to ns-3-users
EDIT:

I solved the problem: when a TCP socket becomes connected after receiving an incoming connection, it gets forked and its callbacks get overwritten, so it is necessary to call SetRecvCallback inside the Accept callback; I had to modify this method:

from

void MyApp::onAccept(Ptr<Socket> s, const Address& from) {

    m_socket
->SetRecvCallback(MakeCallback(&MyApp::onReceive, this));
}

to

void MyApp::onAccept(Ptr<Socket> s, const Address& from) {

    s
->SetRecvCallback(MakeCallback(&MyApp::onReceive, this));
}


Reply all
Reply to author
Forward
0 new messages