src/internet-stack/nsc-tcp-socket-impl.cc
author Florian Westphal <fw@strlen.de>
Wed Jul 15 18:46:14 2009 +0200 (2009-07-15)
changeset 4685 ae536d9e0d6d
parent 4523 b8bdc36a3355
permissions -rw-r--r--
nsc: move nsc glue code from nsc-tcp-l4-protocol to node/nsc-glue.cc.

known problems:
- sim_interface.h is duplicated
- nsc-glue.cc adds hooks in node.cc, "hijacks" incoming packets
- nsc-glue exports NSCs INetStack (instead of wrapping it completely)
- nsc-tcp-l4-protocol and nsc-tcp-socket-impl make calls into nsc-glue
- nsc-tcp-socket-impl should really be "nsc-socket-core" (or something
like that)

needs fixing on nsc side:
- no support for multiple interfaces yet (also not yet supported
on nsc side)
- nsc initialisation still tied to IP (Adding an Interface and assigning the
IP address is a single step; it should be separate)

maybe there is more.

There is a NSC_NEXT define in nsc-glue.h, its main purpose is to flag
the places where the NSC API needs to be adapted to support multiple
interfaces in nsc.
     1 /* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
     2 /*
     3  * This program is free software; you can redistribute it and/or modify
     4  * it under the terms of the GNU General Public License version 2 as
     5  * published by the Free Software Foundation;
     6  *
     7  * This program is distributed in the hope that it will be useful,
     8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    10  * GNU General Public License for more details.
    11  *
    12  * You should have received a copy of the GNU General Public License
    13  * along with this program; if not, write to the Free Software
    14  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    15  *
    16  * based on tcp-socket-impl.cc, Author: Raj Bhattacharjea <raj.b@gatech.edu>
    17  * Author: Florian Westphal <fw@strlen.de>
    18  */
    19 
    20 #include "ns3/node.h"
    21 #include "ns3/inet-socket-address.h"
    22 #include "ns3/log.h"
    23 #include "ns3/ipv4.h"
    24 #include "ipv4-end-point.h"
    25 #include "nsc-tcp-l4-protocol.h"
    26 #include "nsc-tcp-socket-impl.h"
    27 #include "ns3/simulation-singleton.h"
    28 #include "tcp-typedefs.h"
    29 #include "ns3/simulator.h"
    30 #include "ns3/packet.h"
    31 #include "ns3/uinteger.h"
    32 #include "ns3/trace-source-accessor.h"
    33 
    34 #include <algorithm>
    35 
    36 // for ntohs().
    37 #include <arpa/inet.h>
    38 #include <netinet/in.h>
    39 
    40 #include "sim_interface.h"
    41 #include "sim_errno.h"
    42 
    43 NS_LOG_COMPONENT_DEFINE ("NscTcpSocketImpl");
    44 
    45 using namespace std;
    46 
    47 namespace ns3 {
    48 
    49 NS_OBJECT_ENSURE_REGISTERED (NscTcpSocketImpl);
    50 
    51 TypeId
    52 NscTcpSocketImpl::GetTypeId ()
    53 {
    54   static TypeId tid = TypeId("ns3::NscTcpSocketImpl")
    55     .SetParent<TcpSocket> ()
    56     .AddTraceSource ("CongestionWindow",
    57                      "The TCP connection's congestion window",
    58                      MakeTraceSourceAccessor (&NscTcpSocketImpl::m_cWnd))
    59     ;
    60   return tid;
    61 }
    62 
    63   NscTcpSocketImpl::NscTcpSocketImpl ()
    64   : m_endPoint (0),
    65     m_node (0),
    66     m_tcp (0),
    67     m_localAddress (Ipv4Address::GetZero ()),
    68     m_localPort (0),
    69     m_peerAddress ("0.0.0.0", 0),
    70     m_errno (ERROR_NOTERROR),
    71     m_shutdownSend (false),
    72     m_shutdownRecv (false),
    73     m_connected (false),
    74     m_state (CLOSED),
    75     m_closeOnEmpty (false),
    76     m_txBufferSize (0),
    77     m_rtt (0),
    78     m_lastMeasuredRtt (Seconds(0.0))
    79 {
    80   NS_LOG_FUNCTION (this);
    81 }
    82 
    83 NscTcpSocketImpl::NscTcpSocketImpl(const NscTcpSocketImpl& sock)
    84   : TcpSocket(sock), //copy the base class callbacks
    85     m_delAckMaxCount (sock.m_delAckMaxCount),
    86     m_delAckTimeout (sock.m_delAckTimeout),
    87     m_endPoint (0),
    88     m_node (sock.m_node),
    89     m_tcp (sock.m_tcp),
    90     m_remoteAddress (sock.m_remoteAddress),
    91     m_remotePort (sock.m_remotePort),
    92     m_localAddress (sock.m_localAddress),
    93     m_localPort (sock.m_localPort),
    94     m_peerAddress (sock.m_peerAddress),
    95     m_errno (sock.m_errno),
    96     m_shutdownSend (sock.m_shutdownSend),
    97     m_shutdownRecv (sock.m_shutdownRecv),
    98     m_connected (sock.m_connected),
    99     m_state (sock.m_state),
   100     m_closeOnEmpty (sock.m_closeOnEmpty),
   101     m_segmentSize (sock.m_segmentSize),
   102     m_rxWindowSize (sock.m_rxWindowSize),
   103     m_advertisedWindowSize (sock.m_advertisedWindowSize),
   104     m_cWnd (sock.m_cWnd),
   105     m_ssThresh (sock.m_ssThresh),
   106     m_initialCWnd (sock.m_initialCWnd),
   107     m_rtt (0),
   108     m_lastMeasuredRtt (Seconds(0.0)),
   109     m_cnTimeout (sock.m_cnTimeout),
   110     m_cnCount (sock.m_cnCount),
   111     m_rxAvailable (0),
   112     m_nscTcpSocket (0),
   113     m_sndBufSize (sock.m_sndBufSize)
   114 {
   115   NS_LOG_FUNCTION_NOARGS ();
   116   NS_LOG_LOGIC("Invoked the copy constructor");
   117   //copy the pending data if necessary
   118   if(!sock.m_txBuffer.empty () )
   119     {
   120       m_txBuffer = sock.m_txBuffer;
   121     }
   122   //copy the rtt if necessary
   123   if (sock.m_rtt)
   124     {
   125       m_rtt = sock.m_rtt->Copy();
   126     }
   127   //can't "copy" the endpoint just yes, must do this when we know the peer info
   128   //too; this is in SYN_ACK_TX
   129 }
   130 
   131 NscTcpSocketImpl::~NscTcpSocketImpl ()
   132 {
   133   NS_LOG_FUNCTION(this);
   134   m_node = 0;
   135   if (m_endPoint != 0)
   136     {
   137       NS_ASSERT (m_tcp != 0);
   138       /**
   139        * Note that this piece of code is a bit tricky:
   140        * when DeAllocate is called, it will call into
   141        * Ipv4EndPointDemux::Deallocate which triggers
   142        * a delete of the associated endPoint which triggers
   143        * in turn a call to the method ::Destroy below
   144        * will will zero the m_endPoint field.
   145        */
   146       NS_ASSERT (m_endPoint != 0);
   147       m_tcp->DeAllocate (m_endPoint);
   148       NS_ASSERT (m_endPoint == 0);
   149     }
   150   m_tcp = 0;
   151 }
   152 
   153 void
   154 NscTcpSocketImpl::SetNode (Ptr<Node> node)
   155 {
   156   m_node = node;
   157   // Initialize some variables 
   158   m_cWnd = m_initialCWnd * m_segmentSize;
   159   m_rxWindowSize = m_advertisedWindowSize;
   160 }
   161 
   162 void 
   163 NscTcpSocketImpl::SetTcp (Ptr<NscTcpL4Protocol> tcp)
   164 {
   165   m_tcp = tcp;
   166   m_nscTcpSocket = m_node->GetNscInetStack()->new_tcp_socket();
   167 }
   168 void
   169 NscTcpSocketImpl::SetRtt (Ptr<RttEstimator> rtt)
   170 {
   171   m_rtt = rtt;
   172 }
   173 
   174 
   175 enum Socket::SocketErrno
   176 NscTcpSocketImpl::GetErrno (void) const
   177 {
   178   NS_LOG_FUNCTION_NOARGS ();
   179   return m_errno;
   180 }
   181 
   182 Ptr<Node>
   183 NscTcpSocketImpl::GetNode (void) const
   184 {
   185   NS_LOG_FUNCTION_NOARGS ();
   186   return m_node;
   187 }
   188 
   189 void 
   190 NscTcpSocketImpl::Destroy (void)
   191 {
   192   NS_LOG_FUNCTION_NOARGS ();
   193   m_node = 0;
   194   m_endPoint = 0;
   195   m_tcp = 0;
   196 }
   197 int
   198 NscTcpSocketImpl::FinishBind (void)
   199 {
   200   NS_LOG_FUNCTION_NOARGS ();
   201   if (m_endPoint == 0)
   202     {
   203       return -1;
   204     }
   205   m_endPoint->SetRxCallback (MakeCallback (&NscTcpSocketImpl::ForwardUp, Ptr<NscTcpSocketImpl>(this)));
   206   m_endPoint->SetDestroyCallback (MakeCallback (&NscTcpSocketImpl::Destroy, Ptr<NscTcpSocketImpl>(this)));
   207   m_localAddress = m_endPoint->GetLocalAddress ();
   208   m_localPort = m_endPoint->GetLocalPort ();
   209   return 0;
   210 }
   211 
   212 int
   213 NscTcpSocketImpl::Bind (void)
   214 {
   215   NS_LOG_FUNCTION_NOARGS ();
   216   m_endPoint = m_tcp->Allocate ();
   217   return FinishBind ();
   218 }
   219 int 
   220 NscTcpSocketImpl::Bind (const Address &address)
   221 {
   222   NS_LOG_FUNCTION (this<<address);
   223   if (!InetSocketAddress::IsMatchingType (address))
   224     {
   225       return ERROR_INVAL;
   226     }
   227   InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
   228   Ipv4Address ipv4 = transport.GetIpv4 ();
   229   uint16_t port = transport.GetPort ();
   230   if (ipv4 == Ipv4Address::GetAny () && port == 0)
   231     {
   232       m_endPoint = m_tcp->Allocate ();
   233       NS_LOG_LOGIC ("TcpSocketImpl "<<this<<" got an endpoint: "<<m_endPoint);
   234     }
   235   else if (ipv4 == Ipv4Address::GetAny () && port != 0)
   236     {
   237       m_endPoint = m_tcp->Allocate (port);
   238       NS_LOG_LOGIC ("TcpSocketImpl "<<this<<" got an endpoint: "<<m_endPoint);
   239     }
   240   else if (ipv4 != Ipv4Address::GetAny () && port == 0)
   241     {
   242       m_endPoint = m_tcp->Allocate (ipv4);
   243       NS_LOG_LOGIC ("TcpSocketImpl "<<this<<" got an endpoint: "<<m_endPoint);
   244     }
   245   else if (ipv4 != Ipv4Address::GetAny () && port != 0)
   246     {
   247       m_endPoint = m_tcp->Allocate (ipv4, port);
   248       NS_LOG_LOGIC ("TcpSocketImpl "<<this<<" got an endpoint: "<<m_endPoint);
   249     }
   250 
   251   m_localPort = port;
   252   return FinishBind ();
   253 }
   254 
   255 int 
   256 NscTcpSocketImpl::ShutdownSend (void)
   257 {
   258   NS_LOG_FUNCTION_NOARGS ();
   259   m_shutdownSend = true;
   260   return 0;
   261 }
   262 int 
   263 NscTcpSocketImpl::ShutdownRecv (void)
   264 {
   265   NS_LOG_FUNCTION_NOARGS ();
   266   m_shutdownRecv = true;
   267   return 0;
   268 }
   269 
   270 int
   271 NscTcpSocketImpl::Close (void)
   272 {
   273   NS_LOG_FUNCTION (this << m_state);
   274 
   275   if (m_state == CLOSED)
   276     {
   277       return -1;
   278     }
   279   if (!m_txBuffer.empty ())
   280     { // App close with pending data must wait until all data transmitted
   281       m_closeOnEmpty = true;
   282       NS_LOG_LOGIC("Socket " << this << 
   283                    " deferring close, state " << m_state);
   284       return 0;
   285     }
   286 
   287   m_nscTcpSocket->disconnect();
   288   m_state = CLOSED;
   289   ShutdownSend ();
   290   return 0;
   291 }
   292 
   293 int
   294 NscTcpSocketImpl::Connect (const Address & address)
   295 {
   296   NS_LOG_FUNCTION (this << address);
   297   if (m_endPoint == 0)
   298     {
   299       if (Bind () == -1)
   300         {
   301           NS_ASSERT (m_endPoint == 0);
   302           return -1;
   303         }
   304       NS_ASSERT (m_endPoint != 0);
   305     }
   306   InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
   307   m_remoteAddress = transport.GetIpv4 ();
   308   m_remotePort = transport.GetPort ();
   309 
   310   std::ostringstream ss;
   311   m_remoteAddress.Print(ss);
   312   std::string ipstring = ss.str ();
   313 
   314   m_nscTcpSocket->connect(ipstring.c_str (), m_remotePort);
   315   m_state = SYN_SENT;
   316   return 0;
   317 }
   318 
   319 int
   320 NscTcpSocketImpl::Send (const Ptr<Packet> p, uint32_t flags)
   321 {
   322   NS_LOG_FUNCTION (this << p);
   323 
   324   NS_ASSERT (p->GetSize () > 0);
   325   if (m_state == ESTABLISHED || m_state == SYN_SENT || m_state == CLOSE_WAIT)
   326   {
   327     if (p->GetSize () > GetTxAvailable ())
   328     {
   329       m_errno = ERROR_MSGSIZE;
   330       return -1;
   331     }
   332 
   333     uint32_t sent = p->GetSize ();
   334     if (m_state == ESTABLISHED)
   335       {
   336         m_txBuffer.push(p);
   337         m_txBufferSize += sent;
   338         SendPendingData();
   339       }
   340       else
   341       {  // SYN_SET -- Queue Data
   342          m_txBuffer.push(p);
   343          m_txBufferSize += sent;
   344       }
   345     return sent;
   346   }
   347   else
   348   {
   349     m_errno = ERROR_NOTCONN;
   350     return -1;
   351   }
   352 }
   353 
   354 int
   355 NscTcpSocketImpl::SendTo (Ptr<Packet> p, uint32_t flags, const Address &address)
   356 {
   357   NS_LOG_FUNCTION (this << address << p);
   358   if (!m_connected)
   359     {
   360       m_errno = ERROR_NOTCONN;
   361       return -1;
   362     }
   363   else
   364     {
   365       return Send (p, flags); //drop the address according to BSD manpages
   366     }
   367 }
   368 
   369 uint32_t
   370 NscTcpSocketImpl::GetTxAvailable (void) const
   371 {
   372   NS_LOG_FUNCTION_NOARGS ();
   373   if (m_txBufferSize != 0)
   374     {
   375       NS_ASSERT (m_txBufferSize <= m_sndBufSize);
   376       return m_sndBufSize - m_txBufferSize;
   377     }
   378   else
   379     {
   380       return m_sndBufSize;
   381     }
   382 }
   383 
   384 int
   385 NscTcpSocketImpl::Listen (void)
   386 {
   387   NS_LOG_FUNCTION (this);
   388   m_nscTcpSocket->listen(m_localPort);
   389   m_state = LISTEN;
   390   return 0;
   391 }
   392 
   393 
   394 void
   395 NscTcpSocketImpl::NSCWakeup ()
   396 {
   397   switch (m_state) {
   398   case SYN_SENT:
   399       if (!m_nscTcpSocket->is_connected())
   400           break;
   401       m_state = ESTABLISHED;
   402       Simulator::ScheduleNow(&NscTcpSocketImpl::ConnectionSucceeded, this);
   403       // fall through to schedule read/write events
   404   case ESTABLISHED:
   405       if (!m_txBuffer.empty ())
   406           Simulator::ScheduleNow(&NscTcpSocketImpl::SendPendingData, this);
   407       Simulator::ScheduleNow(&NscTcpSocketImpl::ReadPendingData, this);
   408       break;
   409   case LISTEN:
   410       Simulator::ScheduleNow(&NscTcpSocketImpl::Accept, this);
   411       break;
   412   case CLOSED: break;
   413   default:
   414       NS_LOG_DEBUG (this << " invalid state: " << m_state);
   415   }
   416 }
   417 
   418 Ptr<Packet>
   419 NscTcpSocketImpl::Recv (uint32_t maxSize, uint32_t flags)
   420 {
   421   NS_LOG_FUNCTION_NOARGS ();
   422   if (m_deliveryQueue.empty() )
   423     {
   424       m_errno = ERROR_AGAIN;
   425       return 0;
   426     }
   427   Ptr<Packet> p = m_deliveryQueue.front ();
   428   if (p->GetSize () <= maxSize)
   429     {
   430       m_deliveryQueue.pop ();
   431       m_rxAvailable -= p->GetSize ();
   432     }
   433   else
   434     {
   435       m_errno = ERROR_AGAIN;
   436       p = 0;
   437     }
   438   return p;
   439 }
   440 
   441 Ptr<Packet>
   442 NscTcpSocketImpl::RecvFrom (uint32_t maxSize, uint32_t flags,
   443   Address &fromAddress)
   444 {
   445   NS_LOG_FUNCTION (this << maxSize << flags);
   446   Ptr<Packet> packet = Recv (maxSize, flags);
   447   if (packet != 0)
   448     {
   449       SocketAddressTag tag;
   450       bool found;
   451       found = packet->PeekPacketTag (tag);
   452       NS_ASSERT (found);
   453       fromAddress = tag.GetAddress ();
   454     }
   455   return packet;
   456 }
   457 
   458 int
   459 NscTcpSocketImpl::GetSockName (Address &address) const
   460 {
   461   NS_LOG_FUNCTION_NOARGS ();
   462   address = InetSocketAddress(m_localAddress, m_localPort);
   463   return 0;
   464 }
   465 
   466 uint32_t
   467 NscTcpSocketImpl::GetRxAvailable (void) const
   468 {
   469   NS_LOG_FUNCTION_NOARGS ();
   470   // We separately maintain this state to avoid walking the queue 
   471   // every time this might be called
   472   return m_rxAvailable;
   473 }
   474 
   475 void
   476 NscTcpSocketImpl::ForwardUp (Ptr<Packet> packet, Ipv4Address ipv4, uint16_t port)
   477 {
   478   NSCWakeup();
   479 }
   480 
   481 void NscTcpSocketImpl::CompleteFork(void)
   482 {
   483   // The address pairs (m_localAddress, m_localPort, m_remoteAddress, m_remotePort)
   484   // are bogus, but this isn't important at the moment, because
   485   // address <-> Socket handling is done by NSC internally.
   486   // We only need to add the new ns-3 socket to the list of sockets, so
   487   // we use plain Allocate() instead of Allocate(m_localAddress, ... )
   488   struct sockaddr_in sin;
   489   size_t sin_len = sizeof(sin);
   490 
   491   if (0 == m_nscTcpSocket->getpeername((struct sockaddr*) &sin, &sin_len)) {
   492     m_remotePort = ntohs(sin.sin_port);
   493     m_remoteAddress = m_remoteAddress.Deserialize((const uint8_t*) &sin.sin_addr);
   494     m_peerAddress = InetSocketAddress(m_remoteAddress, m_remotePort);
   495   }
   496 
   497   m_endPoint = m_tcp->Allocate ();
   498 
   499   //the cloned socket with be in listen state, so manually change state
   500   NS_ASSERT(m_state == LISTEN);
   501   m_state = ESTABLISHED;
   502 
   503   sin_len = sizeof(sin);
   504 
   505   if (0 == m_nscTcpSocket->getsockname((struct sockaddr *) &sin, &sin_len))
   506     m_localAddress = m_localAddress.Deserialize((const uint8_t*) &sin.sin_addr);
   507 
   508   NS_LOG_LOGIC ("NscTcpSocketImpl " << this << " accepted connection from " 
   509                  << m_remoteAddress << ":" << m_remotePort
   510                  << " to " << m_localAddress << ":" << m_localPort);
   511   //equivalent to FinishBind
   512   m_endPoint->SetRxCallback (MakeCallback (&NscTcpSocketImpl::ForwardUp, Ptr<NscTcpSocketImpl>(this)));
   513   m_endPoint->SetDestroyCallback (MakeCallback (&NscTcpSocketImpl::Destroy, Ptr<NscTcpSocketImpl>(this)));
   514 
   515   NotifyNewConnectionCreated (this, m_peerAddress);
   516 }
   517 
   518 void NscTcpSocketImpl::ConnectionSucceeded()
   519 { // We would preferred to have scheduled an event directly to
   520   // NotifyConnectionSucceeded, but (sigh) these are protected
   521   // and we can get the address of it :(
   522   struct sockaddr_in sin;
   523   size_t sin_len = sizeof(sin);
   524   if (0 == m_nscTcpSocket->getsockname((struct sockaddr *) &sin, &sin_len)) {
   525     m_localAddress = m_localAddress.Deserialize((const uint8_t*)&sin.sin_addr);
   526     m_localPort = ntohs(sin.sin_port);
   527   }
   528 
   529   NS_LOG_LOGIC ("NscTcpSocketImpl " << this << " connected to "
   530                  << m_remoteAddress << ":" << m_remotePort
   531                  << " from " << m_localAddress << ":" << m_localPort);
   532   NotifyConnectionSucceeded();
   533 }
   534 
   535 
   536 bool NscTcpSocketImpl::Accept (void)
   537 {
   538   if (m_state == CLOSED)
   539     {  // Happens if application closes listening socket after Accept() was scheduled.
   540       return false;
   541     }
   542   NS_ASSERT (m_state == LISTEN);
   543 
   544   if (!m_nscTcpSocket->is_listening())
   545     {
   546       return false;
   547     }
   548   INetStreamSocket *newsock;
   549   int res = m_nscTcpSocket->accept(&newsock);
   550   if (res != 0)
   551     {
   552       return false;
   553     }
   554 // We could obtain a fromAddress using getpeername, but we've already
   555 // finished the tcp handshake here, i.e. this is a new connection
   556 // and not a connection request.
   557 // if (!NotifyConnectionRequest(fromAddress))
   558 //   return true;
   559 
   560   // Clone the socket
   561   Ptr<NscTcpSocketImpl> newSock = Copy ();
   562   newSock->m_nscTcpSocket = newsock;
   563   NS_LOG_LOGIC ("Cloned a NscTcpSocketImpl " << newSock);
   564 
   565   Simulator::ScheduleNow (&NscTcpSocketImpl::CompleteFork, newSock);
   566   return true;
   567 }
   568 
   569 bool NscTcpSocketImpl::ReadPendingData (void)
   570 {
   571   if (m_state != ESTABLISHED)
   572     {
   573       return false;
   574     }
   575   int len, err;
   576   uint8_t buffer[8192];
   577   len = sizeof(buffer);
   578   m_errno = ERROR_NOTERROR;
   579   err = m_nscTcpSocket->read_data(buffer, &len);
   580   if (err == 0 && len == 0)
   581     {
   582       NS_LOG_LOGIC ("ReadPendingData got EOF from socket");
   583       m_state = CLOSED;
   584       return false;
   585     }
   586   m_errno = GetNativeNs3Errno(err);
   587   switch (m_errno)
   588     {
   589       case ERROR_NOTERROR: break; // some data was sent
   590       case ERROR_AGAIN: return false;
   591       default:
   592         NS_LOG_WARN ("Error (" << err << ") " <<
   593                      "during read_data, ns-3 errno set to" << m_errno);
   594         m_state = CLOSED;
   595         return false;
   596     }
   597 
   598   Ptr<Packet> p =  Create<Packet> (buffer, len);
   599 
   600   SocketAddressTag tag;
   601 
   602   tag.SetAddress (m_peerAddress);
   603   p->AddPacketTag (tag);
   604   m_deliveryQueue.push (p);
   605   m_rxAvailable += p->GetSize ();
   606 
   607   NotifyDataRecv ();
   608   return true;
   609 }
   610 
   611 bool NscTcpSocketImpl::SendPendingData (void)
   612 {
   613   NS_LOG_FUNCTION (this);
   614   NS_LOG_LOGIC ("ENTERING SendPendingData");
   615 
   616   if (m_txBuffer.empty ())
   617     {
   618       return false;
   619     }
   620 
   621   int ret;
   622   size_t size, written = 0;
   623 
   624   do {
   625     NS_ASSERT (!m_txBuffer.empty ());
   626     Ptr<Packet> &p = m_txBuffer.front ();
   627     size = p->GetSize ();
   628     NS_ASSERT (size > 0);
   629 
   630     m_errno = ERROR_NOTERROR;
   631     ret = m_nscTcpSocket->send_data((const char *)p->PeekData (), size);
   632     if (ret <= 0)
   633       {
   634         break;
   635       }
   636     written += ret;
   637 
   638     NS_ASSERT (m_txBufferSize >= (size_t)ret);
   639     m_txBufferSize -= ret;
   640 
   641     if ((size_t)ret < size)
   642       {
   643         p->RemoveAtStart(ret);
   644         break;
   645       }
   646 
   647     m_txBuffer.pop ();
   648 
   649     if (m_txBuffer.empty ())
   650       {
   651         if (m_closeOnEmpty)
   652           {
   653             m_nscTcpSocket->disconnect();
   654             m_state = CLOSED;
   655           }
   656         break;
   657       }
   658   } while ((size_t) ret == size);
   659 
   660   if (written > 0)
   661     {
   662       Simulator::ScheduleNow(&NscTcpSocketImpl::NotifyDataSent, this, ret);
   663       return true;
   664     }
   665   return false;
   666 }
   667 
   668 Ptr<NscTcpSocketImpl> NscTcpSocketImpl::Copy ()
   669 {
   670   return CopyObject<NscTcpSocketImpl> (this);
   671 }
   672 
   673 void
   674 NscTcpSocketImpl::SetSndBufSize (uint32_t size)
   675 {
   676   m_sndBufSize = size;
   677 }
   678 
   679 uint32_t
   680 NscTcpSocketImpl::GetSndBufSize (void) const
   681 {
   682   return m_sndBufSize;
   683 }
   684 
   685 void
   686 NscTcpSocketImpl::SetRcvBufSize (uint32_t size)
   687 {
   688   m_rcvBufSize = size;
   689 }
   690 
   691 uint32_t
   692 NscTcpSocketImpl::GetRcvBufSize (void) const
   693 {
   694   return m_rcvBufSize;
   695 }
   696 
   697 void
   698 NscTcpSocketImpl::SetSegSize (uint32_t size)
   699 {
   700   m_segmentSize = size;
   701 }
   702 
   703 uint32_t
   704 NscTcpSocketImpl::GetSegSize (void) const
   705 {
   706   return m_segmentSize;
   707 }
   708 
   709 void
   710 NscTcpSocketImpl::SetAdvWin (uint32_t window)
   711 {
   712   m_advertisedWindowSize = window;
   713 }
   714 
   715 uint32_t
   716 NscTcpSocketImpl::GetAdvWin (void) const
   717 {
   718   return m_advertisedWindowSize;
   719 }
   720 
   721 void
   722 NscTcpSocketImpl::SetSSThresh (uint32_t threshold)
   723 {
   724   m_ssThresh = threshold;
   725 }
   726 
   727 uint32_t
   728 NscTcpSocketImpl::GetSSThresh (void) const
   729 {
   730   return m_ssThresh;
   731 }
   732 
   733 void
   734 NscTcpSocketImpl::SetInitialCwnd (uint32_t cwnd)
   735 {
   736   m_initialCWnd = cwnd;
   737 }
   738 
   739 uint32_t
   740 NscTcpSocketImpl::GetInitialCwnd (void) const
   741 {
   742   return m_initialCWnd;
   743 }
   744 
   745 void 
   746 NscTcpSocketImpl::SetConnTimeout (Time timeout)
   747 {
   748   m_cnTimeout = timeout;
   749 }
   750 
   751 Time
   752 NscTcpSocketImpl::GetConnTimeout (void) const
   753 {
   754   return m_cnTimeout;
   755 }
   756 
   757 void 
   758 NscTcpSocketImpl::SetConnCount (uint32_t count)
   759 {
   760   m_cnCount = count;
   761 }
   762 
   763 uint32_t 
   764 NscTcpSocketImpl::GetConnCount (void) const
   765 {
   766   return m_cnCount;
   767 }
   768 
   769 void 
   770 NscTcpSocketImpl::SetDelAckTimeout (Time timeout)
   771 {
   772   m_delAckTimeout = timeout;
   773 }
   774 
   775 Time
   776 NscTcpSocketImpl::GetDelAckTimeout (void) const
   777 {
   778   return m_delAckTimeout;
   779 }
   780 
   781 void
   782 NscTcpSocketImpl::SetDelAckMaxCount (uint32_t count)
   783 {
   784   m_delAckMaxCount = count;
   785 }
   786 
   787 uint32_t
   788 NscTcpSocketImpl::GetDelAckMaxCount (void) const
   789 {
   790   return m_delAckMaxCount;
   791 }
   792 
   793 enum Socket::SocketErrno
   794 NscTcpSocketImpl::GetNativeNs3Errno(int error) const
   795 {
   796   enum nsc_errno err;
   797 
   798   if (error >= 0)
   799     {
   800        return ERROR_NOTERROR;
   801     }
   802   err = (enum nsc_errno) error;
   803   switch (err)
   804     {
   805       case NSC_EADDRINUSE: // fallthrough
   806       case NSC_EADDRNOTAVAIL: return ERROR_AFNOSUPPORT;
   807       case NSC_EINPROGRESS: // Altough nsc sockets are nonblocking, we pretend they're not.
   808       case NSC_EAGAIN: return ERROR_AGAIN;
   809       case NSC_EISCONN: // fallthrough
   810       case NSC_EALREADY: return ERROR_ISCONN;
   811       case NSC_ECONNREFUSED: return ERROR_NOROUTETOHOST; // XXX, better mapping?
   812       case NSC_ECONNRESET: // for no, all of these fall through
   813       case NSC_EHOSTDOWN:
   814       case NSC_ENETUNREACH:
   815       case NSC_EHOSTUNREACH: return ERROR_NOROUTETOHOST;
   816       case NSC_EMSGSIZE: return ERROR_MSGSIZE;
   817       case NSC_ENOTCONN: return ERROR_NOTCONN;
   818       case NSC_ESHUTDOWN: return ERROR_SHUTDOWN;
   819       case NSC_ETIMEDOUT: return ERROR_NOTCONN; // XXX - this mapping isn't correct
   820       case NSC_ENOTDIR: // used by eg. sysctl(2). Shouldn't happen normally,
   821                         // but is triggered by e.g. show_config().
   822       case NSC_EUNKNOWN: return ERROR_INVAL; // Catches stacks that 'return -1' without real mapping
   823     }
   824   NS_ASSERT_MSG(0, "Unknown NSC error");
   825   return ERROR_INVAL;
   826 }
   827 
   828 }//namespace ns3