src/internet-stack/udp-socket-impl.cc
author Tom Henderson <tomh@tomh.org>
Wed Aug 05 20:53:44 2009 -0700 (2009-08-05)
changeset 4697 6e048d6486d8
parent 4603 67a0a49c1db4
child 5152 f14eff131d13
child 5680 25c3039f4144
permissions -rw-r--r--
Implement UdpSocketImpl::Close ()
mathieu@453
     1
/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
mathieu@453
     2
/*
mathieu@453
     3
 * Copyright (c) 2007 INRIA
mathieu@453
     4
 *
mathieu@453
     5
 * This program is free software; you can redistribute it and/or modify
mathieu@453
     6
 * it under the terms of the GNU General Public License version 2 as
mathieu@453
     7
 * published by the Free Software Foundation;
mathieu@453
     8
 *
mathieu@453
     9
 * This program is distributed in the hope that it will be useful,
mathieu@453
    10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
mathieu@453
    11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
mathieu@453
    12
 * GNU General Public License for more details.
mathieu@453
    13
 *
mathieu@453
    14
 * You should have received a copy of the GNU General Public License
mathieu@453
    15
 * along with this program; if not, write to the Free Software
mathieu@453
    16
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
mathieu@453
    17
 *
mathieu@453
    18
 * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
mathieu@453
    19
 */
craigdo@1429
    20
craigdo@1504
    21
#include "ns3/log.h"
mathieu@729
    22
#include "ns3/node.h"
mathieu@1171
    23
#include "ns3/inet-socket-address.h"
tomh@1317
    24
#include "ns3/ipv4-route.h"
tomh@1317
    25
#include "ns3/ipv4.h"
tomh@4472
    26
#include "ns3/ipv4-header.h"
tomh@4472
    27
#include "ns3/ipv4-routing-protocol.h"
tomh@3125
    28
#include "ns3/udp-socket-factory.h"
tomh@3117
    29
#include "ns3/trace-source-accessor.h"
tomh@3130
    30
#include "udp-socket-impl.h"
mathieu@741
    31
#include "udp-l4-protocol.h"
mathieu@495
    32
#include "ipv4-end-point.h"
mathieu@3718
    33
#include <limits>
mathieu@1270
    34
tomh@3130
    35
NS_LOG_COMPONENT_DEFINE ("UdpSocketImpl");
mathieu@453
    36
mathieu@453
    37
namespace ns3 {
mathieu@453
    38
tomh@3122
    39
static const uint32_t MAX_IPV4_UDP_DATAGRAM_SIZE = 65507;
tomh@3122
    40
tomh@3127
    41
// Add attributes generic to all UdpSockets to base class UdpSocket
tomh@3105
    42
TypeId
tomh@3130
    43
UdpSocketImpl::GetTypeId (void)
tomh@3105
    44
{
tomh@3130
    45
  static TypeId tid = TypeId ("ns3::UdpSocketImpl")
tomh@3130
    46
    .SetParent<UdpSocket> ()
tomh@3130
    47
    .AddConstructor<UdpSocketImpl> ()
tomh@3105
    48
    .AddTraceSource ("Drop", "Drop UDP packet due to receive buffer overflow",
tomh@3130
    49
                     MakeTraceSourceAccessor (&UdpSocketImpl::m_dropTrace))
craigdo@3820
    50
    .AddAttribute ("IcmpCallback", "Callback invoked whenever an icmp error is received on this socket.",
craigdo@3820
    51
                   CallbackValue (),
craigdo@3820
    52
                   MakeCallbackAccessor (&UdpSocketImpl::m_icmpCallback),
craigdo@3820
    53
                   MakeCallbackChecker ())
tomh@3105
    54
    ;
tomh@3105
    55
  return tid;
tomh@3105
    56
}
tomh@3105
    57
tomh@3130
    58
UdpSocketImpl::UdpSocketImpl ()
mathieu@453
    59
  : m_endPoint (0),
mathieu@2592
    60
    m_node (0),
mathieu@2592
    61
    m_udp (0),
gjc@646
    62
    m_errno (ERROR_NOTERROR),
mathieu@453
    63
    m_shutdownSend (false),
mathieu@453
    64
    m_shutdownRecv (false),
tomh@3104
    65
    m_connected (false),
tomh@3123
    66
    m_rxAvailable (0)
craigdo@1429
    67
{
mathieu@2983
    68
  NS_LOG_FUNCTION_NOARGS ();
craigdo@1429
    69
}
craigdo@1429
    70
tomh@3130
    71
UdpSocketImpl::~UdpSocketImpl ()
mathieu@453
    72
{
mathieu@2983
    73
  NS_LOG_FUNCTION_NOARGS ();
craigdo@1429
    74
tomh@4472
    75
  // XXX todo:  leave any multicast groups that have been joined
mathieu@557
    76
  m_node = 0;
mathieu@515
    77
  if (m_endPoint != 0)
mathieu@515
    78
    {
mathieu@515
    79
      NS_ASSERT (m_udp != 0);
mathieu@515
    80
      /**
mathieu@515
    81
       * Note that this piece of code is a bit tricky:
mathieu@515
    82
       * when DeAllocate is called, it will call into
mathieu@515
    83
       * Ipv4EndPointDemux::Deallocate which triggers
mathieu@515
    84
       * a delete of the associated endPoint which triggers
mathieu@515
    85
       * in turn a call to the method ::Destroy below
mathieu@515
    86
       * will will zero the m_endPoint field.
mathieu@515
    87
       */
mathieu@515
    88
      NS_ASSERT (m_endPoint != 0);
mathieu@515
    89
      m_udp->DeAllocate (m_endPoint);
mathieu@515
    90
      NS_ASSERT (m_endPoint == 0);
mathieu@515
    91
    }
mathieu@568
    92
  m_udp = 0;
mathieu@453
    93
}
mathieu@453
    94
mathieu@2592
    95
void 
tomh@3130
    96
UdpSocketImpl::SetNode (Ptr<Node> node)
mathieu@2592
    97
{
tomh@3113
    98
  NS_LOG_FUNCTION_NOARGS ();
mathieu@2592
    99
  m_node = node;
tomh@3105
   100
mathieu@2592
   101
}
mathieu@2592
   102
void 
tomh@3130
   103
UdpSocketImpl::SetUdp (Ptr<UdpL4Protocol> udp)
mathieu@2592
   104
{
tomh@3113
   105
  NS_LOG_FUNCTION_NOARGS ();
mathieu@2592
   106
  m_udp = udp;
mathieu@2592
   107
}
mathieu@2592
   108
mathieu@2592
   109
mathieu@1264
   110
enum Socket::SocketErrno
tomh@3130
   111
UdpSocketImpl::GetErrno (void) const
mathieu@1264
   112
{
mathieu@2983
   113
  NS_LOG_FUNCTION_NOARGS ();
mathieu@1264
   114
  return m_errno;
mathieu@1264
   115
}
mathieu@1264
   116
mathieu@728
   117
Ptr<Node>
tomh@3130
   118
UdpSocketImpl::GetNode (void) const
mathieu@453
   119
{
mathieu@2983
   120
  NS_LOG_FUNCTION_NOARGS ();
mathieu@453
   121
  return m_node;
mathieu@453
   122
}
mathieu@453
   123
mathieu@495
   124
void 
tomh@3130
   125
UdpSocketImpl::Destroy (void)
mathieu@495
   126
{
mathieu@2983
   127
  NS_LOG_FUNCTION_NOARGS ();
mathieu@557
   128
  m_node = 0;
mathieu@495
   129
  m_endPoint = 0;
mathieu@568
   130
  m_udp = 0;
mathieu@495
   131
}
craigdo@1429
   132
mathieu@495
   133
int
tomh@3130
   134
UdpSocketImpl::FinishBind (void)
mathieu@495
   135
{
mathieu@2983
   136
  NS_LOG_FUNCTION_NOARGS ();
mathieu@495
   137
  if (m_endPoint == 0)
mathieu@495
   138
    {
mathieu@495
   139
      return -1;
mathieu@495
   140
    }
gjc@3157
   141
  m_endPoint->SetRxCallback (MakeCallback (&UdpSocketImpl::ForwardUp, Ptr<UdpSocketImpl> (this)));
craigdo@3820
   142
  m_endPoint->SetIcmpCallback (MakeCallback (&UdpSocketImpl::ForwardIcmp, Ptr<UdpSocketImpl> (this)));
gjc@3157
   143
  m_endPoint->SetDestroyCallback (MakeCallback (&UdpSocketImpl::Destroy, Ptr<UdpSocketImpl> (this)));
mathieu@495
   144
  return 0;
mathieu@495
   145
}
mathieu@495
   146
mathieu@453
   147
int
tomh@3130
   148
UdpSocketImpl::Bind (void)
mathieu@453
   149
{
mathieu@2983
   150
  NS_LOG_FUNCTION_NOARGS ();
mathieu@499
   151
  m_endPoint = m_udp->Allocate ();
mathieu@495
   152
  return FinishBind ();
mathieu@453
   153
}
craigdo@1429
   154
mathieu@453
   155
int 
tomh@3130
   156
UdpSocketImpl::Bind (const Address &address)
mathieu@453
   157
{
mathieu@2983
   158
  NS_LOG_FUNCTION (this << address);
craigdo@1429
   159
mathieu@1172
   160
  if (!InetSocketAddress::IsMatchingType (address))
mathieu@1172
   161
    {
craigdo@1504
   162
      NS_LOG_ERROR ("Not IsMatchingType");
raj@3846
   163
      m_errno = ERROR_INVAL;
raj@3846
   164
      return -1;
mathieu@1172
   165
    }
mathieu@1207
   166
  InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
mathieu@1162
   167
  Ipv4Address ipv4 = transport.GetIpv4 ();
mathieu@1162
   168
  uint16_t port = transport.GetPort ();
mathieu@1162
   169
  if (ipv4 == Ipv4Address::GetAny () && port == 0)
mathieu@1162
   170
    {
mathieu@1162
   171
      m_endPoint = m_udp->Allocate ();
mathieu@1162
   172
    }
mathieu@1162
   173
  else if (ipv4 == Ipv4Address::GetAny () && port != 0)
mathieu@1162
   174
    {
mathieu@1162
   175
      m_endPoint = m_udp->Allocate (port);
mathieu@1162
   176
    }
mathieu@1162
   177
  else if (ipv4 != Ipv4Address::GetAny () && port == 0)
mathieu@1162
   178
    {
mathieu@2608
   179
      m_endPoint = m_udp->Allocate (ipv4);
mathieu@1162
   180
    }
mathieu@1162
   181
  else if (ipv4 != Ipv4Address::GetAny () && port != 0)
mathieu@1162
   182
    {
mathieu@2608
   183
      m_endPoint = m_udp->Allocate (ipv4, port);
mathieu@1162
   184
    }
mathieu@1162
   185
mathieu@495
   186
  return FinishBind ();
mathieu@453
   187
}
mathieu@453
   188
mathieu@453
   189
int 
tomh@3130
   190
UdpSocketImpl::ShutdownSend (void)
mathieu@453
   191
{
mathieu@2983
   192
  NS_LOG_FUNCTION_NOARGS ();
mathieu@453
   193
  m_shutdownSend = true;
mathieu@453
   194
  return 0;
mathieu@453
   195
}
craigdo@1429
   196
mathieu@453
   197
int 
tomh@3130
   198
UdpSocketImpl::ShutdownRecv (void)
mathieu@453
   199
{
mathieu@2983
   200
  NS_LOG_FUNCTION_NOARGS ();
mathieu@4491
   201
  m_shutdownRecv = true;
mathieu@453
   202
  return 0;
mathieu@453
   203
}
mathieu@453
   204
mathieu@1186
   205
int
tomh@4697
   206
UdpSocketImpl::Close (void)
mathieu@453
   207
{
mathieu@2983
   208
  NS_LOG_FUNCTION_NOARGS ();
tomh@4697
   209
  if (m_shutdownRecv == true && m_shutdownSend == true)
tomh@4697
   210
    {
tomh@4697
   211
      m_errno = Socket::ERROR_BADF;
tomh@4697
   212
      return -1;
tomh@4697
   213
    }
tomh@4697
   214
  m_shutdownRecv = true;
tomh@4697
   215
  m_shutdownSend = true;
mathieu@1186
   216
  return 0;
mathieu@453
   217
}
mathieu@1264
   218
mathieu@1186
   219
int
tomh@3130
   220
UdpSocketImpl::Connect(const Address & address)
mathieu@453
   221
{
mathieu@2983
   222
  NS_LOG_FUNCTION (this << address);
mathieu@1207
   223
  InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
mathieu@1162
   224
  m_defaultAddress = transport.GetIpv4 ();
mathieu@1162
   225
  m_defaultPort = transport.GetPort ();
mathieu@1264
   226
  NotifyConnectionSucceeded ();
mathieu@453
   227
  m_connected = true;
craigdo@1434
   228
mathieu@1186
   229
  return 0;
mathieu@453
   230
}
tomh@1317
   231
mathieu@453
   232
int 
craigdo@3772
   233
UdpSocketImpl::Listen (void)
mathieu@3213
   234
{
mathieu@3213
   235
  m_errno = Socket::ERROR_OPNOTSUPP;
mathieu@3213
   236
  return -1;
mathieu@3213
   237
}
mathieu@3213
   238
mathieu@3213
   239
int 
tomh@3269
   240
UdpSocketImpl::Send (Ptr<Packet> p, uint32_t flags)
mathieu@453
   241
{
tomh@3269
   242
  NS_LOG_FUNCTION (this << p << flags);
craigdo@1429
   243
mathieu@453
   244
  if (!m_connected)
mathieu@453
   245
    {
gjc@646
   246
      m_errno = ERROR_NOTCONN;
mathieu@453
   247
      return -1;
mathieu@453
   248
    }
tomh@1317
   249
  return DoSend (p);
mathieu@453
   250
}
tomh@1317
   251
tomh@1317
   252
int 
tomh@3130
   253
UdpSocketImpl::DoSend (Ptr<Packet> p)
tomh@1317
   254
{
tomh@3269
   255
  NS_LOG_FUNCTION (this << p);
tomh@1317
   256
  if (m_endPoint == 0)
tomh@1317
   257
    {
tomh@1317
   258
      if (Bind () == -1)
tomh@1317
   259
       {
tomh@1317
   260
          NS_ASSERT (m_endPoint == 0);
tomh@1317
   261
         return -1;
tomh@1317
   262
       }
tomh@1317
   263
      NS_ASSERT (m_endPoint != 0);
tomh@1317
   264
    }
tomh@1317
   265
  if (m_shutdownSend)
tomh@1317
   266
    {
tomh@1317
   267
      m_errno = ERROR_SHUTDOWN;
tomh@1317
   268
      return -1;
tomh@1317
   269
    } 
tomh@1318
   270
  
tomh@1318
   271
  return DoSendTo (p, m_defaultAddress, m_defaultPort);
tomh@1317
   272
}
tomh@1317
   273
mathieu@453
   274
int
tomh@3130
   275
UdpSocketImpl::DoSendTo (Ptr<Packet> p, const Address &address)
mathieu@1162
   276
{
mathieu@2983
   277
  NS_LOG_FUNCTION (this << p << address);
craigdo@1449
   278
tomh@1318
   279
  if (!m_connected)
tomh@1318
   280
    {
craigdo@1504
   281
      NS_LOG_LOGIC ("Not connected");
tomh@1318
   282
      InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
tomh@1318
   283
      Ipv4Address ipv4 = transport.GetIpv4 ();
tomh@1318
   284
      uint16_t port = transport.GetPort ();
tomh@1318
   285
      return DoSendTo (p, ipv4, port);
tomh@1318
   286
    }
tomh@1318
   287
  else
tomh@1318
   288
    {
tomh@1318
   289
      // connected UDP socket must use default addresses
craigdo@1504
   290
      NS_LOG_LOGIC ("Connected");
tomh@1318
   291
      return DoSendTo (p, m_defaultAddress, m_defaultPort);
tomh@1318
   292
    }
mathieu@1162
   293
}
craigdo@1429
   294
mathieu@1162
   295
int
tomh@3130
   296
UdpSocketImpl::DoSendTo (Ptr<Packet> p, Ipv4Address dest, uint16_t port)
mathieu@453
   297
{
mathieu@2983
   298
  NS_LOG_FUNCTION (this << p << dest << port);
craigdo@1429
   299
mathieu@453
   300
  if (m_endPoint == 0)
mathieu@453
   301
    {
mathieu@453
   302
      if (Bind () == -1)
mathieu@453
   303
	{
mathieu@453
   304
          NS_ASSERT (m_endPoint == 0);
mathieu@453
   305
	  return -1;
mathieu@453
   306
	}
mathieu@453
   307
      NS_ASSERT (m_endPoint != 0);
mathieu@453
   308
    }
mathieu@453
   309
  if (m_shutdownSend)
mathieu@453
   310
    {
gjc@646
   311
      m_errno = ERROR_SHUTDOWN;
mathieu@453
   312
      return -1;
mathieu@453
   313
    }
craigdo@1452
   314
tomh@3122
   315
  if (p->GetSize () > GetTxAvailable () )
tomh@3122
   316
    {
tomh@3122
   317
      m_errno = ERROR_MSGSIZE;
tomh@3122
   318
      return -1;
tomh@3122
   319
    }
tomh@3122
   320
mathieu@2257
   321
  Ptr<Ipv4> ipv4 = m_node->GetObject<Ipv4> ();
craigdo@1452
   322
tomh@3124
   323
  // Locally override the IP TTL for this socket
tomh@3124
   324
  // We cannot directly modify the TTL at this stage, so we set a Packet tag
tomh@3124
   325
  // The destination can be either multicast, unicast/anycast, or
tomh@3124
   326
  // either all-hosts broadcast or limited (subnet-directed) broadcast.
tomh@3124
   327
  // For the latter two broadcast types, the TTL will later be set to one
tomh@3124
   328
  // irrespective of what is set in these socket options.  So, this tagging  
tomh@3124
   329
  // may end up setting the TTL of a limited broadcast packet to be
tomh@3124
   330
  // the same as a unicast, but it will be fixed further down the stack
tomh@3124
   331
  if (m_ipMulticastTtl != 0 && dest.IsMulticast ())
tomh@3124
   332
    {
tomh@3124
   333
      SocketIpTtlTag tag;
tomh@3124
   334
      tag.SetTtl (m_ipMulticastTtl);
mathieu@4502
   335
      p->AddPacketTag (tag);
tomh@3124
   336
    }
tomh@3124
   337
  else if (m_ipTtl != 0 && !dest.IsMulticast () && !dest.IsBroadcast ())
tomh@3124
   338
    {
tomh@3124
   339
      SocketIpTtlTag tag;
tomh@3124
   340
      tag.SetTtl (m_ipTtl);
mathieu@4502
   341
      p->AddPacketTag (tag);
tomh@3124
   342
    }
craigdo@3820
   343
  {
craigdo@3820
   344
    SocketSetDontFragmentTag tag;
mathieu@4502
   345
    bool found = p->RemovePacketTag (tag);
craigdo@3820
   346
    if (!found)
craigdo@3820
   347
      {
craigdo@3820
   348
        if (m_mtuDiscover)
craigdo@3820
   349
          {
craigdo@3820
   350
            tag.Enable ();
craigdo@3820
   351
          }
craigdo@3820
   352
        else
craigdo@3820
   353
          {
craigdo@3820
   354
            tag.Disable ();
craigdo@3820
   355
          }
mathieu@4502
   356
        p->AddPacketTag (tag);
craigdo@3820
   357
      }
craigdo@3820
   358
  }
tomh@1318
   359
  //
tomh@3956
   360
  // If dest is set to the limited broadcast address (all ones),
tomh@3956
   361
  // convert it to send a copy of the packet out of every 
tomh@3956
   362
  // interface as a subnet-directed broadcast.
tomh@3956
   363
  // Exception:  if the interface has a /32 address, there is no
tomh@3956
   364
  // valid subnet-directed broadcast, so send it as limited broadcast
tomh@3956
   365
  // Note also that some systems will only send limited broadcast packets
tomh@3956
   366
  // out of the "default" interface; here we send it out all interfaces
tomh@1318
   367
  //
tomh@1318
   368
  if (dest.IsBroadcast ())
tomh@1318
   369
    {
gjc@2299
   370
      NS_LOG_LOGIC ("Limited broadcast start.");
tomh@1318
   371
      for (uint32_t i = 0; i < ipv4->GetNInterfaces (); i++ )
tomh@1318
   372
        {
tomh@4375
   373
          // Get the primary address
tomh@4375
   374
          Ipv4InterfaceAddress iaddr = ipv4->GetAddress (i, 0);
tomh@4375
   375
          Ipv4Address addri = iaddr.GetLocal ();
tomh@4375
   376
          Ipv4Mask maski = iaddr.GetMask ();
tomh@3956
   377
          if (maski == Ipv4Mask::GetOnes ())
tomh@3956
   378
            {
tomh@3956
   379
              // if the network mask is 255.255.255.255, do not convert dest
tomh@3956
   380
              NS_LOG_LOGIC ("Sending one copy from " << addri << " to " << dest
tomh@3956
   381
                            << " (mask is " << maski << ")");
tomh@3956
   382
              m_udp->Send (p->Copy (), addri, dest,
tomh@3956
   383
                           m_endPoint->GetLocalPort (), port);
tomh@3956
   384
              NotifyDataSent (p->GetSize ());
tomh@3956
   385
              NotifySend (GetTxAvailable ());
tomh@3956
   386
            }
tomh@3956
   387
          else
tomh@3956
   388
            {
tomh@3956
   389
              // Convert to subnet-directed broadcast
tomh@3956
   390
              Ipv4Address bcast = addri.GetSubnetDirectedBroadcast (maski);
tomh@3956
   391
              NS_LOG_LOGIC ("Sending one copy from " << addri << " to " << bcast
tomh@3956
   392
                            << " (mask is " << maski << ")");
tomh@3956
   393
              m_udp->Send (p->Copy (), addri, bcast,
tomh@3956
   394
                           m_endPoint->GetLocalPort (), port);
tomh@3956
   395
              NotifyDataSent (p->GetSize ());
tomh@3956
   396
              NotifySend (GetTxAvailable ());
tomh@3956
   397
            }
tomh@1318
   398
        }
gjc@2299
   399
      NS_LOG_LOGIC ("Limited broadcast end.");
liujatp@2912
   400
      return p->GetSize();
tomh@1318
   401
    }
tomh@4472
   402
  else if (ipv4->GetRoutingProtocol () != 0)
tomh@1317
   403
    {
tomh@4472
   404
      Ipv4Header header;
tomh@4472
   405
      header.SetDestination (dest);
faker@4567
   406
      Socket::SocketErrno errno_;
tomh@4472
   407
      Ptr<Ipv4Route> route;
tomh@4472
   408
      uint32_t oif = 0; //specify non-zero if bound to a source address
tomh@4472
   409
      // TBD-- we could cache the route and just check its validity
joshpelkey@4603
   410
      route = ipv4->GetRoutingProtocol ()->RouteOutput (p, header, oif, errno_); 
tomh@4472
   411
      if (route != 0)
tomh@4472
   412
        {
tomh@4472
   413
          NS_LOG_LOGIC ("Route exists");
tomh@4472
   414
          header.SetSource (route->GetSource ());
tomh@4472
   415
          m_udp->Send (p->Copy (), header.GetSource (), header.GetDestination (),
tomh@4472
   416
                       m_endPoint->GetLocalPort (), port, route);
tomh@4472
   417
          NotifyDataSent (p->GetSize ());
tomh@4472
   418
          return p->GetSize();
tomh@4472
   419
        }
tomh@4472
   420
      else 
tomh@4472
   421
        {
tomh@4472
   422
          NS_LOG_LOGIC ("No route to destination");
faker@4567
   423
          NS_LOG_ERROR (errno_);
faker@4567
   424
          m_errno = errno_;
tomh@4472
   425
          return -1;
tomh@4472
   426
        }
tomh@1317
   427
    }
tomh@1317
   428
  else
tomh@1317
   429
   {
craigdo@1504
   430
      NS_LOG_ERROR ("ERROR_NOROUTETOHOST");
tomh@1317
   431
      m_errno = ERROR_NOROUTETOHOST;
tomh@1317
   432
      return -1;
tomh@1317
   433
   }
craigdo@1429
   434
mathieu@453
   435
  return 0;
mathieu@453
   436
}
tomh@1317
   437
tomh@3122
   438
// XXX maximum message size for UDP broadcast is limited by MTU
tomh@3122
   439
// size of underlying link; we are not checking that now.
tomh@3105
   440
uint32_t
tomh@3130
   441
UdpSocketImpl::GetTxAvailable (void) const
tomh@3105
   442
{
tomh@3113
   443
  NS_LOG_FUNCTION_NOARGS ();
tomh@3122
   444
  // No finite send buffer is modelled, but we must respect
tomh@3122
   445
  // the maximum size of an IP datagram (65535 bytes - headers).
tomh@3122
   446
  return MAX_IPV4_UDP_DATAGRAM_SIZE;
tomh@3105
   447
}
tomh@3105
   448
mathieu@453
   449
int 
tomh@3269
   450
UdpSocketImpl::SendTo (Ptr<Packet> p, uint32_t flags, const Address &address)
mathieu@453
   451
{
tomh@3269
   452
  NS_LOG_FUNCTION (this << p << flags << address);
mathieu@1207
   453
  InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
mathieu@1162
   454
  Ipv4Address ipv4 = transport.GetIpv4 ();
mathieu@1162
   455
  uint16_t port = transport.GetPort ();
mathieu@1264
   456
  return DoSendTo (p, ipv4, port);
mathieu@453
   457
}
mathieu@453
   458
tomh@3269
   459
uint32_t
tomh@3269
   460
UdpSocketImpl::GetRxAvailable (void) const
tomh@3269
   461
{
tomh@3269
   462
  NS_LOG_FUNCTION_NOARGS ();
tomh@3269
   463
  // We separately maintain this state to avoid walking the queue 
tomh@3269
   464
  // every time this might be called
tomh@3269
   465
  return m_rxAvailable;
tomh@3269
   466
}
tomh@3269
   467
tomh@3098
   468
Ptr<Packet>
tomh@3130
   469
UdpSocketImpl::Recv (uint32_t maxSize, uint32_t flags)
tomh@3098
   470
{
tomh@3269
   471
  NS_LOG_FUNCTION (this << maxSize << flags);
tomh@3098
   472
  if (m_deliveryQueue.empty() )
tomh@3098
   473
    {
craigdo@3820
   474
      m_errno = ERROR_AGAIN;
tomh@3098
   475
      return 0;
tomh@3098
   476
    }
tomh@3098
   477
  Ptr<Packet> p = m_deliveryQueue.front ();
tomh@3104
   478
  if (p->GetSize () <= maxSize) 
tomh@3098
   479
    {
tomh@3098
   480
      m_deliveryQueue.pop ();
tomh@3104
   481
      m_rxAvailable -= p->GetSize ();
tomh@3098
   482
    }
tomh@3098
   483
  else
tomh@3098
   484
    {
tomh@3098
   485
      p = 0; 
tomh@3098
   486
    }
tomh@3098
   487
  return p;
tomh@3098
   488
}
tomh@3098
   489
tomh@3269
   490
Ptr<Packet>
tomh@3269
   491
UdpSocketImpl::RecvFrom (uint32_t maxSize, uint32_t flags, 
tomh@3269
   492
  Address &fromAddress)
tomh@3104
   493
{
tomh@3269
   494
  NS_LOG_FUNCTION (this << maxSize << flags);
tomh@3269
   495
  Ptr<Packet> packet = Recv (maxSize, flags);
tomh@3269
   496
  if (packet != 0)
tomh@3269
   497
    {
tomh@3269
   498
      SocketAddressTag tag;
tomh@3269
   499
      bool found;
mathieu@4502
   500
      found = packet->PeekPacketTag (tag);
tomh@3269
   501
      NS_ASSERT (found);
tomh@3269
   502
      fromAddress = tag.GetAddress ();
tomh@3269
   503
    }
tomh@3269
   504
  return packet;
tomh@3104
   505
}
tomh@3104
   506
craigdo@3778
   507
int
craigdo@3778
   508
UdpSocketImpl::GetSockName (Address &address) const
craigdo@3778
   509
{
craigdo@3778
   510
  NS_LOG_FUNCTION_NOARGS ();
craigdo@3778
   511
  if (m_endPoint != 0)
craigdo@3778
   512
    {
craigdo@3778
   513
      address = InetSocketAddress (m_endPoint->GetLocalAddress (), m_endPoint->GetLocalPort());
craigdo@3778
   514
    }
craigdo@3778
   515
  else
craigdo@3778
   516
    {
craigdo@3778
   517
      address = InetSocketAddress(Ipv4Address::GetZero(), 0);
craigdo@3778
   518
    }
craigdo@3778
   519
  return 0;
craigdo@3778
   520
}
craigdo@3778
   521
tomh@4472
   522
int 
tomh@4472
   523
UdpSocketImpl::MulticastJoinGroup (uint32_t interface, const Address &groupAddress)
tomh@4472
   524
{
tomh@4472
   525
  NS_LOG_FUNCTION (interface << groupAddress);
tomh@4472
   526
  /*
tomh@4472
   527
   1) sanity check interface
tomh@4472
   528
   2) sanity check that it has not been called yet on this interface/group
tomh@4472
   529
   3) determine address family of groupAddress
tomh@4472
   530
   4) locally store a list of (interface, groupAddress)
tomh@4472
   531
   5) call ipv4->MulticastJoinGroup () or Ipv6->MulticastJoinGroup ()
tomh@4472
   532
  */
tomh@4472
   533
  return 0;
tomh@4472
   534
} 
tomh@4472
   535
tomh@4472
   536
int 
tomh@4472
   537
UdpSocketImpl::MulticastLeaveGroup (uint32_t interface, const Address &groupAddress) 
tomh@4472
   538
{
tomh@4472
   539
  NS_LOG_FUNCTION (interface << groupAddress);
tomh@4472
   540
  /*
tomh@4472
   541
   1) sanity check interface
tomh@4472
   542
   2) determine address family of groupAddress
tomh@4472
   543
   3) delete from local list of (interface, groupAddress); raise a LOG_WARN
tomh@4472
   544
      if not already present (but return 0) 
tomh@4472
   545
   5) call ipv4->MulticastLeaveGroup () or Ipv6->MulticastLeaveGroup ()
tomh@4472
   546
  */
tomh@4472
   547
  return 0;
tomh@4472
   548
}
tomh@4472
   549
mathieu@453
   550
void 
tomh@3130
   551
UdpSocketImpl::ForwardUp (Ptr<Packet> packet, Ipv4Address ipv4, uint16_t port)
mathieu@453
   552
{
mathieu@2983
   553
  NS_LOG_FUNCTION (this << packet << ipv4 << port);
craigdo@1429
   554
mathieu@453
   555
  if (m_shutdownRecv)
mathieu@453
   556
    {
mathieu@453
   557
      return;
mathieu@453
   558
    }
tomh@3123
   559
  if ((m_rxAvailable + packet->GetSize ()) <= m_rcvBufSize)
tomh@3105
   560
    {
tomh@3105
   561
      Address address = InetSocketAddress (ipv4, port);
tomh@3269
   562
      SocketAddressTag tag;
tomh@3105
   563
      tag.SetAddress (address);
mathieu@4502
   564
      packet->AddPacketTag (tag);
tomh@3105
   565
      m_deliveryQueue.push (packet);
tomh@3105
   566
      m_rxAvailable += packet->GetSize ();
tomh@3105
   567
      NotifyDataRecv ();
tomh@3105
   568
    }
tomh@3105
   569
  else
tomh@3105
   570
    {
tomh@3105
   571
      // In general, this case should not occur unless the
tomh@3105
   572
      // receiving application reads data from this socket slowly
tomh@3105
   573
      // in comparison to the arrival rate
tomh@3105
   574
      //
tomh@3105
   575
      // drop and trace packet
tomh@3105
   576
      NS_LOG_WARN ("No receive buffer space available.  Drop.");
tomh@3105
   577
      m_dropTrace (packet);
tomh@3105
   578
    }
mathieu@453
   579
}
mathieu@453
   580
craigdo@3820
   581
void
craigdo@3820
   582
UdpSocketImpl::ForwardIcmp (Ipv4Address icmpSource, uint8_t icmpTtl, 
craigdo@3820
   583
                            uint8_t icmpType, uint8_t icmpCode,
craigdo@3820
   584
                            uint32_t icmpInfo)
craigdo@3820
   585
{
craigdo@3820
   586
  NS_LOG_FUNCTION (this << icmpSource << (uint32_t)icmpTtl << (uint32_t)icmpType <<
craigdo@3820
   587
                   (uint32_t)icmpCode << icmpInfo);
craigdo@3820
   588
  if (!m_icmpCallback.IsNull ())
craigdo@3820
   589
    {
craigdo@3820
   590
      m_icmpCallback (icmpSource, icmpTtl, icmpType, icmpCode, icmpInfo);
craigdo@3820
   591
    }
craigdo@3820
   592
}
craigdo@3820
   593
tomh@3127
   594
tomh@3127
   595
void 
tomh@3130
   596
UdpSocketImpl::SetRcvBufSize (uint32_t size)
tomh@3127
   597
{
tomh@3127
   598
  m_rcvBufSize = size;
tomh@3127
   599
}
tomh@3127
   600
tomh@3127
   601
uint32_t 
tomh@3130
   602
UdpSocketImpl::GetRcvBufSize (void) const
tomh@3127
   603
{
tomh@3127
   604
  return m_rcvBufSize;
tomh@3127
   605
}
tomh@3127
   606
tomh@3127
   607
void 
tomh@4472
   608
UdpSocketImpl::SetIpTtl (uint8_t ipTtl)
tomh@3127
   609
{
tomh@3127
   610
  m_ipTtl = ipTtl;
tomh@3127
   611
}
tomh@3127
   612
tomh@4472
   613
uint8_t 
tomh@3130
   614
UdpSocketImpl::GetIpTtl (void) const
tomh@3127
   615
{
tomh@3127
   616
  return m_ipTtl;
tomh@3127
   617
}
tomh@3127
   618
tomh@3127
   619
void 
tomh@4472
   620
UdpSocketImpl::SetIpMulticastTtl (uint8_t ipTtl)
tomh@3127
   621
{
tomh@3127
   622
  m_ipMulticastTtl = ipTtl;
tomh@3127
   623
}
tomh@3127
   624
tomh@4472
   625
uint8_t 
tomh@3130
   626
UdpSocketImpl::GetIpMulticastTtl (void) const
tomh@3127
   627
{
tomh@3127
   628
  return m_ipMulticastTtl;
tomh@3127
   629
}
tomh@3127
   630
craigdo@3820
   631
void 
tomh@4472
   632
UdpSocketImpl::SetIpMulticastIf (int32_t ipIf)
tomh@4472
   633
{
tomh@4472
   634
  m_ipMulticastIf = ipIf;
tomh@4472
   635
}
tomh@4472
   636
tomh@4472
   637
int32_t 
tomh@4472
   638
UdpSocketImpl::GetIpMulticastIf (void) const
tomh@4472
   639
{
tomh@4472
   640
  return m_ipMulticastIf;
tomh@4472
   641
}
tomh@4472
   642
tomh@4472
   643
void 
tomh@4472
   644
UdpSocketImpl::SetIpMulticastLoop (bool loop)
tomh@4472
   645
{
tomh@4472
   646
  m_ipMulticastLoop = loop;
tomh@4472
   647
}
tomh@4472
   648
tomh@4472
   649
bool 
tomh@4472
   650
UdpSocketImpl::GetIpMulticastLoop (void) const
tomh@4472
   651
{
tomh@4472
   652
  return m_ipMulticastLoop;
tomh@4472
   653
}
tomh@4472
   654
tomh@4472
   655
void 
craigdo@3820
   656
UdpSocketImpl::SetMtuDiscover (bool discover)
craigdo@3820
   657
{
craigdo@3820
   658
  m_mtuDiscover = discover;
craigdo@3820
   659
}
craigdo@3820
   660
bool 
craigdo@3820
   661
UdpSocketImpl::GetMtuDiscover (void) const
craigdo@3820
   662
{
craigdo@3820
   663
  return m_mtuDiscover;
craigdo@3820
   664
}
craigdo@3820
   665
craigdo@3820
   666
craigdo@1435
   667
} //namespace ns3