Bug 1249518 - Make DaemonSocketPDU able to send multiple file descriptors in single unit. r=tzimmermann
authorJames Cheng <jacheng@mozilla.com>
Wed, 30 Mar 2016 14:58:13 +0800
changeset 291695 078c99acf35ab27a10c03f1385552e34158c0f5d
parent 291694 79728047389a199075f17fff34c0aefcfdafcc96
child 291696 e99061fde28a93d29e0032903d56cc6bec451557
push id74648
push usercbook@mozilla.com
push dateTue, 05 Apr 2016 14:54:47 +0000
treeherdermozilla-inbound@98a2f0b4690a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstzimmermann
bugs1249518
milestone48.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1249518 - Make DaemonSocketPDU able to send multiple file descriptors in single unit. r=tzimmermann
dom/bluetooth/bluedroid/BluetoothDaemonSocketInterface.cpp
ipc/hal/DaemonSocketPDU.cpp
ipc/hal/DaemonSocketPDU.h
--- a/dom/bluetooth/bluedroid/BluetoothDaemonSocketInterface.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonSocketInterface.cpp
@@ -216,17 +216,21 @@ public:
   : PDUInitOp(aPDU)
   { }
 
   nsresult
   operator () (int& aArg1) const
   {
     DaemonSocketPDU& pdu = GetPDU();
 
-    aArg1 = pdu.AcquireFd();
+    auto receiveFds = pdu.AcquireFds();
+    if (NS_WARN_IF(receiveFds.Length() == 0)) {
+      return NS_ERROR_ILLEGAL_VALUE;
+    }
+    aArg1 = receiveFds[0];
 
     if (NS_WARN_IF(aArg1 < 0)) {
       return NS_ERROR_ILLEGAL_VALUE;
     }
     WarnAboutTrailingData();
     return NS_OK;
   }
 };
@@ -273,17 +277,24 @@ public:
 };
 
 void
 BluetoothDaemonSocketModule::ConnectRsp(const DaemonSocketPDUHeader& aHeader,
                                         DaemonSocketPDU& aPDU,
                                         BluetoothSocketResultHandler* aRes)
 {
   /* the file descriptor is attached in the PDU's ancillary data */
-  int fd = aPDU.AcquireFd();
+  auto receiveFds = aPDU.AcquireFds();
+  if (receiveFds.Length() == 0) {
+    ErrorRunnable::Dispatch(aRes, &BluetoothSocketResultHandler::OnError,
+                            ConstantInitOp1<BluetoothStatus>(STATUS_FAIL));
+    return;
+  }
+  int fd = -1;
+  fd = receiveFds[0];
   if (fd < 0) {
     ErrorRunnable::Dispatch(aRes, &BluetoothSocketResultHandler::OnError,
                             ConstantInitOp1<BluetoothStatus>(STATUS_FAIL));
     return;
   }
 
   /* receive Bluedroid's socket-setup messages */
   Task* t = new SocketMessageWatcherTask(new ConnectWatcher(fd, aRes));
--- a/ipc/hal/DaemonSocketPDU.cpp
+++ b/ipc/hal/DaemonSocketPDU.cpp
@@ -114,17 +114,17 @@ DaemonSocketPDU::Send(int aFd)
 ssize_t
 DaemonSocketPDU::Receive(int aFd)
 {
   struct iovec iv;
   memset(&iv, 0, sizeof(iv));
   iv.iov_base = GetData(0);
   iv.iov_len = GetAvailableSpace();
 
-  uint8_t cmsgbuf[CMSG_SPACE(sizeof(int))];
+  uint8_t cmsgbuf[CMSG_SPACE(sizeof(int)* MAX_NFDS)];
 
   struct msghdr msg;
   memset(&msg, 0, sizeof(msg));
   msg.msg_iov = &iv;
   msg.msg_iovlen = 1;
   msg.msg_control = cmsgbuf;
   msg.msg_controllen = sizeof(cmsgbuf);
 
@@ -135,34 +135,43 @@ DaemonSocketPDU::Receive(int aFd)
     return -1;
   }
   if (msg.msg_flags & (MSG_CTRUNC | MSG_OOB | MSG_ERRQUEUE)) {
     return -1;
   }
 
   SetRange(0, res);
 
-  struct cmsghdr *chdr = CMSG_FIRSTHDR(&msg);
+  struct cmsghdr* chdr = CMSG_FIRSTHDR(&msg);
 
   for (; chdr; chdr = CMSG_NXTHDR(&msg, chdr)) {
     if (NS_WARN_IF(!CMSGHDR_CONTAINS_FD(chdr))) {
       continue;
     }
-    // Retrieve sent file descriptor. If multiple file descriptors
-    // have been sent, we close all but the final one.
-    mReceivedFd = *(static_cast<int*>(CMSG_DATA(chdr)));
+    // Retrieve sent file descriptors.
+    size_t fdCount = (chdr->cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr))) / sizeof(int);
+    for (size_t i = 0; i < fdCount; i++) {
+      int* receivedFd = static_cast<int*>(CMSG_DATA(chdr)) + i;
+      mReceivedFds.AppendElement(ScopedClose(*receivedFd));
+    }
   }
 
   return res;
 }
 
-int
-DaemonSocketPDU::AcquireFd()
+nsTArray<int>
+DaemonSocketPDU::AcquireFds()
 {
-  return mReceivedFd.forget();
+  // Forget all RAII object to avoid closing the fds.
+  nsTArray<int> fds;
+  for (auto& fd : mReceivedFds) {
+    fds.AppendElement(fd.forget());
+  }
+  mReceivedFds.Clear();
+  return fds;
 }
 
 nsresult
 DaemonSocketPDU::UpdateHeader()
 {
   size_t len = GetPayloadSize();
   if (len >= PDU_MAX_PAYLOAD_LENGTH) {
     return NS_ERROR_ILLEGAL_VALUE;
--- a/ipc/hal/DaemonSocketPDU.h
+++ b/ipc/hal/DaemonSocketPDU.h
@@ -5,20 +5,22 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_ipc_DaemonSocketPDU_h
 #define mozilla_ipc_DaemonSocketPDU_h
 
 #include "mozilla/FileUtils.h"
 #include "mozilla/ipc/SocketBase.h"
 #include "mozilla/ipc/DaemonSocketMessageHandlers.h"
+#include "nsTArray.h"
 
 namespace mozilla {
 namespace ipc {
 
+static const size_t MAX_NFDS = 16;
 class DaemonSocketIOConsumer;
 
 /**
  * |DaemonSocketPDU| represents a single PDU that is transfered from or to
  * the HAL daemon. Each PDU contains exactly one command.
  *
  * A PDU as the following format
  *
@@ -67,26 +69,26 @@ public:
   }
 
   void GetHeader(uint8_t& aService, uint8_t& aOpcode,
                  uint16_t& aPayloadSize);
 
   ssize_t Send(int aFd) override;
   ssize_t Receive(int aFd) override;
 
-  int AcquireFd();
+  nsTArray<int> AcquireFds();
 
   nsresult UpdateHeader();
 
 private:
   size_t GetPayloadSize() const;
   void OnError(const char* aFunction, int aErrno);
 
   DaemonSocketIOConsumer* mConsumer;
   RefPtr<DaemonSocketResultHandler> mRes;
-  ScopedClose mReceivedFd;
+  nsTArray<ScopedClose> mReceivedFds;
 };
 
 }
 }
 
 #endif