Hi Guys,
I want to bound my sockets to NetDevices since I need such scenario in simulations with multiple netdevices.
I created a UDP socket using code:
/**---------------------------------------------------------------------
* UDP socket settings
*----------------------------------------------------------------------*/
/**
* UDP SINK socket settings
*/
// Create the socket if not already
if (!m_sinkSocket_udp )
m_sinkSocket_udp = Socket::CreateSocket (GetNode (), m_tid);
m_sinkSocket_udp->SetIpTos(16);
m_sinkSocket_udp->SetIpRecvTos(true);
m_sinkSocket_udp->Bind (m_local);
m_sinkSocket_udp->BindToNetDevice(m_sinkDevice);
m_sinkSocket_udp->ShutdownSend ();
m_sinkSocket_udp->SetRecvCallback (MakeCallback (&MyAPP::HandleRead, this));
m_sinkSocket_udp->SetAcceptCallback (
MakeNullCallback<bool, Ptr<Socket>, const Address &> (),
MakeCallback (&MyAPP::HandleAccept, this));
m_sinkSocket_udp->SetCloseCallbacks (
MakeCallback (&MyAPP::HandlePeerClose, this),
MakeCallback (&MyAPP::HandlePeerError, this));
/**
* UDP SEND socket settings
*/
// Create the socket if not already
if (!m_sendSocket_udp)
m_sendSocket_udp = Socket::CreateSocket (GetNode (), m_tid);
//setIPtos to top priority
m_sendSocket_udp->SetIpTos(16);
m_sendSocket_udp->SetIpRecvTos(true);
//m_sendSocket_udp->Bind (m_local);
m_sendSocket_udp->BindToNetDevice(m_sendDevice);
m_sendSocket_udp->Connect (m_peer);
which works just fine.
However, I created a TCP socket using following code:
/**
* SINK socket settings
*/
// Create the socket if not already
if (!m_sinkSocket)
m_sinkSocket = Socket::CreateSocket (GetNode (), m_tid);
m_sinkSocket->SetIpTos(16);
m_sinkSocket->SetIpRecvTos(true);
m_sinkSocket->Bind (m_local);
m_sinkSocket->BindToNetDevice(m_sinkDevice);
m_sinkSocket->Listen ();
m_sinkSocket->ShutdownSend ();
m_sinkSocket->SetRecvCallback (MakeCallback (&MyAPP::HandleRead, this));
m_sinkSocket->SetAcceptCallback (
MakeNullCallback<bool, Ptr<Socket>, const Address &> (),
MakeCallback (&MyAPP::HandleAccept, this));
m_sinkSocket->SetCloseCallbacks (
MakeCallback (&MyAPP::HandlePeerClose, this),
MakeCallback (&MyAPP::HandlePeerError, this));
/**
* SEND socket settings
*/
// Create the socket if not already
if (!m_sendSocket)
m_sendSocket = Socket::CreateSocket (GetNode (), m_tid);
//setIPtos to top priority
m_sendSocket->SetIpTos(16);
m_sendSocket->SetIpRecvTos(true);
m_sendSocket->Bind (m_local);
m_sendSocket->BindToNetDevice(m_sendDevice);
//initate TCP-threehand shaking
if (InetSocketAddress::IsMatchingType (m_peer))
NS_LOG_FUNCTION (this << m_peer << "IT IS IPV4!!!!!");
m_sendSocket->Connect (m_peer);
//disable receiving any data on this socket
m_sendSocket->ShutdownRecv ();
m_sendSocket->SetConnectCallback (
MakeCallback (&MyAPP::ConnectionSucceeded, this),
MakeCallback (&MyAPP::ConnectionFailed, this));
m_sendSocket->SetDataSentCallback (
MakeCallback (&MyAPP::DataSend, this));
m_sendSocket->TraceConnectWithoutContext ("RTT", MakeCallback (&MyAPP::RegisterAckTime, this));
but TCP never execute Connect phase (SYN packets). I dig into the code and I found out that in TcpSocketBase::BindToNetDevice both endpoints (m_endPoint and m_endPoint6) are set.
/* Inherit from Socket class: Bind this socket to the specified NetDevice */
void
TcpSocketBase::BindToNetDevice (Ptr<NetDevice> netdevice)
{
NS_LOG_FUNCTION (netdevice);
Socket::BindToNetDevice (netdevice); // Includes sanity check
if (m_endPoint == 0)
{
if (Bind () == -1)
{
NS_ASSERT (m_endPoint == 0);
return;
}
NS_ASSERT (m_endPoint != 0);
}
m_endPoint->BindToNetDevice (netdevice);
if (m_endPoint6 == 0)
{
if (Bind6 () == -1)
{
NS_ASSERT (m_endPoint6 == 0);
return;
}
NS_ASSERT (m_endPoint6 != 0);
}
m_endPoint6->BindToNetDevice (netdevice);
return;
}
So when TcpSocketBase::Connect is called, it simply fail since both endpoints !=0 :
int
TcpSocketBase::Connect (const Address & address)
{
NS_LOG_FUNCTION (this << address);
// If haven't do so, Bind() this socket first
if (InetSocketAddress::IsMatchingType (address) && m_endPoint6 == 0)
{
if (m_endPoint == 0)
{
if (Bind () == -1)
{
NS_ASSERT (m_endPoint == 0);
return -1; // Bind() failed
}
NS_ASSERT (m_endPoint != 0);
}
InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
m_endPoint->SetPeer (transport.GetIpv4 (), transport.GetPort ());
SetIpTos (transport.GetTos ());
m_endPoint6 = 0;
// Get the appropriate local address and port number from the routing protocol and set up endpoint
if (SetupEndpoint () != 0)
{
NS_LOG_ERROR ("Route to destination does not exist ?!");
return -1;
}
}
else if (Inet6SocketAddress::IsMatchingType (address) && m_endPoint == 0)
{
// If we are operating on a v4-mapped address, translate the address to
// a v4 address and re-call this function
Inet6SocketAddress transport = Inet6SocketAddress::ConvertFrom (address);
Ipv6Address v6Addr = transport.GetIpv6 ();
if (v6Addr.IsIpv4MappedAddress () == true)
{
Ipv4Address v4Addr = v6Addr.GetIpv4MappedAddress ();
return Connect (InetSocketAddress (v4Addr, transport.GetPort ()));
}
if (m_endPoint6 == 0)
{
if (Bind6 () == -1)
{
NS_ASSERT (m_endPoint6 == 0);
return -1; // Bind() failed
}
NS_ASSERT (m_endPoint6 != 0);
}
m_endPoint6->SetPeer (v6Addr, transport.GetPort ());
m_endPoint = 0;
// Get the appropriate local address and port number from the routing protocol and set up endpoint
if (SetupEndpoint6 () != 0)
{ // Route to destination does not exist
return -1;
}
}
else
{
m_errno = ERROR_INVAL;
return -1;
}
// Re-initialize parameters in case this socket is being reused after CLOSE
m_rtt->Reset ();
m_synCount = m_synRetries;
m_dataRetrCount = m_dataRetries;
// DoConnect() will do state-checking and send a SYN packet
return DoConnect ();
}
Note that this is not the case in UDPSocketImpl which does not check whether m_endpoint are 0:
int
UdpSocketImpl::Connect (const Address & address)
{
NS_LOG_FUNCTION (this << address);
if (InetSocketAddress::IsMatchingType(address) == true)
{
InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
m_defaultAddress = Address(transport.GetIpv4 ());
m_defaultPort = transport.GetPort ();
SetIpTos (transport.GetTos ());
m_connected = true;
NotifyConnectionSucceeded ();
}
else if (Inet6SocketAddress::IsMatchingType(address) == true)
{
Inet6SocketAddress transport = Inet6SocketAddress::ConvertFrom (address);
m_defaultAddress = Address(transport.GetIpv6 ());
m_defaultPort = transport.GetPort ();
m_connected = true;
NotifyConnectionSucceeded ();
}
else
{
NotifyConnectionFailed ();
return -1;
}
return 0;
}
I belive that this might be the reason why TPC cannot be used with BindToNetDevice command.
Best,
M