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