Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sending a single UDP packet scattered in memory with sendmsg sends multiple UDP packets #75

Open
cwmos opened this issue Apr 19, 2018 · 0 comments

Comments

@cwmos
Copy link

cwmos commented Apr 19, 2018

Using the sendmsg function it is possible to send a UDP packet by collecting the payload from different parts of memory . This can be done by providing a msghdr to sendmsg with an msg_iovlen>1. However, it seems like DCE will send a packet for each memory location specified.

The patch below solved the problem for me for the particular application I was porting. I haven not looked deeply into this so there may be issues / other things that need to be fixed as well. As an example, there seems to be a similar problem when receiving a UDP packet (I have not tested this particular patch as I have manually reconstructed it from another patch I did test).

diff --git a/model/unix-datagram-socket-fd.cc b/model/unix-datagram-socket-fd.cc
index 5aca622..690b0e0 100644
--- a/model/unix-datagram-socket-fd.cc
+++ b/model/unix-datagram-socket-fd.cc
@@ -282,95 +282,105 @@ UnixDatagramSocketFd::DoSendmsg (const struct msghdr *msg, int flags)
   BooleanValue isIpHeaderIncluded (false);
   m_socket->GetAttributeFailSafe ("IpHeaderInclude", isIpHeaderIncluded);
 
-  ssize_t retval = 0;
+  int iov_idx=0;
   Ipv4Header ipHeader;
-  for (uint32_t i = 0; i < msg->msg_iovlen; ++i)
-    {
-      uint8_t *buf = (uint8_t *)msg->msg_iov[i].iov_base;
-      uint32_t len = msg->msg_iov[i].iov_len;
+  if(isIpHeaderIncluded && iov_idx<msg->msg_iovlen) {
+    struct ip *iph = (struct ip *)msg->msg_iov[iov_idx++].iov_base;;
+    NS_ASSERT_MSG (m_socket->GetInstanceTypeId () == TypeId::LookupByName ("ns3::Ipv4RawSocketImpl"),
+                   "IsIpHdrIncl==TRUE make sense only for Ipv4RawSocketImpl sockets");
+    ipHeader.SetSource (Ipv4Address (htonl (iph->ip_src.s_addr)));
+    ipHeader.SetDestination (Ipv4Address (htonl (iph->ip_dst.s_addr)));
+    ipHeader.SetProtocol (iph->ip_p);
+    ipHeader.SetPayloadSize (ntohs (iph->ip_len) - 20);
+    ipHeader.SetTtl (iph->ip_ttl);
+  }
+
+  Ptr<Packet> packet;
+  int result;
+  if(msg->msg_iovlen - iov_idx == 0) {
+    return 0;
+  } else if(msg->msg_iovlen - iov_idx==1) {
+    uint8_t* buf = (uint8_t *)msg->msg_iov[iov_idx].iov_base;
+    result = msg->msg_iov[iov_idx].iov_len;
+    packet=Create<Packet> (buf, result);
+  } else {
+    result=0;
+    for(int i=iov_idx; i<msg->msg_iovlen; i++)
+      result+=msg->msg_iov[i].iov_len;
+    uint8_t* buf=(uint8_t*)alloca(result);
+    uint32_t ofs=0;
+    for(int i=iov_idx; i<msg->msg_iovlen; i++) {
+      uint32_t len=msg->msg_iov[i].iov_len;
+      memcpy(buf+ofs,msg->msg_iov[i].iov_base,len);
+      ofs+=len;
+    }
+    packet=Create<Packet> (buf,result);
+  }
 
-      if (isIpHeaderIncluded && i == 0)
-        {
-          struct ip *iph = (struct ip *)buf;
-          NS_ASSERT_MSG (m_socket->GetInstanceTypeId () == TypeId::LookupByName ("ns3::Ipv4RawSocketImpl"),
-                         "IsIpHdrIncl==TRUE make sense only for Ipv4RawSocketImpl sockets");
-
-          ipHeader.SetSource (Ipv4Address (htonl (iph->ip_src.s_addr)));
-          ipHeader.SetDestination (Ipv4Address (htonl (iph->ip_dst.s_addr)));
-          ipHeader.SetProtocol (iph->ip_p);
-          ipHeader.SetPayloadSize (ntohs (iph->ip_len) - 20);
-          ipHeader.SetTtl (iph->ip_ttl);
-          continue;
-        }
+  if (isIpHeaderIncluded)
+  {
+    packet->AddHeader (ipHeader);
+  }
 
-      Ptr<Packet> packet = Create<Packet> (buf, len);
-      if (isIpHeaderIncluded)
-        {
-          packet->AddHeader (ipHeader);
-        }
+  if (msg->msg_name != 0 && msg->msg_namelen != 0)
+    {
+      Address ad;
 
-      int result;
-      if (msg->msg_name != 0 && msg->msg_namelen != 0)
+      if (DynamicCast<PacketSocket> (m_socket))
         {
-          Address ad;
-
-          if (DynamicCast<PacketSocket> (m_socket))
+          Ptr<PacketSocket> s = DynamicCast<PacketSocket> (m_socket);
+          struct sockaddr_ll* addr = (struct sockaddr_ll*)msg->msg_name;
+          Mac48Address dest;
+          PacketSocketAddress pad;
+
+          dest.CopyFrom (addr->sll_addr);
+          pad.SetPhysicalAddress (dest);
+
+          // Retrieve binded protocol
+          Address binded = pad;
+          s->GetSockName (binded);
+          if (PacketSocketAddress::IsMatchingType (binded))
             {
-              Ptr<PacketSocket> s = DynamicCast<PacketSocket> (m_socket);
-              struct sockaddr_ll* addr = (struct sockaddr_ll*)msg->msg_name;
-              Mac48Address dest;
-              PacketSocketAddress pad;
-
-              dest.CopyFrom (addr->sll_addr);
-              pad.SetPhysicalAddress (dest);
-
-              // Retrieve binded protocol
-              Address binded = pad;
-              s->GetSockName (binded);
-              if (PacketSocketAddress::IsMatchingType (binded))
-                {
-                  PacketSocketAddress pad2 = PacketSocketAddress::ConvertFrom (binded);
-
-                  pad.SetProtocol (pad2.GetProtocol ());
-                }
+              PacketSocketAddress pad2 = PacketSocketAddress::ConvertFrom (binded);
 
-              // Set Interface index
-              if (addr->sll_ifindex > 0)
-                {
-                  pad.SetSingleDevice (addr->sll_ifindex - 1);
-                }
-              else
-                {
-                  pad.SetAllDevices ();
-                }
+              pad.SetProtocol (pad2.GetProtocol ());
+            }
 
-              ad = pad;
-              packet->RemoveAtStart (14);
+          // Set Interface index
+          if (addr->sll_ifindex > 0)
+            {
+              pad.SetSingleDevice (addr->sll_ifindex - 1);
             }
           else
             {
-              ad = PosixAddressToNs3Address ((const struct sockaddr *)msg->msg_name,
-                                             (socklen_t)msg->msg_namelen);
+              pad.SetAllDevices ();
             }
-          TaskManager *manager = TaskManager::Current ();
 
-          result = -1;
-          manager->ExecOnMain (MakeEvent (&UnixDatagramSocketFd::MainSendTo,
-                                          this, &result, packet, flags, ad));
+          ad = pad;
+          packet->RemoveAtStart (14);
         }
       else
         {
-          TaskManager *manager = TaskManager::Current ();
-          result = -1;
-          manager->ExecOnMain (MakeEvent (&UnixDatagramSocketFd::MainSend,
-                                          this, &result, packet));
+          ad = PosixAddressToNs3Address ((const struct sockaddr *)msg->msg_name,
+                                         (socklen_t)msg->msg_namelen);
         }
-      if (result == -1)
-        {
-          current->err = ErrnoToSimuErrno ();
-          return -1;
-        }
-      retval += result;
+      TaskManager *manager = TaskManager::Current ();
+
+      result = -1;
+      manager->ExecOnMain (MakeEvent (&UnixDatagramSocketFd::MainSendTo,
+                                      this, &result, packet, flags, ad));
+    }
+  else
+    {
+      TaskManager *manager = TaskManager::Current ();
+      result = -1;
+      manager->ExecOnMain (MakeEvent (&UnixDatagramSocketFd::MainSend,
+                                      this, &result, packet));
+    }
+  if (result == -1)
+    {
+      current->err = ErrnoToSimuErrno ();
+      return -1;
     }
   return retval;
 }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant