ns-3 Direct Code Execution
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
unix-datagram-socket-fd.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2006,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 #include "process.h"
21 #include "dce-manager.h"
22 #include "utils.h"
24 #include "ns3/log.h"
25 #include "ns3/socket.h"
26 #include "ns3/packet.h"
27 #include "ns3/simulator.h"
28 #include "ns3/inet-socket-address.h"
29 #include "ns3/packet-socket-address.h"
30 #include "ns3/packet-socket.h"
31 #include "ns3/point-to-point-net-device.h"
32 #include "ns3/mac48-address.h"
33 #include "ns3/boolean.h"
34 #include "ns3/node.h"
35 #include "ns3/ipv4.h"
36 #include "ns3/ipv6.h"
37 #include "ns3/ipv4-packet-info-tag.h"
38 #include "ns3/ipv6-packet-info-tag.h"
39 #include "cmsg.h"
40 #include <errno.h>
41 #include <netinet/in.h>
42 #include <netinet/ip.h>
43 #include <linux/types.h>
44 #include <linux/errqueue.h>
45 #include <arpa/inet.h>
46 #include <linux/if_arp.h>
47 #include <poll.h>
48 NS_LOG_COMPONENT_DEFINE ("UnixDatagramSocketFd");
49 
50 namespace ns3 {
51 
53  : UnixSocketFd (sock)
54 {
55  // XXX: should I really do this here ?
56  m_socket->SetAttributeFailSafe ("IcmpCallback", CallbackValue (MakeCallback (&UnixDatagramSocketFd::IcmpCallback, this)));
57 }
58 
59 bool
61 {
62  return m_socket != 0 && m_socket->GetRxAvailable () != 0;
63 }
64 bool
66 {
67  return m_socket != 0 && m_socket->GetTxAvailable () != 0;
68 }
69 bool
71 {
72  return false;
73 }
74 void
75 UnixDatagramSocketFd::QueueErr (sock_extended_err ee, struct sockaddr_in offender, uint8_t ttl)
76 {
77  NS_LOG_FUNCTION (this);
78  if (!IsRecvErr ())
79  {
80  return;
81  }
82  struct Error e;
83  e.ee = ee;
84  e.offender = offender;
85  e.ttl = ttl;
86  m_errQueue.push_back (e);
87 }
88 
89 void
90 UnixDatagramSocketFd::IcmpCallback (Ipv4Address icmpSource, uint8_t icmpTtl,
91  uint8_t icmpType, uint8_t icmpCode,
92  uint32_t icmpInfo)
93 {
94  NS_LOG_FUNCTION (this << icmpSource << (uint32_t)icmpTtl << (uint32_t)icmpType <<
95  (uint32_t)icmpCode << icmpInfo);
96  // received icmp errors never interrupt a blocked recv and
97  // never notify a blocked select/poll.
98 
99  sock_extended_err ee;
100  struct sockaddr_in offender;
101 
102  if (icmpType == Icmpv4Header::DEST_UNREACH
103  && icmpCode == Icmpv4DestinationUnreachable::FRAG_NEEDED)
104  {
105  ee.ee_errno = EMSGSIZE;
106  }
107  else if (icmpType == Icmpv4Header::DEST_UNREACH
108  && icmpCode == Icmpv4DestinationUnreachable::PORT_UNREACHABLE)
109  {
110  ee.ee_errno = EHOSTUNREACH;
111  }
112  else if (icmpType == Icmpv4Header::TIME_EXCEEDED
113  && icmpCode == Icmpv4TimeExceeded::TIME_TO_LIVE)
114  {
115  ee.ee_errno = EHOSTUNREACH;
116  }
117  else if (icmpType == Icmpv4Header::TIME_EXCEEDED
118  && icmpCode == Icmpv4TimeExceeded::FRAGMENT_REASSEMBLY)
119  {
120  ee.ee_errno = ETIMEDOUT;
121  }
122  else
123  {
124  NS_ASSERT (false);
125  ee.ee_errno = 0;
126  }
127  ee.ee_origin = SO_EE_ORIGIN_ICMP;
128  ee.ee_type = icmpType;
129  ee.ee_code = icmpCode;
130  ee.ee_pad = 0;
131  ee.ee_info = icmpInfo;
132  ee.ee_data = 0;
133  offender.sin_family = AF_INET;
134  offender.sin_addr.s_addr = htonl (icmpSource.Get ());
135  offender.sin_port = 0;
136  memset (offender.sin_zero, 0, sizeof (offender.sin_zero));
137  QueueErr (ee, offender, icmpTtl);
138 }
139 
140 ssize_t
141 UnixDatagramSocketFd::DoRecvmsg (struct msghdr *msg, int flags)
142 {
143  Thread *current = Current ();
144  NS_LOG_FUNCTION (this << current);
145  NS_ASSERT (current != 0);
146 
147  if (flags & MSG_ERRQUEUE)
148  {
149  // MSG_ERRQUEUE is valid only for DGRAM sockets.
150  if (m_errQueue.empty ())
151  {
152  current->err = EAGAIN;
153  return -1;
154  }
155 
156  Cmsg cmsg = Cmsg (msg);
157  if (IsRecvErr ())
158  {
159  cmsg.Add (SOL_IP, IP_RECVERR, sizeof (struct Error), (const uint8_t*)&m_errQueue.front ());
160  }
161  if (IsRecvTtl ())
162  {
163  int tmp = m_errQueue.front ().ttl;
164  cmsg.Add (SOL_IP, IP_TTL, sizeof (int), (const uint8_t*)&tmp);
165  }
166  cmsg.Finish ();
167  m_errQueue.pop_front ();
168  return 0;
169  }
170  else
171  {
172  // msg->msg_controllen = 0; // why???
173  }
174 
175  if (!WaitRecvDoSignal (flags & MSG_DONTWAIT))
176  {
177  // current->err set by call above.
178  return -1;
179  }
180 
181  uint32_t count = msg->msg_iov[0].iov_len;
182  uint8_t *buf = (uint8_t *)msg->msg_iov[0].iov_base;
183  // we ignore the secondary items of the iovec buffers.
184  // because we implement a datagram-only socket for now.
185  Address from;
186  Ptr<Packet> packet = m_socket->RecvFrom (count, flags, from);
187  uint32_t l = 0;
188 
189  if (packet == 0)
190  {
191  current->err = ErrnoToSimuErrno ();
192  return -1;
193  }
194  if ((PacketSocketAddress::IsMatchingType (from)))
195  {
196  if (msg->msg_namelen < sizeof (sockaddr_ll))
197  {
198  current->err = EINVAL;
199  return -1;
200  }
201  Ns3AddressToDeviceIndependantPhysicalLayerAddress (from, *packet, (struct sockaddr_ll*)msg->msg_name, &msg->msg_namelen);
202 
203  // XXX: we ignore MSG_TRUNC for the return value.
204  NS_ASSERT (packet->GetSize () + 14 <= count);
205 
206  memset (buf, 0, count);
207  l = packet->CopyData (buf + 14, count - 14) + 14;
208 
209  SocketAddressTag sat;
210  PacketSocketTag pst;
211  bool found;
212 
213  found = packet->PeekPacketTag (pst);
214  if (found)
215  {
216  CopyMacAddress (pst.GetDestAddress (), buf);
217  }
218  found = packet->PeekPacketTag (sat);
219  if (found)
220  {
221  if (PacketSocketAddress::IsMatchingType (sat.GetAddress ()))
222  {
223  PacketSocketAddress psa = PacketSocketAddress::ConvertFrom (sat.GetAddress ());
224  CopyMacAddress (psa.GetPhysicalAddress (), buf);
225  }
226  }
227  memcpy (buf + 12, &(((struct sockaddr_ll *)msg->msg_name)->sll_protocol), 2);
228  }
229  else
230  {
231  Ns3AddressToPosixAddress (from, (struct sockaddr*)msg->msg_name, &msg->msg_namelen);
232 
233  if (msg->msg_controllen > 0)
234  {
235  Cmsg cmsg = Cmsg (msg);
236  if (m_socket->IsRecvPktInfo ())
237  {
238  NS_LOG_DEBUG ("RecvPktInfo requested");
239 
240  Ptr<Node> node = current->process->manager->GetObject<Node> ();
241 
242  Ipv4PacketInfoTag ipv4Tag;
243  bool isTagPresent = packet->PeekPacketTag (ipv4Tag);
244  if (isTagPresent)
245  {
246  struct in_pktinfo pkt;
247  Ptr<Ipv4> ipv4 = node->GetObject<Ipv4> ();
248  pkt.ipi_ifindex = ipv4->GetInterfaceForDevice (node->GetDevice (ipv4Tag.GetRecvIf ()));
249  if (msg->msg_name)
250  {
251  memcpy (&pkt.ipi_addr, msg->msg_name, sizeof (pkt.ipi_addr));
252  }
253  cmsg.Add (SOL_IP, IP_PKTINFO, sizeof (struct in_pktinfo), (const uint8_t *)&pkt);
254 
255  NS_LOG_DEBUG ("ipv4 tag, iface: " << pkt.ipi_ifindex);
256  }
257 
258  Ipv6PacketInfoTag ipv6Tag;
259  isTagPresent = packet->PeekPacketTag (ipv6Tag);
260  if (isTagPresent)
261  {
262  struct in6_pktinfo pkt6;
263  Ptr<Ipv6> ipv6 = node->GetObject<Ipv6> ();
264  pkt6.ipi6_ifindex = ipv6->GetInterfaceForDevice (node->GetDevice (ipv6Tag.GetRecvIf ()));
265  if (msg->msg_name)
266  {
267  memcpy (&pkt6.ipi6_addr, msg->msg_name, sizeof (pkt6.ipi6_addr));
268  }
269  cmsg.Add (SOL_IPV6, IPV6_PKTINFO, sizeof (struct in6_pktinfo), (const uint8_t *)&pkt6);
270  }
271 
272  }
273  cmsg.Finish ();
274  }
275 
276  // XXX: we ignore MSG_TRUNC for the return value.
277  NS_ASSERT (packet->GetSize () <= count);
278  l = packet->CopyData (buf, count);
279  NS_ASSERT (l == packet->GetSize ());
280  }
281 
282  return l;
283 }
284 
285 ssize_t
286 UnixDatagramSocketFd::DoSendmsg (const struct msghdr *msg, int flags)
287 {
288  Thread *current = Current ();
289  NS_LOG_FUNCTION (this << current);
290  NS_ASSERT (current != 0);
291 
292  BooleanValue isIpHeaderIncluded (false);
293  m_socket->GetAttributeFailSafe ("IpHeaderInclude", isIpHeaderIncluded);
294 
295  ssize_t retval = 0;
296  Ipv4Header ipHeader;
297  for (uint32_t i = 0; i < msg->msg_iovlen; ++i)
298  {
299  uint8_t *buf = (uint8_t *)msg->msg_iov[i].iov_base;
300  uint32_t len = msg->msg_iov[i].iov_len;
301 
302  if (isIpHeaderIncluded && i == 0)
303  {
304  struct ip *iph = (struct ip *)buf;
305  NS_ASSERT_MSG (m_socket->GetInstanceTypeId () == TypeId::LookupByName ("ns3::Ipv4RawSocketImpl"),
306  "IsIpHdrIncl==TRUE make sense only for Ipv4RawSocketImpl sockets");
307 
308  ipHeader.SetSource (Ipv4Address (htonl (iph->ip_src.s_addr)));
309  ipHeader.SetDestination (Ipv4Address (htonl (iph->ip_dst.s_addr)));
310  ipHeader.SetProtocol (iph->ip_p);
311  ipHeader.SetPayloadSize (ntohs (iph->ip_len) - 20);
312  ipHeader.SetTtl (iph->ip_ttl);
313  continue;
314  }
315 
316  Ptr<Packet> packet = Create<Packet> (buf, len);
317  if (isIpHeaderIncluded)
318  {
319  packet->AddHeader (ipHeader);
320  }
321 
322  int result;
323  if (msg->msg_name != 0 && msg->msg_namelen != 0)
324  {
325  Address ad;
326 
327  if (DynamicCast<PacketSocket> (m_socket))
328  {
329  Ptr<PacketSocket> s = DynamicCast<PacketSocket> (m_socket);
330  struct sockaddr_ll* addr = (struct sockaddr_ll*)msg->msg_name;
331  Mac48Address dest;
332  PacketSocketAddress pad;
333 
334  dest.CopyFrom (addr->sll_addr);
335  pad.SetPhysicalAddress (dest);
336 
337  // Retrieve binded protocol
338  Address binded = pad;
339  s->GetSockName (binded);
340  if (PacketSocketAddress::IsMatchingType (binded))
341  {
342  PacketSocketAddress pad2 = PacketSocketAddress::ConvertFrom (binded);
343 
344  pad.SetProtocol (pad2.GetProtocol ());
345  }
346 
347  // Set Interface index
348  if (addr->sll_ifindex > 0)
349  {
350  pad.SetSingleDevice (addr->sll_ifindex - 1);
351  }
352  else
353  {
354  pad.SetAllDevices ();
355  }
356 
357  ad = pad;
358  packet->RemoveAtStart (14);
359  }
360  else
361  {
362  ad = PosixAddressToNs3Address ((const struct sockaddr *)msg->msg_name,
363  (socklen_t)msg->msg_namelen);
364  }
365  TaskManager *manager = TaskManager::Current ();
366 
367  result = -1;
368  manager->ExecOnMain (MakeEvent (&UnixDatagramSocketFd::MainSendTo,
369  this, &result, packet, flags, ad));
370  }
371  else
372  {
373  result = m_socket->Send (packet);
374  }
375  if (result == -1)
376  {
377  current->err = ErrnoToSimuErrno ();
378  return -1;
379  }
380  retval += result;
381  }
382  return retval;
383 }
384 int
386 {
387  Thread *current = Current ();
388  NS_LOG_FUNCTION (this << current);
389  NS_ASSERT (current != 0);
390  current->err = EOPNOTSUPP;
391  return -1;
392 }
393 int
394 UnixDatagramSocketFd::Accept (struct sockaddr *my_addr, socklen_t *addrlen)
395 {
396  Thread *current = Current ();
397  NS_LOG_FUNCTION (this << current << my_addr << addrlen);
398  NS_ASSERT (current != 0);
399  current->err = EOPNOTSUPP;
400  return -1;
401 }
402 int
404 {
405  Thread *current = Current ();
406  NS_LOG_FUNCTION (this << current << how);
407  NS_ASSERT (current != 0);
408  // XXX: linux does not generate EOPNOTSUPP for this. I _think_ it
409  // generates ENOTCONN which, honestly, makes _zero_ sense.
410  current->err = EOPNOTSUPP;
411  return -1;
412 }
413 void
414 UnixDatagramSocketFd::CopyMacAddress (const Address &a, uint8_t* const buf)
415 {
416  if (Mac48Address::IsMatchingType (a))
417  {
418  uint8_t addr[8];
419  uint32_t l = a.CopyAllTo (addr, sizeof (addr));
420 
421  if ((sizeof (addr) == l) && (addr[1] == 6))
422  {
423  memcpy (buf, addr + 2, 6);
424  }
425  }
426 }
427 int
429 {
430  int ret = 0;
431 
432  if (CanRecv ())
433  {
434  ret |= POLLIN;
435  }
436  if (CanSend ())
437  {
438  ret |= POLLOUT;
439  }
440  if (HangupReceived ())
441  {
442  ret |= POLLHUP;
443  }
444 
445  if (ptable)
446  {
447  ptable->PollWait (this);
448  }
449 
450  return ret;
451 }
452 void
453 UnixDatagramSocketFd::MainSendTo (int *r, Ptr<Packet> p, uint32_t f, Address ad)
454 {
455  *r = m_socket->SendTo (p, f, ad);
456 }
457 } // namespace ns3