1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2007 INRIA
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  *
18  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
19  */
20 
21 #include "ns3/log.h"
22 #include "ns3/node.h"
23 #include "ns3/inet-socket-address.h"
24 #include "ns3/inet6-socket-address.h"
25 #include "ns3/ipv4-route.h"
26 #include "ns3/ipv6-route.h"
27 #include "ns3/ipv4.h"
28 #include "ns3/ipv6.h"
29 #include "ns3/ipv6-l3-protocol.h"
30 #include "ns3/ipv4-header.h"
31 #include "ns3/ipv4-routing-protocol.h"
32 #include "ns3/ipv6-routing-protocol.h"
33 #include "ns3/udp-socket-factory.h"
34 #include "ns3/trace-source-accessor.h"
35 #include "ns3/ipv4-packet-info-tag.h"
36 #include "ns3/ipv6-packet-info-tag.h"
37 #include "udp-socket-impl.h"
38 #include "udp-l4-protocol.h"
39 #include "ipv4-end-point.h"
40 #include "ipv6-end-point.h"
41 #include <limits>
42 
43 namespace ns3 {
44 
45 NS_LOG_COMPONENT_DEFINE ("UdpSocketImpl");
46 
47 NS_OBJECT_ENSURE_REGISTERED (UdpSocketImpl);
48 
49 // The correct maximum UDP message size is 65507, as determined by the following formula:
50 // 0xffff - (sizeof(IP Header) + sizeof(UDP Header)) = 65535-(20+8) = 65507
51 // \todo MAX_IPV4_UDP_DATAGRAM_SIZE is correct only for IPv4
52 static const uint32_t MAX_IPV4_UDP_DATAGRAM_SIZE = 65507; //!< Maximum UDP datagram size
53 
54 // Add attributes generic to all UdpSockets to base class UdpSocket
55 TypeId
GetTypeId(void)56 UdpSocketImpl::GetTypeId (void)
57 {
58   static TypeId tid = TypeId ("ns3::UdpSocketImpl")
59     .SetParent<UdpSocket> ()
60     .SetGroupName ("Internet")
61     .AddConstructor<UdpSocketImpl> ()
62     .AddTraceSource ("Drop",
63                      "Drop UDP packet due to receive buffer overflow",
64                      MakeTraceSourceAccessor (&UdpSocketImpl::m_dropTrace),
65                      "ns3::Packet::TracedCallback")
66     .AddAttribute ("IcmpCallback", "Callback invoked whenever an icmp error is received on this socket.",
67                    CallbackValue (),
68                    MakeCallbackAccessor (&UdpSocketImpl::m_icmpCallback),
69                    MakeCallbackChecker ())
70     .AddAttribute ("IcmpCallback6", "Callback invoked whenever an icmpv6 error is received on this socket.",
71                    CallbackValue (),
72                    MakeCallbackAccessor (&UdpSocketImpl::m_icmpCallback6),
73                    MakeCallbackChecker ())
74   ;
75   return tid;
76 }
77 
UdpSocketImpl()78 UdpSocketImpl::UdpSocketImpl ()
79   : m_endPoint (0),
80     m_endPoint6 (0),
81     m_node (0),
82     m_udp (0),
83     m_errno (ERROR_NOTERROR),
84     m_shutdownSend (false),
85     m_shutdownRecv (false),
86     m_connected (false),
87     m_rxAvailable (0)
88 {
89   NS_LOG_FUNCTION (this);
90   m_allowBroadcast = false;
91 }
92 
~UdpSocketImpl()93 UdpSocketImpl::~UdpSocketImpl ()
94 {
95   NS_LOG_FUNCTION (this);
96 
97   /// \todo  leave any multicast groups that have been joined
98   m_node = 0;
99   /**
100    * Note: actually this function is called AFTER
101    * UdpSocketImpl::Destroy or UdpSocketImpl::Destroy6
102    * so the code below is unnecessary in normal operations
103    */
104   if (m_endPoint != 0)
105     {
106       NS_ASSERT (m_udp != 0);
107       /**
108        * Note that this piece of code is a bit tricky:
109        * when DeAllocate is called, it will call into
110        * Ipv4EndPointDemux::Deallocate which triggers
111        * a delete of the associated endPoint which triggers
112        * in turn a call to the method UdpSocketImpl::Destroy below
113        * will will zero the m_endPoint field.
114        */
115       NS_ASSERT (m_endPoint != 0);
116       m_udp->DeAllocate (m_endPoint);
117       NS_ASSERT (m_endPoint == 0);
118     }
119   if (m_endPoint6 != 0)
120     {
121       NS_ASSERT (m_udp != 0);
122       /**
123        * Note that this piece of code is a bit tricky:
124        * when DeAllocate is called, it will call into
125        * Ipv4EndPointDemux::Deallocate which triggers
126        * a delete of the associated endPoint which triggers
127        * in turn a call to the method UdpSocketImpl::Destroy below
128        * will will zero the m_endPoint field.
129        */
130       NS_ASSERT (m_endPoint6 != 0);
131       m_udp->DeAllocate (m_endPoint6);
132       NS_ASSERT (m_endPoint6 == 0);
133     }
134   m_udp = 0;
135 }
136 
137 void
SetNode(Ptr<Node> node)138 UdpSocketImpl::SetNode (Ptr<Node> node)
139 {
140   NS_LOG_FUNCTION (this << node);
141   m_node = node;
142 
143 }
144 void
SetUdp(Ptr<UdpL4Protocol> udp)145 UdpSocketImpl::SetUdp (Ptr<UdpL4Protocol> udp)
146 {
147   NS_LOG_FUNCTION (this << udp);
148   m_udp = udp;
149 }
150 
151 
152 enum Socket::SocketErrno
GetErrno(void) const153 UdpSocketImpl::GetErrno (void) const
154 {
155   NS_LOG_FUNCTION (this);
156   return m_errno;
157 }
158 
159 enum Socket::SocketType
GetSocketType(void) const160 UdpSocketImpl::GetSocketType (void) const
161 {
162   return NS3_SOCK_DGRAM;
163 }
164 
165 Ptr<Node>
GetNode(void) const166 UdpSocketImpl::GetNode (void) const
167 {
168   NS_LOG_FUNCTION (this);
169   return m_node;
170 }
171 
172 void
Destroy(void)173 UdpSocketImpl::Destroy (void)
174 {
175   NS_LOG_FUNCTION (this);
176   m_endPoint = 0;
177 }
178 
179 void
Destroy6(void)180 UdpSocketImpl::Destroy6 (void)
181 {
182   NS_LOG_FUNCTION (this);
183   m_endPoint6 = 0;
184 }
185 
186 /* Deallocate the end point and cancel all the timers */
187 void
DeallocateEndPoint(void)188 UdpSocketImpl::DeallocateEndPoint (void)
189 {
190   if (m_endPoint != 0)
191     {
192       m_endPoint->SetDestroyCallback (MakeNullCallback<void> ());
193       m_udp->DeAllocate (m_endPoint);
194       m_endPoint = 0;
195     }
196   if (m_endPoint6 != 0)
197     {
198       m_endPoint6->SetDestroyCallback (MakeNullCallback<void> ());
199       m_udp->DeAllocate (m_endPoint6);
200       m_endPoint6 = 0;
201     }
202 }
203 
204 
205 int
FinishBind(void)206 UdpSocketImpl::FinishBind (void)
207 {
208   NS_LOG_FUNCTION (this);
209   bool done = false;
210   if (m_endPoint != 0)
211     {
212       m_endPoint->SetRxCallback (MakeCallback (&UdpSocketImpl::ForwardUp, Ptr<UdpSocketImpl> (this)));
213       m_endPoint->SetIcmpCallback (MakeCallback (&UdpSocketImpl::ForwardIcmp, Ptr<UdpSocketImpl> (this)));
214       m_endPoint->SetDestroyCallback (MakeCallback (&UdpSocketImpl::Destroy, Ptr<UdpSocketImpl> (this)));
215       done = true;
216     }
217   if (m_endPoint6 != 0)
218     {
219       m_endPoint6->SetRxCallback (MakeCallback (&UdpSocketImpl::ForwardUp6, Ptr<UdpSocketImpl> (this)));
220       m_endPoint6->SetIcmpCallback (MakeCallback (&UdpSocketImpl::ForwardIcmp6, Ptr<UdpSocketImpl> (this)));
221       m_endPoint6->SetDestroyCallback (MakeCallback (&UdpSocketImpl::Destroy6, Ptr<UdpSocketImpl> (this)));
222       done = true;
223     }
224   if (done)
225     {
226       return 0;
227     }
228   return -1;
229 }
230 
231 int
Bind(void)232 UdpSocketImpl::Bind (void)
233 {
234   NS_LOG_FUNCTION (this);
235   m_endPoint = m_udp->Allocate ();
236   if (m_boundnetdevice)
237     {
238       m_endPoint->BindToNetDevice (m_boundnetdevice);
239     }
240   return FinishBind ();
241 }
242 
243 int
Bind6(void)244 UdpSocketImpl::Bind6 (void)
245 {
246   NS_LOG_FUNCTION (this);
247   m_endPoint6 = m_udp->Allocate6 ();
248   if (m_boundnetdevice)
249     {
250       m_endPoint6->BindToNetDevice (m_boundnetdevice);
251     }
252   return FinishBind ();
253 }
254 
255 int
Bind(const Address & address)256 UdpSocketImpl::Bind (const Address &address)
257 {
258   NS_LOG_FUNCTION (this << address);
259 
260   if (InetSocketAddress::IsMatchingType (address))
261     {
262       NS_ASSERT_MSG (m_endPoint == 0, "Endpoint already allocated.");
263 
264       InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
265       Ipv4Address ipv4 = transport.GetIpv4 ();
266       uint16_t port = transport.GetPort ();
267       SetIpTos (transport.GetTos ());
268       if (ipv4 == Ipv4Address::GetAny () && port == 0)
269         {
270           m_endPoint = m_udp->Allocate ();
271         }
272       else if (ipv4 == Ipv4Address::GetAny () && port != 0)
273         {
274           m_endPoint = m_udp->Allocate (GetBoundNetDevice (), port);
275         }
276       else if (ipv4 != Ipv4Address::GetAny () && port == 0)
277         {
278           m_endPoint = m_udp->Allocate (ipv4);
279         }
280       else if (ipv4 != Ipv4Address::GetAny () && port != 0)
281         {
282           m_endPoint = m_udp->Allocate (GetBoundNetDevice (), ipv4, port);
283         }
284       if (0 == m_endPoint)
285         {
286           m_errno = port ? ERROR_ADDRINUSE : ERROR_ADDRNOTAVAIL;
287           return -1;
288         }
289       if (m_boundnetdevice)
290         {
291           m_endPoint->BindToNetDevice (m_boundnetdevice);
292         }
293 
294     }
295   else if (Inet6SocketAddress::IsMatchingType (address))
296     {
297       NS_ASSERT_MSG (m_endPoint == 0, "Endpoint already allocated.");
298 
299       Inet6SocketAddress transport = Inet6SocketAddress::ConvertFrom (address);
300       Ipv6Address ipv6 = transport.GetIpv6 ();
301       uint16_t port = transport.GetPort ();
302       if (ipv6 == Ipv6Address::GetAny () && port == 0)
303         {
304           m_endPoint6 = m_udp->Allocate6 ();
305         }
306       else if (ipv6 == Ipv6Address::GetAny () && port != 0)
307         {
308           m_endPoint6 = m_udp->Allocate6 (GetBoundNetDevice (), port);
309         }
310       else if (ipv6 != Ipv6Address::GetAny () && port == 0)
311         {
312           m_endPoint6 = m_udp->Allocate6 (ipv6);
313         }
314       else if (ipv6 != Ipv6Address::GetAny () && port != 0)
315         {
316           m_endPoint6 = m_udp->Allocate6 (GetBoundNetDevice (), ipv6, port);
317         }
318       if (0 == m_endPoint6)
319         {
320           m_errno = port ? ERROR_ADDRINUSE : ERROR_ADDRNOTAVAIL;
321           return -1;
322         }
323       if (m_boundnetdevice)
324         {
325           m_endPoint6->BindToNetDevice (m_boundnetdevice);
326         }
327 
328       if (ipv6.IsMulticast ())
329         {
330           Ptr<Ipv6L3Protocol> ipv6l3 = m_node->GetObject <Ipv6L3Protocol> ();
331           if (ipv6l3)
332             {
333               if (m_boundnetdevice == 0)
334                 {
335                   ipv6l3->AddMulticastAddress (ipv6);
336                 }
337               else
338                 {
339                   uint32_t index = ipv6l3->GetInterfaceForDevice (m_boundnetdevice);
340                   ipv6l3->AddMulticastAddress (m_endPoint6->GetLocalAddress (), index);
341                 }
342             }
343         }
344     }
345   else
346     {
347       NS_LOG_ERROR ("Not IsMatchingType");
348       m_errno = ERROR_INVAL;
349       return -1;
350     }
351 
352   return FinishBind ();
353 }
354 
355 int
ShutdownSend(void)356 UdpSocketImpl::ShutdownSend (void)
357 {
358   NS_LOG_FUNCTION (this);
359   m_shutdownSend = true;
360   return 0;
361 }
362 
363 int
ShutdownRecv(void)364 UdpSocketImpl::ShutdownRecv (void)
365 {
366   NS_LOG_FUNCTION (this);
367   m_shutdownRecv = true;
368   if (m_endPoint)
369     {
370       m_endPoint->SetRxEnabled (false);
371     }
372   if (m_endPoint6)
373     {
374       m_endPoint6->SetRxEnabled (false);
375     }
376   return 0;
377 }
378 
379 int
Close(void)380 UdpSocketImpl::Close (void)
381 {
382   NS_LOG_FUNCTION (this);
383   if (m_shutdownRecv == true && m_shutdownSend == true)
384     {
385       m_errno = Socket::ERROR_BADF;
386       return -1;
387     }
388   Ipv6LeaveGroup ();
389   m_shutdownRecv = true;
390   m_shutdownSend = true;
391   DeallocateEndPoint ();
392   return 0;
393 }
394 
395 int
Connect(const Address & address)396 UdpSocketImpl::Connect (const Address & address)
397 {
398   NS_LOG_FUNCTION (this << address);
399   if (InetSocketAddress::IsMatchingType(address) == true)
400     {
401       InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
402       m_defaultAddress = Address(transport.GetIpv4 ());
403       m_defaultPort = transport.GetPort ();
404       SetIpTos (transport.GetTos ());
405       m_connected = true;
406       NotifyConnectionSucceeded ();
407     }
408   else if (Inet6SocketAddress::IsMatchingType(address) == true)
409     {
410       Inet6SocketAddress transport = Inet6SocketAddress::ConvertFrom (address);
411       m_defaultAddress = Address(transport.GetIpv6 ());
412       m_defaultPort = transport.GetPort ();
413       m_connected = true;
414       NotifyConnectionSucceeded ();
415     }
416   else
417     {
418       NotifyConnectionFailed ();
419       return -1;
420     }
421 
422   return 0;
423 }
424 
425 int
Listen(void)426 UdpSocketImpl::Listen (void)
427 {
428   m_errno = Socket::ERROR_OPNOTSUPP;
429   return -1;
430 }
431 
432 int
Send(Ptr<Packet> p,uint32_t flags)433 UdpSocketImpl::Send (Ptr<Packet> p, uint32_t flags)
434 {
435   NS_LOG_FUNCTION (this << p << flags);
436 
437   if (!m_connected)
438     {
439       m_errno = ERROR_NOTCONN;
440       return -1;
441     }
442 
443   return DoSend (p);
444 }
445 
446 int
DoSend(Ptr<Packet> p)447 UdpSocketImpl::DoSend (Ptr<Packet> p)
448 {
449   NS_LOG_FUNCTION (this << p);
450   if ((m_endPoint == 0) && (Ipv4Address::IsMatchingType(m_defaultAddress) == true))
451     {
452       if (Bind () == -1)
453         {
454           NS_ASSERT (m_endPoint == 0);
455           return -1;
456         }
457       NS_ASSERT (m_endPoint != 0);
458     }
459   else if ((m_endPoint6 == 0) && (Ipv6Address::IsMatchingType(m_defaultAddress) == true))
460     {
461       if (Bind6 () == -1)
462         {
463           NS_ASSERT (m_endPoint6 == 0);
464           return -1;
465         }
466       NS_ASSERT (m_endPoint6 != 0);
467     }
468   if (m_shutdownSend)
469     {
470       m_errno = ERROR_SHUTDOWN;
471       return -1;
472     }
473 
474   if (Ipv4Address::IsMatchingType (m_defaultAddress))
475     {
476       return DoSendTo (p, Ipv4Address::ConvertFrom (m_defaultAddress), m_defaultPort, GetIpTos ());
477     }
478   else if (Ipv6Address::IsMatchingType (m_defaultAddress))
479     {
480       return DoSendTo (p, Ipv6Address::ConvertFrom (m_defaultAddress), m_defaultPort);
481     }
482 
483   m_errno = ERROR_AFNOSUPPORT;
484   return(-1);
485 }
486 
487 int
DoSendTo(Ptr<Packet> p,Ipv4Address dest,uint16_t port,uint8_t tos)488 UdpSocketImpl::DoSendTo (Ptr<Packet> p, Ipv4Address dest, uint16_t port, uint8_t tos)
489 {
490   NS_LOG_FUNCTION (this << p << dest << port << (uint16_t) tos);
491   if (m_boundnetdevice)
492     {
493       NS_LOG_LOGIC ("Bound interface number " << m_boundnetdevice->GetIfIndex ());
494     }
495   if (m_endPoint == 0)
496     {
497       if (Bind () == -1)
498         {
499           NS_ASSERT (m_endPoint == 0);
500           return -1;
501         }
502       NS_ASSERT (m_endPoint != 0);
503     }
504   if (m_shutdownSend)
505     {
506       m_errno = ERROR_SHUTDOWN;
507       return -1;
508     }
509 
510   if (p->GetSize () > GetTxAvailable () )
511     {
512       m_errno = ERROR_MSGSIZE;
513       return -1;
514     }
515 
516   uint8_t priority = GetPriority ();
517   if (tos)
518     {
519       SocketIpTosTag ipTosTag;
520       ipTosTag.SetTos (tos);
521       // This packet may already have a SocketIpTosTag (see BUG 2440)
522       p->ReplacePacketTag (ipTosTag);
523       priority = IpTos2Priority (tos);
524     }
525 
526   if (priority)
527     {
528       SocketPriorityTag priorityTag;
529       priorityTag.SetPriority (priority);
530       p->ReplacePacketTag (priorityTag);
531     }
532 
533   Ptr<Ipv4> ipv4 = m_node->GetObject<Ipv4> ();
534 
535   // Locally override the IP TTL for this socket
536   // We cannot directly modify the TTL at this stage, so we set a Packet tag
537   // The destination can be either multicast, unicast/anycast, or
538   // either all-hosts broadcast or limited (subnet-directed) broadcast.
539   // For the latter two broadcast types, the TTL will later be set to one
540   // irrespective of what is set in these socket options.  So, this tagging
541   // may end up setting the TTL of a limited broadcast packet to be
542   // the same as a unicast, but it will be fixed further down the stack
543   if (m_ipMulticastTtl != 0 && dest.IsMulticast ())
544     {
545       SocketIpTtlTag tag;
546       tag.SetTtl (m_ipMulticastTtl);
547       p->AddPacketTag (tag);
548     }
549   else if (IsManualIpTtl () && GetIpTtl () != 0 && !dest.IsMulticast () && !dest.IsBroadcast ())
550     {
551       SocketIpTtlTag tag;
552       tag.SetTtl (GetIpTtl ());
553       p->AddPacketTag (tag);
554     }
555   {
556     SocketSetDontFragmentTag tag;
557     bool found = p->RemovePacketTag (tag);
558     if (!found)
559       {
560         if (m_mtuDiscover)
561           {
562             tag.Enable ();
563           }
564         else
565           {
566             tag.Disable ();
567           }
568         p->AddPacketTag (tag);
569       }
570   }
571 
572   // Note that some systems will only send limited broadcast packets
573   // out of the "default" interface; here we send it out all interfaces
574   if (dest.IsBroadcast ())
575     {
576       if (!m_allowBroadcast)
577         {
578           m_errno = ERROR_OPNOTSUPP;
579           return -1;
580         }
581       NS_LOG_LOGIC ("Limited broadcast start.");
582       for (uint32_t i = 0; i < ipv4->GetNInterfaces (); i++ )
583         {
584           // Get the primary address
585           Ipv4InterfaceAddress iaddr = ipv4->GetAddress (i, 0);
586           Ipv4Address addri = iaddr.GetLocal ();
587           if (addri == Ipv4Address ("127.0.0.1"))
588             continue;
589           // Check if interface-bound socket
590           if (m_boundnetdevice)
591             {
592               if (ipv4->GetNetDevice (i) != m_boundnetdevice)
593                 continue;
594             }
595           NS_LOG_LOGIC ("Sending one copy from " << addri << " to " << dest);
596           m_udp->Send (p->Copy (), addri, dest,
597                        m_endPoint->GetLocalPort (), port);
598           NotifyDataSent (p->GetSize ());
599           NotifySend (GetTxAvailable ());
600         }
601       NS_LOG_LOGIC ("Limited broadcast end.");
602       return p->GetSize ();
603     }
604   else if (m_endPoint->GetLocalAddress () != Ipv4Address::GetAny ())
605     {
606       m_udp->Send (p->Copy (), m_endPoint->GetLocalAddress (), dest,
607                    m_endPoint->GetLocalPort (), port, 0);
608       NotifyDataSent (p->GetSize ());
609       NotifySend (GetTxAvailable ());
610       return p->GetSize ();
611     }
612   else if (ipv4->GetRoutingProtocol () != 0)
613     {
614       Ipv4Header header;
615       header.SetDestination (dest);
616       header.SetProtocol (UdpL4Protocol::PROT_NUMBER);
617       Socket::SocketErrno errno_;
618       Ptr<Ipv4Route> route;
619       Ptr<NetDevice> oif = m_boundnetdevice; //specify non-zero if bound to a specific device
620       // TBD-- we could cache the route and just check its validity
621       route = ipv4->GetRoutingProtocol ()->RouteOutput (p, header, oif, errno_);
622       if (route != 0)
623         {
624           NS_LOG_LOGIC ("Route exists");
625           if (!m_allowBroadcast)
626             {
627               // Here we try to route subnet-directed broadcasts
628               uint32_t outputIfIndex = ipv4->GetInterfaceForDevice (route->GetOutputDevice ());
629               uint32_t ifNAddr = ipv4->GetNAddresses (outputIfIndex);
630               for (uint32_t addrI = 0; addrI < ifNAddr; ++addrI)
631                 {
632                   Ipv4InterfaceAddress ifAddr = ipv4->GetAddress (outputIfIndex, addrI);
633                   if (dest == ifAddr.GetBroadcast ())
634                     {
635                       m_errno = ERROR_OPNOTSUPP;
636                       return -1;
637                     }
638                 }
639             }
640 
641           header.SetSource (route->GetSource ());
642           m_udp->Send (p->Copy (), header.GetSource (), header.GetDestination (),
643                        m_endPoint->GetLocalPort (), port, route);
644           NotifyDataSent (p->GetSize ());
645           return p->GetSize ();
646         }
647       else
648         {
649           NS_LOG_LOGIC ("No route to destination");
650           NS_LOG_ERROR (errno_);
651           m_errno = errno_;
652           return -1;
653         }
654     }
655   else
656     {
657       NS_LOG_ERROR ("ERROR_NOROUTETOHOST");
658       m_errno = ERROR_NOROUTETOHOST;
659       return -1;
660     }
661 
662   return 0;
663 }
664 
665 int
DoSendTo(Ptr<Packet> p,Ipv6Address dest,uint16_t port)666 UdpSocketImpl::DoSendTo (Ptr<Packet> p, Ipv6Address dest, uint16_t port)
667 {
668   NS_LOG_FUNCTION (this << p << dest << port);
669 
670   if (dest.IsIpv4MappedAddress ())
671     {
672         return (DoSendTo(p, dest.GetIpv4MappedAddress (), port, 0));
673     }
674   if (m_boundnetdevice)
675     {
676       NS_LOG_LOGIC ("Bound interface number " << m_boundnetdevice->GetIfIndex ());
677     }
678   if (m_endPoint6 == 0)
679     {
680       if (Bind6 () == -1)
681         {
682           NS_ASSERT (m_endPoint6 == 0);
683           return -1;
684         }
685       NS_ASSERT (m_endPoint6 != 0);
686     }
687   if (m_shutdownSend)
688     {
689       m_errno = ERROR_SHUTDOWN;
690       return -1;
691     }
692 
693   if (p->GetSize () > GetTxAvailable () )
694     {
695       m_errno = ERROR_MSGSIZE;
696       return -1;
697     }
698 
699   if (IsManualIpv6Tclass ())
700     {
701       SocketIpv6TclassTag ipTclassTag;
702       ipTclassTag.SetTclass (GetIpv6Tclass ());
703       p->AddPacketTag (ipTclassTag);
704     }
705 
706   uint8_t priority = GetPriority ();
707   if (priority)
708     {
709       SocketPriorityTag priorityTag;
710       priorityTag.SetPriority (priority);
711       p->ReplacePacketTag (priorityTag);
712     }
713 
714   Ptr<Ipv6> ipv6 = m_node->GetObject<Ipv6> ();
715 
716   // Locally override the IP TTL for this socket
717   // We cannot directly modify the TTL at this stage, so we set a Packet tag
718   // The destination can be either multicast, unicast/anycast, or
719   // either all-hosts broadcast or limited (subnet-directed) broadcast.
720   // For the latter two broadcast types, the TTL will later be set to one
721   // irrespective of what is set in these socket options.  So, this tagging
722   // may end up setting the TTL of a limited broadcast packet to be
723   // the same as a unicast, but it will be fixed further down the stack
724   if (m_ipMulticastTtl != 0 && dest.IsMulticast ())
725     {
726       SocketIpv6HopLimitTag tag;
727       tag.SetHopLimit (m_ipMulticastTtl);
728       p->AddPacketTag (tag);
729     }
730   else if (IsManualIpv6HopLimit () && GetIpv6HopLimit () != 0 && !dest.IsMulticast ())
731     {
732       SocketIpv6HopLimitTag tag;
733       tag.SetHopLimit (GetIpv6HopLimit ());
734       p->AddPacketTag (tag);
735     }
736   // There is no analgous to an IPv4 broadcast address in IPv6.
737   // Instead, we use a set of link-local, site-local, and global
738   // multicast addresses.  The Ipv6 routing layers should all
739   // provide an interface-specific route to these addresses such
740   // that we can treat these multicast addresses as "not broadcast"
741 
742   if (m_endPoint6->GetLocalAddress () != Ipv6Address::GetAny ())
743     {
744       m_udp->Send (p->Copy (), m_endPoint6->GetLocalAddress (), dest,
745                    m_endPoint6->GetLocalPort (), port, 0);
746       NotifyDataSent (p->GetSize ());
747       NotifySend (GetTxAvailable ());
748       return p->GetSize ();
749     }
750   else if (ipv6->GetRoutingProtocol () != 0)
751     {
752       Ipv6Header header;
753       header.SetDestination (dest);
754       header.SetNextHeader (UdpL4Protocol::PROT_NUMBER);
755       Socket::SocketErrno errno_;
756       Ptr<Ipv6Route> route;
757       Ptr<NetDevice> oif = m_boundnetdevice; //specify non-zero if bound to a specific device
758       // TBD-- we could cache the route and just check its validity
759       route = ipv6->GetRoutingProtocol ()->RouteOutput (p, header, oif, errno_);
760       if (route != 0)
761         {
762           NS_LOG_LOGIC ("Route exists");
763           header.SetSource (route->GetSource ());
764           m_udp->Send (p->Copy (), header.GetSource (), header.GetDestination (),
765                        m_endPoint6->GetLocalPort (), port, route);
766           NotifyDataSent (p->GetSize ());
767           return p->GetSize ();
768         }
769       else
770         {
771           NS_LOG_LOGIC ("No route to destination");
772           NS_LOG_ERROR (errno_);
773           m_errno = errno_;
774           return -1;
775         }
776     }
777   else
778     {
779       NS_LOG_ERROR ("ERROR_NOROUTETOHOST");
780       m_errno = ERROR_NOROUTETOHOST;
781       return -1;
782     }
783 
784   return 0;
785 }
786 
787 
788 // maximum message size for UDP broadcast is limited by MTU
789 // size of underlying link; we are not checking that now.
790 // \todo Check MTU size of underlying link
791 uint32_t
GetTxAvailable(void) const792 UdpSocketImpl::GetTxAvailable (void) const
793 {
794   NS_LOG_FUNCTION (this);
795   // No finite send buffer is modelled, but we must respect
796   // the maximum size of an IP datagram (65535 bytes - headers).
797   return MAX_IPV4_UDP_DATAGRAM_SIZE;
798 }
799 
800 int
SendTo(Ptr<Packet> p,uint32_t flags,const Address & address)801 UdpSocketImpl::SendTo (Ptr<Packet> p, uint32_t flags, const Address &address)
802 {
803   NS_LOG_FUNCTION (this << p << flags << address);
804   if (InetSocketAddress::IsMatchingType (address))
805     {
806       InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
807       Ipv4Address ipv4 = transport.GetIpv4 ();
808       uint16_t port = transport.GetPort ();
809       uint8_t tos = transport.GetTos ();
810       return DoSendTo (p, ipv4, port, tos);
811     }
812   else if (Inet6SocketAddress::IsMatchingType (address))
813     {
814       Inet6SocketAddress transport = Inet6SocketAddress::ConvertFrom (address);
815       Ipv6Address ipv6 = transport.GetIpv6 ();
816       uint16_t port = transport.GetPort ();
817       return DoSendTo (p, ipv6, port);
818     }
819   return -1;
820 }
821 
822 uint32_t
GetRxAvailable(void) const823 UdpSocketImpl::GetRxAvailable (void) const
824 {
825   NS_LOG_FUNCTION (this);
826   // We separately maintain this state to avoid walking the queue
827   // every time this might be called
828   return m_rxAvailable;
829 }
830 
831 Ptr<Packet>
Recv(uint32_t maxSize,uint32_t flags)832 UdpSocketImpl::Recv (uint32_t maxSize, uint32_t flags)
833 {
834   NS_LOG_FUNCTION (this << maxSize << flags);
835 
836   Address fromAddress;
837   Ptr<Packet> packet = RecvFrom (maxSize, flags, fromAddress);
838   return packet;
839 }
840 
841 Ptr<Packet>
RecvFrom(uint32_t maxSize,uint32_t flags,Address & fromAddress)842 UdpSocketImpl::RecvFrom (uint32_t maxSize, uint32_t flags,
843                          Address &fromAddress)
844 {
845   NS_LOG_FUNCTION (this << maxSize << flags);
846 
847   if (m_deliveryQueue.empty () )
848     {
849       m_errno = ERROR_AGAIN;
850       return 0;
851     }
852   Ptr<Packet> p = m_deliveryQueue.front ().first;
853   fromAddress = m_deliveryQueue.front ().second;
854 
855   if (p->GetSize () <= maxSize)
856     {
857       m_deliveryQueue.pop ();
858       m_rxAvailable -= p->GetSize ();
859     }
860   else
861     {
862       p = 0;
863     }
864   return p;
865 }
866 
867 int
GetSockName(Address & address) const868 UdpSocketImpl::GetSockName (Address &address) const
869 {
870   NS_LOG_FUNCTION (this << address);
871   if (m_endPoint != 0)
872     {
873       address = InetSocketAddress (m_endPoint->GetLocalAddress (), m_endPoint->GetLocalPort ());
874     }
875   else if (m_endPoint6 != 0)
876     {
877       address = Inet6SocketAddress (m_endPoint6->GetLocalAddress (), m_endPoint6->GetLocalPort ());
878     }
879   else
880     { // It is possible to call this method on a socket without a name
881       // in which case, behavior is unspecified
882       // Should this return an InetSocketAddress or an Inet6SocketAddress?
883       address = InetSocketAddress (Ipv4Address::GetZero (), 0);
884     }
885   return 0;
886 }
887 
888 int
GetPeerName(Address & address) const889 UdpSocketImpl::GetPeerName (Address &address) const
890 {
891   NS_LOG_FUNCTION (this << address);
892 
893   if (!m_connected)
894     {
895       m_errno = ERROR_NOTCONN;
896       return -1;
897     }
898 
899   if (Ipv4Address::IsMatchingType (m_defaultAddress))
900     {
901       Ipv4Address addr = Ipv4Address::ConvertFrom (m_defaultAddress);
902       InetSocketAddress inet (addr, m_defaultPort);
903       inet.SetTos (GetIpTos ());
904       address = inet;
905     }
906   else if (Ipv6Address::IsMatchingType (m_defaultAddress))
907     {
908       Ipv6Address addr = Ipv6Address::ConvertFrom (m_defaultAddress);
909       address = Inet6SocketAddress (addr, m_defaultPort);
910     }
911   else
912     {
913       NS_ASSERT_MSG (false, "unexpected address type");
914     }
915 
916   return 0;
917 }
918 
919 int
MulticastJoinGroup(uint32_t interface,const Address & groupAddress)920 UdpSocketImpl::MulticastJoinGroup (uint32_t interface, const Address &groupAddress)
921 {
922   NS_LOG_FUNCTION (interface << groupAddress);
923   /*
924    1) sanity check interface
925    2) sanity check that it has not been called yet on this interface/group
926    3) determine address family of groupAddress
927    4) locally store a list of (interface, groupAddress)
928    5) call ipv4->MulticastJoinGroup () or Ipv6->MulticastJoinGroup ()
929   */
930   return 0;
931 }
932 
933 int
MulticastLeaveGroup(uint32_t interface,const Address & groupAddress)934 UdpSocketImpl::MulticastLeaveGroup (uint32_t interface, const Address &groupAddress)
935 {
936   NS_LOG_FUNCTION (interface << groupAddress);
937   /*
938    1) sanity check interface
939    2) determine address family of groupAddress
940    3) delete from local list of (interface, groupAddress); raise a LOG_WARN
941       if not already present (but return 0)
942    5) call ipv4->MulticastLeaveGroup () or Ipv6->MulticastLeaveGroup ()
943   */
944   return 0;
945 }
946 
947 void
BindToNetDevice(Ptr<NetDevice> netdevice)948 UdpSocketImpl::BindToNetDevice (Ptr<NetDevice> netdevice)
949 {
950   NS_LOG_FUNCTION (netdevice);
951 
952   Ptr<NetDevice> oldBoundNetDevice = m_boundnetdevice;
953 
954   Socket::BindToNetDevice (netdevice); // Includes sanity check
955   if (m_endPoint != 0)
956     {
957       m_endPoint->BindToNetDevice (netdevice);
958     }
959 
960   if (m_endPoint6 != 0)
961     {
962       m_endPoint6->BindToNetDevice (netdevice);
963 
964       // The following is to fix the multicast distribution inside the node
965       // and to upgrade it to the actual bound NetDevice.
966       if (m_endPoint6->GetLocalAddress ().IsMulticast ())
967         {
968           Ptr<Ipv6L3Protocol> ipv6l3 = m_node->GetObject <Ipv6L3Protocol> ();
969           if (ipv6l3)
970             {
971               // Cleanup old one
972               if (oldBoundNetDevice)
973                 {
974                   uint32_t index = ipv6l3->GetInterfaceForDevice (oldBoundNetDevice);
975                   ipv6l3->RemoveMulticastAddress (m_endPoint6->GetLocalAddress (), index);
976                 }
977               else
978                 {
979                   ipv6l3->RemoveMulticastAddress (m_endPoint6->GetLocalAddress ());
980                 }
981               // add new one
982               if (netdevice)
983                 {
984                   uint32_t index = ipv6l3->GetInterfaceForDevice (netdevice);
985                   ipv6l3->AddMulticastAddress (m_endPoint6->GetLocalAddress (), index);
986                 }
987               else
988                 {
989                   ipv6l3->AddMulticastAddress (m_endPoint6->GetLocalAddress ());
990                 }
991             }
992         }
993     }
994 
995   return;
996 }
997 
998 void
ForwardUp(Ptr<Packet> packet,Ipv4Header header,uint16_t port,Ptr<Ipv4Interface> incomingInterface)999 UdpSocketImpl::ForwardUp (Ptr<Packet> packet, Ipv4Header header, uint16_t port,
1000                           Ptr<Ipv4Interface> incomingInterface)
1001 {
1002   NS_LOG_FUNCTION (this << packet << header << port);
1003 
1004   if (m_shutdownRecv)
1005     {
1006       return;
1007     }
1008 
1009   // Should check via getsockopt ()..
1010   if (IsRecvPktInfo ())
1011     {
1012       Ipv4PacketInfoTag tag;
1013       packet->RemovePacketTag (tag);
1014       tag.SetAddress (header.GetDestination ());
1015       tag.SetTtl (header.GetTtl ());
1016       tag.SetRecvIf (incomingInterface->GetDevice ()->GetIfIndex ());
1017       packet->AddPacketTag (tag);
1018     }
1019 
1020   //Check only version 4 options
1021   if (IsIpRecvTos ())
1022     {
1023       SocketIpTosTag ipTosTag;
1024       ipTosTag.SetTos (header.GetTos ());
1025       packet->AddPacketTag (ipTosTag);
1026     }
1027 
1028   if (IsIpRecvTtl ())
1029     {
1030       SocketIpTtlTag ipTtlTag;
1031       ipTtlTag.SetTtl (header.GetTtl ());
1032       packet->AddPacketTag (ipTtlTag);
1033     }
1034 
1035   // in case the packet still has a priority tag attached, remove it
1036   SocketPriorityTag priorityTag;
1037   packet->RemovePacketTag (priorityTag);
1038 
1039   if ((m_rxAvailable + packet->GetSize ()) <= m_rcvBufSize)
1040     {
1041       Address address = InetSocketAddress (header.GetSource (), port);
1042       m_deliveryQueue.push (std::make_pair (packet, address));
1043       m_rxAvailable += packet->GetSize ();
1044       NotifyDataRecv ();
1045     }
1046   else
1047     {
1048       // In general, this case should not occur unless the
1049       // receiving application reads data from this socket slowly
1050       // in comparison to the arrival rate
1051       //
1052       // drop and trace packet
1053       NS_LOG_WARN ("No receive buffer space available.  Drop.");
1054       m_dropTrace (packet);
1055     }
1056 }
1057 
1058 void
ForwardUp6(Ptr<Packet> packet,Ipv6Header header,uint16_t port,Ptr<Ipv6Interface> incomingInterface)1059 UdpSocketImpl::ForwardUp6 (Ptr<Packet> packet, Ipv6Header header, uint16_t port, Ptr<Ipv6Interface> incomingInterface)
1060 {
1061   NS_LOG_FUNCTION (this << packet << header.GetSource () << port);
1062 
1063   if (m_shutdownRecv)
1064     {
1065       return;
1066     }
1067 
1068   // Should check via getsockopt ().
1069   if (IsRecvPktInfo ())
1070     {
1071       Ipv6PacketInfoTag tag;
1072       packet->RemovePacketTag (tag);
1073       tag.SetAddress (header.GetDestination ());
1074       tag.SetHoplimit (header.GetHopLimit ());
1075       tag.SetTrafficClass (header.GetTrafficClass ());
1076       tag.SetRecvIf (incomingInterface->GetDevice ()->GetIfIndex ());
1077       packet->AddPacketTag (tag);
1078     }
1079 
1080   // Check only version 6 options
1081   if (IsIpv6RecvTclass ())
1082     {
1083       SocketIpv6TclassTag ipTclassTag;
1084       ipTclassTag.SetTclass (header.GetTrafficClass ());
1085       packet->AddPacketTag (ipTclassTag);
1086     }
1087 
1088   if (IsIpv6RecvHopLimit ())
1089     {
1090       SocketIpv6HopLimitTag ipHopLimitTag;
1091       ipHopLimitTag.SetHopLimit (header.GetHopLimit ());
1092       packet->AddPacketTag (ipHopLimitTag);
1093     }
1094 
1095   // in case the packet still has a priority tag attached, remove it
1096   SocketPriorityTag priorityTag;
1097   packet->RemovePacketTag (priorityTag);
1098 
1099   if ((m_rxAvailable + packet->GetSize ()) <= m_rcvBufSize)
1100     {
1101       Address address = Inet6SocketAddress (header.GetSource (), port);
1102       m_deliveryQueue.push (std::make_pair (packet, address));
1103       m_rxAvailable += packet->GetSize ();
1104       NotifyDataRecv ();
1105     }
1106   else
1107     {
1108       // In general, this case should not occur unless the
1109       // receiving application reads data from this socket slowly
1110       // in comparison to the arrival rate
1111       //
1112       // drop and trace packet
1113       NS_LOG_WARN ("No receive buffer space available.  Drop.");
1114       m_dropTrace (packet);
1115     }
1116 }
1117 
1118 void
ForwardIcmp(Ipv4Address icmpSource,uint8_t icmpTtl,uint8_t icmpType,uint8_t icmpCode,uint32_t icmpInfo)1119 UdpSocketImpl::ForwardIcmp (Ipv4Address icmpSource, uint8_t icmpTtl,
1120                             uint8_t icmpType, uint8_t icmpCode,
1121                             uint32_t icmpInfo)
1122 {
1123   NS_LOG_FUNCTION (this << icmpSource << (uint32_t)icmpTtl << (uint32_t)icmpType <<
1124                    (uint32_t)icmpCode << icmpInfo);
1125   if (!m_icmpCallback.IsNull ())
1126     {
1127       m_icmpCallback (icmpSource, icmpTtl, icmpType, icmpCode, icmpInfo);
1128     }
1129 }
1130 
1131 void
ForwardIcmp6(Ipv6Address icmpSource,uint8_t icmpTtl,uint8_t icmpType,uint8_t icmpCode,uint32_t icmpInfo)1132 UdpSocketImpl::ForwardIcmp6 (Ipv6Address icmpSource, uint8_t icmpTtl,
1133                             uint8_t icmpType, uint8_t icmpCode,
1134                             uint32_t icmpInfo)
1135 {
1136   NS_LOG_FUNCTION (this << icmpSource << (uint32_t)icmpTtl << (uint32_t)icmpType <<
1137                    (uint32_t)icmpCode << icmpInfo);
1138   if (!m_icmpCallback6.IsNull ())
1139     {
1140       m_icmpCallback6 (icmpSource, icmpTtl, icmpType, icmpCode, icmpInfo);
1141     }
1142 }
1143 
1144 void
SetRcvBufSize(uint32_t size)1145 UdpSocketImpl::SetRcvBufSize (uint32_t size)
1146 {
1147   m_rcvBufSize = size;
1148 }
1149 
1150 uint32_t
GetRcvBufSize(void) const1151 UdpSocketImpl::GetRcvBufSize (void) const
1152 {
1153   return m_rcvBufSize;
1154 }
1155 
1156 void
SetIpMulticastTtl(uint8_t ipTtl)1157 UdpSocketImpl::SetIpMulticastTtl (uint8_t ipTtl)
1158 {
1159   m_ipMulticastTtl = ipTtl;
1160 }
1161 
1162 uint8_t
GetIpMulticastTtl(void) const1163 UdpSocketImpl::GetIpMulticastTtl (void) const
1164 {
1165   return m_ipMulticastTtl;
1166 }
1167 
1168 void
SetIpMulticastIf(int32_t ipIf)1169 UdpSocketImpl::SetIpMulticastIf (int32_t ipIf)
1170 {
1171   m_ipMulticastIf = ipIf;
1172 }
1173 
1174 int32_t
GetIpMulticastIf(void) const1175 UdpSocketImpl::GetIpMulticastIf (void) const
1176 {
1177   return m_ipMulticastIf;
1178 }
1179 
1180 void
SetIpMulticastLoop(bool loop)1181 UdpSocketImpl::SetIpMulticastLoop (bool loop)
1182 {
1183   m_ipMulticastLoop = loop;
1184 }
1185 
1186 bool
GetIpMulticastLoop(void) const1187 UdpSocketImpl::GetIpMulticastLoop (void) const
1188 {
1189   return m_ipMulticastLoop;
1190 }
1191 
1192 void
SetMtuDiscover(bool discover)1193 UdpSocketImpl::SetMtuDiscover (bool discover)
1194 {
1195   m_mtuDiscover = discover;
1196 }
1197 bool
GetMtuDiscover(void) const1198 UdpSocketImpl::GetMtuDiscover (void) const
1199 {
1200   return m_mtuDiscover;
1201 }
1202 
1203 bool
SetAllowBroadcast(bool allowBroadcast)1204 UdpSocketImpl::SetAllowBroadcast (bool allowBroadcast)
1205 {
1206   m_allowBroadcast = allowBroadcast;
1207   return true;
1208 }
1209 
1210 bool
GetAllowBroadcast() const1211 UdpSocketImpl::GetAllowBroadcast () const
1212 {
1213   return m_allowBroadcast;
1214 }
1215 
1216 void
Ipv6JoinGroup(Ipv6Address address,Socket::Ipv6MulticastFilterMode filterMode,std::vector<Ipv6Address> sourceAddresses)1217 UdpSocketImpl::Ipv6JoinGroup (Ipv6Address address, Socket::Ipv6MulticastFilterMode filterMode, std::vector<Ipv6Address> sourceAddresses)
1218 {
1219   NS_LOG_FUNCTION (this << address << &filterMode << &sourceAddresses);
1220 
1221   // We can join only one multicast group (or change its params)
1222   NS_ASSERT_MSG ((m_ipv6MulticastGroupAddress == address || m_ipv6MulticastGroupAddress.IsAny ()), "Can join only one IPv6 multicast group.");
1223 
1224   m_ipv6MulticastGroupAddress = address;
1225 
1226   Ptr<Ipv6L3Protocol> ipv6l3 = m_node->GetObject <Ipv6L3Protocol> ();
1227   if (ipv6l3)
1228     {
1229       if (filterMode == INCLUDE && sourceAddresses.empty ())
1230         {
1231           // it is a leave
1232           if (m_boundnetdevice)
1233             {
1234               int32_t index = ipv6l3->GetInterfaceForDevice (m_boundnetdevice);
1235               NS_ASSERT_MSG (index >= 0, "Interface without a valid index");
1236               ipv6l3->RemoveMulticastAddress (address, index);
1237             }
1238           else
1239             {
1240               ipv6l3->RemoveMulticastAddress (address);
1241             }
1242         }
1243       else
1244         {
1245           // it is a join or a modification
1246           if (m_boundnetdevice)
1247             {
1248               int32_t index = ipv6l3->GetInterfaceForDevice (m_boundnetdevice);
1249               NS_ASSERT_MSG (index >= 0, "Interface without a valid index");
1250               ipv6l3->AddMulticastAddress (address, index);
1251             }
1252           else
1253             {
1254               ipv6l3->AddMulticastAddress (address);
1255             }
1256         }
1257     }
1258 }
1259 
1260 } // namespace ns3
1261