Skip to content
New issue

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

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

Already on GitHub? # 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;
 }
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant